/* Create an OTR Data message. Pass the plaintext as msg, and an * optional chain of TLVs. A newly-allocated string will be returned in * *encmessagep. Put the current extra symmetric key into extrakey * (if non-NULL). */ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context, const char *msg, const OtrlTLV *tlvs, unsigned char flags, unsigned char *extrakey) { size_t justmsglen = strlen(msg); size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs); size_t buflen; size_t pubkeylen; unsigned char *buf = NULL; unsigned char *bufp; size_t lenp; DH_sesskeys *sess = &(context->context_priv->sesskeys[1][0]); gcry_error_t err; size_t reveallen = 20 * context->context_priv->numsavedkeys; char *base64buf = NULL; unsigned char *msgbuf = NULL; enum gcry_mpi_format format = GCRYMPI_FMT_USG; char *msgdup; int version = context->protocol_version; *encmessagep = NULL; /* Make sure we're actually supposed to be able to encrypt */ if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED || context->context_priv->their_keyid == 0) { return gcry_error(GPG_ERR_CONFLICT); } /* We need to copy the incoming msg, since it might be an alias for * context->lastmessage, which we'll be freeing soon. */ msgdup = gcry_malloc_secure(justmsglen + 1); if (msgdup == NULL) { return gcry_error(GPG_ERR_ENOMEM); } strcpy(msgdup, msg); /* Header, msg flags, send keyid, recv keyid, counter, msg len, msg * len of revealed mac keys, revealed mac keys, MAC */ buflen = OTRL_HEADER_LEN + (version == 3 ? 8 : 0) + (version == 2 || version == 3 ? 1 : 0) + 4 + 4 + 8 + 4 + msglen + 4 + reveallen + 20; gcry_mpi_print(format, NULL, 0, &pubkeylen, context->context_priv->our_dh_key.pub); buflen += pubkeylen + 4; buf = malloc(buflen); msgbuf = gcry_malloc_secure(msglen); if (buf == NULL || msgbuf == NULL) { free(buf); gcry_free(msgbuf); gcry_free(msgdup); return gcry_error(GPG_ERR_ENOMEM); } memmove(msgbuf, msgdup, justmsglen); msgbuf[justmsglen] = '\0'; otrl_tlv_serialize(msgbuf + justmsglen + 1, tlvs); bufp = buf; lenp = buflen; if (version == 1) { memmove(bufp, "\x00\x01\x03", 3); /* header */ } else if (version == 2) { memmove(bufp, "\x00\x02\x03", 3); /* header */ } else { memmove(bufp, "\x00\x03\x03", 3); /* header */ } debug_data("Header", bufp, 3); bufp += 3; lenp -= 3; if (version == 3) { /* v3 instance tags */ write_int(context->our_instance); debug_int("Sender instag", bufp-4); write_int(context->their_instance); debug_int("Recipient instag", bufp-4); } if (version == 2 || version == 3) { bufp[0] = flags; bufp += 1; lenp -= 1; } write_int(context->context_priv->our_keyid-1); /* sender keyid */ debug_int("Sender keyid", bufp-4); write_int(context->context_priv->their_keyid); /* recipient keyid */ debug_int("Recipient keyid", bufp-4); write_mpi(context->context_priv->our_dh_key.pub, pubkeylen, "Y"); /* Y */ otrl_dh_incctr(sess->sendctr); memmove(bufp, sess->sendctr, 8); /* Counter (top 8 bytes only) */ debug_data("Counter", bufp, 8); bufp += 8; lenp -= 8; write_int(msglen); /* length of encrypted data */ debug_int("Msg len", bufp-4); err = gcry_cipher_reset(sess->sendenc); if (err) goto err; err = gcry_cipher_setctr(sess->sendenc, sess->sendctr, 16); if (err) goto err; err = gcry_cipher_encrypt(sess->sendenc, bufp, msglen, msgbuf, msglen); if (err) goto err; /* encrypted data */ debug_data("Enc data", bufp, msglen); bufp += msglen; lenp -= msglen; gcry_md_reset(sess->sendmac); gcry_md_write(sess->sendmac, buf, bufp-buf); memmove(bufp, gcry_md_read(sess->sendmac, GCRY_MD_SHA1), 20); debug_data("MAC", bufp, 20); bufp += 20; /* MAC */ lenp -= 20; write_int(reveallen); /* length of revealed MAC keys */ debug_int("Revealed MAC length", bufp-4); if (reveallen > 0) { memmove(bufp, context->context_priv->saved_mac_keys, reveallen); debug_data("Revealed MAC data", bufp, reveallen); bufp += reveallen; lenp -= reveallen; free(context->context_priv->saved_mac_keys); context->context_priv->saved_mac_keys = NULL; context->context_priv->numsavedkeys = 0; } assert(lenp == 0); /* Make the base64-encoding. */ base64buf = otrl_base64_otr_encode(buf, buflen); if (base64buf == NULL) { err = gcry_error(GPG_ERR_ENOMEM); goto err; } free(buf); gcry_free(msgbuf); *encmessagep = base64buf; gcry_free(context->context_priv->lastmessage); context->context_priv->lastmessage = NULL; context->context_priv->may_retransmit = 0; if (msglen > 0) { context->context_priv->lastmessage = gcry_malloc_secure(justmsglen + 1); if (context->context_priv->lastmessage) { strcpy(context->context_priv->lastmessage, msgdup); } } gcry_free(msgdup); /* Save a copy of the current extra key */ if (extrakey) { memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES); } return gcry_error(GPG_ERR_NO_ERROR); err: free(buf); gcry_free(msgbuf); gcry_free(msgdup); *encmessagep = NULL; return err; }
static void slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester ) { static int is_initialized = 0; static NETSTATISTICSGET pNetStatisticsGet = NULL; static NETAPIBUFFERSIZE pNetApiBufferSize = NULL; static NETAPIBUFFERFREE pNetApiBufferFree = NULL; static int is_workstation = 1; static int cbPerfData = PERFORMANCE_BUFFER_SIZE; PERF_DATA_BLOCK *pPerfData; HANDLE hDevice, hNetAPI32 = NULL; DWORD dwSize, status; int nDrive; if ( !is_initialized ) { HKEY hKey; if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" ); /* Find out whether this is an NT server or workstation if necessary */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { BYTE szValue[32]; dwSize = sizeof (szValue); if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: check product options\n" ); status = RegQueryValueEx (hKey, "ProductType", 0, NULL, szValue, &dwSize); if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) { /* Note: There are (at least) three cases for ProductType: * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = * NT Server acting as a Domain Controller */ is_workstation = 0; if ( debug_me ) log_debug ("rndw32: this is a NT server\n"); } RegCloseKey (hKey); } /* Initialize the NetAPI32 function pointers if necessary */ if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) { if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" ); pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, "NetStatisticsGet"); pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, "NetApiBufferSize"); pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, "NetApiBufferFree"); if ( !pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree ) { FreeLibrary (hNetAPI32); hNetAPI32 = NULL; log_debug ("rndw32: No NETAPI found\n" ); } } is_initialized = 1; } /* Get network statistics. Note: Both NT Workstation and NT Server by * default will be running both the workstation and server services. The * heuristic below is probably useful though on the assumption that the * majority of the network traffic will be via the appropriate service. * In any case the network statistics return almost no randomness */ { LPBYTE lpBuffer; if (hNetAPI32 && !pNetStatisticsGet (NULL, is_workstation ? L"LanmanWorkstation" : L"LanmanServer", 0, 0, &lpBuffer) ) { if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: get netstats\n" ); pNetApiBufferSize (lpBuffer, &dwSize); (*add) ( lpBuffer, dwSize,requester ); pNetApiBufferFree (lpBuffer); } } /* Get disk I/O statistics for all the hard drives */ for (nDrive = 0;; nDrive++) { char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT]; char szDevice[50]; /* Check whether we can access this device */ sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive); hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) break; /* Note: This only works if you have turned on the disk performance * counters with 'diskperf -y'. These counters are off by default */ if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, &dwSize, NULL)) { if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n", nDrive ); (*add) (diskPerformance, dwSize, requester ); } else { log_info ("NOTE: you should run 'diskperf -y' " "to enable the disk statistics\n"); } CloseHandle (hDevice); } #if 0 /* we don't need this in GnuPG */ /* Wait for any async keyset driver binding to complete. You may be * wondering what this call is doing here... the reason it's necessary is * because RegQueryValueEx() will hang indefinitely if the async driver * bind is in progress. The problem occurs in the dynamic loading and * linking of driver DLL's, which work as follows: * * hDriver = LoadLibrary( DRIVERNAME ); * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 ); * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 ); * * If RegQueryValueEx() is called while the GetProcAddress()'s are in * progress, it will hang indefinitely. This is probably due to some * synchronisation problem in the NT kernel where the GetProcAddress() * calls affect something like a module reference count or function * reference count while RegQueryValueEx() is trying to take a snapshot * of the statistics, which include the reference counts. Because of * this, we have to wait until any async driver bind has completed * before we can call RegQueryValueEx() */ waitSemaphore (SEMAPHORE_DRIVERBIND); #endif /* Get information from the system performance counters. This can take * a few seconds to do. In some environments the call to * RegQueryValueEx() can produce an access violation at some random time * in the future, adding a short delay after the following code block * makes the problem go away. This problem is extremely difficult to * reproduce, I haven't been able to get it to occur despite running it * on a number of machines. The best explanation for the problem is that * on the machine where it did occur, it was caused by an external driver * or other program which adds its own values under the * HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external * modules to map in the data, if there's a synchronisation problem the * external module would write its data at an inappropriate moment, * causing the access violation. A low-level memory checker indicated * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an * interminable number of calls down inside RegQueryValueEx(), was * overwriting memory (it wrote twice the allocated size of a buffer to a * buffer allocated by the NT kernel). This may be what's causing the * problem, but since it's in the kernel there isn't much which can be * done. * * In addition to these problems the code in RegQueryValueEx() which * estimates the amount of memory required to return the performance * counter information isn't very accurate, since it always returns a * worst-case estimate which is usually nowhere near the actual amount * required. For example it may report that 128K of memory is required, * but only return 64K of data */ { pPerfData = gcry_xmalloc (cbPerfData); for (;;) { dwSize = cbPerfData; if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, (LPBYTE) pPerfData, &dwSize); if (status == ERROR_SUCCESS) { if (!memcmp (pPerfData->Signature, L"PERF", 8)) { (*add) ( pPerfData, dwSize, requester ); } else log_debug ( "rndw32: no PERF signature\n"); break; } else if (status == ERROR_MORE_DATA) { cbPerfData += PERFORMANCE_BUFFER_STEP; pPerfData = gcry_realloc (pPerfData, cbPerfData); } else { log_debug ( "rndw32: get performance data problem\n"); break; } } gcry_free (pPerfData); } /* Although this isn't documented in the Win32 API docs, it's necessary to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's implicitly opened on the first call to RegQueryValueEx()). If this isn't done then any system components which provide performance data can't be removed or changed while the handle remains active */ RegCloseKey (HKEY_PERFORMANCE_DATA); }
/* Return the secret key as an S-Exp in RESULT after locating it using the GRIP. Stores NULL at RESULT if the operation shall be diverted to a token; in this case an allocated S-expression with the shadow_info part from the file is stored at SHADOW_INFO. CACHE_MODE defines now the cache shall be used. DESC_TEXT may be set to present a custom description for the pinentry. LOOKUP_TTL is an optional function to convey a TTL to the cache manager; we do not simply pass the TTL value because the value is only needed if an unprotect action was needed and looking up the TTL may have some overhead (e.g. scanning the sshcontrol file). If a CACHE_NONCE is given that cache item is first tried to get a passphrase. If R_PASSPHRASE is not NULL, the function succeeded and the key was protected the used passphrase (entered or from the cache) is stored there; if not NULL will be stored. The caller needs to free the returned passphrase. */ gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, const unsigned char *grip, unsigned char **shadow_info, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, gcry_sexp_t *result, char **r_passphrase) { int rc; unsigned char *buf; size_t len, buflen, erroff; gcry_sexp_t s_skey; int got_shadow_info = 0; *result = NULL; if (shadow_info) *shadow_info = NULL; if (r_passphrase) *r_passphrase = NULL; rc = read_key_file (grip, &s_skey); if (rc) return rc; /* For use with the protection functions we also need the key as an canonical encoded S-expression in a buffer. Create this buffer now. */ rc = make_canon_sexp (s_skey, &buf, &len); if (rc) return rc; switch (agent_private_key_type (buf)) { case PRIVATE_KEY_CLEAR: break; /* no unprotection needed */ case PRIVATE_KEY_PROTECTED: { char *desc_text_final; char *comment = NULL; /* Note, that we will take the comment as a C string for display purposes; i.e. all stuff beyond a Nul character is ignored. */ { gcry_sexp_t comment_sexp; comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); if (comment_sexp) comment = gcry_sexp_nth_string (comment_sexp, 1); gcry_sexp_release (comment_sexp); } desc_text_final = NULL; if (desc_text) rc = modify_description (desc_text, comment? comment:"", s_skey, &desc_text_final); gcry_free (comment); if (!rc) { rc = unprotect (ctrl, cache_nonce, desc_text_final, &buf, grip, cache_mode, lookup_ttl, r_passphrase); if (rc) log_error ("failed to unprotect the secret key: %s\n", gpg_strerror (rc)); } xfree (desc_text_final); } break; case PRIVATE_KEY_SHADOWED: if (shadow_info) { const unsigned char *s; size_t n; rc = agent_get_shadow_info (buf, &s); if (!rc) { n = gcry_sexp_canon_len (s, 0, NULL,NULL); assert (n); *shadow_info = xtrymalloc (n); if (!*shadow_info) rc = out_of_core (); else { memcpy (*shadow_info, s, n); rc = 0; got_shadow_info = 1; } } if (rc) log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc)); } else rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY); break; default: log_error ("invalid private key format\n"); rc = gpg_error (GPG_ERR_BAD_SECKEY); break; } gcry_sexp_release (s_skey); s_skey = NULL; if (rc || got_shadow_info) { xfree (buf); if (r_passphrase) { xfree (*r_passphrase); *r_passphrase = NULL; } return rc; } buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL); rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen); wipememory (buf, buflen); xfree (buf); if (rc) { log_error ("failed to build S-Exp (off=%u): %s\n", (unsigned int)erroff, gpg_strerror (rc)); if (r_passphrase) { xfree (*r_passphrase); *r_passphrase = NULL; } return rc; } *result = s_skey; return 0; }
static void check_dsa_gen_186_2 (void) { static struct { int nbits; const char *p, *q, *g; const char *seed; int counter; const char *h; } tbl[] = { /* These tests are from FIPS 186-2, B.3.1. */ { 1024, "d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69", "9c916d121de9a03f71fb21bc2e1c0d116f065a4f", "8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44", "0cb1990c1fd3626055d7a0096f8fa99807399871", 98, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002" }, { 1024, "f5c73304080353357de1b5967597c27d65f70aa2fe9b6aed1d0afc2b499adf22f" "8e37937096d88548ac36c4a067f8353c7fed73f96f0d688b19b0624aedbae5dbb" "0ee8835a4c269288c0e1d69479e701ee266bb767af39d748fe7d6afc73fdf44be" "3eb6e661e599670061203e75fc8b3dbd59e40b54f358d0097013a0f3867f9", "f8751166cf4f6f3b07c081fd2a9071f23ca1988d", "1e288a442e02461c418ed67a66d24cacbeb8936fbde62ff995f5fd569dee6be62" "4e4f0f9f8c8093f5d192ab3b3f9ae3f2665d95d27fb10e382f45cd356e7f4eb7a" "665db432113ed06478f93b7cf188ec7a1ee97aec8f91ea7bfceaf8b6e7e5a349c" "4ad3225362ef440c57cbc6e69df15b6699caac85f733555075f04781b2b33", "34b3520d45d240a8861b82c8b61ffa16e67b5cce", 622, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, { 1024, "c6c6f4f4eed927fb1c3b0c81010967e530658e6f9698ebe058b4f47b2dc8fcbc7" "b69296b9e8b6cf55681181fe72492668061b262b0046a0d409902e269b0cb69a4" "55ed1a086caf41927f5912bf0e0cbc45ee81a4f98bf6146f6168a228aec80e9cc" "1162d6f6aa412efe82d4f18b95e34ab790daac5bd7aef0b22fa08ba5dbaad", "d32b29f065c1394a30490b6fcbf812a32a8634ab", "06f973c879e2e89345d0ac04f9c34ad69b9eff1680f18d1c8f3e1596c2e8fa8e1" "ecef6830409e9012d4788bef6ec7414d09c981b47c941b77f39dfc49caff5e714" "c97abe25a7a8b5d1fe88700bb96eff91cca64d53700a28b1146d81bad1212d231" "80154c95a01f5aeebb553a8365c38a5ebe05539b51734233776ce9aff98b2", "b6ec750da2f824cb42c5f7e28c81350d97f75125", 185, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, { 1024, "b827a9dc9221a6ed1bec7b64d61232aacb2812f888b0a0b3a95033d7a22e77d0b" "ff23bfeed0fb1281b21b8ff7421f0c727d1fb8aa2b843d6885f067e763f83d41f" "d800ab15a7e2b12f71ec2058ee7bd62cd72c26989b272e519785da57bfa1f974b" "c652e1a2d6cfb68477de5635fd019b37add656cff0b802558b31b6d2851e5", "de822c03445b77cec4ad3a6fb0ca39ff97059ddf", "65a9e2d43a378d7063813104586868cacf2fccd51aec1e0b6af8ba3e66dee6371" "681254c3fb5e3929d65e3c4bcd20abd4ddc7cf815623e17b9fc92f02b8d44278b" "848480ffd193104cf5612639511e45bd247708ff6028bd3824f8844c263b46c69" "1f2076f8cd13c5d0be95f1f2a1a17ab1f7e5bc73500bac27d57b473ba9748", "cd2221dd73815a75224e9fde7faf52829b81ac7a", 62, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, { 1024, "898a8d93e295c8ef2ffd46976225a1543640640d155a576fafa0be32136165803" "ba2eff2782a2be75cc9ec65db6bd3238cca695b3a5a14726a2a314775c377d891" "354b3de6c89e714a05599ca04132c987f889f72c4fe298ccb31f711c03b07e1d9" "8d72af590754cf3847398b60cecd55a4611692b308809560a83880404c227", "c6d786643d2acfc6b8d576863fda8cfbfbd5e03f", "2fd38b8d21c58e8fb5315a177b8d5dc4c450d574e69348b7b9da367c26e72438d" "af8372e7f0bee84ef5dcbbc3727194a2228431192f1779be24837f22a0e14d10d" "5344da1b8b403df9f9b2655095b3d0f67418ed6cd989f35aa4232e4b7001764fb" "e85d6b2c716980f13272fc4271ac1e234f7e24c023cfc2d2dc0aa1e9af2fb", "73483e697599871af983a281e3afa22e0ed86b68", 272, "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000002", }, /* These tests are generated by the OpenSSL FIPS version. */ { 1024, "A404363903FDCE86839BCFD953AAD2DA2B0E70CAED3B5FF5D68F15A1C4BB0A793C" "A9D58FC956804C5901DE0AF99F345ED1A8617C687864BAC044B7C3C3E732A2B255" "EC986AA76EA8CB0E0815B3E0E605650AF7D8058EE7E8EBCDEFFDAB8100D3FC1033" "11BA3AB232EF06BB74BA9A949EC0C7ED324C19B202F4AB725BBB4080C9", "C643946CEA8748E12D430C48DB038F9165814389", "59B7E7BA0033CCE8E6837173420FBB382A784D4154A3C166043F5A68CB92945D16" "892D4CC5585F2D28C780E75A6C20A379E2B58304C1E5FC0D8C15E4E89C4498C8BC" "B90FB36ED8DC0489B9D0BC09EC4411FB0BFADF25485EEAB6700BE0ACF5C44A6ED7" "44A015382FF9B8DA7EAA00DEA135FADC59212DBBFFC1537336FA4B7225", "02708ab36e3f0bfd67ec3b8bd8829d03b84f56bd", 50, "02" }, { 1024, "9C664033DB8B203D826F896D2293C62EF9351D5CFD0F4C0AD7EFDA4DDC7F15987" "6A3C68CAB2586B44FD1BD4DEF7A17905D88D321DD77C4E1720D848CA21D79F9B3" "D8F537338E09B44E9F481E8DA3C56569F63146596A050EF8FAEE8ACA32C666450" "04F675C8806EB4025B0A5ECC39CE89983EA40A183A7CF5208BA958045ABD5", "AD0D8CBA369AF6CD0D2BAC0B4CFCAF0A1F9BCDF7", "74D717F7092A2AF725FDD6C2561D1DBE5AEE40203C638BA8B9F49003857873701" "95A44E515C4E8B344F5CDC7F4A6D38097CD57675E7643AB9700692C69F0A99B0E" "039FDDDFCA8CEB607BDB4ADF2834DE1690F5823FC8199FB8F6F29E5A583B6786A" "C14C7E67106C3B30568CBB9383F89287D578159778EB18216799D16D46498", "6481a12a50384888ee84b61024f7c9c685d6ac96", 289, "02" }, { 1024, "B0DFB602EB8462B1DC8C2214A52B587D3E6842CCF1C38D0F7C7F967ED30CF6828" "1E2675B3BAB594755FB1634E66B4C23936F0725A358F8DFF3C307E2601FD66D63" "5B17270450C50BD2BEC29E0E9A471DF1C15B0191517952268A2763D4BD28B8503" "B3399686272B76B11227F693D7833105EF70C2289C3194CF4527024B272DF", "EA649C04911FAB5A41440287A517EF752A40354B", "88C5A4563ECB949763E0B696CD04B21321360F54C0EE7B23E2CEDC30E9E486162" "01BFB1619E7C54B653D1F890C50E04B29205F5E3E2F93A13B0751AF25491C5194" "93C09DDF6B9C173B3846DFB0E7A5C870BBFC78419260C90E20315410691C8326C" "858D7063E7921F3F601158E912C7EE487FF259202BEEB10F6D9E99190F696", "5bf9d17bc62fbbf3d569c92bd4505586b2e5ef1a", 626, "02" }, { 1024, "F783C08D7F9463E48BA87893805C4B34B63C85DF7EBDD9EBEE94DB4AF4E4A415C" "F0F3793AE55096BA1199598798FA8403B28DED7F7C7AFD54FD535861A0150EF4D" "5871465B13837CCF46BEB0A22F8D38DC7D6AE0E14A3845FD0C027CFA97791B977" "CE2808BAD9B43CE69390C0F40016056722D82C0D7B1B27413D026A39D7DAD", "A40D9EE456AED4C8A653FDB47B6629C0B843FE8F", "DF876263E21F263AE6DA57409BD517DCEADB9216048F066D6B58867F8E59A5EEE" "700283A946C1455534618979BE6C227673C1B803910262BD93BC94D5089850614" "F3E29AB64E8C989A7E3E28FE670FFA3EE21DEEEC1AB0B60E1D8E2AA39663BADD7" "2C9F957D7F3D4F17D9FDAD050EB373A6DEFD09F5DA752EAFE046836E14B67", "8a9a57706f69f4f566252cdf6d5cbfdf2020150b", 397, "02" }, { 1024, "D40E4F6461E145859CCF60FD57962840BD75FFF12C22F76626F566842252AD068" "29745F0147056354F6C016CF12762B0E331787925B8128CF5AF81F9B176A51934" "96D792430FF83C7B79BD595BDA10787B34600787FA552EFE3662F37B99AAD3F3A" "093732680A01345192A19BECCE6BF5D498E44ED6BED5B0BA72AAD49E8276B", "D12F1BD0AA78B99247FD9F18EAFEE5C136686EA5", "468EBD20C99449C1E440E6F8E452C6A6BC7551C555FE5E94996E20CFD4DA3B9CC" "58499D6CC2374CCF9C392715A537DE10CFCA8A6A37AFBD187CF6B88D26881E5F5" "7521D9D2C9BBA51E7B87B070BBE73F5C5FE31E752CAF88183516D8503BAAC1159" "928EF50DEE52D96F396B93FB4138D786464C315401A853E57C9A0F9D25839", "30b3599944a914a330a3f49d11ec88f555422aef", 678, "02" } }; gpg_error_t err; int tno; gcry_sexp_t key_spec, key, pub_key, sec_key, seed_values; gcry_sexp_t l1; for (tno = 0; tno < DIM (tbl); tno++) { if (verbose) info ("generating FIPS 186-2 test key %d\n", tno); { void *data; size_t datalen; data = data_from_hex (tbl[tno].seed, &datalen); err = gcry_sexp_build (&key_spec, NULL, "(genkey (dsa (nbits %d)(use-fips186-2)" "(derive-parms(seed %b))))", tbl[tno].nbits, (int)datalen, data); gcry_free (data); } if (err) die ("error creating S-expression %d: %s\n", tno, gpg_strerror (err)); err = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (err) { fail ("error generating key %d: %s\n", tno, gpg_strerror (err)); continue; } if (verbose > 1) show_sexp ("generated key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) fail ("public part missing in key %d\n", tno); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) fail ("private part missing in key %d\n", tno); l1 = gcry_sexp_find_token (key, "misc-key-info", 0); if (!l1) fail ("misc_key_info part missing in key %d\n", tno); seed_values = gcry_sexp_find_token (l1, "seed-values", 0); if (!seed_values) fail ("seed-values part missing in key %d\n", tno); gcry_sexp_release (l1); extract_cmp_mpi (sec_key, "p", tbl[tno].p); extract_cmp_mpi (sec_key, "q", tbl[tno].q); extract_cmp_mpi (sec_key, "g", tbl[tno].g); extract_cmp_data (seed_values, "seed", tbl[tno].seed); extract_cmp_int (seed_values, "counter", tbl[tno].counter); extract_cmp_mpi (seed_values, "h", tbl[tno].h); gcry_sexp_release (seed_values); gcry_sexp_release (sec_key); gcry_sexp_release (pub_key); gcry_sexp_release (key); } }
int main( int argc, char **argv ) { ARGPARSE_ARGS pargs; enum cmd_and_opt_values cmd = 0; unsigned long from = 0, to = ULONG_MAX; int dry_run = 0; early_system_init (); set_strusage( my_strusage ); gcry_control (GCRYCTL_DISABLE_SECMEM); log_set_prefix ("kbxutil", 1); /* Make sure that our subsystems are ready. */ i18n_init (); init_common_subsystems (&argc, &argv); /* Check that the libraries are suitable. Do it here because the option parsing may need services of the library. */ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) ) { log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt", NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) ); } gcry_set_log_handler (my_gcry_logger, NULL); /*create_dotlock(NULL); register locking cleanup */ /* We need to use the gcry malloc function because jnlib uses them. */ keybox_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free ); pargs.argc = &argc; pargs.argv = &argv; pargs.flags= 1; /* do not remove the args */ while (arg_parse( &pargs, opts) ) { switch (pargs.r_opt) { case oVerbose: /*opt.verbose++;*/ /*gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );*/ break; case oDebug: /*opt.debug |= pargs.r.ret_ulong; */ break; case oDebugAll: /*opt.debug = ~0;*/ break; case aFindByFpr: case aFindByKid: case aFindByUid: case aStats: case aImportOpenPGP: case aFindDups: case aCut: cmd = pargs.r_opt; break; case oFrom: from = pargs.r.ret_ulong; break; case oTo: to = pargs.r.ret_ulong; break; case oDryRun: dry_run = 1; break; default: pargs.err = 2; break; } } if (to < from) log_error ("record number of \"--to\" is lower than \"--from\" one\n"); if (log_get_errorcount(0) ) myexit(2); if (!cmd) { /* Default is to list a KBX file */ if (!argc) _keybox_dump_file (NULL, 0, stdout); else { for (; argc; argc--, argv++) _keybox_dump_file (*argv, 0, stdout); } } else if (cmd == aStats ) { if (!argc) _keybox_dump_file (NULL, 1, stdout); else { for (; argc; argc--, argv++) _keybox_dump_file (*argv, 1, stdout); } } else if (cmd == aFindDups ) { if (!argc) _keybox_dump_find_dups (NULL, 0, stdout); else { for (; argc; argc--, argv++) _keybox_dump_find_dups (*argv, 0, stdout); } } else if (cmd == aCut ) { if (!argc) _keybox_dump_cut_records (NULL, from, to, stdout); else { for (; argc; argc--, argv++) _keybox_dump_cut_records (*argv, from, to, stdout); } } else if (cmd == aImportOpenPGP) { if (!argc) import_openpgp ("-", dry_run); else { for (; argc; argc--, argv++) import_openpgp (*argv, dry_run); } } #if 0 else if ( cmd == aFindByFpr ) { char *fpr; if ( argc != 2 ) wrong_args ("kbxfile foingerprint"); fpr = format_fingerprint ( argv[1] ); if ( !fpr ) log_error ("invalid formatted fingerprint\n"); else { kbxfile_search_by_fpr ( argv[0], fpr ); gcry_free ( fpr ); } } else if ( cmd == aFindByKid ) { u32 kid[2]; int mode; if ( argc != 2 ) wrong_args ("kbxfile short-or-long-keyid"); mode = format_keyid ( argv[1], kid ); if ( !mode ) log_error ("invalid formatted keyID\n"); else { kbxfile_search_by_kid ( argv[0], kid, mode ); } } else if ( cmd == aFindByUid ) { if ( argc != 2 ) wrong_args ("kbxfile userID"); kbxfile_search_by_uid ( argv[0], argv[1] ); } #endif else log_error ("unsupported action\n"); myexit(0); return 8; /*NEVER REACHED*/ }
gcry_err_code_t _gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen, int algo, int subalgo, const unsigned char *salt, size_t saltlen, unsigned long iterations, size_t dkLen, unsigned char *DK) { u64 N = subalgo; /* CPU/memory cost paramter. */ u32 r; /* Block size. */ u32 p = iterations; /* Parallelization parameter. */ gpg_err_code_t ec; u32 i; unsigned char *B = NULL; unsigned char *tmp1 = NULL; unsigned char *tmp2 = NULL; size_t r128; size_t nbytes; if (subalgo < 1 || !iterations) return GPG_ERR_INV_VALUE; if (algo == GCRY_KDF_SCRYPT) r = 8; else if (algo == 41) /* Hack to allow the use of all test vectors. */ r = 1; else return GPG_ERR_UNKNOWN_ALGORITHM; r128 = r * 128; if (r128 / 128 != r) return GPG_ERR_ENOMEM; nbytes = p * r128; if (r128 && nbytes / r128 != p) return GPG_ERR_ENOMEM; nbytes = N * r128; if (r128 && nbytes / r128 != N) return GPG_ERR_ENOMEM; nbytes = 64 + r128; if (nbytes < r128) return GPG_ERR_ENOMEM; B = gcry_malloc (p * r128); if (!B) { ec = gpg_err_code_from_syserror (); goto leave; } tmp1 = gcry_malloc (N * r128); if (!tmp1) { ec = gpg_err_code_from_syserror (); goto leave; } tmp2 = gcry_malloc (64 + r128); if (!tmp2) { ec = gpg_err_code_from_syserror (); goto leave; } ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen, 1 /* iterations */, p * r128, B); for (i = 0; !ec && i < p; i++) _scryptROMix (r, &B[i * r128], N, tmp1, tmp2); for (i = 0; !ec && i < p; i++) ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * r128, 1 /* iterations */, dkLen, DK); leave: gcry_free (tmp2); gcry_free (tmp1); gcry_free (B); return ec; }
extern void io_encryption_init(IO_HANDLE ptr, enum gcry_cipher_algos c, enum gcry_md_algos h, enum gcry_cipher_modes m, const uint8_t *k, size_t l, io_extra_t x) { io_private_t *io_ptr = ptr; if (!io_ptr || io_ptr->fd < 0) return errno = EBADF , (void)NULL; /* * start setting up the encryption buffer */ if (!(io_ptr->buffer_crypt = gcry_malloc_secure(sizeof( buffer_t )))) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, sizeof( buffer_t )); gcry_md_open(&io_ptr->hash_handle, h, GCRY_MD_FLAG_SECURE); gcry_cipher_open(&io_ptr->cipher_handle, c, m, GCRY_CIPHER_SECURE); /* * generate a hash of the supplied key data */ size_t hash_length = gcry_md_get_algo_dlen(h); uint8_t *hash = gcry_malloc_secure(hash_length); if (!hash) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, hash_length); gcry_md_hash_buffer(gcry_md_get_algo(io_ptr->hash_handle), hash, k, l); /* * set the key as the hash of supplied data */ size_t key_length = gcry_cipher_get_algo_keylen(c); uint8_t *key = gcry_calloc_secure(key_length, sizeof( byte_t )); if (!key) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, key_length); memcpy(key, hash, key_length < hash_length ? key_length : hash_length); gcry_cipher_setkey(io_ptr->cipher_handle, key, key_length); /* here is where it blows-up on Windows 8, using AES */ gcry_free(key); /* * the 2011.* versions (incorrectly) used key length instead of block * length; versions after 2014.06 randomly generate the IV instead */ io_ptr->buffer_crypt->block = gcry_cipher_get_algo_blklen(c); uint8_t *iv = gcry_calloc_secure(x.x_iv == IV_BROKEN ? key_length : io_ptr->buffer_crypt->block, sizeof( byte_t )); if (!iv) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, io_ptr->buffer_crypt->block); if (x.x_iv == IV_RANDOM) { if (x.x_encrypt) { gcry_create_nonce(iv, io_ptr->buffer_crypt->block); io_write(ptr, iv, io_ptr->buffer_crypt->block); } else io_read(ptr, iv, io_ptr->buffer_crypt->block); } else { uint8_t *iv_hash = gcry_malloc_secure(hash_length); if (!iv_hash) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, hash_length); /* * set the IV as the hash of the hash */ gcry_md_hash_buffer(gcry_md_get_algo(io_ptr->hash_handle), iv_hash, hash, hash_length); memcpy(iv, iv_hash, io_ptr->buffer_crypt->block < hash_length ? io_ptr->buffer_crypt->block : hash_length); gcry_free(iv_hash); } gcry_free(hash); if (m == GCRY_CIPHER_MODE_CTR) gcry_cipher_setctr(io_ptr->cipher_handle, iv, io_ptr->buffer_crypt->block); else gcry_cipher_setiv(io_ptr->cipher_handle, iv, io_ptr->buffer_crypt->block); gcry_free(iv); /* * set the rest of the buffer */ if (!(io_ptr->buffer_crypt->stream = gcry_malloc_secure(io_ptr->buffer_crypt->block))) die(_("Out of memory @ %s:%d:%s [%zu]"), __FILE__, __LINE__, __func__, io_ptr->buffer_crypt->block); /* * when encrypting/writing data: * 0: length of data buffered so far (in stream) * 1: length of data processed (from d) * when decrypting/reading data: * 0: length of available data in input buffer (stream) * 1: available space in read buffer (d) * 2: next available memory location for data (from d) */ for (unsigned i = 0; i < OFFSET_SLOTS; i++) io_ptr->buffer_crypt->offset[i] = 0; io_ptr->cipher_init = true; io_ptr->hash_init = true; io_ptr->operation = IO_ENCRYPT; return; }
/* Check against PKCS#1 v1.5 encryption test vectors as found at ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt . */ static void check_v15crypt (void) { #include "pkcs1v2-v15c.h" gpg_error_t err; int tno, mno; for (tno = 0; tno < DIM (tbl); tno++) { void *rsa_n, *rsa_e, *rsa_d; size_t rsa_n_len, rsa_e_len, rsa_d_len; gcry_sexp_t sec_key, pub_key; if (verbose > 1) info ("(%s)\n", tbl[tno].desc); rsa_n = data_from_hex (tbl[tno].n, &rsa_n_len); rsa_e = data_from_hex (tbl[tno].e, &rsa_e_len); rsa_d = data_from_hex (tbl[tno].d, &rsa_d_len); err = gcry_sexp_build (&sec_key, NULL, "(private-key (rsa (n %b)(e %b)(d %b)))", (int)rsa_n_len, rsa_n, (int)rsa_e_len, rsa_e, (int)rsa_d_len, rsa_d); if (err) die ("constructing private key failed: %s\n", gpg_strerror (err)); err = gcry_sexp_build (&pub_key, NULL, "(public-key (rsa (n %b)(e %b)))", (int)rsa_n_len, rsa_n, (int)rsa_e_len, rsa_e); if (err) die ("constructing public key failed: %s\n", gpg_strerror (err)); gcry_free (rsa_n); gcry_free (rsa_e); gcry_free (rsa_d); for (mno = 0; mno < DIM (tbl[0].m); mno++) { void *mesg, *seed, *encr; size_t mesg_len, seed_len, encr_len; gcry_sexp_t plain, ciph; if (verbose) info ("running test: %s\n", tbl[tno].m[mno].desc); mesg = data_from_hex (tbl[tno].m[mno].mesg, &mesg_len); seed = data_from_hex (tbl[tno].m[mno].seed, &seed_len); err = gcry_sexp_build (&plain, NULL, "(data (flags pkcs1)(hash-algo sha1)" "(value %b)(random-override %b))", (int)mesg_len, mesg, (int)seed_len, seed); if (err) die ("constructing plain data failed: %s\n", gpg_strerror (err)); gcry_free (mesg); gcry_free (seed); err = gcry_pk_encrypt (&ciph, plain, pub_key); if (err) { show_sexp ("plain:\n", ciph); fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (err)); } else { if (extract_cmp_data (ciph, "a", tbl[tno].m[mno].encr, tbl[tno].m[mno].desc)) { show_sexp ("encrypt result:\n", ciph); fail ("mismatch in gcry_pk_encrypt\n"); } gcry_sexp_release (ciph); ciph = NULL; } gcry_sexp_release (plain); plain = NULL; /* Now test the decryption. */ seed = data_from_hex (tbl[tno].m[mno].seed, &seed_len); encr = data_from_hex (tbl[tno].m[mno].encr, &encr_len); err = gcry_sexp_build (&ciph, NULL, "(enc-val (flags pkcs1)(hash-algo sha1)" "(random-override %b)" "(rsa (a %b)))", (int)seed_len, seed, (int)encr_len, encr); if (err) die ("constructing cipher data failed: %s\n", gpg_strerror (err)); gcry_free (encr); gcry_free (seed); err = gcry_pk_decrypt (&plain, ciph, sec_key); if (err) { show_sexp ("ciph:\n", ciph); fail ("gcry_pk_decrypt failed: %s\n", gpg_strerror (err)); } else { if (extract_cmp_data (plain, "value", tbl[tno].m[mno].mesg, tbl[tno].m[mno].desc)) { show_sexp ("decrypt result:\n", plain); fail ("mismatch in gcry_pk_decrypt\n"); } gcry_sexp_release (plain); plain = NULL; } gcry_sexp_release (ciph); ciph = NULL; } gcry_sexp_release (sec_key); gcry_sexp_release (pub_key); } }
/* Check against PKCS#1 v1.5 signature test vectors as found at ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt . */ static void check_v15sign (void) { #include "pkcs1v2-v15s.h" gpg_error_t err; int tno, mno; for (tno = 0; tno < DIM (tbl); tno++) { void *rsa_n, *rsa_e, *rsa_d; size_t rsa_n_len, rsa_e_len, rsa_d_len; gcry_sexp_t sec_key, pub_key; if (verbose > 1) info ("(%s)\n", tbl[tno].desc); rsa_n = data_from_hex (tbl[tno].n, &rsa_n_len); rsa_e = data_from_hex (tbl[tno].e, &rsa_e_len); rsa_d = data_from_hex (tbl[tno].d, &rsa_d_len); err = gcry_sexp_build (&sec_key, NULL, "(private-key (rsa (n %b)(e %b)(d %b)))", (int)rsa_n_len, rsa_n, (int)rsa_e_len, rsa_e, (int)rsa_d_len, rsa_d); if (err) die ("constructing private key failed: %s\n", gpg_strerror (err)); err = gcry_sexp_build (&pub_key, NULL, "(public-key (rsa (n %b)(e %b)))", (int)rsa_n_len, rsa_n, (int)rsa_e_len, rsa_e); if (err) die ("constructing public key failed: %s\n", gpg_strerror (err)); gcry_free (rsa_n); gcry_free (rsa_e); gcry_free (rsa_d); for (mno = 0; mno < DIM (tbl[0].m); mno++) { void *mesg, *sign; size_t mesg_len, sign_len; gcry_sexp_t sigtmpl, sig; char mhash[20]; if (verbose) info ("running test: %s\n", tbl[tno].m[mno].desc); mesg = data_from_hex (tbl[tno].m[mno].mesg, &mesg_len); gcry_md_hash_buffer (GCRY_MD_SHA1, mhash, mesg, mesg_len); err = gcry_sexp_build (&sigtmpl, NULL, "(data (flags pkcs1)" "(hash sha1 %b))", 20, mhash); if (err) die ("constructing sig template failed: %s\n", gpg_strerror (err)); gcry_free (mesg); err = gcry_pk_sign (&sig, sigtmpl, sec_key); if (err) { show_sexp ("sigtmpl:\n", sigtmpl); fail ("gcry_pk_sign failed: %s\n", gpg_strerror (err)); } else { if (extract_cmp_data (sig, "s", tbl[tno].m[mno].sign, tbl[tno].m[mno].desc)) { show_sexp ("sign result:\n", sig); fail ("mismatch in gcry_pk_sign\n"); } gcry_sexp_release (sig); sig = NULL; } gcry_sexp_release (sigtmpl); sigtmpl = NULL; /* Now test the verification. */ sign = data_from_hex (tbl[tno].m[mno].sign, &sign_len); err = gcry_sexp_build (&sig, NULL, "(sig-val(rsa(s %b)))", (int)sign_len, sign); if (err) die ("constructing verify data failed: %s\n", gpg_strerror (err)); err = gcry_sexp_build (&sigtmpl, NULL, "(data (flags pkcs1)" "(hash sha1 %b))", 20, mhash); if (err) die ("constructing verify tmpl failed: %s\n", gpg_strerror (err)); gcry_free (sign); err = gcry_pk_verify (sig, sigtmpl, pub_key); if (err) { show_sexp ("sig:\n", sig); show_sexp ("sigtmpl:\n", sigtmpl); fail ("gcry_pk_verify failed: %s\n", gpg_strerror (err)); } gcry_sexp_release (sig); sig = NULL; gcry_sexp_release (sigtmpl); sigtmpl = NULL; } gcry_sexp_release (sec_key); gcry_sexp_release (pub_key); } }
void aes256ctr_done(struct aes256ctr *ac) { gcry_cipher_close(ac->ch); memset(ac->buf, 0, CIPHER_BLOCK_SIZE); gcry_free(ac); }
void Cipher::computeAES(){ Util print; //rePlain = new QRegExp("^[\\w|/]+\\.(plain)$"); reCipher = new QRegExp("([\\w]+)"); // Next line is not needed since we derive the key from the passphrase // reKey = new QRegExp("^[\\w|/]+\\.(key)$"); reIv = new QRegExp("[a-fA-F0-9]+"); // Let's derive the key given by the password if( (leKey->text().isEmpty() || lePlain->text().isEmpty() || leCipher->text().isEmpty() || leIv->text().size() != 16 && radioIv->isChecked()) ) { mb = new QMessageBox(this); mb->setWindowTitle("Information"); mb->setText("One field is still empty!"); mb->exec(); return ; } int keylen = comboSize->currentText().toLocal8Bit().toInt()/8; int pass_len = leKey->text().length(); // Here check whether radioIv is checked and if not randomly generate IV and store in the file unsigned char *iv = NULL; int blklen = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES); if(!radioIv->isChecked()) { iv = (unsigned char *) gcry_calloc(blklen, sizeof(unsigned char)); gcry_randomize(iv, blklen, GCRY_STRONG_RANDOM); } else iv = (unsigned char *) leIv->text().toLocal8Bit().constData(); int hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA256); unsigned char *pass = (unsigned char *) gcry_calloc(sizeof(unsigned char), hash_len); strcpy( (char *) pass, leKey->text().toLocal8Bit().constData()); gcry_error_t err = 0; gcry_md_hd_t hd = NULL; if(err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_SECURE)) { fprintf (stderr, "Failure to open MD_SHA256: %s/%s\n", gcry_strsource (err), gcry_strerror (err)); goto out; } gcry_md_write(hd, pass, pass_len); if(pass) gcry_free(pass); pass = gcry_md_read(hd, GCRY_MD_SHA256); /* Dans un soucis de contrôle minimaliste des entrées, nous vérifions, avant toutes opérations, que les QLineEdit contienne bien une extension .in pour le fichier d'entrée, une extension .out pour le fi- chier de sortie et une extension .key pour le fichier de clé */ if(!reIv->exactMatch(leIv->text()) && radioIv->isChecked()) { mb = new QMessageBox(this); mb->setText("The IV field is incorrect"); mb->setWindowTitle("Information"); mb->exec(); return ; } if(reCipher->exactMatch(leCipher->text())) { aes = new AES(); if(!(strcmp(comboMode->currentText().toLocal8Bit().constData(), "CBC") || strcmp(comboSize->currentText().toLocal8Bit().constData(), "128"))) { printf("AES-128-CBC encryption\n"); rep = aes->aes_encrypt(lePlain->text().toLocal8Bit().constData(), leCipher->text().toLocal8Bit().constData(), GCRY_CIPHER_AES, comboMode->currentData().toInt(), (const char *) pass, (const char*) iv); } else if(!(strcmp(comboMode->currentText().toLocal8Bit().constData(), "CBC") || strcmp(comboSize->currentText().toLocal8Bit().constData(), "256"))) { printf("AES-256-CBC encryption\n"); rep = aes->aes_cbc_256_encrypt(lePlain->text().toLocal8Bit().constData(), leCipher->text().toLocal8Bit().constData(), (const char *) pass, (const char *) iv); } if(rep == 1){ mb = new QMessageBox(this); mb->setText("Symmetric encryption error"); mb->setWindowTitle("Information"); mb->exec(); }else{ mb = new QMessageBox(this); mb->setWindowTitle("Information"); mb->setText("Success"); mb->exec(); this->close(); } } else{ /*if(!rePlain->exactMatch(lePlain->text())){ mb = new QMessageBox(this); mb->setText("The given plain file is wrong."); mb->setWindowTitle("Information"); mb->exec(); this->close(); } else if(!reKey->exactMatch(leKey->text())){ mb = new QMessageBox(this); mb->setText("The given key is wrong."); mb->setWindowTitle("Information"); mb->exec(); this->close(); }*/ if(!reCipher->exactMatch(leCipher->text())){ mb = new QMessageBox(this); mb->setText("The given name doesn't respect the given format."); mb->setWindowTitle("Information"); mb->exec(); this->close(); } } // not actually needed, it is done by derivePassphrase // why is gcry_free(pass) failing? out: memset(pass, 0, hash_len); memset(iv, 0, blklen); leKey->clear(); leIv->clear(); if(hd) gcry_md_close(hd); if(iv && !radioIv->isChecked()) gcry_free(iv); return ; }
unsigned char *crypto_decrypt_signature(crypto_ctx *ctx, const unsigned char *sig_data, size_t sig_len, size_t *out_len, unsigned int padding, crypto_error **error) { unsigned char *buf = NULL, *rec_hash = NULL; gnutls_datum_t n = { NULL, 0 }, e = { NULL, 0 }; int err, algo; gcry_sexp_t key = NULL, sig = NULL, decrypted = NULL, child = NULL; gcry_mpi_t n_mpi = NULL, e_mpi = NULL, sig_mpi = NULL, dec_mpi = NULL; size_t buf_len = 0, hash_len = 0; if (!ctx) { crypto_error_set(error, 1, 0, "invalid crypto context"); return NULL; } if (!ctx->num) { crypto_error_set(error, 1, 0, "no certificates in the stack"); return NULL; } algo = gnutls_x509_crt_get_pk_algorithm(ctx->stack[ctx->num - 1], NULL); if (algo != GNUTLS_PK_RSA) { crypto_error_set(error, 1, 0, "certificate public key algorithm not RSA"); return NULL; } err = gnutls_x509_crt_get_pk_rsa_raw(ctx->stack[ctx->num - 1], &n, &e); if (err != GNUTLS_E_SUCCESS) { crypto_error_set(error, 1, 0, "error getting certificate public key"); return NULL; } err = gcry_mpi_scan(&n_mpi, GCRYMPI_FMT_USG, n.data, n.size, NULL); if (err) { crypto_error_set(error, 1, 0, "invalid RSA key 'n' format"); goto out; } err = gcry_mpi_scan(&e_mpi, GCRYMPI_FMT_USG, e.data, e.size, NULL); if (err) { crypto_error_set(error, 1, 0, "invalid RSA key 'e' format"); goto out; } err = gcry_sexp_build(&key, NULL, "(public-key (rsa (n %m) (e %m)))", n_mpi, e_mpi); if (err) { crypto_error_set(error, 1, 0, "could not create public-key expression"); goto out; } err = gcry_mpi_scan(&sig_mpi, GCRYMPI_FMT_USG, sig_data, sig_len, NULL); if (err) { crypto_error_set(error, 1, 0, "invalid signature format"); goto out; } err = gcry_sexp_build(&sig, NULL, "(data (flags raw) (value %m))", sig_mpi); if (err) { crypto_error_set(error, 1, 0, "could not create signature expression"); goto out; } /* encrypt is equivalent to public key decryption for RSA keys */ err = gcry_pk_encrypt(&decrypted, sig, key); if (err) { crypto_error_set(error, 1, 0, "could not decrypt signature"); goto out; } child = gcry_sexp_find_token(decrypted, "a", 1); if (!child) { crypto_error_set(error, 1, 0, "could not get decrypted signature result"); goto out; } dec_mpi = gcry_sexp_nth_mpi(child, 1, GCRYMPI_FMT_USG); gcry_sexp_release(child); if (!dec_mpi) { crypto_error_set(error, 1, 0, "could not get decrypted signature result"); goto out; } gcry_mpi_aprint(GCRYMPI_FMT_USG, &buf, &buf_len, dec_mpi); if (!buf) { crypto_error_set(error, 1, 0, "could not get extract decrypted signature"); goto out; } switch (padding) { case CRYPTO_PAD_NONE: rec_hash = buf; hash_len = buf_len; buf = NULL; *out_len = (int) hash_len; break; case CRYPTO_PAD_PKCS1: rec_hash = check_pkcs1_padding(buf, buf_len, &hash_len, error); if (!rec_hash) { crypto_error_set(error, 1, 0, "could not get extract decrypted padded signature"); goto out; } *out_len = (int) hash_len; break; default: crypto_error_set(error, 1, 0, "unknown padding mechanism %d", padding); break; } out: if (buf) free(buf); if (dec_mpi) gcry_mpi_release(dec_mpi); if (decrypted) gcry_sexp_release(decrypted); if (key) gcry_sexp_release(key); if (sig) gcry_sexp_release(sig); if (sig_mpi) gcry_mpi_release(sig_mpi); if (n_mpi) gcry_mpi_release(n_mpi); if (e_mpi) gcry_mpi_release(e_mpi); if (n.data) gcry_free(n.data); if (e.data) gcry_free(e.data); return rec_hash; }
/* Return the Secure Shell type fingerprint for KEY using digest ALGO. The length of the fingerprint is returned at R_LEN and the fingerprint itself at R_FPR. In case of a error code is returned and NULL stored at R_FPR. */ static gpg_error_t get_fingerprint (gcry_sexp_t key, int algo, void **r_fpr, size_t *r_len, int as_string) { gpg_error_t err; gcry_sexp_t list = NULL; gcry_sexp_t l2 = NULL; const char *s; char *name = NULL; int idx; const char *elems; gcry_md_hd_t md = NULL; int blobmode = 0; *r_fpr = NULL; *r_len = 0; /* Check that the first element is valid. */ list = gcry_sexp_find_token (key, "public-key", 0); if (!list) list = gcry_sexp_find_token (key, "private-key", 0); if (!list) list = gcry_sexp_find_token (key, "protected-private-key", 0); if (!list) list = gcry_sexp_find_token (key, "shadowed-private-key", 0); if (!list) { err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_SEXP); goto leave; } l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; l2 = NULL; name = gcry_sexp_nth_string (list, 0); if (!name) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } err = gcry_md_open (&md, algo, 0); if (err) goto leave; switch (gcry_pk_map_name (name)) { case GCRY_PK_RSA: elems = "en"; gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11); break; case GCRY_PK_DSA: elems = "pqgy"; gcry_md_write (md, "\0\0\0\x07ssh-dss", 11); break; case GCRY_PK_ECC: if (is_eddsa (list)) { elems = "q"; blobmode = 1; /* For now there is just one curve, thus no need to switch on it. */ gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15); } else { /* We only support the 3 standard curves for now. It is just a quick hack. */ elems = "q"; gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20); l2 = gcry_sexp_find_token (list, "curve", 0); if (!l2) elems = ""; else { gcry_free (name); name = gcry_sexp_nth_string (l2, 1); gcry_sexp_release (l2); l2 = NULL; if (!name) elems = ""; else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256")) gcry_md_write (md, "256\0\0\0\x08nistp256", 15); else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384")) gcry_md_write (md, "384\0\0\0\x08nistp384", 15); else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521")) gcry_md_write (md, "521\0\0\0\x08nistp521", 15); else elems = ""; } if (!*elems) err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE); } break; default: elems = ""; err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO); break; } if (err) goto leave; for (idx = 0, s = elems; *s; s++, idx++) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } if (blobmode) { const char *blob; size_t bloblen; unsigned char lenbuf[4]; blob = gcry_sexp_nth_data (l2, 1, &bloblen); if (!blob) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } blob++; bloblen--; lenbuf[0] = bloblen >> 24; lenbuf[1] = bloblen >> 16; lenbuf[2] = bloblen >> 8; lenbuf[3] = bloblen; gcry_md_write (md, lenbuf, 4); gcry_md_write (md, blob, bloblen); } else { gcry_mpi_t a; unsigned char *buf; size_t buflen; a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); l2 = NULL; if (!a) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a); gcry_mpi_release (a); if (err) goto leave; gcry_md_write (md, buf, buflen); gcry_free (buf); } }
/* Assume that the reader is at a pkcs#12 message and try to import certificates from that stupid format. We will transfer secret keys to the agent. */ static gpg_error_t parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats) { gpg_error_t err = 0; char buffer[1024]; size_t ntotal, nread; membuf_t p12mbuf; char *p12buffer = NULL; size_t p12buflen; size_t p12bufoff; gcry_mpi_t *kparms = NULL; struct rsa_secret_key_s sk; char *passphrase = NULL; unsigned char *key = NULL; size_t keylen; void *kek = NULL; size_t keklen; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; gcry_cipher_hd_t cipherhd = NULL; gcry_sexp_t s_key = NULL; unsigned char grip[20]; int bad_pass = 0; int i; struct store_cert_parm_s store_cert_parm; memset (&store_cert_parm, 0, sizeof store_cert_parm); store_cert_parm.ctrl = ctrl; store_cert_parm.stats = stats; init_membuf (&p12mbuf, 4096); ntotal = 0; while (!(err = ksba_reader_read (reader, buffer, sizeof buffer, &nread))) { if (ntotal >= MAX_P12OBJ_SIZE*1024) { /* Arbitrary limit to avoid DoS attacks. */ err = gpg_error (GPG_ERR_TOO_LARGE); log_error ("pkcs#12 object is larger than %dk\n", MAX_P12OBJ_SIZE); break; } put_membuf (&p12mbuf, buffer, nread); ntotal += nread; } if (gpg_err_code (err) == GPG_ERR_EOF) err = 0; if (!err) { p12buffer = get_membuf (&p12mbuf, &p12buflen); if (!p12buffer) err = gpg_error_from_syserror (); } if (err) { log_error (_("error reading input: %s\n"), gpg_strerror (err)); goto leave; } /* GnuPG 2.0.4 accidently created binary P12 files with the string "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data. We fix that here. */ if (p12buflen > 29 && !memcmp (p12buffer, "The passphrase is ", 18)) { for (p12bufoff=18; p12bufoff < p12buflen && p12buffer[p12bufoff] != '\n'; p12bufoff++) ; p12bufoff++; if (p12bufoff < p12buflen && p12buffer[p12bufoff] == '\n') p12bufoff++; } else p12bufoff = 0; err = gpgsm_agent_ask_passphrase (ctrl, i18n_utf8 ("Please enter the passphrase to unprotect the PKCS#12 object."), 0, &passphrase); if (err) goto leave; kparms = p12_parse (p12buffer + p12bufoff, p12buflen - p12bufoff, passphrase, store_cert_cb, &store_cert_parm, &bad_pass); xfree (passphrase); passphrase = NULL; if (!kparms) { log_error ("error parsing or decrypting the PKCS#12 file\n"); err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } /* print_mpi (" n", kparms[0]); */ /* print_mpi (" e", kparms[1]); */ /* print_mpi (" d", kparms[2]); */ /* print_mpi (" p", kparms[3]); */ /* print_mpi (" q", kparms[4]); */ /* print_mpi ("dmp1", kparms[5]); */ /* print_mpi ("dmq1", kparms[6]); */ /* print_mpi (" u", kparms[7]); */ sk.n = kparms[0]; sk.e = kparms[1]; sk.d = kparms[2]; sk.q = kparms[3]; sk.p = kparms[4]; sk.u = kparms[7]; err = rsa_key_check (&sk); if (err) goto leave; /* print_mpi (" n", sk.n); */ /* print_mpi (" e", sk.e); */ /* print_mpi (" d", sk.d); */ /* print_mpi (" p", sk.p); */ /* print_mpi (" q", sk.q); */ /* print_mpi (" u", sk.u); */ /* Create an S-expresion from the parameters. */ err = gcry_sexp_build (&s_key, NULL, "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL); for (i=0; i < 8; i++) gcry_mpi_release (kparms[i]); gcry_free (kparms); kparms = NULL; if (err) { log_error ("failed to create S-expression from key: %s\n", gpg_strerror (err)); goto leave; } /* Compute the keygrip. */ if (!gcry_pk_get_keygrip (s_key, grip)) { err = gpg_error (GPG_ERR_GENERAL); log_error ("can't calculate keygrip\n"); goto leave; } log_printhex ("keygrip=", grip, 20); /* Convert to canonical encoding using a function which pads it to a multiple of 64 bits. We need this padding for AESWRAP. */ err = make_canon_sexp_pad (s_key, 1, &key, &keylen); if (err) { log_error ("error creating canonical S-expression\n"); goto leave; } gcry_sexp_release (s_key); s_key = NULL; /* Get the current KEK. */ err = gpgsm_agent_keywrap_key (ctrl, 0, &kek, &keklen); if (err) { log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } /* Wrap the key. */ err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); if (err) goto leave; err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) goto leave; xfree (kek); kek = NULL; wrappedkeylen = keylen + 8; wrappedkey = xtrymalloc (wrappedkeylen); if (!wrappedkey) { err = gpg_error_from_syserror (); goto leave; } err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen); if (err) goto leave; xfree (key); key = NULL; gcry_cipher_close (cipherhd); cipherhd = NULL; /* Send the wrapped key to the agent. */ err = gpgsm_agent_import_key (ctrl, wrappedkey, wrappedkeylen); if (!err) { stats->count++; stats->secret_read++; stats->secret_imported++; } else if ( gpg_err_code (err) == GPG_ERR_EEXIST ) { err = 0; stats->count++; stats->secret_read++; stats->secret_dups++; } /* If we did not get an error from storing the secret key we return a possible error from parsing the certificates. We do this after storing the secret keys so that a bad certificate does not inhibit our chance to store the secret key. */ if (!err && store_cert_parm.err) err = store_cert_parm.err; leave: if (kparms) { for (i=0; i < 8; i++) gcry_mpi_release (kparms[i]); gcry_free (kparms); kparms = NULL; } xfree (key); gcry_sexp_release (s_key); xfree (passphrase); gcry_cipher_close (cipherhd); xfree (wrappedkey); xfree (kek); xfree (get_membuf (&p12mbuf, NULL)); xfree (p12buffer); if (bad_pass) { /* We only write a plain error code and not direct BAD_PASSPHRASE because the pkcs12 parser might issue this message multiple times, BAD_PASSPHRASE in general requires a keyID and parts of the import might actually succeed so that IMPORT_PROBLEM is also not appropriate. */ gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "import.parsep12", GPG_ERR_BAD_PASSPHRASE); } return err; }
gboolean egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input, gconstpointer salt, gsize n_salt, gconstpointer info, gsize n_info, gpointer output, gsize n_output) { gpointer alloc = NULL; gpointer buffer = NULL; gcry_md_hd_t md1, md2; guint hash_len; gint i; gint flags, algo; gsize step, n_buffer; guchar *at; gcry_error_t gcry; algo = gcry_md_map_name (hash_algo); g_return_val_if_fail (algo != 0, FALSE); hash_len = gcry_md_get_algo_dlen (algo); g_return_val_if_fail (hash_len != 0, FALSE); g_return_val_if_fail (n_output <= 255 * hash_len, FALSE); /* Buffer we need to for intermediate stuff */ if (gcry_is_secure (input)) { flags = GCRY_MD_FLAG_SECURE; buffer = gcry_malloc_secure (hash_len); } else { flags = 0; buffer = gcry_malloc (hash_len); } g_return_val_if_fail (buffer, FALSE); n_buffer = 0; /* Salt defaults to hash_len zeros */ if (!salt) { salt = alloc = g_malloc0 (hash_len); n_salt = hash_len; } /* Step 1: Extract */ gcry = gcry_md_open (&md1, algo, GCRY_MD_FLAG_HMAC | flags); g_return_val_if_fail (gcry == 0, FALSE); gcry = gcry_md_setkey (md1, salt, n_salt); g_return_val_if_fail (gcry == 0, FALSE); gcry_md_write (md1, input, n_input); /* Step 2: Expand */ gcry = gcry_md_open (&md2, algo, GCRY_MD_FLAG_HMAC | flags); g_return_val_if_fail (gcry == 0, FALSE); gcry = gcry_md_setkey (md2, gcry_md_read (md1, algo), hash_len); g_return_val_if_fail (gcry == 0, FALSE); gcry_md_close (md1); at = output; for (i = 1; i < 256; ++i) { gcry_md_reset (md2); gcry_md_write (md2, buffer, n_buffer); gcry_md_write (md2, info, n_info); gcry_md_putc (md2, i); n_buffer = hash_len; memcpy (buffer, gcry_md_read (md2, algo), n_buffer); step = MIN (n_buffer, n_output); memcpy (at, buffer, step); n_output -= step; at += step; if (!n_output) break; } g_free (alloc); gcry_free (buffer); return TRUE; }
/* * Generate a deterministic secret exponent K less than DSA_Q. H1 is * the to be signed digest with a length of HLEN bytes. HALGO is the * algorithm used to create the hash. On success the value for K is * stored at R_K. */ gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, const unsigned char *h1, unsigned int hlen, int halgo, unsigned int extraloops) { gpg_err_code_t rc; unsigned char *V = NULL; unsigned char *K = NULL; unsigned char *x_buf = NULL; unsigned char *h1_buf = NULL; gcry_md_hd_t hd = NULL; unsigned char *t = NULL; gcry_mpi_t k = NULL; unsigned int tbits, qbits; int i; qbits = mpi_get_nbits (dsa_q); if (!qbits || !h1 || !hlen) return GPG_ERR_EINVAL; if (gcry_md_get_algo_dlen (halgo) != hlen) return GPG_ERR_DIGEST_ALGO; /* Step b: V = 0x01 0x01 0x01 ... 0x01 */ V = gcry_malloc (hlen); if (!V) { rc = gpg_err_code_from_syserror (); goto leave; } for (i=0; i < hlen; i++) V[i] = 1; /* Step c: K = 0x00 0x00 0x00 ... 0x00 */ K = gcry_calloc (1, hlen); if (!K) { rc = gpg_err_code_from_syserror (); goto leave; } rc = int2octets (&x_buf, dsa_x, (qbits+7)/8); if (rc) goto leave; rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits); if (rc) goto leave; /* Create a handle to compute the HMACs. */ rc = gpg_err_code (gcry_md_open (&hd, halgo, (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC))); if (rc) goto leave; /* Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); gcry_md_write (hd, "", 1); gcry_md_write (hd, x_buf, (qbits+7)/8); gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, gcry_md_read (hd, 0), hlen); /* Step e: V = HMAC_K(V) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); memcpy (V, gcry_md_read (hd, 0), hlen); /* Step f: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); gcry_md_write (hd, "\x01", 1); gcry_md_write (hd, x_buf, (qbits+7)/8); gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, gcry_md_read (hd, 0), hlen); /* Step g: V = HMAC_K(V) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); memcpy (V, gcry_md_read (hd, 0), hlen); /* Step h. */ t = gcry_malloc ((qbits+7)/8+hlen); if (!t) { rc = gpg_err_code_from_syserror (); goto leave; } again: for (tbits = 0; tbits < qbits;) { /* V = HMAC_K(V) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); memcpy (V, gcry_md_read (hd, 0), hlen); /* T = T || V */ memcpy (t+(tbits+7)/8, V, hlen); tbits += 8*hlen; } /* k = bits2int (T) */ mpi_free (k); k = NULL; rc = gpg_err_code (gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL)); if (rc) goto leave; if (tbits > qbits) gcry_mpi_rshift (k, k, tbits - qbits); /* Check: k < q and k > 1 */ if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0)) { /* K = HMAC_K(V || 0x00) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); gcry_md_write (hd, "", 1); memcpy (K, gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); memcpy (V, gcry_md_read (hd, 0), hlen); goto again; } /* The caller may have requested that we introduce some extra loops. This is for example useful if the caller wants another value for K because the last returned one yielded an R of 0. Becuase this is very unlikely we implement it in a straightforward way. */ if (extraloops) { extraloops--; /* K = HMAC_K(V || 0x00) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); gcry_md_write (hd, "", 1); memcpy (K, gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = gpg_err_code (gcry_md_setkey (hd, K, hlen)); if (rc) goto leave; gcry_md_write (hd, V, hlen); memcpy (V, gcry_md_read (hd, 0), hlen); goto again; } /* log_mpidump (" k", k); */ leave: gcry_free (t); gcry_md_close (hd); gcry_free (h1_buf); gcry_free (x_buf); gcry_free (K); gcry_free (V); if (rc) mpi_free (k); else *r_k = k; return rc; }
/* decrypts the RSA encrypted text read from the XML file, * and saves the AES key and the other needed info * uses libgcrypt for decryption */ int AESKey::decryptRSA( string s_cipher_text_b64 ) { RSAKey rsa_key( this->p_demux ); unsigned char *ps_cipher_text = NULL; unsigned char *ps_plain_text = NULL; gcry_mpi_t cipher_text_mpi = NULL; gcry_sexp_t cipher_text_sexp = NULL; gcry_sexp_t plain_text_sexp = NULL; gcry_mpi_t plain_text_mpi = NULL; gcry_sexp_t tmp_sexp = NULL; gcry_error_t err; size_t length; int i_ret = VLC_EGENERIC; /* get RSA private key file path */ if( rsa_key.setPath() ) goto end; /* read private key from file */ if( rsa_key.readPEM() ) goto end; /* remove spaces and newlines from encoded cipher text * (usually added for indentation in XML files) * */ try { s_cipher_text_b64.erase( remove_if( s_cipher_text_b64.begin(), s_cipher_text_b64.end(), static_cast<int(*)(int)>(isspace) ), s_cipher_text_b64.end() ); } catch( ... ) { msg_Err( this->p_demux, "error while handling string" ); goto end; } /* decode cipher from BASE64 to binary */ if( ! ( length = vlc_b64_decode_binary( &ps_cipher_text, s_cipher_text_b64.c_str() ) ) ) { msg_Err( this->p_demux, "could not decode cipher from Base64" ); goto end; } /* initialize libgcrypt */ vlc_gcrypt_init (); /* create S-expression for ciphertext */ if( ( err = gcry_mpi_scan( &cipher_text_mpi, GCRYMPI_FMT_USG, ps_cipher_text, 256, NULL ) ) ) { msg_Err( this->p_demux, "could not scan MPI from cipher text: %s", gcry_strerror( err ) ); goto end; } if( ( err = gcry_sexp_build( &cipher_text_sexp, NULL, "(enc-val(flags oaep)(rsa(a %m)))", cipher_text_mpi ) ) ) { msg_Err( this->p_demux, "could not build S-expression for cipher text: %s", gcry_strerror( err ) ); goto end; } /* decrypt */ if( ( err = gcry_pk_decrypt( &plain_text_sexp, cipher_text_sexp, rsa_key.priv_key ) ) ) { msg_Err( this->p_demux, "error while decrypting RSA encrypted info: %s", gcry_strerror( err ) ); goto end; } /* extract plain-text from S-expression */ if( ! ( tmp_sexp = gcry_sexp_find_token( plain_text_sexp, "value", 0 ) ) ) /* when using padding flags, the decrypted S-expression is of the form * "(value <plaintext>)", where <plaintext> is an MPI */ { msg_Err( this->p_demux, "decrypted text is in an unexpected form; decryption may have failed" ); goto end; } /* we could have used the gcry_sexp_nth_data to get the data directly, * but as that function is newly introduced (libgcrypt v1.6), * we prefer compatibility, even though that means passing the data through an MPI first */ if( ! ( plain_text_mpi = gcry_sexp_nth_mpi( tmp_sexp, 1, GCRYMPI_FMT_USG ) ) ) { msg_Err( this->p_demux, "could not extract MPI from decrypted S-expression" ); goto end; } if( ( err = gcry_mpi_aprint( GCRYMPI_FMT_USG, &ps_plain_text, &length, plain_text_mpi ) ) ) { msg_Err( this->p_demux, "error while extracting plain text from MPI: %s", gcry_strerror( err ) ); goto end; } /* interpret the plaintext data */ switch( length ) { case 138: /* SMPTE DCP */ if( this->extractInfo( ps_plain_text, true ) ) goto end; break; case 134: /* Interop DCP */ if( this->extractInfo( ps_plain_text, false ) ) goto end; break; case -1: msg_Err( this->p_demux, "could not decrypt" ); goto end; default: msg_Err( this->p_demux, "CipherValue field length does not match SMPTE nor Interop standards" ); goto end; } i_ret = VLC_SUCCESS; end: free( ps_cipher_text ); gcry_mpi_release( cipher_text_mpi ); gcry_sexp_release( cipher_text_sexp ); gcry_sexp_release( plain_text_sexp ); gcry_mpi_release( plain_text_mpi ); gcry_sexp_release( tmp_sexp ); gcry_free( ps_plain_text ); return i_ret; }
/* * Generate a random secret exponent K less than Q. * Note that ECDSA uses this code also to generate D. */ gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level) { gcry_mpi_t k = mpi_alloc_secure (mpi_get_nlimbs (q)); unsigned int nbits = mpi_get_nbits (q); unsigned int nbytes = (nbits+7)/8; char *rndbuf = NULL; /* To learn why we don't use mpi_mod to get the requested bit size, read the paper: "The Insecurity of the Digital Signature Algorithm with Partially Known Nonces" by Nguyen and Shparlinski. Journal of Cryptology, New York. Vol 15, nr 3 (2003) */ if (DBG_CIPHER) log_debug ("choosing a random k of %u bits at seclevel %d\n", nbits, security_level); for (;;) { if ( !rndbuf || nbits < 32 ) { gcry_free (rndbuf); rndbuf = gcry_random_bytes_secure (nbytes, security_level); } else { /* Change only some of the higher bits. We could improve this by directly requesting more memory at the first call to get_random_bytes() and use these extra bytes here. However the required management code is more complex and thus we better use this simple method. */ char *pp = gcry_random_bytes_secure (4, security_level); memcpy (rndbuf, pp, 4); gcry_free (pp); } _gcry_mpi_set_buffer (k, rndbuf, nbytes, 0); /* Make sure we have the requested number of bits. This code looks a bit funny but it is easy to understand if you consider that mpi_set_highbit clears all higher bits. We don't have a clear_highbit, thus we first set the high bit and then clear it again. */ if (mpi_test_bit (k, nbits-1)) mpi_set_highbit (k, nbits-1); else { mpi_set_highbit (k, nbits-1); mpi_clear_bit (k, nbits-1); } if (!(mpi_cmp (k, q) < 0)) /* check: k < q */ { if (DBG_CIPHER) log_debug ("\tk too large - again\n"); continue; /* no */ } if (!(mpi_cmp_ui (k, 0) > 0)) /* check: k > 0 */ { if (DBG_CIPHER) log_debug ("\tk is zero - again\n"); continue; /* no */ } break; /* okay */ } gcry_free (rndbuf); return k; }
static void cipher_bench ( const char *algoname ) { static int header_printed; int algo; gcry_cipher_hd_t hd; int i; int keylen, blklen; char key[128]; char *outbuf, *buf; char *raw_outbuf, *raw_buf; size_t allocated_buflen, buflen; int repetitions; static struct { int mode; const char *name; int blocked; } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1 }, { GCRY_CIPHER_MODE_CBC, " CBC", 1 }, { GCRY_CIPHER_MODE_CFB, " CFB", 0 }, { GCRY_CIPHER_MODE_OFB, " OFB", 0 }, { GCRY_CIPHER_MODE_CTR, " CTR", 0 }, { GCRY_CIPHER_MODE_STREAM, "", 0 }, {0} }; int modeidx; gcry_error_t err = GPG_ERR_NO_ERROR; if (!algoname) { for (i=1; i < 400; i++) if ( !gcry_cipher_test_algo (i) ) cipher_bench (gcry_cipher_algo_name (i)); return; } if (large_buffers) { allocated_buflen = 1024 * 100; repetitions = 10; } else { allocated_buflen = 1024; repetitions = 1000; } repetitions *= cipher_repetitions; raw_buf = gcry_xmalloc (allocated_buflen+15); buf = (raw_buf + ((16 - ((size_t)raw_buf & 0x0f)) % buffer_alignment)); outbuf = raw_outbuf = gcry_xmalloc (allocated_buflen+15); outbuf = (raw_outbuf + ((16 - ((size_t)raw_outbuf & 0x0f)) % buffer_alignment)); if (!header_printed) { if (cipher_repetitions != 1) printf ("Running each test %d times.\n", cipher_repetitions); printf ("%-12s", ""); for (modeidx=0; modes[modeidx].mode; modeidx++) if (*modes[modeidx].name) printf (" %-15s", modes[modeidx].name ); putchar ('\n'); printf ("%-12s", ""); for (modeidx=0; modes[modeidx].mode; modeidx++) if (*modes[modeidx].name) printf (" ---------------" ); putchar ('\n'); header_printed = 1; } algo = gcry_cipher_map_name (algoname); if (!algo) { fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname); exit (1); } keylen = gcry_cipher_get_algo_keylen (algo); if (!keylen) { fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n", algoname); exit (1); } if ( keylen > sizeof key ) { fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n", algo, keylen ); exit (1); } for (i=0; i < keylen; i++) key[i] = i + (clock () & 0xff); blklen = gcry_cipher_get_algo_blklen (algo); if (!blklen) { fprintf (stderr, PGM ": failed to get block length for algorithm `%s'\n", algoname); exit (1); } printf ("%-12s", gcry_cipher_algo_name (algo)); fflush (stdout); for (modeidx=0; modes[modeidx].mode; modeidx++) { if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM) | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) continue; for (i=0; i < sizeof buf; i++) buf[i] = i; err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0); if (err) { fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname); exit (1); } if (!cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, keylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } buflen = allocated_buflen; if (modes[modeidx].blocked) buflen = (buflen / blklen) * blklen; start_timer (); for (i=err=0; !err && i < repetitions; i++) { if (cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, keylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); fflush (stdout); gcry_cipher_close (hd); if (err) { fprintf (stderr, "gcry_cipher_encrypt failed: %s\n", gpg_strerror (err) ); exit (1); } err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0); if (err) { fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname); exit (1); } if (!cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, keylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } start_timer (); for (i=err=0; !err && i < repetitions; i++) { if (cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, keylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } err = gcry_cipher_decrypt ( hd, outbuf, buflen, buf, buflen); } stop_timer (); printf (" %s", elapsed_time ()); fflush (stdout); gcry_cipher_close (hd); if (err) { fprintf (stderr, "gcry_cipher_decrypt failed: %s\n", gpg_strerror (err) ); exit (1); } } putchar ('\n'); gcry_free (raw_buf); gcry_free (raw_outbuf); }
int main(int argc, char **argv) { int ret; setlocale(LC_ALL, ""); if (argc != 3) { wprintf(L"Usage: psafe file.psafe3 passphrase"); exit(EXIT_FAILURE); } init_crypto(64*1024); size_t sz; uint8_t *ptr; ptr = mapfile_ro(argv[1], &sz); if (ptr == NULL) err(1, "%s", argv[1]); struct psafe3_pro *pro; pro = (struct psafe3_pro *)(ptr + 4); struct safe_sec *sec; sec = gcry_malloc_secure(sizeof(*sec)); ret = stretch_and_check_pass(argv[2], strlen(argv[2]), pro, sec); if (ret != 0) { gcry_free(sec); wprintf(L"Invalid password.\n"); exit(1); } uint8_t *safe; size_t safe_size; safe_size = sz - (4 + sizeof(*pro) + 48); assert(safe_size > 0); assert(safe_size % TWOF_BLKSIZE == 0); safe = gcry_malloc_secure(safe_size); assert(safe != NULL); gcry_error_t gerr; struct decrypt_ctx ctx; if (init_decrypt_ctx(&ctx, pro, sec) < 0) gcrypt_fatal(ctx.gerr); size_t bcnt; bcnt = safe_size / TWOF_BLKSIZE; assert(bcnt > 0); uint8_t *encp; uint8_t *safep; encp = ptr + 4 + sizeof(*pro); safep = safe; while (bcnt--) { gerr = gcry_cipher_decrypt(ctx.cipher, safep, TWOF_BLKSIZE, encp, TWOF_BLKSIZE); if (gerr != GPG_ERR_NO_ERROR) gcrypt_fatal(gerr); safep += TWOF_BLKSIZE; encp += TWOF_BLKSIZE; } enum { HDR, DB }; int state = HDR; safep = safe; while (safep < safe + safe_size) { struct field *fld; fld = (struct field *)safep; wprintf(L"len=%-3u type=%02x ", fld->len, fld->type); if (state == DB) db_print(stdout, fld); else hd_print(stdout, fld); if (fld->type == 0xff) state = DB; putwc('\n', stdout); if (fld->len) gcry_md_write(ctx.hmac, safep + sizeof(*fld), fld->len); safep += ((fld->len + 5 + 15) / TWOF_BLKSIZE) * TWOF_BLKSIZE; } assert(memcmp(ptr + (sz - 48), "PWS3-EOFPWS3-EOF", TWOF_BLKSIZE) == 0); #define EOL() putwc('\n', stdout) EOL(); print_prologue(stdout, pro); wprintf(L"KEY "); printhex(stdout, sec->pprime, 32); EOL(); wprintf(L"H(KEY) "); printhex(stdout, pro->h_pprime, 32); EOL(); gcry_md_final(ctx.hmac); wprintf(L"HMAC' "); uint8_t hmac[32]; memmove(hmac, gcry_md_read(ctx.hmac, GCRY_MD_SHA256), 32); printhex(stdout, hmac, 32); EOL(); wprintf(L"HMAC "); printhex(stdout, ptr + (sz - 32), 32); EOL(); #undef EOL gcry_free(safe); gcry_free(sec); unmapfile(ptr, sz); term_decrypt_ctx(&ctx); exit(0); }
/* Convert the big integer A into the external representation described by FORMAT and store it in the provided BUFFER which has been allocated by the user with a size of BUFLEN bytes. NWRITTEN receives the actual length of the external representation unless it has been passed as NULL. BUFFER may be NULL to query the required length. */ gcry_error_t gcry_mpi_print (enum gcry_mpi_format format, unsigned char *buffer, size_t buflen, size_t *nwritten, struct gcry_mpi *a) { unsigned int nbits = mpi_get_nbits (a); size_t len; size_t dummy_nwritten; if (!nwritten) nwritten = &dummy_nwritten; len = buflen; *nwritten = 0; if (format == GCRYMPI_FMT_STD) { unsigned char *tmp; int extra = 0; unsigned int n; if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */ tmp = _gcry_mpi_get_buffer (a, &n, NULL); if (!tmp) return gpg_error_from_syserror (); if (n && (*tmp & 0x80)) { n++; extra=1; } if (buffer && n > len) { /* The provided buffer is too short. */ gcry_free (tmp); return gcry_error (GPG_ERR_TOO_SHORT); } if (buffer) { unsigned char *s = buffer; if (extra) *s++ = 0; memcpy (s, tmp, n-extra); } gcry_free(tmp); *nwritten = n; return 0; } else if (format == GCRYMPI_FMT_USG) { unsigned int n = (nbits + 7)/8; /* Note: We ignore the sign for this format. */ /* FIXME: for performance reasons we should put this into mpi_aprint because we can then use the buffer directly. */ if (buffer && n > len) return gcry_error (GPG_ERR_TOO_SHORT); if (buffer) { unsigned char *tmp; tmp = _gcry_mpi_get_buffer (a, &n, NULL); if (!tmp) return gpg_error_from_syserror (); memcpy (buffer, tmp, n); gcry_free (tmp); } *nwritten = n; return 0; } else if (format == GCRYMPI_FMT_PGP) { unsigned int n = (nbits + 7)/8; /* The PGP format can only handle unsigned integers. */ if( a->sign ) return gcry_error (GPG_ERR_INV_ARG); if (buffer && n+2 > len) return gcry_error (GPG_ERR_TOO_SHORT); if (buffer) { unsigned char *tmp; unsigned char *s = buffer; s[0] = nbits >> 8; s[1] = nbits; tmp = _gcry_mpi_get_buffer (a, &n, NULL); if (!tmp) return gpg_error_from_syserror (); memcpy (s+2, tmp, n); gcry_free (tmp); } *nwritten = n+2; return 0; }
/* Fallback method using the registry to poll the statistics. */ static void registry_poll (void (*add)(const void*, size_t, enum random_origins), enum random_origins requester) { static int cbPerfData = PERFORMANCE_BUFFER_SIZE; int iterations; DWORD dwSize, status; PERF_DATA_BLOCK *pPerfData; /* Get information from the system performance counters. This can take a few seconds to do. In some environments the call to RegQueryValueEx() can produce an access violation at some random time in the future, in some cases adding a short delay after the following code block makes the problem go away. This problem is extremely difficult to reproduce, I haven't been able to get it to occur despite running it on a number of machines. MS knowledge base article Q178887 covers this type of problem, it's typically caused by an external driver or other program that adds its own values under the HKEY_PERFORMANCE_DATA key. The NT kernel, via Advapi32.dll, calls the required external module to map in the data inside an SEH try/except block, so problems in the module's collect function don't pop up until after it has finished, so the fault appears to occur in Advapi32.dll. There may be problems in the NT kernel as well though, a low-level memory checker indicated that ExpandEnvironmentStrings() in Kernel32.dll, called an interminable number of calls down inside RegQueryValueEx(), was overwriting memory (it wrote twice the allocated size of a buffer to a buffer allocated by the NT kernel). OTOH this could be coming from the external module calling back into the kernel, which eventually causes the problem described above. Possibly as an extension of the problem that the krnlWaitSemaphore() call above works around, running two instances of cryptlib (e.g. two applications that use it) under NT4 can result in one of them hanging in the RegQueryValueEx() call. This happens only under NT4 and is hard to reproduce in any consistent manner. One workaround that helps a bit is to read the registry as a remote (rather than local) registry, it's possible that the use of a network RPC call isolates the calling app from the problem in that whatever service handles the RPC is taking the hit and not affecting the calling app. Since this would require another round of extensive testing to verify and the NT native API call is working fine, we'll stick with the native API call for now. Some versions of NT4 had a problem where the amount of data returned was mis-reported and would never settle down, because of this the code below includes a safety-catch that bails out after 10 attempts have been made, this results in no data being returned but at does ensure that the thread will terminate. In addition to these problems the code in RegQueryValueEx() that estimates the amount of memory required to return the performance counter information isn't very accurate (it's much worse than the "slightly-inaccurate" level that the MS docs warn about, it's usually wildly off) since it always returns a worst-case estimate which is usually nowhere near the actual amount required. For example it may report that 128K of memory is required, but only return 64K of data. Even worse than the registry-based performance counters is the performance data helper (PDH) shim that tries to make the counters look like the old Win16 API (which is also used by Win95). Under NT this can consume tens of MB of memory and huge amounts of CPU time while it gathers its data, and even running once can still consume about 1/2MB of memory */ if (getenv ("GNUPG_RNDW32_NOPERF")) { static int shown; if (!shown) { shown = 1; log_info ("note: get performance data has been disabled\n"); } } else { pPerfData = gcry_xmalloc (cbPerfData); for (iterations=0; iterations < 10; iterations++) { dwSize = cbPerfData; if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, (LPBYTE) pPerfData, &dwSize); if (status == ERROR_SUCCESS) { if (!memcmp (pPerfData->Signature, L"PERF", 8)) (*add) ( pPerfData, dwSize, requester ); else log_debug ("rndw32: no PERF signature\n"); break; } else if (status == ERROR_MORE_DATA) { cbPerfData += PERFORMANCE_BUFFER_STEP; pPerfData = gcry_xrealloc (pPerfData, cbPerfData); } else { static int been_here; /* Silence the error message. In particular under Wine (as of 2008) we would get swamped with such diagnotiscs. One such diagnotiscs should be enough. */ if (been_here != status) { been_here = status; log_debug ("rndw32: get performance data problem: ec=%ld\n", status); } break; } } gcry_free (pPerfData); } /* Although this isn't documented in the Win32 API docs, it's necessary to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's implicitly opened on the first call to RegQueryValueEx()). If this isn't done then any system components which provide performance data can't be removed or changed while the handle remains active. */ RegCloseKey (HKEY_PERFORMANCE_DATA); }
/* Run an integrity check on the binary. Returns 0 on success. */ static int check_binary_integrity (void) { #ifdef ENABLE_HMAC_BINARY_CHECK gpg_error_t err; Dl_info info; unsigned char digest[32]; int dlen; char *fname = NULL; const char key[] = "What am I, a doctor or a moonshuttle conductor?"; if (!dladdr ("gcry_check_version", &info)) err = gpg_error_from_syserror (); else { dlen = _gcry_hmac256_file (digest, sizeof digest, info.dli_fname, key, strlen (key)); if (dlen < 0) err = gpg_error_from_syserror (); else if (dlen != 32) err = gpg_error (GPG_ERR_INTERNAL); else { fname = gcry_malloc (strlen (info.dli_fname) + 1 + 5 + 1 ); if (!fname) err = gpg_error_from_syserror (); else { FILE *fp; char *p; /* Prefix the basename with a dot. */ strcpy (fname, info.dli_fname); p = strrchr (fname, '/'); if (p) p++; else p = fname; memmove (p+1, p, strlen (p)+1); *p = '.'; strcat (fname, ".hmac"); /* Open the file. */ fp = fopen (fname, "r"); if (!fp) err = gpg_error_from_syserror (); else { /* A buffer of 64 bytes plus one for a LF and one to detect garbage. */ unsigned char buffer[64+1+1]; const unsigned char *s; int n; /* The HMAC files consists of lowercase hex digits only with an optional trailing linefeed. Fail if there is any garbage. */ err = gpg_error (GPG_ERR_SELFTEST_FAILED); n = fread (buffer, 1, sizeof buffer, fp); if (n == 64 || (n == 65 && buffer[64] == '\n')) { buffer[64] = 0; for (n=0, s= buffer; n < 32 && loxdigit_p (s) && loxdigit_p (s+1); n++, s += 2) buffer[n] = loxtoi_2 (s); if ( n == 32 && !memcmp (digest, buffer, 32) ) err = 0; } fclose (fp); } } } } reporter ("binary", 0, fname, err? gpg_strerror (err):NULL); #ifdef HAVE_SYSLOG if (err) syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " "integrity check using `%s' failed: %s", fname? fname:"[?]", gpg_strerror (err)); #endif /*HAVE_SYSLOG*/ gcry_free (fname); return !!err; #else return 0; #endif }
static void slow_gatherer ( void (*add)(const void*, size_t, enum random_origins), enum random_origins requester ) { static int is_initialized = 0; static int is_workstation = 1; HANDLE hDevice; DWORD dwType, dwSize, dwResult; ULONG ulSize; int drive_no, status; int no_results = 0; void *buffer; if ( !is_initialized ) { HKEY hKey; if ( debug_me ) log_debug ("rndw32#slow_gatherer: init toolkit\n" ); /* Find out whether this is an NT server or workstation if necessary */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { BYTE szValue[32 + 8]; dwSize = 32; if ( debug_me ) log_debug ("rndw32#slow_gatherer: check product options\n" ); status = RegQueryValueEx (hKey, "ProductType", 0, NULL, szValue, &dwSize); if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) { /* Note: There are (at least) three cases for ProductType: WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = NT Server acting as a Domain Controller. */ is_workstation = 0; if ( debug_me ) log_debug ("rndw32: this is a NT server\n"); } RegCloseKey (hKey); } /* The following are fixed for the lifetime of the process so we only add them once */ /* readPnPData (); - we have not implemented that. */ /* Initialize the NetAPI32 function pointers if necessary */ hNetAPI32 = LoadLibrary ("NETAPI32.DLL"); if (hNetAPI32) { if (debug_me) log_debug ("rndw32#slow_gatherer: netapi32 loaded\n" ); pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, "NetStatisticsGet"); pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, "NetApiBufferSize"); pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, "NetApiBufferFree"); if (!pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree) { FreeLibrary (hNetAPI32); hNetAPI32 = NULL; log_debug ("rndw32: No NETAPI found\n" ); } } /* Initialize the NT kernel native API function pointers if necessary */ hNTAPI = GetModuleHandle ("NTDll.dll"); if (hNTAPI) { /* Get a pointer to the NT native information query functions */ pNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION) GetProcAddress (hNTAPI, "NtQuerySystemInformation"); pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS) GetProcAddress (hNTAPI, "NtQueryInformationProcess"); pNtPowerInformation = (NTPOWERINFORMATION) GetProcAddress(hNTAPI, "NtPowerInformation"); if (!pNtQuerySystemInformation || !pNtQueryInformationProcess) hNTAPI = NULL; } is_initialized = 1; } read_system_rng ( add, requester ); read_mbm_data ( add, requester ); /* Get network statistics. Note: Both NT Workstation and NT Server by default will be running both the workstation and server services. The heuristic below is probably useful though on the assumption that the majority of the network traffic will be via the appropriate service. In any case the network statistics return almost no randomness. */ { LPBYTE lpBuffer; if (hNetAPI32 && !pNetStatisticsGet (NULL, is_workstation ? L"LanmanWorkstation" : L"LanmanServer", 0, 0, &lpBuffer)) { if ( debug_me ) log_debug ("rndw32#slow_gatherer: get netstats\n" ); pNetApiBufferSize (lpBuffer, &dwSize); (*add) ( lpBuffer, dwSize, requester ); pNetApiBufferFree (lpBuffer); } } /* Get disk I/O statistics for all the hard drives. 100 is an arbitrary failsafe limit. */ for (drive_no = 0; drive_no < 100 ; drive_no++) { char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT + 8]; char szDevice[50]; /* Check whether we can access this device. */ snprintf (szDevice, sizeof szDevice, "\\\\.\\PhysicalDrive%d", drive_no); hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) break; /* No more drives. */ /* Note: This only works if you have turned on the disk performance counters with 'diskperf -y'. These counters are off by default. */ dwSize = sizeof diskPerformance; if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, &dwSize, NULL)) { if ( debug_me ) log_debug ("rndw32#slow_gatherer: iostat drive %d\n", drive_no); (*add) (diskPerformance, dwSize, requester); } else { log_info ("NOTE: you should run 'diskperf -y' " "to enable the disk statistics\n"); } CloseHandle (hDevice); } /* In theory we should be using the Win32 performance query API to obtain unpredictable data from the system, however this is so unreliable (see the multiple sets of comments in registryPoll()) that it's too risky to rely on it except as a fallback in emergencies. Instead, we rely mostly on the NT native API function NtQuerySystemInformation(), which has the dual advantages that it doesn't have as many (known) problems as the Win32 equivalent and that it doesn't access the data indirectly via pseudo-registry keys, which means that it's much faster. Note that the Win32 equivalent actually works almost all of the time, the problem is that on one or two systems it can fail in strange ways that are never the same and can't be reproduced on any other system, which is why we use the native API here. Microsoft officially documented this function in early 2003, so it'll be fairly safe to use. */ if ( !hNTAPI ) { registry_poll (add, requester); return; } /* Scan the first 64 possible information types (we don't bother with increasing the buffer size as we do with the Win32 version of the performance data read, we may miss a few classes but it's no big deal). This scan typically yields around 20 pieces of data, there's nothing in the range 65...128 so chances are there won't be anything above there either. */ buffer = gcry_xmalloc (PERFORMANCE_BUFFER_SIZE); for (dwType = 0; dwType < 64; dwType++) { switch (dwType) { /* ID 17 = SystemObjectInformation hangs on some win2k systems. */ case 17: if (system_is_w2000) continue; break; /* Some information types are write-only (the IDs are shared with a set-information call), we skip these. */ case 26: case 27: case 38: case 46: case 47: case 48: case 52: continue; /* ID 53 = SystemSessionProcessInformation reads input from the output buffer, which has to contain a session ID and pointer to the actual buffer in which to store the session information. Because this isn't a standard query, we skip this. */ case 53: continue; } /* Query the info for this ID. Some results (for example for ID = 6, SystemCallCounts) are only available in checked builds of the kernel. A smaller subcless of results require that certain system config flags be set, for example SystemObjectInformation requires that the FLG_MAINTAIN_OBJECT_TYPELIST be set in NtGlobalFlags. To avoid having to special-case all of these, we try reading each one and only use those for which we get a success status. */ dwResult = pNtQuerySystemInformation (dwType, buffer, PERFORMANCE_BUFFER_SIZE - 2048, &ulSize); if (dwResult != ERROR_SUCCESS) continue; /* Some calls (e.g. ID = 23, SystemProcessorStatistics, and ID = 24, SystemDpcInformation) incorrectly return a length of zero, so we manually adjust the length to the correct value. */ if ( !ulSize ) { if (dwType == 23) ulSize = 6 * sizeof (ULONG); else if (dwType == 24) ulSize = 5 * sizeof (ULONG); } /* If we got some data back, add it to the entropy pool. */ if (ulSize > 0 && ulSize <= PERFORMANCE_BUFFER_SIZE - 2048) { if (debug_me) log_debug ("rndw32#slow_gatherer: %lu bytes from sysinfo %ld\n", ulSize, dwType); (*add) (buffer, ulSize, requester); no_results++; } } /* Now we would do the same for the process information. This call would rather ugly in that it requires an exact length match for the data returned, failing with a STATUS_INFO_LENGTH_MISMATCH error code (0xC0000004) if the length isn't an exact match. It requires a compiler to handle complex nested structs, alignment issues, and so on, and without the headers in which the entries are declared it's almost impossible to do. Thus we don't. */ /* Finally, do the same for the system power status information. There are only a limited number of useful information types available so we restrict ourselves to the useful types. In addition since this function doesn't return length information, we have to hardcode in length data. */ if (pNtPowerInformation) { static const struct { int type; int size; } powerInfo[] = { { 0, 128 }, /* SystemPowerPolicyAc */ { 1, 128 }, /* SystemPowerPolicyDc */ { 4, 64 }, /* SystemPowerCapabilities */ { 5, 48 }, /* SystemBatteryState */ { 11, 48 }, /* ProcessorInformation */ { 12, 24 }, /* SystemPowerInformation */ { -1, -1 } }; int i; /* The 100 is a failsafe limit. */ for (i = 0; powerInfo[i].type != -1 && i < 100; i++ ) { /* Query the info for this ID */ dwResult = pNtPowerInformation (powerInfo[i].type, NULL, 0, buffer, PERFORMANCE_BUFFER_SIZE - 2048); if (dwResult != ERROR_SUCCESS) continue; if (debug_me) log_debug ("rndw32#slow_gatherer: %u bytes from powerinfo %d\n", powerInfo[i].size, i); (*add) (buffer, powerInfo[i].size, requester); no_results++; } gcry_assert (i < 100); } gcry_free (buffer); /* We couldn't get enough results from the kernel, fall back to the somewhat troublesome registry poll. */ if (no_results < 15) registry_poll (add, requester); }
/* Return the so called KEYGRIP which is the SHA-1 hash of the public key parameters expressed in a way depending on the algorithm. ARRAY must either be 20 bytes long or NULL; in the latter case a newly allocated array of that size is returned, otherwise ARRAY or NULL is returned to indicate an error which is most likely an unknown algorithm. The function accepts public or secret keys. */ unsigned char * gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) { gcry_sexp_t list = NULL; gcry_sexp_t l2 = NULL; gcry_pk_spec_t *spec = NULL; const char *s; char *name = NULL; int idx; const char *elems; gcry_md_hd_t md = NULL; int okay = 0; /* Check that the first element is valid. */ list = gcry_sexp_find_token (key, "public-key", 0); if (! list) list = gcry_sexp_find_token (key, "private-key", 0); if (! list) list = gcry_sexp_find_token (key, "protected-private-key", 0); if (! list) list = gcry_sexp_find_token (key, "shadowed-private-key", 0); if (! list) return NULL; /* No public- or private-key object. */ l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; l2 = NULL; name = _gcry_sexp_nth_string (list, 0); if (!name) goto fail; /* Invalid structure of object. */ spec = spec_from_name (name); if (!spec) goto fail; /* Unknown algorithm. */ elems = spec->elements_grip; if (!elems) goto fail; /* No grip parameter. */ if (gcry_md_open (&md, GCRY_MD_SHA1, 0)) goto fail; if (spec->comp_keygrip) { /* Module specific method to compute a keygrip. */ if (spec->comp_keygrip (md, list)) goto fail; } else { /* Generic method to compute a keygrip. */ for (idx = 0, s = elems; *s; s++, idx++) { const char *data; size_t datalen; char buf[30]; l2 = gcry_sexp_find_token (list, s, 1); if (! l2) goto fail; data = gcry_sexp_nth_data (l2, 1, &datalen); if (! data) goto fail; snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); gcry_md_write (md, buf, strlen (buf)); gcry_md_write (md, data, datalen); gcry_sexp_release (l2); l2 = NULL; gcry_md_write (md, ")", 1); } } if (!array) { array = gcry_malloc (20); if (! array) goto fail; } memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20); okay = 1; fail: gcry_free (name); gcry_sexp_release (l2); gcry_md_close (md); gcry_sexp_release (list); return okay? array : NULL; }
/**************** * Scan the provided buffer and return the S expression in our internal * format. Returns a newly allocated expression. If erroff is not NULL and * a parsing error has occurred, the offset into buffer will be returned. * If ARGFLAG is true, the function supports some printf like * expressions. * These are: * %m - MPI * %s - string (no autoswitch to secure allocation) * %d - integer stored as string (no autoswitch to secure allocation) * %b - memory buffer; this takes _two_ arguments: an integer with the * length of the buffer and a pointer to the buffer. * %S - Copy an gcry_sexp_t here. The S-expression needs to be a * regular one, starting with a parenthesis. * (no autoswitch to secure allocation) * all other format elements are currently not defined and return an error. * this includes the "%%" sequence becauce the percent sign is not an * allowed character. * FIXME: We should find a way to store the secure-MPIs not in the string * but as reference to somewhere - this can help us to save huge amounts * of secure memory. The problem is, that if only one element is secure, all * other elements are automagicaly copied to secure memory too, so the most * common operation gcry_sexp_cdr_mpi() will always return a secure MPI * regardless whether it is needed or not. */ static gcry_error_t vsexp_sscan (gcry_sexp_t *retsexp, size_t *erroff, const char *buffer, size_t length, int argflag, void **arg_list, va_list arg_ptr) { gcry_err_code_t err = 0; static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789-./_:*+="; const char *p; size_t n; const char *digptr = NULL; const char *quoted = NULL; const char *tokenp = NULL; const char *hexfmt = NULL; const char *base64 = NULL; const char *disphint = NULL; const char *percent = NULL; int hexcount = 0; int quoted_esc = 0; int datalen = 0; size_t dummy_erroff; struct make_space_ctx c; int arg_counter = 0; int level = 0; if (!erroff) erroff = &dummy_erroff; /* Depending on whether ARG_LIST is non-zero or not, this macro gives us the next argument, either from the variable argument list as specified by ARG_PTR or from the argument array ARG_LIST. */ #define ARG_NEXT(storage, type) \ do \ { \ if (!arg_list) \ storage = va_arg (arg_ptr, type); \ else \ storage = *((type *) (arg_list[arg_counter++])); \ } \ while (0) /* The MAKE_SPACE macro is used before each store operation to ensure that the buffer is large enough. It requires a global context named C and jumps out to the label LEAVE on error! It also sets ERROFF using the variables BUFFER and P. */ #define MAKE_SPACE(n) do { \ gpg_err_code_t _ms_err = make_space (&c, (n)); \ if (_ms_err) \ { \ err = _ms_err; \ *erroff = p - buffer; \ goto leave; \ } \ } while (0) /* The STORE_LEN macro is used to store the length N at buffer P. */ #define STORE_LEN(p,n) do { \ DATALEN ashort = (n); \ memcpy ( (p), &ashort, sizeof(ashort) ); \ (p) += sizeof (ashort); \ } while (0) /* We assume that the internal representation takes less memory than the provided one. However, we add space for one extra datalen so that the code which does the ST_CLOSE can use MAKE_SPACE */ c.allocated = length + sizeof(DATALEN); if (buffer && length && gcry_is_secure (buffer)) c.sexp = gcry_malloc_secure (sizeof *c.sexp + c.allocated - 1); else c.sexp = gcry_malloc (sizeof *c.sexp + c.allocated - 1); if (!c.sexp) { err = gpg_err_code_from_errno (errno); *erroff = 0; goto leave; } c.pos = c.sexp->d; for (p = buffer, n = length; n; p++, n--) { if (tokenp && !hexfmt) { if (strchr (tokenchars, *p)) continue; else { datalen = p - tokenp; MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); memcpy (c.pos, tokenp, datalen); c.pos += datalen; tokenp = NULL; } } if (quoted) { if (quoted_esc) { switch (*p) { case 'b': case 't': case 'v': case 'n': case 'f': case 'r': case '"': case '\'': case '\\': quoted_esc = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': if (!((n > 2) && (p[1] >= '0') && (p[1] <= '7') && (p[2] >= '0') && (p[2] <= '7'))) { *erroff = p - buffer; /* Invalid octal value. */ err = GPG_ERR_SEXP_BAD_QUOTATION; goto leave; } p += 2; n -= 2; quoted_esc = 0; break; case 'x': if (!((n > 2) && hexdigitp (p+1) && hexdigitp (p+2))) { *erroff = p - buffer; /* Invalid hex value. */ err = GPG_ERR_SEXP_BAD_QUOTATION; goto leave; } p += 2; n -= 2; quoted_esc = 0; break; case '\r': /* ignore CR[,LF] */ if (n && (p[1] == '\n')) { p++; n--; } quoted_esc = 0; break; case '\n': /* ignore LF[,CR] */ if (n && (p[1] == '\r')) { p++; n--; } quoted_esc = 0; break; default: *erroff = p - buffer; /* Invalid quoted string escape. */ err = GPG_ERR_SEXP_BAD_QUOTATION; goto leave; } } else if (*p == '\\') quoted_esc = 1; else if (*p == '\"') { /* Keep it easy - we know that the unquoted string will never be larger. */ unsigned char *save; size_t len; quoted++; /* Skip leading quote. */ MAKE_SPACE (p - quoted); *c.pos++ = ST_DATA; save = c.pos; STORE_LEN (c.pos, 0); /* Will be fixed up later. */ len = unquote_string (quoted, p - quoted, c.pos); c.pos += len; STORE_LEN (save, len); quoted = NULL; } } else if (hexfmt) { if (isxdigit (*p)) hexcount++; else if (*p == '#') { if ((hexcount & 1)) { *erroff = p - buffer; err = GPG_ERR_SEXP_ODD_HEX_NUMBERS; goto leave; } datalen = hexcount / 2; MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); for (hexfmt++; hexfmt < p; hexfmt++) { int tmpc; if (whitespacep (hexfmt)) continue; tmpc = hextonibble (*(const unsigned char*)hexfmt); for (hexfmt++; hexfmt < p && whitespacep (hexfmt); hexfmt++) ; if (hexfmt < p) { tmpc *= 16; tmpc += hextonibble (*(const unsigned char*)hexfmt); } *c.pos++ = tmpc; } hexfmt = NULL; } else if (!whitespacep (p)) { *erroff = p - buffer; err = GPG_ERR_SEXP_BAD_HEX_CHAR; goto leave; } } else if (base64) { if (*p == '|') base64 = NULL; } else if (digptr) { if (digitp (p)) ; else if (*p == ':') { datalen = atoi (digptr); /* FIXME: check for overflow. */ digptr = NULL; if (datalen > n - 1) { *erroff = p - buffer; /* Buffer too short. */ err = GPG_ERR_SEXP_STRING_TOO_LONG; goto leave; } /* Make a new list entry. */ MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); memcpy (c.pos, p + 1, datalen); c.pos += datalen; n -= datalen; p += datalen; } else if (*p == '\"') { digptr = NULL; /* We ignore the optional length. */ quoted = p; quoted_esc = 0; } else if (*p == '#') { digptr = NULL; /* We ignore the optional length. */ hexfmt = p; hexcount = 0; } else if (*p == '|') { digptr = NULL; /* We ignore the optional length. */ base64 = p; } else { *erroff = p - buffer; err = GPG_ERR_SEXP_INV_LEN_SPEC; goto leave; } } else if (percent) { if (*p == 'm' || *p == 'M') { /* Insert an MPI. */ gcry_mpi_t m; size_t nm = 0; int mpifmt = *p == 'm'? GCRYMPI_FMT_STD: GCRYMPI_FMT_USG; ARG_NEXT (m, gcry_mpi_t); if (gcry_mpi_get_flag (m, GCRYMPI_FLAG_OPAQUE)) { void *mp; unsigned int nbits; mp = gcry_mpi_get_opaque (m, &nbits); nm = (nbits+7)/8; if (mp && nm) { MAKE_SPACE (nm); if (!gcry_is_secure (c.sexp->d) && gcry_mpi_get_flag (m, GCRYMPI_FLAG_SECURE)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_malloc_secure (sizeof *newsexp + c.allocated - 1); if (!newsexp) { err = gpg_err_code_from_errno (errno); goto leave; } newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, nm); memcpy (c.pos, mp, nm); c.pos += nm; } } else { if (gcry_mpi_print (mpifmt, NULL, 0, &nm, m)) BUG (); MAKE_SPACE (nm); if (!gcry_is_secure (c.sexp->d) && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_malloc_secure (sizeof *newsexp + c.allocated - 1); if (!newsexp) { err = gpg_err_code_from_errno (errno); goto leave; } newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, nm); if (gcry_mpi_print (mpifmt, c.pos, nm, &nm, m)) BUG (); c.pos += nm; } } else if (*p == 's') { /* Insert an string. */ const char *astr; size_t alen; ARG_NEXT (astr, const char *); alen = strlen (astr); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, astr, alen); c.pos += alen; } else if (*p == 'b') { /* Insert a memory buffer. */ const char *astr; int alen; ARG_NEXT (alen, int); ARG_NEXT (astr, const char *); MAKE_SPACE (alen); if (alen && !gcry_is_secure (c.sexp->d) && gcry_is_secure (astr)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_malloc_secure (sizeof *newsexp + c.allocated - 1); if (!newsexp) { err = gpg_err_code_from_errno (errno); goto leave; } newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, astr, alen); c.pos += alen; } else if (*p == 'd') { /* Insert an integer as string. */ int aint; size_t alen; char buf[35]; ARG_NEXT (aint, int); sprintf (buf, "%d", aint); alen = strlen (buf); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, buf, alen); c.pos += alen; } else if (*p == 'u') { /* Insert an unsigned integer as string. */ unsigned int aint; size_t alen; char buf[35]; ARG_NEXT (aint, unsigned int); sprintf (buf, "%u", aint); alen = strlen (buf); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, buf, alen); c.pos += alen; } else if (*p == 'S') { /* Insert a gcry_sexp_t. */ gcry_sexp_t asexp; size_t alen, aoff; ARG_NEXT (asexp, gcry_sexp_t); alen = get_internal_buffer (asexp, &aoff); if (alen) { MAKE_SPACE (alen); memcpy (c.pos, asexp->d + aoff, alen); c.pos += alen; } } else { *erroff = p - buffer; /* Invalid format specifier. */ err = GPG_ERR_SEXP_INV_LEN_SPEC; goto leave; } percent = NULL; } else if (*p == '(') { if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; goto leave; } MAKE_SPACE (0); *c.pos++ = ST_OPEN; level++; } else if (*p == ')') { /* Walk up. */ if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; goto leave; } MAKE_SPACE (0); *c.pos++ = ST_CLOSE; level--; } else if (*p == '\"') { quoted = p; quoted_esc = 0; } else if (*p == '#') { hexfmt = p; hexcount = 0; } else if (*p == '|') base64 = p; else if (*p == '[') { if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_NESTED_DH; goto leave; } disphint = p; } else if (*p == ']') { if (!disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; goto leave; } disphint = NULL; } else if (digitp (p)) { if (*p == '0') { /* A length may not begin with zero. */ *erroff = p - buffer; err = GPG_ERR_SEXP_ZERO_PREFIX; goto leave; } digptr = p; } else if (strchr (tokenchars, *p)) tokenp = p; else if (whitespacep (p)) ; else if (*p == '{') { /* fixme: handle rescanning: we can do this by saving our current state and start over at p+1 -- Hmmm. At this point here we are in a well defined state, so we don't need to save it. Great. */ *erroff = p - buffer; err = GPG_ERR_SEXP_UNEXPECTED_PUNC; goto leave; } else if (strchr ("&\\", *p)) { /* Reserved punctuation. */ *erroff = p - buffer; err = GPG_ERR_SEXP_UNEXPECTED_PUNC; goto leave; } else if (argflag && (*p == '%')) percent = p; else { /* Bad or unavailable. */ *erroff = p - buffer; err = GPG_ERR_SEXP_BAD_CHARACTER; goto leave; } } MAKE_SPACE (0); *c.pos++ = ST_STOP; if (level && !err) err = GPG_ERR_SEXP_UNMATCHED_PAREN; leave: if (err) { /* Error -> deallocate. */ if (c.sexp) { /* Extra paranoid wipe on error. */ if (gcry_is_secure (c.sexp)) wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1); gcry_free (c.sexp); } /* This might be expected by existing code... */ *retsexp = NULL; } else *retsexp = normalize (c.sexp); return gcry_error (err); #undef MAKE_SPACE #undef STORE_LEN }
void _gsti_free (void *p) { gcry_free (p); }
static int soft_sign (const uint8_t *to_sign, size_t len, jwa_t alg, void *cookie, uint8_t **out, size_t *out_len) { assert (NULL != key_f); int rc = -1; uint8_t *hash; gcry_sexp_t key, sig, digest; const unsigned int DLEN = gcry_md_get_algo_dlen (GCRY_MD_SHA256); hash = malloc (DLEN); assert (NULL != hash); gcry_md_hash_buffer (GCRY_MD_SHA256, hash, to_sign, len); rc = gcry_sexp_build (&digest, NULL, "(data (flags raw)\n" " (value %b))", DLEN, hash); if (rc) goto OUT; if (rc = lca_load_signing_key (key_f, &key)) goto DIG; /* if (show_digest) */ /* { */ /* lca_set_log_level (DEBUG); */ /* lca_print_sexp (digest); */ /* lca_set_log_level (INFO); */ /* } */ if (rc = gcry_pk_sign (&sig, digest, key)) goto KEY; lca_print_sexp (sig); struct lca_octet_buffer signature = lca_sig2buf (&sig); if (NULL != signature.ptr) { *out = signature.ptr; *out_len = signature.len; rc = 0; } gcry_free (sig); KEY: gcry_free (key); DIG: gcry_free (digest); OUT: free (hash); return rc; }
static void back_and_forth_one (int testno, const char *buffer, size_t length) { gcry_error_t rc; gcry_sexp_t se, se1; size_t n, n1; char *p1; rc = gcry_sexp_new (&se, buffer, length, 1); if (rc) { fail ("baf %d: gcry_sexp_new failed: %s\n", testno, gpg_strerror (rc)); return; } n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, NULL, 0); if (!n1) { fail ("baf %d: get required length for canon failed\n", testno); return; } p1 = gcry_xmalloc (n1); n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1, n1); if (n1 != n+1) /* sprints adds an extra 0 but dies not return it */ { fail ("baf %d: length mismatch for canon\n", testno); return; } rc = gcry_sexp_create (&se1, p1, n, 0, gcry_free); if (rc) { fail ("baf %d: gcry_sexp_create failed: %s\n", testno, gpg_strerror (rc)); return; } gcry_sexp_release (se1); /* Again but with memory checking. */ p1 = gcry_xmalloc (n1+2); *p1 = '\x55'; p1[n1+1] = '\xaa'; n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1+1, n1); if (n1 != n+1) /* sprints adds an extra 0 but does not return it */ { fail ("baf %d: length mismatch for canon\n", testno); return; } if (*p1 != '\x55' || p1[n1+1] != '\xaa') fail ("baf %d: memory corrupted (1)\n", testno); rc = gcry_sexp_create (&se1, p1+1, n, 0, NULL); if (rc) { fail ("baf %d: gcry_sexp_create failed: %s\n", testno, gpg_strerror (rc)); return; } if (*p1 != '\x55' || p1[n1+1] != '\xaa') fail ("baf %d: memory corrupted (2)\n", testno); gcry_sexp_release (se1); if (*p1 != '\x55' || p1[n1+1] != '\xaa') fail ("baf %d: memory corrupted (3)\n", testno); gcry_free (p1); /* FIXME: we need a lot more tests */ gcry_sexp_release (se); }
/* Run the self-tests for <block cipher>-CBC-<block size>, tests bulk CBC decryption. Returns NULL on success. */ const char * _gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func, gcry_cipher_encrypt_t encrypt_one, gcry_cipher_bulk_cbc_dec_t bulk_cbc_dec, const int nblocks, const int blocksize, const int context_size) { int i, offs; unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; unsigned int ctx_aligned_size, memsize; static const unsigned char key[16] ATTR_ALIGNED_16 = { 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22 }; /* Allocate buffers, align first two elements to 16 bytes and latter to block size. */ ctx_aligned_size = context_size + 15; ctx_aligned_size -= ctx_aligned_size & 0xf; memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16; mem = gcry_calloc (1, memsize); if (!mem) return "failed to allocate memory"; offs = (16 - ((uintptr_t)mem & 15)) & 15; ctx = (void*)(mem + offs); iv = ctx + ctx_aligned_size; iv2 = iv + blocksize; plaintext = iv2 + blocksize; plaintext2 = plaintext + nblocks * blocksize; ciphertext = plaintext2 + nblocks * blocksize; /* Initialize ctx */ setkey_func (ctx, key, sizeof(key)); /* Test single block code path */ memset (iv, 0x4e, blocksize); memset (iv2, 0x4e, blocksize); for (i = 0; i < blocksize; i++) plaintext[i] = i; /* CBC manually. */ buf_xor (ciphertext, iv, plaintext, blocksize); encrypt_one (ctx, ciphertext, ciphertext); memcpy (iv, ciphertext, blocksize); /* CBC decrypt. */ bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, 1); if (memcmp (plaintext2, plaintext, blocksize)) { gcry_free (mem); #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " "%s-CBC-%d test failed (plaintext mismatch)", cipher, blocksize * 8); #endif return "selftest for CBC failed - see syslog for details"; } if (memcmp (iv2, iv, blocksize)) { gcry_free (mem); #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8); #endif return "selftest for CBC failed - see syslog for details"; } /* Test parallelized code paths */ memset (iv, 0x5f, blocksize); memset (iv2, 0x5f, blocksize); for (i = 0; i < nblocks * blocksize; i++) plaintext[i] = i; /* Create CBC ciphertext manually. */ for (i = 0; i < nblocks * blocksize; i+=blocksize) { buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize); encrypt_one (ctx, &ciphertext[i], &ciphertext[i]); memcpy (iv, &ciphertext[i], blocksize); } /* Decrypt using bulk CBC and compare result. */ bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks); if (memcmp (plaintext2, plaintext, nblocks * blocksize)) { gcry_free (mem); #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " "%s-CBC-%d test failed (plaintext mismatch, parallel path)", cipher, blocksize * 8); #endif return "selftest for CBC failed - see syslog for details"; } if (memcmp (iv2, iv, blocksize)) { gcry_free (mem); #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " "%s-CBC-%d test failed (IV mismatch, parallel path)", cipher, blocksize * 8); #endif return "selftest for CBC failed - see syslog for details"; } gcry_free (mem); return NULL; }