66#include "whmac.h"
77#include "cotp.h"
88
9+ static void secure_memzero (void * p , size_t n ) {
10+ volatile unsigned char * vp = (volatile unsigned char * )p ;
11+ while (n -- ) {
12+ * vp ++ = 0 ;
13+ }
14+ }
15+
16+ static size_t b32_decoded_len_from_str (const char * s ) {
17+ if (!s ) return 0 ;
18+ size_t chars = 0 ;
19+ for (const char * p = s ; * p ; ++ p ) {
20+ if (* p != '=' && * p != ' ' ) {
21+ ++ chars ;
22+ }
23+ }
24+ return (chars * 5 ) / 8 ; // floor
25+ }
26+
927#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
1028#define REVERSE_BYTES (C , C_reverse_byte_order ) \
1129 for (int j = 0, i = 7; j < 8; j++, i--) { \
@@ -83,9 +101,11 @@ get_hotp (const char *secret,
83101 return NULL ;
84102 }
85103
104+ size_t dlen = whmac_getlen (hd );
86105 int tk = truncate (hmac , digits , hd );
87106 whmac_freehandle (hd );
88107
108+ secure_memzero (hmac , dlen );
89109 free (hmac );
90110
91111 * err_code = NO_ERROR ;
@@ -183,10 +203,12 @@ get_steam_totp_at (const char *secret,
183203
184204 char * totp = get_steam_code (hmac , hd );
185205
206+ size_t dlen = whmac_getlen (hd );
186207 whmac_freehandle (hd );
187208
188209 * err_code = NO_ERROR ;
189210
211+ secure_memzero (hmac , dlen );
190212 free (hmac );
191213
192214 return totp ;
@@ -234,18 +256,19 @@ static char *
234256get_steam_code (const unsigned char * hmac ,
235257 whmac_handle_t * hd )
236258{
237- int offset = (hmac [whmac_getlen (hd )- 1 ] & 0x0f );
259+ size_t hlen = whmac_getlen (hd );
260+ int offset = (hmac [hlen - 1 ] & 0x0f );
238261
239262 // Starting from the offset, take the successive 4 bytes while stripping the topmost bit to prevent it being handled as a signed integer
240- int bin_code = ((hmac [offset ] & 0x7f ) << 24 ) | ((hmac [offset + 1 ] & 0xff ) << 16 ) | ((hmac [offset + 2 ] & 0xff ) << 8 ) | ((hmac [offset + 3 ] & 0xff ));
263+ uint32_t bin_code = ((uint32_t )( hmac [offset ] & 0x7f ) << 24 ) | ((uint32_t )( hmac [offset + 1 ] & 0xff ) << 16 ) | ((uint32_t )( hmac [offset + 2 ] & 0xff ) << 8 ) | (( uint32_t ) (hmac [offset + 3 ] & 0xff ));
241264
242265 const char steam_alphabet [] = "23456789BCDFGHJKMNPQRTVWXY" ;
243266
244267 char code [6 ];
245268 size_t steam_alphabet_len = strlen (steam_alphabet );
246269 for (int i = 0 ; i < 5 ; i ++ ) {
247- int mod = ( int )( bin_code % steam_alphabet_len ) ;
248- bin_code = ( int )( bin_code / steam_alphabet_len ) ;
270+ uint32_t mod = bin_code % ( uint32_t ) steam_alphabet_len ;
271+ bin_code = bin_code / ( uint32_t ) steam_alphabet_len ;
249272 code [i ] = steam_alphabet [mod ];
250273 }
251274 code [5 ] = '\0' ;
@@ -260,13 +283,17 @@ truncate (const unsigned char *hmac,
260283 whmac_handle_t * hd )
261284{
262285 // take the lower four bits of the last byte
263- int offset = hmac [whmac_getlen (hd ) - 1 ] & 0x0f ;
286+ size_t hlen = whmac_getlen (hd );
287+ int offset = hmac [hlen - 1 ] & 0x0f ;
264288
265289 // Starting from the offset, take the successive 4 bytes while stripping the topmost bit to prevent it being handled as a signed integer
266- int bin_code = ((hmac [offset ] & 0x7f ) << 24 ) | ((hmac [offset + 1 ] & 0xff ) << 16 ) | ((hmac [offset + 2 ] & 0xff ) << 8 ) | ((hmac [offset + 3 ] & 0xff ));
290+ uint32_t bin_code = ((uint32_t )( hmac [offset ] & 0x7f ) << 24 ) | ((uint32_t )( hmac [offset + 1 ] & 0xff ) << 16 ) | ((uint32_t )( hmac [offset + 2 ] & 0xff ) << 8 ) | (( uint32_t ) (hmac [offset + 3 ] & 0xff ));
267291
268- long long int DIGITS_POWER [] = {1 , 10 , 100 , 1000 , 10000 , 100000 , 1000000 , 10000000 , 100000000 , 1000000000 , 10000000000 };
269- int token = (int )(bin_code % DIGITS_POWER [digits_length ]);
292+ uint64_t mod = 1 ;
293+ for (int i = 0 ; i < digits_length ; ++ i ) {
294+ mod *= 10ULL ;
295+ }
296+ int token = (int )(((uint64_t )bin_code ) % mod );
270297
271298 return token ;
272299}
@@ -277,13 +304,13 @@ compute_hmac (const char *K,
277304 long C ,
278305 whmac_handle_t * hd )
279306{
280- size_t secret_len = (size_t )((strlen (K ) + 1.6 - 1 ) / 1.6 );
281-
282307 char * normalized_K = normalize_secret (K );
283308 if (normalized_K == NULL ) {
284309 return NULL ;
285310 }
286311
312+ size_t secret_len = b32_decoded_len_from_str (normalized_K );
313+
287314 cotp_error_t err ;
288315 unsigned char * secret = base32_decode (normalized_K , strlen (normalized_K ), & err );
289316 free (normalized_K );
@@ -297,6 +324,7 @@ compute_hmac (const char *K,
297324 err = whmac_setkey (hd , secret , secret_len );
298325 if (err ) {
299326 fprintf (stderr , "Error while setting the cipher key.\n" );
327+ secure_memzero (secret , secret_len );
300328 free (secret );
301329 return NULL ;
302330 }
@@ -306,17 +334,21 @@ compute_hmac (const char *K,
306334 unsigned char * hmac = calloc (dlen , 1 );
307335 if (hmac == NULL ) {
308336 fprintf (stderr , "Error allocating memory" );
337+ secure_memzero (secret , secret_len );
309338 free (secret );
310339 return NULL ;
311340 }
312341
313342 ssize_t flen = whmac_finalize (hd , hmac , dlen );
314343 if (flen < 0 ) {
315344 fprintf (stderr , "Error getting digest\n" );
345+ secure_memzero (hmac , dlen );
316346 free (hmac );
347+ secure_memzero (secret , secret_len );
317348 free (secret );
318349 return NULL ;
319350 }
351+ secure_memzero (secret , secret_len );
320352 free (secret );
321353
322354 return hmac ;
@@ -331,9 +363,8 @@ finalize (int digits_length,
331363 if (token == NULL ) {
332364 return NULL ;
333365 }
334- char fmt [6 ];
335- sprintf (fmt , "%%0%dd" , digits_length );
336- snprintf (token , digits_length + 1 , fmt , tk );
366+ // Print with leading zeros without building an intermediate format string
367+ snprintf (token , digits_length + 1 , "%0*d" , digits_length , tk );
337368 return token ;
338369}
339370
0 commit comments