└── Google_Authenticator ├── Google_Authenticator.vcproj ├── crypto.cpp ├── crypto.h ├── doublylinkedlist.cpp ├── doublylinkedlist.h ├── globals.h ├── main.cpp ├── utilities.cpp └── utilities.h /Google_Authenticator/Google_Authenticator.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 180 | 181 | 184 | 185 | 188 | 189 | 190 | 195 | 198 | 199 | 202 | 203 | 206 | 207 | 210 | 211 | 212 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /Google_Authenticator/crypto.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "crypto.h" 20 | 21 | #include "globals.h" 22 | #include "utilities.h" 23 | 24 | #define ENCRYPT_BLOCK_SIZE 16 25 | 26 | HCRYPTKEY g_hKey = NULL; 27 | HCRYPTPROV g_hCryptProv = NULL; 28 | 29 | void CleanupCrypto() 30 | { 31 | if ( g_hKey != NULL ) 32 | { 33 | CryptDestroyKey( g_hKey ); 34 | } 35 | 36 | if ( g_hCryptProv != NULL ) 37 | { 38 | CryptReleaseContext( g_hCryptProv, 0 ); 39 | } 40 | } 41 | 42 | void InitializeCrypto() 43 | { 44 | CryptAcquireContext( &g_hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ); 45 | } 46 | 47 | void GenerateKeyFile( char *file_path ) 48 | { 49 | AES_256_KEY_BLOB aes256kb; 50 | 51 | if ( g_hKey != NULL ) 52 | { 53 | CryptDestroyKey( g_hKey ); 54 | g_hKey = NULL; 55 | } 56 | 57 | if ( CryptGenKey( g_hCryptProv, CALG_AES_256, CRYPT_EXPORTABLE, &g_hKey ) ) 58 | { 59 | DWORD kb_length; 60 | if ( CryptExportKey( g_hKey, NULL, PLAINTEXTKEYBLOB, 0, ( BYTE * )&aes256kb, &kb_length ) ) 61 | { 62 | HANDLE hFile = CreateFileA( file_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); 63 | if ( hFile != INVALID_HANDLE_VALUE ) 64 | { 65 | if ( aes256kb.len == 32 ) 66 | { 67 | DWORD write; 68 | WriteFile( hFile, aes256kb.key, aes256kb.len, &write, NULL ); 69 | } 70 | /*else 71 | { 72 | _printf( "Invalid key length.\r\n" ); 73 | }*/ 74 | 75 | CloseHandle( hFile ); 76 | } 77 | /*else 78 | { 79 | _printf( "Unable to open key file for writing.\r\n" ); 80 | }*/ 81 | } 82 | /*else 83 | { 84 | _printf( "Unable to export key file.\r\n" ); 85 | }*/ 86 | } 87 | /*else 88 | { 89 | _printf( "Unable to generate key value.\r\n" ); 90 | }*/ 91 | } 92 | 93 | bool LoadKeyFile( char *file_path ) 94 | { 95 | bool ret = false; 96 | 97 | HANDLE hFile = CreateFileA( file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 98 | if ( hFile != INVALID_HANDLE_VALUE ) 99 | { 100 | if ( GetFileSize( hFile, NULL ) == 32 ) 101 | { 102 | AES_256_KEY_BLOB aes256kb; 103 | aes256kb.header.bType = PLAINTEXTKEYBLOB; 104 | aes256kb.header.bVersion = CUR_BLOB_VERSION; 105 | aes256kb.header.reserved = 0; 106 | aes256kb.header.aiKeyAlg = CALG_AES_256; 107 | 108 | ReadFile( hFile, aes256kb.key, 32, &aes256kb.len, NULL ); 109 | 110 | if ( g_hKey != NULL ) 111 | { 112 | CryptDestroyKey( g_hKey ); 113 | g_hKey = NULL; 114 | } 115 | 116 | if ( CryptImportKey( g_hCryptProv, ( BYTE * )&aes256kb, sizeof( AES_256_KEY_BLOB ), NULL, 0, &g_hKey ) ) 117 | { 118 | ret = true; 119 | } 120 | /*else 121 | { 122 | _printf( "Unable to import key file.\r\n" ); 123 | }*/ 124 | } 125 | /*else 126 | { 127 | _printf( "Invalid key length.\r\n" ); 128 | }*/ 129 | 130 | CloseHandle( hFile ); 131 | } 132 | 133 | return ret; 134 | } 135 | 136 | void DecryptData( char *file_path ) 137 | { 138 | PBYTE pbBuffer = NULL; 139 | DWORD dwBlockLen; 140 | DWORD dwBufferLen; 141 | 142 | dwBlockLen = 1023 * ENCRYPT_BLOCK_SIZE; 143 | 144 | dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE; 145 | 146 | HANDLE hFile = CreateFileA( file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 147 | if ( hFile != INVALID_HANDLE_VALUE ) 148 | { 149 | DWORD read; 150 | 151 | pbBuffer = ( BYTE * )GlobalAlloc( GMEM_FIXED, dwBufferLen ); 152 | if ( pbBuffer != NULL ) 153 | { 154 | DoublyLinkedList *list_item = g_list; 155 | DoublyLinkedList *last_list_item = g_list; 156 | DWORD dwBufferOffset = 0; 157 | 158 | pbBuffer = ( BYTE * )GlobalAlloc( GMEM_FIXED, dwBufferLen ); 159 | if ( pbBuffer != NULL ) 160 | { 161 | BOOL fEOF = FALSE; 162 | do 163 | { 164 | ReadFile( hFile, pbBuffer, dwBufferLen, &read, NULL ); 165 | 166 | if ( read < dwBufferLen ) 167 | { 168 | fEOF = TRUE; 169 | } 170 | 171 | if ( !CryptDecrypt( g_hKey, NULL, fEOF, 0, pbBuffer, &read ) ) 172 | { 173 | break; 174 | } 175 | 176 | BYTE *p = pbBuffer; 177 | dwBufferOffset = 0; 178 | 179 | while ( dwBufferOffset < read ) 180 | { 181 | AUTH_INFO *ai = ( AUTH_INFO * )GlobalAlloc( GPTR, sizeof( AUTH_INFO ) ); 182 | 183 | dwBufferOffset += sizeof( unsigned int ); 184 | if ( dwBufferOffset >= read ) { goto CLEANUP; } 185 | memcpy_s( &ai->username_length, sizeof( unsigned int ), p, sizeof( unsigned int ) ); 186 | p += sizeof( unsigned int ); 187 | 188 | dwBufferOffset += ai->username_length; 189 | if ( dwBufferOffset >= read ) { goto CLEANUP; } 190 | ai->username = ( char * )GlobalAlloc( GMEM_FIXED, ai->username_length + 1 ); 191 | memcpy_s( ai->username, ai->username_length + 1, p, ai->username_length ); 192 | ai->username[ ai->username_length ] = 0; // Sanity. 193 | p += ai->username_length; 194 | 195 | dwBufferOffset += sizeof( unsigned int ); 196 | if ( dwBufferOffset >= read ) { goto CLEANUP; } 197 | memcpy_s( &ai->key_length, sizeof( unsigned int ), p, sizeof( unsigned int ) ); 198 | p += sizeof( unsigned int ); 199 | 200 | dwBufferOffset += ai->key_length; 201 | if ( dwBufferOffset > read ) { goto CLEANUP; } 202 | ai->key = ( char * )GlobalAlloc( GMEM_FIXED, ai->key_length + 1 ); 203 | memcpy_s( ai->key, ai->key_length + 1, p, ai->key_length ); 204 | ai->key[ ai->key_length ] = 0; // Sanity. 205 | p += ai->key_length; 206 | 207 | ai->code = -1; 208 | 209 | DoublyLinkedList *dll = DLL_CreateNode( ( void * )ai ); 210 | DLL_AddNode( &g_list, dll, -1 ); 211 | 212 | ++g_list_count; 213 | 214 | continue; 215 | 216 | CLEANUP: 217 | 218 | GlobalFree( ai->username ); 219 | GlobalFree( ai->key ); 220 | GlobalFree( ai ); 221 | } 222 | } 223 | while ( !fEOF ); 224 | 225 | GlobalFree( pbBuffer ); 226 | } 227 | 228 | CloseHandle( hFile ); 229 | } 230 | } 231 | } 232 | 233 | void EncryptData( char *file_path ) 234 | { 235 | PBYTE pbBuffer = NULL; 236 | DWORD dwBlockLen; 237 | DWORD dwBufferLen; 238 | 239 | dwBlockLen = 1023 * ENCRYPT_BLOCK_SIZE; 240 | dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE; 241 | 242 | HANDLE hFile = CreateFileA( file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 243 | if ( hFile != INVALID_HANDLE_VALUE ) 244 | { 245 | DWORD write; 246 | 247 | pbBuffer = ( BYTE * )GlobalAlloc( GMEM_FIXED, dwBufferLen ); 248 | if ( pbBuffer != NULL ) 249 | { 250 | DoublyLinkedList *list_item; 251 | DoublyLinkedList *last_list_item = g_list; 252 | DWORD dwBufferOffset = 0; 253 | 254 | BOOL fEOF = FALSE; 255 | do 256 | { 257 | list_item = last_list_item; 258 | 259 | while ( list_item != NULL ) 260 | { 261 | AUTH_INFO *ai = ( AUTH_INFO * )list_item->data; 262 | if ( ai != NULL ) 263 | { 264 | if ( dwBufferOffset + sizeof( unsigned int ) + ai->username_length + sizeof( unsigned int ) + ai->key_length <= dwBlockLen ) 265 | { 266 | memcpy_s( pbBuffer + dwBufferOffset, dwBufferLen - dwBufferOffset, &ai->username_length, sizeof( unsigned int ) ); 267 | dwBufferOffset += sizeof( unsigned int ); 268 | if ( ai->username_length > 0 ) 269 | { 270 | memcpy_s( pbBuffer + dwBufferOffset, dwBufferLen - dwBufferOffset, ai->username, ai->username_length ); 271 | dwBufferOffset += ai->username_length; 272 | } 273 | memcpy_s( pbBuffer + dwBufferOffset, dwBufferLen - dwBufferOffset, &ai->key_length, sizeof( unsigned int ) ); 274 | dwBufferOffset += sizeof( unsigned int ); 275 | if ( ai->key_length > 0 ) 276 | { 277 | memcpy_s( pbBuffer + dwBufferOffset, dwBufferLen - dwBufferOffset, ai->key, ai->key_length ); 278 | dwBufferOffset += ai->key_length; 279 | } 280 | } 281 | else 282 | { 283 | break; 284 | } 285 | } 286 | 287 | list_item = list_item->next; 288 | last_list_item = list_item; 289 | } 290 | 291 | if ( list_item == NULL ) 292 | { 293 | fEOF = TRUE; 294 | } 295 | 296 | if ( !CryptEncrypt( g_hKey, NULL, fEOF, 0, pbBuffer, &dwBufferOffset, dwBufferLen ) ) 297 | { 298 | break; 299 | } 300 | 301 | WriteFile( hFile, pbBuffer, dwBufferOffset, &write, NULL ); 302 | 303 | dwBufferOffset = 0; 304 | } 305 | while( !fEOF ); 306 | 307 | GlobalFree( pbBuffer ); 308 | } 309 | 310 | CloseHandle( hFile ); 311 | } 312 | } 313 | 314 | unsigned long GetTOTP( char *key, unsigned int key_length ) 315 | { 316 | unsigned long code = -1; 317 | 318 | HCRYPTPROV hProv = NULL; 319 | HCRYPTHASH hHash = NULL; 320 | HCRYPTKEY hKey = NULL; 321 | HCRYPTHASH hHmacHash = NULL; 322 | PBYTE pbHash = NULL; 323 | DWORD dwDataLen = 0; 324 | HMAC_INFO HmacInfo; 325 | 326 | KEY_BLOB *kb = NULL; 327 | 328 | unsigned char *dkey = ( unsigned char * )GlobalAlloc( GMEM_FIXED, sizeof( unsigned char ) * key_length ); 329 | unsigned int dkey_length = base32_decode( ( unsigned char * )key, dkey ); 330 | 331 | if ( dkey_length == 0 ) 332 | { 333 | goto CLEANUP; 334 | } 335 | 336 | ZeroMemory( &HmacInfo, sizeof( HmacInfo ) ); 337 | HmacInfo.HashAlgid = CALG_SHA1; 338 | 339 | if ( !CryptAcquireContext( &hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET ) ) 340 | { 341 | goto CLEANUP; 342 | } 343 | 344 | DWORD kbSize = sizeof( KEY_BLOB ) + dkey_length; 345 | 346 | kb = ( KEY_BLOB * )GlobalAlloc( GMEM_FIXED, kbSize ); 347 | kb->header.bType = PLAINTEXTKEYBLOB; 348 | kb->header.bVersion = CUR_BLOB_VERSION; 349 | kb->header.reserved = 0; 350 | kb->header.aiKeyAlg = CALG_RC2; 351 | memcpy( &kb->key, dkey, dkey_length ); 352 | kb->len = dkey_length; 353 | 354 | if ( !CryptImportKey( hProv, ( BYTE * )kb, kbSize, 0, CRYPT_IPSEC_HMAC_KEY, &hKey ) ) 355 | { 356 | goto CLEANUP; 357 | } 358 | 359 | if ( !CryptCreateHash( hProv, CALG_HMAC, hKey, 0, &hHmacHash ) ) 360 | { 361 | goto CLEANUP; 362 | } 363 | 364 | if ( !CryptSetHashParam( hHmacHash, HP_HMAC_INFO, ( BYTE * )&HmacInfo, 0 ) ) 365 | { 366 | goto CLEANUP; 367 | } 368 | 369 | unsigned long data = GetUnixTimestamp() / 30; 370 | 371 | BYTE cdata[ 8 ]; 372 | ZeroMemory( &cdata, sizeof( cdata ) ); 373 | 374 | cdata[ 7 ] = ( BYTE )( data & 0xFF ); 375 | cdata[ 6 ] = ( BYTE )( ( data & 0xFF00 ) >> 8 ); 376 | cdata[ 5 ] = ( BYTE )( ( data & 0xFF0000 ) >> 16 ); 377 | cdata[ 4 ] = ( BYTE )( ( data & 0xFF000000 ) >> 24 ); 378 | 379 | if ( !CryptHashData( hHmacHash, cdata, sizeof( cdata ), 0 ) ) 380 | { 381 | goto CLEANUP; 382 | } 383 | 384 | if ( !CryptGetHashParam( hHmacHash, HP_HASHVAL, NULL, &dwDataLen, 0 ) ) 385 | { 386 | goto CLEANUP; 387 | } 388 | 389 | pbHash = ( BYTE * )GlobalAlloc( GMEM_FIXED, dwDataLen ); 390 | if ( pbHash == NULL ) 391 | { 392 | goto CLEANUP; 393 | } 394 | 395 | if ( !CryptGetHashParam( hHmacHash, HP_HASHVAL, pbHash, &dwDataLen, 0 ) ) 396 | { 397 | goto CLEANUP; 398 | } 399 | 400 | unsigned char offset = pbHash[ dwDataLen - 1 ] & 0x0F; 401 | 402 | code = ( ( pbHash[ offset + 0 ] & 0x7F ) << 24 ) | 403 | ( ( pbHash[ offset + 1 ] & 0xFF ) << 16 ) | 404 | ( ( pbHash[ offset + 2 ] & 0xFF ) << 8 ) | 405 | ( pbHash[ offset + 3 ] & 0xFF ); 406 | 407 | code %= 1000000; 408 | 409 | CLEANUP: 410 | 411 | // Free resources. 412 | if ( hHmacHash ) { CryptDestroyHash( hHmacHash ); } 413 | if ( hKey ) { CryptDestroyKey( hKey ); } 414 | if ( hHash ) { CryptDestroyHash( hHash ); } 415 | if ( hProv ) { CryptReleaseContext( hProv, 0 ); } 416 | if ( pbHash ) { GlobalFree( pbHash ); } 417 | if ( dkey ) { GlobalFree( dkey ); } 418 | if ( kb ) { GlobalFree( kb ); } 419 | 420 | return code; 421 | } 422 | -------------------------------------------------------------------------------- /Google_Authenticator/crypto.h: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef _CRYPTO_H 20 | #define _CRYPTO_H 21 | 22 | #define STRICT 23 | #define WIN32_LEAN_AND_MEAN 24 | 25 | #include 26 | #include 27 | 28 | struct AES_256_KEY_BLOB 29 | { 30 | BLOBHEADER header; 31 | DWORD len; 32 | BYTE key[ 32 ]; 33 | }; 34 | 35 | struct KEY_BLOB 36 | { 37 | BLOBHEADER header; 38 | DWORD len; 39 | BYTE *key; 40 | }; 41 | 42 | void InitializeCrypto(); 43 | void CleanupCrypto(); 44 | 45 | void GenerateKeyFile( char *file_path ); 46 | bool LoadKeyFile( char *file_path ); 47 | void EncryptData( char *file_path ); 48 | void DecryptData( char *file_path ); 49 | 50 | unsigned long GetTOTP( char *key, unsigned int key_length ); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Google_Authenticator/doublylinkedlist.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "doublylinkedlist.h" 20 | 21 | #define STRICT 22 | #define WIN32_LEAN_AND_MEAN 23 | #include 24 | 25 | DoublyLinkedList *DLL_CreateNode( void *data ) 26 | { 27 | DoublyLinkedList *dll = ( DoublyLinkedList * )GlobalAlloc( GPTR, sizeof( DoublyLinkedList ) ); 28 | if ( dll != NULL ) 29 | { 30 | dll->next = NULL; 31 | dll->prev = NULL; 32 | dll->data = data; 33 | } 34 | 35 | return dll; 36 | } 37 | 38 | void DLL_RemoveNode( DoublyLinkedList **head, DoublyLinkedList *node ) 39 | { 40 | if ( *head != NULL && node != NULL ) 41 | { 42 | if ( node == *head ) // Node is the head. 43 | { 44 | if ( node->next != NULL ) // See if we can make a new head. 45 | { 46 | if ( node->next != node->prev ) // Make sure the new tail's previous value isn't itself. 47 | { 48 | node->next->prev = node->prev; // Set the new tail. 49 | } 50 | else 51 | { 52 | node->next->prev = NULL; 53 | } 54 | 55 | *head = node->next; 56 | } 57 | else // No head exists now. 58 | { 59 | *head = NULL; 60 | } 61 | } 62 | else if ( node->next == NULL ) // Node is a tail. 63 | { 64 | if ( node->prev != NULL ) // This should always be the case so long as node != head. 65 | { 66 | if ( node->prev != *head ) // Make sure the node's previous value is not the head. 67 | { 68 | if ( ( *head )->prev == node ) // Make sure the head list actually contains the node we're removing. 69 | { 70 | ( *head )->prev = node->prev; // Set the new tail. 71 | } 72 | 73 | node->prev->next = NULL; 74 | } 75 | else // All that exists now is the head. 76 | { 77 | ( *head )->next = NULL; 78 | ( *head )->prev = NULL; 79 | } 80 | } 81 | } 82 | else if ( node->next != NULL && node->prev != NULL ) // Node is between two other nodes. 83 | { 84 | node->prev->next = node->next; 85 | node->next->prev = node->prev; 86 | } 87 | 88 | node->next = NULL; 89 | node->prev = NULL; 90 | } 91 | } 92 | 93 | void DLL_AddNode( DoublyLinkedList **head, DoublyLinkedList *node, int position ) 94 | { 95 | if ( node == NULL ) 96 | { 97 | return; 98 | } 99 | 100 | if ( *head == NULL ) 101 | { 102 | *head = node; 103 | return; 104 | } 105 | 106 | if ( position < 0 ) // Insert node as the new tail. 107 | { 108 | node->next = NULL; 109 | 110 | if ( ( *head )->prev != NULL ) // Head has a tail. 111 | { 112 | node->prev = ( *head )->prev; 113 | ( *head )->prev->next = node; 114 | } 115 | else // Head has no tail. 116 | { 117 | node->prev = *head; 118 | ( *head )->next = node; 119 | } 120 | 121 | ( *head )->prev = node; 122 | } 123 | else if ( position == 0 ) // Insert node as the new head. 124 | { 125 | node->next = *head; 126 | node->prev = ( *head )->prev; 127 | ( *head )->prev = node; 128 | 129 | *head = node; // Set the new head. 130 | } 131 | else 132 | { 133 | int count = 0; 134 | DoublyLinkedList *last_node = *head; 135 | DoublyLinkedList *current_node = ( *head )->next; 136 | while ( current_node != NULL ) 137 | { 138 | if ( ++count == position ) 139 | { 140 | node->next = current_node; 141 | node->prev = last_node; 142 | last_node->next = node; 143 | return; 144 | } 145 | 146 | last_node = current_node; 147 | current_node = current_node->next; 148 | } 149 | 150 | // The position is at the end of the list. Add node as the new tail. 151 | if ( current_node == NULL && ++count == position ) 152 | { 153 | node->next = current_node; 154 | node->prev = last_node; 155 | last_node->next = node; 156 | 157 | ( *head )->prev = node; 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Google_Authenticator/doublylinkedlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef _DOUBLYLINKEDLIST_H 20 | #define _DOUBLYLINKEDLIST_H 21 | 22 | struct DoublyLinkedList 23 | { 24 | DoublyLinkedList *prev; 25 | DoublyLinkedList *next; 26 | void *data; 27 | }; 28 | 29 | 30 | DoublyLinkedList *DLL_CreateNode( void *data ); 31 | 32 | void DLL_RemoveNode( DoublyLinkedList **head, DoublyLinkedList *node ); 33 | void DLL_AddNode( DoublyLinkedList **head, DoublyLinkedList *node, int position ); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Google_Authenticator/globals.h: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef _GLOBALS_H 20 | #define _GLOBALS_H 21 | 22 | // Pretty window. 23 | #pragma comment( linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"" ) 24 | 25 | #define STRICT 26 | #define WIN32_LEAN_AND_MEAN 27 | 28 | #include 29 | #include 30 | 31 | #include "doublylinkedlist.h" 32 | 33 | #define CONSOLE_BUFFER_SIZE MAX_PATH 34 | 35 | #define LEFT_PADDING 5 36 | #define TOP_PADDING 5 37 | 38 | #define HEADER_HEIGHT ( TOP_PADDING + 7 ) 39 | #define TIMER_OFFSET ( HEADER_HEIGHT + 1 ) 40 | #define LIST_OFFSET ( TIMER_OFFSET + 2 ) 41 | #define SELECTION_OFFSET ( LIST_OFFSET + 2 ) 42 | #define LIST_MOD_HEIGHT 3 43 | 44 | #define VISIBLE_LINES 10 45 | 46 | #define FRAME_HEIGHT ( SELECTION_OFFSET + VISIBLE_LINES + LIST_MOD_HEIGHT ) 47 | 48 | #define INPUT_OFFSET ( FRAME_HEIGHT + 2 ) 49 | 50 | struct AUTH_INFO 51 | { 52 | char *key; 53 | char *username; 54 | unsigned int code; 55 | unsigned int key_length; 56 | unsigned int username_length; 57 | }; 58 | 59 | extern DoublyLinkedList *g_list; 60 | extern int g_list_count; 61 | 62 | extern HANDLE g_hInput; 63 | extern HANDLE g_hOutput[ 2 ]; 64 | extern unsigned char current_console; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /Google_Authenticator/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include "globals.h" 22 | #include "utilities.h" 23 | 24 | #include "crypto.h" 25 | 26 | HANDLE g_hInput = NULL; 27 | HANDLE g_hOutput[ 2 ] = { NULL }; 28 | unsigned char current_console = 0; 29 | 30 | char g_console_buffer[ CONSOLE_BUFFER_SIZE + 1 ]; 31 | 32 | unsigned char g_status = 0; 33 | 34 | bool g_timers_running = false; 35 | HANDLE g_timer_semaphore = NULL; 36 | 37 | CRITICAL_SECTION console_cs; 38 | 39 | DoublyLinkedList *g_list = NULL; 40 | DoublyLinkedList *g_first_visible = NULL; 41 | DoublyLinkedList *g_selected_item = NULL; 42 | 43 | short g_selection_offset = 0; 44 | int g_selected_index = 0; 45 | int g_list_count = 0; 46 | 47 | char g_save_path[ MAX_PATH ]; 48 | char g_key_path[ MAX_PATH ]; 49 | 50 | // Ordered by month. 51 | wchar_t *month_string_table[ 12 ] = 52 | { 53 | L"January", 54 | L"February", 55 | L"March", 56 | L"April", 57 | L"May", 58 | L"June", 59 | L"July", 60 | L"August", 61 | L"September", 62 | L"October", 63 | L"November", 64 | L"December" 65 | }; 66 | 67 | // Ordered by day. 68 | wchar_t *day_string_table[ 7 ] = 69 | { 70 | L"Sunday", 71 | L"Monday", 72 | L"Tuesday", 73 | L"Wednesday", 74 | L"Thursday", 75 | L"Friday", 76 | L"Saturday" 77 | }; 78 | 79 | void WriteCharInfo( HANDLE output, char *str, WORD width, SHORT x, SHORT y, WORD attributes ) 80 | { 81 | CHAR_INFO ci[ 64 * VISIBLE_LINES ] = { NULL }; 82 | 83 | WORD lines = 0; 84 | 85 | if ( str != NULL && width > 0 ) 86 | { 87 | for ( WORD i = 0; i < width; ) 88 | { 89 | if ( *str != NULL ) 90 | { 91 | if ( *str == '\n' ) 92 | { 93 | if ( *( str + 1 ) == NULL ) 94 | { 95 | break; 96 | } 97 | 98 | i = 0; 99 | ++lines; 100 | ++str; 101 | 102 | continue; 103 | } 104 | else 105 | { 106 | ci[ ( lines * width ) + i ].Char.AsciiChar = *str++; 107 | ci[ ( lines * width ) + i ].Attributes = attributes; 108 | } 109 | } 110 | else 111 | { 112 | break; 113 | } 114 | 115 | ++i; 116 | } 117 | 118 | COORD bs; 119 | bs.X = width; 120 | bs.Y = 1 + lines; 121 | 122 | COORD bc; 123 | bc.X = 0; 124 | bc.Y = 0; 125 | 126 | SMALL_RECT sr; 127 | sr.Left = x; 128 | sr.Top = y; 129 | sr.Right = x + ( width - 1 ); 130 | sr.Bottom = y + lines; 131 | 132 | WriteConsoleOutputA( output, ci, bs, bc, &sr ); 133 | } 134 | } 135 | 136 | BOOL WINAPI ConsoleHandler( DWORD signal ) 137 | { 138 | if ( signal == CTRL_C_EVENT || signal == CTRL_CLOSE_EVENT || CTRL_LOGOFF_EVENT || CTRL_SHUTDOWN_EVENT ) 139 | { 140 | g_status = 1; 141 | } 142 | 143 | return TRUE; 144 | } 145 | 146 | void ClearConsole( HANDLE hConsole ) 147 | { 148 | COORD ccp = { 0, 0 }; 149 | DWORD written; 150 | CONSOLE_SCREEN_BUFFER_INFO csbi; 151 | 152 | GetConsoleScreenBufferInfo( hConsole, &csbi ); 153 | 154 | FillConsoleOutputCharacterA( hConsole, ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 155 | 156 | SetConsoleCursorPosition( hConsole, ccp ); 157 | } 158 | 159 | void UpdateList() 160 | { 161 | DoublyLinkedList *dll = g_list; 162 | 163 | while ( dll != NULL ) 164 | { 165 | AUTH_INFO *ai = ( AUTH_INFO * )dll->data; 166 | 167 | if ( ai != NULL ) 168 | { 169 | ai->code = GetTOTP( ai->key, ai->key_length ); 170 | } 171 | 172 | dll = dll->next; 173 | } 174 | } 175 | 176 | void CleanupList() 177 | { 178 | while ( g_list != NULL ) 179 | { 180 | DoublyLinkedList *del_node = g_list; 181 | 182 | g_list = g_list->next; 183 | 184 | AUTH_INFO *ai = ( AUTH_INFO * )del_node->data; 185 | if ( ai != NULL ) 186 | { 187 | GlobalFree( ai->username ); 188 | GlobalFree( ai->key ); 189 | GlobalFree( ai ); 190 | } 191 | 192 | GlobalFree( del_node ); 193 | } 194 | 195 | g_list_count = 0; 196 | g_selection_offset = 0; 197 | g_selected_index = 0; 198 | g_first_visible = NULL; 199 | g_selected_item = NULL; 200 | } 201 | 202 | void EnableTimer( bool timer_state ) 203 | { 204 | // Trigger the timers out of their infinite wait. 205 | if ( timer_state ) 206 | { 207 | if ( !g_timers_running ) 208 | { 209 | g_timers_running = true; 210 | 211 | if ( g_timer_semaphore != NULL ) 212 | { 213 | ReleaseSemaphore( g_timer_semaphore, 1, NULL ); 214 | } 215 | } 216 | } 217 | else // Let the timers complete their current task and then wait indefinitely. 218 | { 219 | g_timers_running = false; 220 | } 221 | } 222 | 223 | void PrintFrame( HANDLE hOutput, WORD attributes ) 224 | { 225 | DWORD written; 226 | 227 | COORD ccp; 228 | ccp.X = 0; 229 | ccp.Y = TOP_PADDING; 230 | SetConsoleCursorPosition( hOutput, ccp ); 231 | 232 | _printf( "\xC9\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" \ 233 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" \ 234 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" \ 235 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBB\r\n" ); 236 | _printf( "\xBA%*s\xBA\r\n", 62, "" ); 237 | _printf( "\xBA " ); 238 | SetConsoleTextAttribute( hOutput, FOREGROUND_BLUE | FOREGROUND_INTENSITY ); 239 | WriteConsoleA( hOutput, "G", 1, &written, NULL ); 240 | SetConsoleTextAttribute( hOutput, FOREGROUND_RED | FOREGROUND_INTENSITY ); 241 | WriteConsoleA( hOutput, "o", 1, &written, NULL ); 242 | SetConsoleTextAttribute( hOutput, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY ); 243 | WriteConsoleA( hOutput, "o", 1, &written, NULL ); 244 | SetConsoleTextAttribute( hOutput, FOREGROUND_BLUE | FOREGROUND_INTENSITY ); 245 | WriteConsoleA( hOutput, "g", 1, &written, NULL ); 246 | SetConsoleTextAttribute( hOutput, FOREGROUND_GREEN | FOREGROUND_INTENSITY ); 247 | WriteConsoleA( hOutput, "l", 1, &written, NULL ); 248 | SetConsoleTextAttribute( hOutput, FOREGROUND_RED | FOREGROUND_INTENSITY ); 249 | WriteConsoleA( hOutput, "e", 1, &written, NULL ); 250 | SetConsoleTextAttribute( hOutput, attributes ); 251 | WriteConsoleA( hOutput, " Authenticator", 14, &written, NULL ); 252 | _printf( " \xBA\r\n" ); 253 | _printf( "\xBA%*s\xBA\r\n", 62, "" ); 254 | _printf( "\xCC\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xD1" \ 255 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xD1" \ 256 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xD1" \ 257 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xB9\r\n" ); 258 | _printf( "\xBA Ctrl + [N]ew \xB3 Ctrl + [O]pen \xB3 Ctrl + [S]ave \xB3 Ctrl + [Q]uit \xBA\r\n" ); 259 | _printf( "\xCC\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCF" \ 260 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCF" \ 261 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCF" \ 262 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xB9\r\n" ); 263 | 264 | for ( char i = 0; i < VISIBLE_LINES + 6; ++i ) 265 | { 266 | _printf( "\xBA%62s\xBA\r\n", "" ); 267 | } 268 | 269 | _printf( "\xCC\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xD1" \ 270 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xD1" \ 271 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xD1" \ 272 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xB9\r\n" ); 273 | _printf( "\xBA [A]dd \xB3 [E]dit \xB3 [R]emove \xB3 Ctrl + [C]opy \xBA\r\n" ); 274 | _printf( "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCF" \ 275 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCF" \ 276 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCF" \ 277 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC" ); 278 | } 279 | 280 | void PrintList() 281 | { 282 | DWORD written; 283 | 284 | char buffer[ 255 ]; 285 | int buffer_length; 286 | 287 | DoublyLinkedList *dll = g_first_visible; 288 | 289 | COORD ccp; 290 | ccp.X = LEFT_PADDING + 1; 291 | 292 | CONSOLE_CURSOR_INFO cci; 293 | GetConsoleCursorInfo( g_hOutput[ 0 ], &cci ); 294 | if ( cci.bVisible == FALSE ) 295 | { 296 | current_console = ( current_console == 0 ? 1 : 0 ); 297 | } 298 | 299 | CONSOLE_SCREEN_BUFFER_INFO csbi; 300 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 301 | 302 | if ( g_list_count > 0 ) 303 | { 304 | EnableTimer( true ); 305 | 306 | WriteCharInfo( g_hOutput[ current_console ], "Username", 8, LEFT_PADDING + 5, LIST_OFFSET, FOREGROUND_INTENSITY ); 307 | WriteCharInfo( g_hOutput[ current_console ], "One-Time Password", 17, LEFT_PADDING + 42, LIST_OFFSET, FOREGROUND_INTENSITY ); 308 | 309 | ccp.Y = SELECTION_OFFSET; 310 | 311 | for ( char i = 0; i < VISIBLE_LINES; ++i ) 312 | { 313 | ccp.X = LEFT_PADDING + 1; 314 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 60, ccp, &written ); 315 | 316 | if ( dll != NULL ) 317 | { 318 | AUTH_INFO *ai = ( AUTH_INFO * )dll->data; 319 | 320 | if ( ai != NULL ) 321 | { 322 | if ( dll == g_selected_item ) 323 | { 324 | ccp.X = LEFT_PADDING + 2; 325 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], '>', 1, ccp, &written ); 326 | } 327 | 328 | buffer_length = sprintf_s( buffer, 255, "%s", ai->username ); 329 | if ( buffer_length > 32 ) 330 | { 331 | memcpy_s( buffer + 32, 255 - 32, "...", 3 ); 332 | buffer_length = 35; 333 | } 334 | 335 | ccp.X = LEFT_PADDING + 5; 336 | 337 | WriteCharInfo( g_hOutput[ current_console ], buffer, buffer_length, ccp.X, ccp.Y, ( dll == g_selected_item ? FOREGROUND_GREEN | FOREGROUND_INTENSITY : csbi.wAttributes ) ); 338 | 339 | // MSB should not be set. 340 | if ( ai->code & 0xF0000000 ) 341 | { 342 | memcpy_s( buffer, 255, "BAD KEY", 7 ); 343 | buffer_length = 7; 344 | 345 | ccp.X = LEFT_PADDING + 52; 346 | } 347 | else 348 | { 349 | buffer_length = sprintf_s( buffer, 255, "%06lu", ai->code ); 350 | ccp.X = LEFT_PADDING + 53; 351 | } 352 | 353 | WriteCharInfo( g_hOutput[ current_console ], buffer, buffer_length, ccp.X, ccp.Y, ( dll == g_selected_item ? FOREGROUND_GREEN | FOREGROUND_INTENSITY : csbi.wAttributes ) ); 354 | } 355 | 356 | dll = dll->next; 357 | } 358 | 359 | ++ccp.Y; 360 | } 361 | 362 | ccp.X = LEFT_PADDING + 61; 363 | ccp.Y = SELECTION_OFFSET; 364 | //if ( ( g_selected_index + 1 ) > VISIBLE_LINES || ( g_selected_index > 0 && g_selection_offset == 0 ) ) 365 | if ( g_first_visible != g_list ) 366 | { 367 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ':', 1, ccp, &written ); 368 | } 369 | else 370 | { 371 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 1, ccp, &written ); 372 | } 373 | 374 | ccp.Y = SELECTION_OFFSET + VISIBLE_LINES - 1; 375 | int offset = g_list_count - g_selected_index; 376 | if ( g_list_count <= VISIBLE_LINES || 377 | ( offset <= VISIBLE_LINES && ( VISIBLE_LINES - offset ) == g_selection_offset ) ) 378 | { 379 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 1, ccp, &written ); 380 | } 381 | else 382 | { 383 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ':', 1, ccp, &written ); 384 | } 385 | } 386 | else 387 | { 388 | EnableTimer( false ); 389 | 390 | // Clear the line that shows the time. 391 | ccp.Y = TIMER_OFFSET; 392 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 60, ccp, &written ); 393 | 394 | // Clear the line that shows Username and One-Time Password. 395 | ccp.Y = LIST_OFFSET; 396 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 60, ccp, &written ); 397 | 398 | // Clear the usernames and passwords. 399 | ccp.Y = SELECTION_OFFSET; 400 | for ( char i = 0; i < VISIBLE_LINES; ++i ) 401 | { 402 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 60, ccp, &written ); 403 | ++ccp.Y; 404 | } 405 | } 406 | 407 | SetConsoleActiveScreenBuffer( g_hOutput[ current_console ] ); 408 | } 409 | 410 | void RefreshLine( AUTH_INFO *ai, short line, bool selected ) 411 | { 412 | if ( ai != NULL ) 413 | { 414 | char buffer[ 255 ]; 415 | COORD ccp; 416 | DWORD written; 417 | CONSOLE_SCREEN_BUFFER_INFO csbi; 418 | 419 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 420 | 421 | ccp.X = LEFT_PADDING + 1; 422 | ccp.Y = line; 423 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', 60, ccp, &written ); 424 | 425 | int buffer_length = sprintf_s( buffer, 255, "%s", ai->username ); 426 | if ( buffer_length > 32 ) 427 | { 428 | memcpy_s( buffer + 32, 255 - 32, "...", 3 ); 429 | buffer_length = 35; 430 | } 431 | 432 | WriteCharInfo( g_hOutput[ current_console ], buffer, buffer_length, LEFT_PADDING + 5, line, ( selected ? FOREGROUND_GREEN | FOREGROUND_INTENSITY : csbi.wAttributes ) ); 433 | 434 | // MSB should not be set. 435 | if ( ai->code & 0xF0000000 ) 436 | { 437 | memcpy_s( buffer, 255, "BAD KEY", 7 ); 438 | buffer_length = 7; 439 | ccp.X = LEFT_PADDING + 52; 440 | } 441 | else 442 | { 443 | buffer_length = sprintf_s( buffer, 255, "%06lu", ai->code ); 444 | ccp.X = LEFT_PADDING + 53; 445 | } 446 | 447 | WriteCharInfo( g_hOutput[ current_console ], buffer, buffer_length, ccp.X, line, ( selected ? FOREGROUND_GREEN | FOREGROUND_INTENSITY : csbi.wAttributes ) ); 448 | 449 | if ( selected ) 450 | { 451 | ccp.X = LEFT_PADDING + 2; 452 | ccp.Y = SELECTION_OFFSET + g_selection_offset; 453 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], '>', 1, ccp, &written ); 454 | } 455 | } 456 | } 457 | 458 | DWORD WINAPI UpdateWindow( LPVOID WorkThreadContext ) 459 | { 460 | bool run_timer = g_timers_running; 461 | bool updated = false; 462 | 463 | char time_buf[ 11 ]; 464 | 465 | CONSOLE_SCREEN_BUFFER_INFO csbi; 466 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 467 | 468 | while ( g_status != 1 ) 469 | { 470 | WaitForSingleObject( g_timer_semaphore, ( run_timer ? 1000 : INFINITE ) ); 471 | 472 | if ( g_status == 1 ) 473 | { 474 | break; 475 | } 476 | 477 | EnterCriticalSection( &console_cs ); 478 | 479 | // This will allow the timer to go through at least one loop after it's been disabled (g_timers_running == false). 480 | run_timer = g_timers_running; 481 | 482 | if ( run_timer ) 483 | { 484 | COORD ccp; 485 | ccp.X = LEFT_PADDING + 1; 486 | ccp.Y = TIMER_OFFSET; 487 | 488 | if ( g_list_count > 0 ) 489 | { 490 | unsigned long ts = 30 - ( GetUnixTimestamp() % 30 ); 491 | 492 | if ( run_timer ) 493 | { 494 | WriteCharInfo( g_hOutput[ 0 ], "Time remaining: ", 16, LEFT_PADDING + 19, TIMER_OFFSET, csbi.wAttributes ); 495 | WriteCharInfo( g_hOutput[ 1 ], "Time remaining: ", 16, LEFT_PADDING + 19, TIMER_OFFSET, csbi.wAttributes ); 496 | 497 | WORD attributes = FOREGROUND_INTENSITY; 498 | if ( ts > 5 && ts <= 10 ) 499 | { 500 | attributes |= FOREGROUND_RED | FOREGROUND_GREEN; 501 | } 502 | else if ( ts > 0 && ts <= 5 ) 503 | { 504 | attributes |= FOREGROUND_RED; 505 | } 506 | else 507 | { 508 | attributes |= FOREGROUND_GREEN; 509 | } 510 | int time_buf_length = sprintf_s( time_buf, 11, "%02lu", ts ); 511 | WriteCharInfo( g_hOutput[ 0 ], time_buf, time_buf_length, LEFT_PADDING + 19 + 16, TIMER_OFFSET, attributes ); 512 | WriteCharInfo( g_hOutput[ 1 ], time_buf, time_buf_length, LEFT_PADDING + 19 + 16, TIMER_OFFSET, attributes ); 513 | 514 | WriteCharInfo( g_hOutput[ 0 ], " seconds", 8, LEFT_PADDING + 19 + 16 + time_buf_length, TIMER_OFFSET, csbi.wAttributes ); 515 | WriteCharInfo( g_hOutput[ 1 ], " seconds", 8, LEFT_PADDING + 19 + 16 + time_buf_length, TIMER_OFFSET, csbi.wAttributes ); 516 | } 517 | 518 | // Attempt to update the list in case the timer skipped a second. 519 | if ( ts >= 25 ) 520 | { 521 | if ( !updated ) 522 | { 523 | updated = true; 524 | 525 | UpdateList(); 526 | 527 | PrintList(); 528 | } 529 | } 530 | else 531 | { 532 | updated = false; 533 | } 534 | } 535 | else 536 | { 537 | run_timer = g_timers_running = false; 538 | } 539 | } 540 | 541 | LeaveCriticalSection( &console_cs ); 542 | } 543 | 544 | CloseHandle( g_timer_semaphore ); 545 | g_timer_semaphore = NULL; 546 | 547 | ExitThread( 0 ); 548 | return 0; 549 | } 550 | 551 | void EnableCursor( BOOL enable ) 552 | { 553 | CONSOLE_CURSOR_INFO cci; 554 | 555 | GetConsoleCursorInfo( g_hOutput[ 0 ], &cci ); 556 | cci.bVisible = enable; 557 | SetConsoleCursorInfo( g_hOutput[ 0 ], &cci ); 558 | 559 | GetConsoleCursorInfo( g_hOutput[ 1 ], &cci ); 560 | cci.bVisible = enable; 561 | SetConsoleCursorInfo( g_hOutput[ 1 ], &cci ); 562 | } 563 | 564 | void FillConsoleInputLine( char *input ) 565 | { 566 | if ( input != NULL ) 567 | { 568 | size_t input_length = strlen( input ); 569 | INPUT_RECORD *pir = ( INPUT_RECORD * )GlobalAlloc( GMEM_FIXED, sizeof( INPUT_RECORD ) * input_length ); 570 | 571 | char *c = input; 572 | INPUT_RECORD *tir = pir; 573 | for ( unsigned int i = 0; i < input_length; ++i ) 574 | { 575 | tir->EventType = KEY_EVENT; 576 | tir->Event.KeyEvent.bKeyDown = TRUE; 577 | tir->Event.KeyEvent.dwControlKeyState = 0; 578 | tir->Event.KeyEvent.wRepeatCount = 1; 579 | tir->Event.KeyEvent.uChar.AsciiChar = *c; 580 | tir->Event.KeyEvent.wVirtualKeyCode = VkKeyScanA( *c ); 581 | tir->Event.KeyEvent.wVirtualScanCode = MapVirtualKey( tir->Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC ); 582 | 583 | ++tir; 584 | ++c; 585 | } 586 | 587 | DWORD write; 588 | WriteConsoleInputA( g_hInput, pir, ( DWORD )input_length, &write ); 589 | 590 | GlobalFree( pir ); 591 | } 592 | } 593 | 594 | int main( int argc, char *argv[] ) 595 | { 596 | SYSTEMTIME compile_time; 597 | memset( &compile_time, 0, sizeof( SYSTEMTIME ) ); 598 | HINSTANCE hInstance = GetModuleHandle( NULL ); 599 | if ( hInstance != NULL ) 600 | { 601 | IMAGE_DOS_HEADER *idh = ( IMAGE_DOS_HEADER * )hInstance; 602 | IMAGE_NT_HEADERS *inth = ( IMAGE_NT_HEADERS * )( ( BYTE * )idh + idh->e_lfanew ); 603 | 604 | UnixTimeToSystemTime( inth->FileHeader.TimeDateStamp, &compile_time ); 605 | } 606 | 607 | InitializeCrypto(); 608 | 609 | g_timer_semaphore = CreateSemaphore( NULL, 0, 1, NULL ); 610 | 611 | HANDLE timer_handle = CreateThread( NULL, 0, UpdateWindow, NULL, 0, NULL ); 612 | SetThreadPriority( timer_handle, THREAD_PRIORITY_LOWEST ); 613 | CloseHandle( timer_handle ); 614 | 615 | 616 | g_first_visible = g_list; 617 | g_selected_item = g_list; 618 | 619 | DWORD written; 620 | DWORD read; 621 | COORD ccp; 622 | INPUT_RECORD ir[ 1 ]; 623 | CONSOLE_SCREEN_BUFFER_INFO csbi; 624 | 625 | InitializeCriticalSection( &console_cs ); 626 | 627 | // Set our console to receive Ctrl + x key presses. 628 | CONSOLE_READCONSOLE_CONTROL crcc; 629 | crcc.nLength = sizeof( CONSOLE_READCONSOLE_CONTROL ); 630 | crcc.nInitialChars = 0; 631 | crcc.dwCtrlWakeupMask = 0xFFFFFFFF; 632 | crcc.dwControlKeyState = 0; 633 | 634 | SetConsoleCtrlHandler( ConsoleHandler, TRUE ); 635 | 636 | g_hInput = GetStdHandle( STD_INPUT_HANDLE ); 637 | 638 | // Save the current console buffer. We'll restore it when we're done. 639 | HANDLE g_hOutput_old = GetStdHandle( STD_OUTPUT_HANDLE ); 640 | 641 | g_hOutput[ 0 ] = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL ); 642 | g_hOutput[ 1 ] = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL ); 643 | 644 | SHORT width = LEFT_PADDING + LEFT_PADDING + 64; 645 | SHORT height = INPUT_OFFSET + TOP_PADDING; 646 | 647 | // Window size 648 | SMALL_RECT src; 649 | src.Top = 0; 650 | src.Left = 0; 651 | src.Right = width; 652 | src.Bottom = height; 653 | 654 | // Buffer size 655 | COORD csize; 656 | csize.X = width + 1; 657 | csize.Y = height + 1; 658 | 659 | csize.X += 1000; 660 | csize.Y += 1000; 661 | BOOL test2 = SetConsoleScreenBufferSize( g_hOutput[ 0 ], csize ); 662 | SetConsoleScreenBufferSize( g_hOutput[ 1 ], csize ); 663 | 664 | BOOL test = SetConsoleWindowInfo( g_hOutput[ 0 ], TRUE, &src ); 665 | SetConsoleWindowInfo( g_hOutput[ 1 ], TRUE, &src ); 666 | 667 | csize.X -= 1000; 668 | csize.Y -= 1000; 669 | test = SetConsoleScreenBufferSize( g_hOutput[ 0 ], csize ); 670 | SetConsoleScreenBufferSize( g_hOutput[ 1 ], csize ); 671 | 672 | 673 | HWND hWnd_console = GetConsoleWindow(); 674 | SetWindowLongPtr( hWnd_console, GWL_STYLE, GetWindowLongPtr( hWnd_console, GWL_STYLE ) & ~WS_MAXIMIZEBOX & ~WS_SIZEBOX ); 675 | 676 | 677 | ///// 678 | 679 | GetConsoleScreenBufferInfo( g_hOutput[ 0 ], &csbi ); 680 | 681 | PrintFrame( g_hOutput[ 0 ], csbi.wAttributes ); 682 | current_console = 1; 683 | PrintFrame( g_hOutput[ 1 ], csbi.wAttributes ); 684 | current_console = 0; 685 | 686 | SetConsoleActiveScreenBuffer( g_hOutput[ 0 ] ); 687 | 688 | char loaded_args = 0; // 1 = key and database loaded, 2 = key loaded 689 | if ( argc > 1 ) 690 | { 691 | if ( GetFileAttributesA( argv[ 1 ] ) != INVALID_FILE_ATTRIBUTES ) 692 | { 693 | GetFullPathNameA( argv[ 1 ], MAX_PATH, g_save_path, NULL ); 694 | 695 | loaded_args = 1; 696 | } 697 | } 698 | 699 | if ( loaded_args == 1 && argc > 2 ) 700 | { 701 | if ( GetFileAttributesA( argv[ 2 ] ) != INVALID_FILE_ATTRIBUTES ) 702 | { 703 | GetFullPathNameA( argv[ 2 ], MAX_PATH, g_key_path, NULL ); 704 | 705 | if ( LoadKeyFile( g_key_path ) ) 706 | { 707 | DecryptData( g_save_path ); 708 | 709 | g_selection_offset = 0; 710 | g_selected_index = 0; 711 | g_first_visible = g_list; 712 | g_selected_item = g_list; 713 | 714 | loaded_args = 2; 715 | } 716 | } 717 | } 718 | 719 | /////////////////////////////// 720 | 721 | do 722 | { 723 | g_status = 0; 724 | 725 | EnterCriticalSection( &console_cs ); 726 | 727 | ClearConsole( g_hOutput[ current_console ] ); 728 | PrintFrame( g_hOutput[ current_console ], csbi.wAttributes ); 729 | 730 | if ( loaded_args == 2 ) 731 | { 732 | UpdateList(); 733 | 734 | PrintList(); 735 | } 736 | else 737 | { 738 | g_save_path[ 0 ] = 0; // Sanity. 739 | g_key_path[ 0 ] = 0; // Sanity. 740 | } 741 | 742 | LeaveCriticalSection( &console_cs ); 743 | 744 | loaded_args = 0; 745 | 746 | EnableCursor( FALSE ); 747 | 748 | BOOL read_console; 749 | do 750 | { 751 | SetConsoleMode( g_hInput, ENABLE_WINDOW_INPUT ); 752 | read_console = ReadConsoleInputW( g_hInput, ir, 1, &read ); 753 | 754 | if ( ir[ 0 ].EventType == KEY_EVENT ) 755 | { 756 | KEY_EVENT_RECORD ker = ir[ 0 ].Event.KeyEvent; 757 | 758 | DWORD ctrl_down = ( ker.dwControlKeyState & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED ) ); 759 | 760 | if ( ker.bKeyDown ) 761 | { 762 | if ( ctrl_down ) 763 | { 764 | if ( ker.wVirtualKeyCode == 'A' ) 765 | { 766 | wchar_t msg[ 512 ]; 767 | _snwprintf_s( msg, 512, L"Google Authenticator is made free under the GPLv3 license.\r\n\r\n" \ 768 | L"Version 1.0.0.1 (%u-bit)\r\n\r\n" \ 769 | L"Built on %s, %s %d, %04d %d:%02d:%02d %s (UTC)\r\n\r\n" \ 770 | L"Copyright \xA9 2019 Eric Kutcher", 771 | #ifdef _WIN64 772 | 64, 773 | #else 774 | 32, 775 | #endif 776 | ( compile_time.wDayOfWeek > 6 ? L"" : day_string_table[ compile_time.wDayOfWeek ] ), 777 | ( ( compile_time.wMonth > 12 || compile_time.wMonth < 1 ) ? L"" : month_string_table[ compile_time.wMonth - 1 ] ), 778 | compile_time.wDay, 779 | compile_time.wYear, 780 | ( compile_time.wHour > 12 ? compile_time.wHour - 12 : ( compile_time.wHour != 0 ? compile_time.wHour : 12 ) ), 781 | compile_time.wMinute, 782 | compile_time.wSecond, 783 | ( compile_time.wHour >= 12 ? L"PM" : L"AM" ) ); 784 | 785 | MessageBoxW( hWnd_console, msg, L"Google Authenticator", MB_APPLMODAL | MB_ICONINFORMATION ); 786 | } 787 | else if ( ker.wVirtualKeyCode == 'N' ) 788 | { 789 | g_status = 2; // New instance 790 | 791 | break; 792 | } 793 | else if ( ker.wVirtualKeyCode == 'Q' ) 794 | { 795 | g_status = 1; // Quit 796 | 797 | break; 798 | } 799 | else if ( ker.wVirtualKeyCode == 'O' ) 800 | { 801 | EnableCursor( TRUE ); 802 | 803 | ccp.X = 2; 804 | ccp.Y = INPUT_OFFSET; 805 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 806 | 807 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 808 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 809 | 810 | _printf( "Open database file: " ); 811 | 812 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 813 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 814 | 815 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 816 | 817 | if ( read > 2 ) 818 | { 819 | read -= 2; 820 | 821 | g_console_buffer[ read ] = 0; 822 | 823 | if ( GetFileAttributesA( g_console_buffer ) != INVALID_FILE_ATTRIBUTES ) 824 | { 825 | GetFullPathNameA( g_console_buffer, MAX_PATH, g_save_path, NULL ); 826 | 827 | ccp.X = 2; 828 | ccp.Y = INPUT_OFFSET; 829 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 830 | 831 | _printf( "Load key file: " ); 832 | 833 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 834 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 835 | 836 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 837 | 838 | bool read_key = false; 839 | 840 | if ( read > 2 ) 841 | { 842 | read -= 2; 843 | 844 | g_console_buffer[ read ] = 0; 845 | 846 | if ( GetFileAttributesA( g_console_buffer ) != INVALID_FILE_ATTRIBUTES ) 847 | { 848 | GetFullPathNameA( g_console_buffer, MAX_PATH, g_key_path, NULL ); 849 | 850 | if ( LoadKeyFile( g_key_path ) ) 851 | { 852 | read_key = true; 853 | 854 | CleanupList(); 855 | 856 | DecryptData( g_save_path ); 857 | 858 | g_selection_offset = 0; 859 | g_selected_index = 0; 860 | g_first_visible = g_list; 861 | g_selected_item = g_list; 862 | 863 | EnterCriticalSection( &console_cs ); 864 | 865 | PrintList(); 866 | 867 | LeaveCriticalSection( &console_cs ); 868 | } 869 | } 870 | } 871 | 872 | if ( !read_key ) 873 | { 874 | g_save_path[ 0 ] = 0; // Sanity. 875 | g_key_path[ 0 ] = 0; // Sanity. 876 | } 877 | } 878 | } 879 | 880 | EnableCursor( FALSE ); 881 | } 882 | else if ( ker.wVirtualKeyCode == 'S' ) 883 | { 884 | EnableCursor( TRUE ); 885 | 886 | ccp.X = 2; 887 | ccp.Y = INPUT_OFFSET; 888 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 889 | 890 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 891 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 892 | 893 | if ( g_key_path[ 0 ] == NULL ) 894 | { 895 | _printf( "Generate key file: " ); 896 | 897 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 898 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 899 | 900 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 901 | 902 | if ( read > 2 ) 903 | { 904 | read -= 2; 905 | 906 | g_console_buffer[ read ] = 0; 907 | 908 | GetFullPathNameA( g_console_buffer, MAX_PATH, g_key_path, NULL ); 909 | 910 | GenerateKeyFile( g_key_path ); 911 | } 912 | 913 | ccp.X = 2; 914 | ccp.Y = INPUT_OFFSET; 915 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 916 | 917 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 918 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 919 | } 920 | 921 | if ( g_key_path[ 0 ] != NULL ) 922 | { 923 | _printf( "Save database file: " ); 924 | 925 | FillConsoleInputLine( g_save_path ); 926 | 927 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 928 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 929 | 930 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 931 | 932 | if ( read > 2 ) 933 | { 934 | read -= 2; 935 | 936 | g_console_buffer[ read ] = 0; 937 | 938 | GetFullPathNameA( g_console_buffer, MAX_PATH, g_save_path, NULL ); 939 | 940 | EncryptData( g_save_path ); 941 | } 942 | } 943 | 944 | EnableCursor( FALSE ); 945 | } 946 | else if ( ker.wVirtualKeyCode == 'C' ) 947 | { 948 | if ( g_selected_item != NULL && g_selected_item->data != NULL ) 949 | { 950 | AUTH_INFO *ai = ( AUTH_INFO * )g_selected_item->data; 951 | 952 | if ( OpenClipboard( NULL ) ) 953 | { 954 | EmptyClipboard(); 955 | 956 | // Allocate a global memory object for the text. 957 | HGLOBAL hglbCopy = GlobalAlloc( GMEM_MOVEABLE, sizeof( char ) * 11 ); 958 | if ( hglbCopy != NULL ) 959 | { 960 | // Lock the handle and copy the text to the buffer. lptstrCopy doesn't get freed. 961 | char *lptstrCopy = ( char * )GlobalLock( hglbCopy ); 962 | if ( lptstrCopy != NULL ) 963 | { 964 | if ( ai->code >= 1000000 ) 965 | { 966 | memcpy_s( lptstrCopy, 11, "BAD KEY\0", 8 ); 967 | } 968 | else 969 | { 970 | sprintf_s( lptstrCopy, 11, "%06lu", ai->code ); 971 | } 972 | } 973 | 974 | GlobalUnlock( hglbCopy ); 975 | 976 | if ( SetClipboardData( CF_TEXT, hglbCopy ) == NULL ) 977 | { 978 | GlobalFree( hglbCopy ); // Only free this Global memory if SetClipboardData fails. 979 | } 980 | 981 | CloseClipboard(); 982 | } 983 | } 984 | } 985 | } 986 | } 987 | else if ( ker.wVirtualKeyCode == VK_UP ) 988 | { 989 | if ( g_selected_index > 0 ) 990 | { 991 | --g_selected_index; 992 | DoublyLinkedList *last_selected_item = g_selected_item; 993 | g_selected_item = g_selected_item->prev; 994 | 995 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 996 | 997 | EnterCriticalSection( &console_cs ); 998 | 999 | if ( g_selection_offset == 0 ) 1000 | { 1001 | g_first_visible = g_first_visible->prev; 1002 | PrintList(); 1003 | } 1004 | 1005 | RefreshLine( ( AUTH_INFO * )last_selected_item->data, SELECTION_OFFSET + g_selection_offset, false ); 1006 | 1007 | if ( g_selection_offset > 0 ) 1008 | { 1009 | --g_selection_offset; 1010 | } 1011 | 1012 | RefreshLine( ( AUTH_INFO * )g_selected_item->data, SELECTION_OFFSET + g_selection_offset, true ); 1013 | 1014 | LeaveCriticalSection( &console_cs ); 1015 | } 1016 | } 1017 | else if ( ker.wVirtualKeyCode == VK_DOWN ) 1018 | { 1019 | if ( g_selected_index < g_list_count - 1 ) 1020 | { 1021 | ++g_selected_index; 1022 | DoublyLinkedList *last_selected_item = g_selected_item; 1023 | g_selected_item = g_selected_item->next; 1024 | 1025 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 1026 | 1027 | EnterCriticalSection( &console_cs ); 1028 | 1029 | if ( g_selection_offset >= VISIBLE_LINES - 1 ) 1030 | { 1031 | g_first_visible = g_first_visible->next; 1032 | PrintList(); 1033 | } 1034 | 1035 | RefreshLine( ( AUTH_INFO * )last_selected_item->data, SELECTION_OFFSET + g_selection_offset, false ); 1036 | 1037 | if ( g_selection_offset < VISIBLE_LINES - 1 ) 1038 | { 1039 | ++g_selection_offset; 1040 | } 1041 | 1042 | RefreshLine( ( AUTH_INFO * )g_selected_item->data, SELECTION_OFFSET + g_selection_offset, true ); 1043 | 1044 | LeaveCriticalSection( &console_cs ); 1045 | } 1046 | } 1047 | else if ( ker.wVirtualKeyCode == 'A' ) 1048 | { 1049 | EnableCursor( TRUE ); 1050 | 1051 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 1052 | 1053 | ccp.X = 2; 1054 | ccp.Y = INPUT_OFFSET; 1055 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 1056 | 1057 | _printf( "Add username: " ); 1058 | 1059 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 1060 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 1061 | 1062 | if ( read > 2 ) 1063 | { 1064 | read -= 2; 1065 | 1066 | unsigned int username_length = min( read, 254 ); 1067 | char *username = ( char * )GlobalAlloc( GMEM_FIXED, sizeof( char ) * ( username_length + 1 ) ); 1068 | memcpy_s( username, sizeof( char ) * ( username_length + 1 ), g_console_buffer, username_length ); 1069 | username[ username_length ] = 0; // Sanity. 1070 | 1071 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1072 | 1073 | ccp.X = 2; 1074 | ccp.Y = INPUT_OFFSET; 1075 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 1076 | 1077 | _printf( "Add key: " ); 1078 | 1079 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 1080 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 1081 | 1082 | if ( read > 2 ) 1083 | { 1084 | read -= 2; 1085 | 1086 | unsigned int key_length = min( read, 254 ); 1087 | char *key = ( char * )GlobalAlloc( GMEM_FIXED, sizeof( char ) * ( key_length + 1 ) ); 1088 | memcpy_s( key, sizeof( char ) * ( key_length + 1 ), g_console_buffer, key_length ); 1089 | key[ key_length ] = 0; // Sanity. 1090 | 1091 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1092 | 1093 | EnterCriticalSection( &console_cs ); 1094 | 1095 | AUTH_INFO *ai = ( AUTH_INFO * )GlobalAlloc( GMEM_FIXED, sizeof( AUTH_INFO ) ); 1096 | ai->username = username; 1097 | ai->username_length = username_length; 1098 | ai->key = key; 1099 | ai->key_length = key_length; 1100 | ai->code = GetTOTP( ai->key, ai->key_length ); 1101 | 1102 | DoublyLinkedList *dll = DLL_CreateNode( ( void * )ai ); 1103 | DLL_AddNode( &g_list, dll, -1 ); 1104 | 1105 | if ( g_list_count == 0 ) 1106 | { 1107 | g_first_visible = g_list; 1108 | g_selected_item = g_list; 1109 | } 1110 | 1111 | ++g_list_count; 1112 | 1113 | PrintList(); 1114 | 1115 | LeaveCriticalSection( &console_cs ); 1116 | } 1117 | else 1118 | { 1119 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1120 | 1121 | GlobalFree( username ); 1122 | } 1123 | } 1124 | else 1125 | { 1126 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1127 | } 1128 | 1129 | EnableCursor( FALSE ); 1130 | } 1131 | else if ( ker.wVirtualKeyCode == 'E' ) 1132 | { 1133 | if ( g_selected_item != NULL && g_selected_item->data != NULL ) 1134 | { 1135 | AUTH_INFO *ai = ( AUTH_INFO * )g_selected_item->data; 1136 | 1137 | EnableCursor( TRUE ); 1138 | 1139 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 1140 | 1141 | ccp.X = 2; 1142 | ccp.Y = INPUT_OFFSET; 1143 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 1144 | 1145 | _printf( "Edit username: " ); 1146 | 1147 | FillConsoleInputLine( ai->username ); 1148 | 1149 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 1150 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 1151 | 1152 | if ( read > 2 ) 1153 | { 1154 | read -= 2; 1155 | 1156 | unsigned int username_length = min( read, 254 ); 1157 | char *username = ( char * )GlobalAlloc( GMEM_FIXED, sizeof( char ) * ( username_length + 1 ) ); 1158 | memcpy_s( username, sizeof( char ) * ( username_length + 1 ), g_console_buffer, username_length ); 1159 | username[ username_length ] = 0; // Sanity. 1160 | 1161 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1162 | 1163 | ccp.X = 2; 1164 | ccp.Y = INPUT_OFFSET; 1165 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 1166 | 1167 | _printf( "Edit key: " ); 1168 | 1169 | FillConsoleInputLine( ai->key ); 1170 | 1171 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 1172 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 1173 | 1174 | if ( read > 2 ) 1175 | { 1176 | read -= 2; 1177 | 1178 | unsigned int key_length = min( read, 254 ); 1179 | char *key = ( char * )GlobalAlloc( GMEM_FIXED, sizeof( char ) * ( key_length + 1 ) ); 1180 | memcpy_s( key, sizeof( char ) * ( key_length + 1 ), g_console_buffer, key_length ); 1181 | key[ key_length ] = 0; // Sanity. 1182 | 1183 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1184 | 1185 | EnterCriticalSection( &console_cs ); 1186 | 1187 | char *tmp = ai->username; 1188 | ai->username = username; 1189 | GlobalFree( tmp ); 1190 | ai->username_length = username_length; 1191 | 1192 | tmp = ai->key; 1193 | ai->key = key; 1194 | GlobalFree( tmp ); 1195 | ai->key_length = key_length; 1196 | ai->code = GetTOTP( ai->key, ai->key_length ); 1197 | 1198 | RefreshLine( ai, SELECTION_OFFSET + g_selection_offset, true ); 1199 | 1200 | LeaveCriticalSection( &console_cs ); 1201 | } 1202 | else 1203 | { 1204 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1205 | } 1206 | } 1207 | else 1208 | { 1209 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1210 | } 1211 | 1212 | EnableCursor( FALSE ); 1213 | } 1214 | } 1215 | else if ( ker.wVirtualKeyCode == 'R' ) 1216 | { 1217 | if ( g_selected_item != NULL ) 1218 | { 1219 | EnableCursor( TRUE ); 1220 | 1221 | ccp.X = 2; 1222 | ccp.Y = INPUT_OFFSET; 1223 | SetConsoleCursorPosition( g_hOutput[ current_console ], ccp ); 1224 | 1225 | _printf( "Are you sure you want to remove the selected entry? (Y/N): " ); 1226 | 1227 | SetConsoleMode( g_hInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); 1228 | ReadConsoleA( g_hInput, g_console_buffer, CONSOLE_BUFFER_SIZE + 1, &read, NULL ); 1229 | 1230 | EnableCursor( FALSE ); 1231 | 1232 | FillConsoleOutputCharacterA( g_hOutput[ current_console ], ' ', csbi.dwSize.X * csbi.dwSize.Y, ccp, &written ); 1233 | 1234 | if ( read == 3 && g_console_buffer[ 0 ] == 'Y' || g_console_buffer[ 0 ] == 'y' ) 1235 | { 1236 | EnterCriticalSection( &console_cs ); 1237 | 1238 | DoublyLinkedList *tmp_dll = NULL; 1239 | 1240 | if ( g_first_visible != g_list ) 1241 | { 1242 | int offset = g_list_count - g_selected_index; 1243 | if ( offset <= VISIBLE_LINES && 1244 | ( VISIBLE_LINES - offset ) == g_selection_offset ) 1245 | { 1246 | tmp_dll = g_selected_item->prev; 1247 | 1248 | --g_selected_index; 1249 | 1250 | g_first_visible = g_first_visible->prev; 1251 | } 1252 | else 1253 | { 1254 | tmp_dll = g_selected_item->next; 1255 | } 1256 | } 1257 | else 1258 | { 1259 | if ( g_selected_item == g_first_visible ) 1260 | { 1261 | g_first_visible = g_first_visible->next; 1262 | } 1263 | 1264 | if ( g_selected_item->next == NULL ) 1265 | { 1266 | if ( g_selected_index > 0 ) 1267 | { 1268 | --g_selected_index; 1269 | --g_selection_offset; 1270 | } 1271 | 1272 | tmp_dll = g_selected_item->prev; 1273 | } 1274 | else 1275 | { 1276 | tmp_dll = g_selected_item->next; 1277 | } 1278 | } 1279 | 1280 | --g_list_count; 1281 | DLL_RemoveNode( &g_list, g_selected_item ); 1282 | 1283 | AUTH_INFO *ai = ( AUTH_INFO * )g_selected_item->data; 1284 | GlobalFree( ai->username ); 1285 | GlobalFree( ai->key ); 1286 | GlobalFree( ai ); 1287 | GlobalFree( g_selected_item ); 1288 | 1289 | g_selected_item = tmp_dll; 1290 | 1291 | PrintList(); 1292 | 1293 | LeaveCriticalSection( &console_cs ); 1294 | } 1295 | } 1296 | } 1297 | } 1298 | } 1299 | } 1300 | while ( read_console ); 1301 | 1302 | // Show the console cursor position. 1303 | EnableCursor( TRUE ); 1304 | 1305 | EnterCriticalSection( &console_cs ); 1306 | EnableTimer( false ); 1307 | 1308 | CleanupList(); 1309 | 1310 | LeaveCriticalSection( &console_cs ); 1311 | } 1312 | while ( g_status == 2 ); 1313 | 1314 | // Exit our timer thread if it's active. 1315 | if ( g_timer_semaphore != NULL ) 1316 | { 1317 | ReleaseSemaphore( g_timer_semaphore, 1, NULL ); 1318 | } 1319 | 1320 | // Restore the old buffer. 1321 | SetConsoleActiveScreenBuffer( g_hOutput_old ); 1322 | 1323 | CloseHandle( g_hOutput[ 0 ] ); 1324 | CloseHandle( g_hOutput[ 1 ] ); 1325 | 1326 | DeleteCriticalSection( &console_cs ); 1327 | 1328 | CleanupCrypto(); 1329 | 1330 | return 0; 1331 | } 1332 | -------------------------------------------------------------------------------- /Google_Authenticator/utilities.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "globals.h" 20 | #include "utilities.h" 21 | 22 | #include 23 | 24 | #define FILETIME_TICKS_PER_SECOND 10000000LL 25 | 26 | #define decode_char( c ) ( ( c >= 'A' && c <= 'Z' ) ? c - 'A' : ( ( c >= '2' && c <= '7' ) ? ( c - '2' ) + 26 : -1 ) ) 27 | 28 | int decode_sequence( unsigned char *str_in, unsigned char *str_out ) 29 | { 30 | static char offset_map[] = { 3, -2, 1, -4, -1, 2, -3, 0 }; 31 | 32 | str_out[ 0 ] = 0; 33 | 34 | for ( char block = 0, octet = 0; block < 8; ++block, octet = ( block * 5 ) / 8 ) 35 | { 36 | int c = decode_char( str_in[ block ] ); 37 | if ( c < 0 ) 38 | { 39 | return octet; 40 | } 41 | 42 | if ( offset_map[ block ] < 0 ) 43 | { 44 | str_out[ octet ] |= ( c >> -offset_map[ block ] ); 45 | str_out[ octet + 1 ] = c << ( 8 + offset_map[ block ] ); 46 | } 47 | else 48 | { 49 | str_out[ octet ] |= ( c << offset_map[ block ] ); 50 | } 51 | } 52 | 53 | return 5; 54 | } 55 | 56 | unsigned int base32_decode( unsigned char *str_in, unsigned char *str_out ) 57 | { 58 | unsigned int written = 0; 59 | 60 | if ( str_in != NULL ) 61 | { 62 | for ( unsigned int i = 0, j = 0; ; i += 8, j += 5 ) 63 | { 64 | int n = decode_sequence( &str_in[ i ], &str_out[ j ] ); 65 | 66 | written += n; 67 | 68 | if ( n < 5 ) 69 | { 70 | break; 71 | } 72 | } 73 | } 74 | 75 | return written; 76 | } 77 | 78 | unsigned long GetUnixTimestamp() 79 | { 80 | FILETIME ft; 81 | GetSystemTimeAsFileTime( &ft ); 82 | 83 | // Convert the time into a 32bit Unix timestamp. 84 | ULARGE_INTEGER ts; 85 | ts.HighPart = ft.dwHighDateTime; 86 | ts.LowPart = ft.dwLowDateTime; 87 | 88 | return ( unsigned long )( ( ts.QuadPart - ( 11644473600000 * 10000 ) ) / FILETIME_TICKS_PER_SECOND ); 89 | } 90 | 91 | void UnixTimeToSystemTime( DWORD t, SYSTEMTIME *st ) 92 | { 93 | FILETIME ft; 94 | LARGE_INTEGER li; 95 | li.QuadPart = Int32x32To64( t, 10000000 ) + 116444736000000000; 96 | 97 | ft.dwLowDateTime = li.LowPart; 98 | ft.dwHighDateTime = li.HighPart; 99 | 100 | FileTimeToSystemTime( &ft, st ); 101 | } 102 | 103 | int _printf( const char *_Format, ... ) 104 | { 105 | int ret = -1; 106 | 107 | DWORD written; 108 | va_list arglist; 109 | 110 | va_start( arglist, _Format ); 111 | 112 | char buffer[ 8192 ]; 113 | 114 | int buffer_length = _vsnprintf_s( buffer, 8192, _Format, arglist ); 115 | 116 | va_end( arglist ); 117 | 118 | CONSOLE_SCREEN_BUFFER_INFO csbi; 119 | GetConsoleScreenBufferInfo( g_hOutput[ current_console ], &csbi ); 120 | 121 | csbi.dwCursorPosition.X += LEFT_PADDING; 122 | SetConsoleCursorPosition( g_hOutput[ current_console ], csbi.dwCursorPosition ); 123 | 124 | if ( buffer_length >= 0 && WriteConsoleA( g_hOutput[ current_console ], buffer, buffer_length, &written, NULL ) ) 125 | { 126 | ret = written; 127 | } 128 | 129 | return ret; 130 | } 131 | -------------------------------------------------------------------------------- /Google_Authenticator/utilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | Google Authenticator generates one-time passwords for Google accounts. 3 | Copyright (C) 2019 Eric Kutcher 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef _UTILITIES_H 20 | #define _UTILITIES_H 21 | 22 | unsigned int base32_decode( unsigned char *str_in, unsigned char *str_out ); 23 | 24 | unsigned long GetUnixTimestamp(); 25 | void UnixTimeToSystemTime( DWORD t, SYSTEMTIME *st ); 26 | 27 | int _printf( const char *_Format, ... ); 28 | 29 | #endif 30 | --------------------------------------------------------------------------------