- /* Allocate the AES cipher */
- if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
- SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
- blocklen = silc_cipher_get_block_len(aes);
- if (blocklen * 2 > sizeof(tmp)) {
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
-
- /* Allocate MD5 hash */
- if (!silc_hash_alloc("md5", &md5)) {
- SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
- silc_cipher_free(aes);
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
-
- /* Allocate HMAC */
- if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
- SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
- silc_hash_free(md5);
- silc_cipher_free(aes);
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
-
- /* Derive the decryption key from the provided key material. The key
- is 256 bits length, and derived by taking hash of the data, then
- re-hashing the data and the previous digest, and using the first and
- second digest as the key. */
- silc_hash_init(md5);
- silc_hash_update(md5, passphrase, passphrase_len);
- silc_hash_final(md5, keymat);
- silc_hash_init(md5);
- silc_hash_update(md5, passphrase, passphrase_len);
- silc_hash_update(md5, keymat, 16);
- silc_hash_final(md5, keymat + 16);
-
- /* Set the key to the cipher */
- silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
-
- /* First, verify the MAC of the private key data */
- mac_len = silc_hmac_len(sha1hmac);
- silc_hmac_init_with_key(sha1hmac, keymat, 16);
- silc_hmac_update(sha1hmac, data, len - mac_len);
- silc_hmac_final(sha1hmac, tmp, NULL);
- if (memcmp(tmp, data + (len - mac_len), mac_len)) {
- SILC_LOG_DEBUG(("Integrity check for private key failed"));
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(md5);
- silc_cipher_free(aes);
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
- data += 4;
- len -= 4;
-
- /* Decrypt the private key buffer */
- silc_cipher_decrypt(aes, data, data, len - mac_len, silc_cipher_get_iv(aes));
- SILC_GET32_MSB(i, data);
- if (i > len) {
- SILC_LOG_DEBUG(("Bad private key length in buffer!"));
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(md5);
- silc_cipher_free(aes);
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
- data += 4;
- len = i;
-
- /* Cleanup */
- memset(keymat, 0, sizeof(keymat));
- memset(tmp, 0, sizeof(tmp));
- silc_hmac_free(sha1hmac);
- silc_hash_free(md5);
- silc_cipher_free(aes);
-
- /* Now decode the actual private key */
- if (!silc_pkcs_private_key_decode(data, len, private_key)) {
- memset(old, 0, data_len);
- silc_free(old);
- return FALSE;
- }
-
- memset(old, 0, data_len);
- silc_free(old);