+
+ memset(old, 0, data_len);
+ silc_free(old);
+ return TRUE;
+ }
+
+ /* 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 SHA1 hash */
+ if (!silc_hash_alloc("sha1", &sha1)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 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(sha1);
+ 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(sha1);
+ silc_hash_update(sha1, passphrase, passphrase_len);
+ silc_hash_final(sha1, keymat);
+ silc_hash_init(sha1);
+ silc_hash_update(sha1, passphrase, passphrase_len);
+ silc_hash_update(sha1, keymat, 16);
+ silc_hash_final(sha1, keymat + 16);
+
+ /* Set the key to the cipher */
+ silc_cipher_set_key(aes, keymat, 256);
+
+ /* 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(sha1);
+ 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, NULL);
+ 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(sha1);
+ 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(sha1);
+ 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;