/** * Calculates the hash of the given message and hashtype */ int hash(int hashtype, const unsigned char *src, unsigned int srclen, unsigned char *dest, unsigned int *destlen) { HCRYPTHASH hash; ALG_ID alg; int hashlen, rval; DWORD _destlen; hashlen = get_hash_len(hashtype); alg = get_hash(hashtype); if (!CryptCreateHash(base_prov, alg, 0, 0, &hash)) { mserror("CryptCreateHash failed"); return 0; } if (!CryptHashData(hash, src, srclen, 0)) { mserror("CryptHashData failed"); rval = 0; goto end; } _destlen = hashlen; if (!CryptGetHashParam(hash, HP_HASHVAL, dest, &_destlen, 0)) { mserror("CryptGetHashParam failed"); rval = 0; goto end; } *destlen = _destlen; rval = 1; end: if (!CryptDestroyHash(hash)) { mserror("CryptDestroyHash failed"); } return rval; }
/** * Initialize crypto library, generate keys */ void key_init() { unsigned char *prf_buf; time_t t; uint32_t t2; int explen, len; if (keytype == KEY_NONE) { return; } set_sys_keys(sys_keys); get_key_info(keytype, &keylen, &ivlen); hmaclen = get_hash_len(hashtype); memset(groupkey, 0, sizeof(groupkey)); memset(groupsalt, 0, sizeof(groupsalt)); memset(grouphmackey, 0, sizeof(grouphmackey)); if (!get_random_bytes(groupmaster, sizeof(groupmaster))) { log(0, 0, "Failed to generate group master"); exit(1); } groupmaster[0] = UFTP_VER_NUM; if (!get_random_bytes(rand1, sizeof(rand1))) { log(0, 0, "Failed to generate rand1"); exit(1); } // Sets the first 4 bytes of rand1 to the current time t = time(NULL); t2 = (uint32_t)(t & 0xFFFFFFFF); *(uint32_t *)rand1 = t2; explen = hmaclen + keylen + ivlen; prf_buf = calloc(explen + hmaclen, 1); if (prf_buf == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } PRF(hashtype, explen, groupmaster, sizeof(groupmaster), "key expansion", rand1, sizeof(rand1), prf_buf, &len); memcpy(grouphmackey, prf_buf, hmaclen); memcpy(groupkey, prf_buf + hmaclen, keylen); memcpy(groupsalt, prf_buf + hmaclen + keylen, ivlen); free(prf_buf); if ((!strcmp(keyfile, "")) || (newkeylen != 0)) { privkey = gen_RSA_key(newkeylen, RSA_EXP, keyfile); } else { privkey = read_RSA_key(keyfile); } if (!privkey) { log(0, 0, "Failed to read/generate private key"); exit(1); } rsalen = RSA_keylen(privkey); }
/** * Hashes a block of data and verifies it against an RSA signature. */ int verify_RSA_sig(RSA_key_t rsa, int hashtype, const unsigned char *mes, unsigned int meslen, unsigned char *sig, unsigned int siglen) { HCRYPTHASH hash; ALG_ID alg; unsigned hashlen, i; int rval; unsigned char *insig; hashlen = get_hash_len(hashtype); alg = get_hash(hashtype); if (!CryptCreateHash(base_prov, alg, 0, 0, &hash)) { mserror("CryptCreateHash failed"); return 0; } if (!CryptHashData(hash, mes, meslen, 0)) { mserror("CryptHashData failed"); rval = 0; goto end; } insig = calloc(siglen, 1); if (insig == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } // CryptoAPI expects signatures in little endian, so reverse the bytes for (i = 0; i < siglen; i++) { insig[i] = sig[siglen - i - 1]; } if (!CryptVerifySignature(hash, insig, siglen, rsa, NULL, 0)) { mserror("CryptVerifySignature failed"); free(insig); rval = 0; goto end; } free(insig); rval = 1; end: if (!CryptDestroyHash(hash)) { mserror("CryptDestroyHash failed"); } return rval; }
/** * Hashes a block of data and signs it with an RSA private key. * Output buffer must be at least the key size. */ int create_RSA_sig(RSA_key_t rsa, int hashtype, const unsigned char *mes, unsigned int meslen, unsigned char *sig, unsigned int *siglen) { HCRYPTHASH hash; DWORD _siglen; int idx, found; ALG_ID alg; int hashlen, rval; unsigned int i; unsigned char *outsig; for (idx = 0, found = 0; (idx < MAXLIST) && (!found); idx++) { if (private_key_list[idx].key == rsa) { found = 1; } } if (!found) { log(0, 0, "Couldn't find provider for RSA key"); return 0; } idx--; hashlen = get_hash_len(hashtype); alg = get_hash(hashtype); if (!CryptCreateHash(private_key_list[idx].provider, alg, 0, 0, &hash)) { mserror("CryptCreateHash failed"); return 0; } if (!CryptHashData(hash, mes, meslen, 0)) { mserror("CryptHashData failed"); rval = 0; goto end; } _siglen = RSA_keylen(rsa); outsig = calloc(_siglen, 1); if (outsig == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } if (!CryptSignHash(hash, AT_KEYEXCHANGE, NULL, 0, outsig, &_siglen)) { mserror("CryptSignHash failed"); free(outsig); rval = 0; goto end; } *siglen = _siglen; // CryptoAPI returns signatures in little endian, so reverse the bytes for (i = 0; i < _siglen; i++) { sig[i] = outsig[_siglen - i - 1]; } free(outsig); rval = 1; end: if (!CryptDestroyHash(hash)) { mserror("CryptDestroyHash failed"); } return rval; }
/** * Calculates the HMAC of the given message, hashtype, and hashkey. * dest must be at least the hash length. */ int create_hmac(int hashtype, const unsigned char *key, unsigned int keylen, const unsigned char *src, unsigned int srclen, unsigned char *dest, unsigned int *destlen) { // TODO: right now we reimport the hmac key each time. Test to see if this // is quick enough or if we need to cache an imported hmac key. HCRYPTKEY hmackey; HCRYPTHASH hash; char keyblob[BLOBLEN]; BLOBHEADER *bheader; DWORD *keysize; BYTE *keydata; HMAC_INFO info; ALG_ID alg; int bloblen, hashlen, rval; DWORD _destlen; hashlen = get_hash_len(hashtype); alg = get_hash(hashtype); bheader = (BLOBHEADER *)keyblob; keysize = (DWORD *)(keyblob + sizeof(BLOBHEADER)); keydata = (BYTE *)((char *)keysize + sizeof(DWORD)); memset(keyblob, 0, sizeof(keyblob)); bheader->bType = PLAINTEXTKEYBLOB; bheader->bVersion = CUR_BLOB_VERSION; bheader->aiKeyAlg = CALG_RC2; *keysize = keylen; memcpy(keydata, key, keylen); bloblen = sizeof(BLOBHEADER) + sizeof(DWORD) + hashlen; if (!CryptImportKey(base_prov, keyblob, bloblen, 0, CRYPT_IPSEC_HMAC_KEY, &hmackey)) { mserror("CryptImportKey failed"); return 0; } if (!CryptCreateHash(base_prov, CALG_HMAC, hmackey, 0, &hash)) { mserror("CryptCreateHash failed"); rval = 0; goto end1; } memset(&info, 0, sizeof(info)); info.HashAlgid = alg; if (!CryptSetHashParam(hash, HP_HMAC_INFO, (BYTE *)&info, 0)) { mserror("CryptSetHashParam failed"); rval = 0; goto end2; } if (!CryptHashData(hash, src, srclen, 0)) { mserror("CryptHashData failed"); rval = 0; goto end2; } _destlen = hashlen; if (!CryptGetHashParam(hash, HP_HASHVAL, dest, &_destlen, 0)) { mserror("CryptGetHashParam failed"); rval = 0; goto end2; } *destlen = _destlen; rval = 1; end2: if (!CryptDestroyHash(hash)) { mserror("CryptDestroyHash failed"); } end1: if (!CryptDestroyKey(hmackey)) { mserror("CryptDestroyKey failed"); } return rval; }
/** * Calculate the master key and do key expansion to determine the symmetric * cypher key and IV salt, and hash key for the server */ int calculate_server_keys(struct group_list_t *group, const struct enc_info_he *encinfo) { unsigned char *seed, *prf_buf; int explen, len, seedlen; time_t t; uint32_t t2; memcpy(group->rand1, encinfo->rand1, sizeof(encinfo->rand1)); if (!get_random_bytes(group->rand2, sizeof(group->rand2))) { glog0(group, "Failed to get random bytes for rand2"); send_abort(group, "Failed to get random bytes for rand2"); return 0; } // Sets the first 4 bytes of rand2 to the current time t = time(NULL); t2 = (uint32_t)(t & 0xFFFFFFFF); *(uint32_t *)(group->rand2) = t2; if (group->keyextype == KEYEX_RSA) { if (!get_random_bytes(group->premaster, MASTER_LEN)) { glog0(group, "Failed to get random bytes for premaster"); send_abort(group, "Failed to get random bytes for premaster"); return 0; } group->premaster_len = MASTER_LEN; } else { EC_key_t pubecdh; if (has_proxy) { pubecdh = proxy_dhkey.ec; } else { pubecdh = group->server_dhkey.ec; } if (!get_ECDH_key(pubecdh, group->client_dhkey.ec, group->premaster, &group->premaster_len)) { glog0(group, "Failed to calculate ECDH key"); send_abort(group, "Failed to calculate ECDH key"); return 0; } } get_key_info(group->keytype, &group->keylen, &group->ivlen); group->hmaclen = get_hash_len(group->hashtype); explen = group->keylen + SALT_LEN + group->hmaclen; seedlen = RAND_LEN * 2; seed = safe_calloc(seedlen, 1); prf_buf = safe_calloc(MASTER_LEN + explen + group->hmaclen, 1); memcpy(seed, group->rand1, sizeof(group->rand1)); memcpy(seed + sizeof(group->rand1), group->rand2, sizeof(group->rand2)); PRF(group->hashtype, MASTER_LEN, group->premaster, group->premaster_len, "master secret", seed, seedlen, prf_buf, &len); memcpy(group->master,prf_buf, sizeof(group->master)); PRF(group->hashtype, explen, group->master, sizeof(group->master), "key expansion", seed, seedlen, prf_buf, &len); memcpy(group->hmackey, prf_buf, group->hmaclen); memcpy(group->key, prf_buf + group->hmaclen, group->keylen); memcpy(group->salt, prf_buf + group->hmaclen + group->keylen, SALT_LEN); free(seed); free(prf_buf); return 1; }
/** * Initialize crypto library, generate keys */ void key_init(void) { unsigned char *prf_buf; time_t t; uint32_t t2; int explen, len; if (keytype == KEY_NONE) { return; } set_sys_keys(sys_keys); get_key_info(keytype, &keylen, &ivlen); hmaclen = get_hash_len(hashtype); memset(groupkey, 0, sizeof(groupkey)); memset(groupsalt, 0, sizeof(groupsalt)); memset(grouphmackey, 0, sizeof(grouphmackey)); if (!get_random_bytes(groupmaster, sizeof(groupmaster))) { log0(0, 0, 0, "Failed to generate group master"); exit(ERR_CRYPTO); } groupmaster[0] = UFTP_VER_NUM; if (!get_random_bytes(rand1, sizeof(rand1))) { log0(0, 0, 0, "Failed to generate rand1"); exit(ERR_CRYPTO); } // Sets the first 4 bytes of rand1 to the current time t = time(NULL); t2 = (uint32_t)(t & 0xFFFFFFFF); *(uint32_t *)rand1 = t2; explen = hmaclen + keylen + SALT_LEN; prf_buf = safe_calloc(explen + hmaclen, 1); PRF(hashtype, explen, groupmaster, sizeof(groupmaster), "key expansion", rand1, sizeof(rand1), prf_buf, &len); memcpy(grouphmackey, prf_buf, hmaclen); memcpy(groupkey, prf_buf + hmaclen, keylen); memcpy(groupsalt, prf_buf + hmaclen + keylen, SALT_LEN); ivctr = 0; free(prf_buf); if ((keyextype == KEYEX_RSA) || (keyextype == KEYEX_ECDH_RSA)) { if ((!strcmp(keyfile, "")) || (newkeylen != 0)) { privkey.rsa = gen_RSA_key(newkeylen, RSA_EXP, keyfile); } else { privkey.rsa = read_RSA_key(keyfile); } if (!privkey.key) { log0(0, 0, 0, "Failed to read/generate private key"); exit(ERR_CRYPTO); } privkeylen = RSA_keylen(privkey.rsa); } else { if ((!strcmp(keyfile, "")) || (ecdsa_curve != 0)) { privkey.ec = gen_EC_key(ecdsa_curve, 0, keyfile); } else { privkey.ec = read_EC_key(keyfile); } if (!privkey.key) { log0(0, 0, 0, "Failed to read/generate private key"); exit(ERR_CRYPTO); } privkeylen = ECDSA_siglen(privkey.ec); } if ((keyextype == KEYEX_ECDH_RSA) || (keyextype == KEYEX_ECDH_ECDSA)) { dhkey.ec = gen_EC_key(ecdh_curve, 1, NULL); if (!dhkey.key) { log0(0, 0, 0, "Failed to generate DH key"); exit(ERR_CRYPTO); } } }