From 810e9348924fbb2c700b3893e875491ff3028881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Klime=C5=A1?= Date: Fri, 9 May 2014 13:48:30 +0200 Subject: [PATCH] libnm-util: add nm_utils_rsa_key_encrypt_aes() encrypting RSA key with AES --- libnm-util/crypto_gnutls.c | 11 +++- libnm-util/crypto_nss.c | 2 + libnm-util/libnm-util.ver | 1 + libnm-util/nm-utils.c | 100 ++++++++++++++++++++++++++++----- libnm-util/nm-utils.h | 4 ++ libnm-util/tests/test-crypto.c | 27 ++++++++- 6 files changed, 128 insertions(+), 17 deletions(-) diff --git a/libnm-util/crypto_gnutls.c b/libnm-util/crypto_gnutls.c index c272e373e0..e829c23c10 100644 --- a/libnm-util/crypto_gnutls.c +++ b/libnm-util/crypto_gnutls.c @@ -253,10 +253,15 @@ crypto_encrypt (const char *cipher, gsize padded_buf_len, pad_len, output_len; char *padded_buf = NULL; guint32 i; + gsize salt_len; - if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) + if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { cipher_mech = GCRY_CIPHER_3DES; - else { + salt_len = SALT_LEN; + } else if (!strcmp (cipher, CIPHER_AES_CBC)) { + cipher_mech = GCRY_CIPHER_AES; + salt_len = iv_len; + } else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), @@ -296,7 +301,7 @@ crypto_encrypt (const char *cipher, } /* gcrypt only wants 8 bytes of the IV (same as the DES block length) */ - err = gcry_cipher_setiv (ctx, iv, SALT_LEN); + err = gcry_cipher_setiv (ctx, iv, salt_len); if (err) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_SET_IV_FAILED, diff --git a/libnm-util/crypto_nss.c b/libnm-util/crypto_nss.c index 23863902f6..af3de6664c 100644 --- a/libnm-util/crypto_nss.c +++ b/libnm-util/crypto_nss.c @@ -323,6 +323,8 @@ crypto_encrypt (const char *cipher, if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) cipher_mech = CKM_DES3_CBC_PAD; + else if (!strcmp (cipher, CIPHER_AES_CBC)) + cipher_mech = CKM_AES_CBC_PAD; else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_UNKNOWN_CIPHER, diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index ab7c2846ca..17133cc18f 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -638,6 +638,7 @@ global: nm_utils_is_empty_ssid; nm_utils_is_uuid; nm_utils_rsa_key_encrypt; + nm_utils_rsa_key_encrypt_aes; nm_utils_same_ssid; nm_utils_security_type_get_type; nm_utils_security_valid; diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index aead8e3e6c..890e17ca0e 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -1516,7 +1516,8 @@ out: } static char * -make_key (const char *salt, +make_key (const char *cipher, + const char *salt, const gsize salt_len, const char *password, gsize *out_len, @@ -1530,6 +1531,11 @@ make_key (const char *salt, g_return_val_if_fail (password != NULL, NULL); g_return_val_if_fail (out_len != NULL, NULL); + if (!strcmp (cipher, "DES-EDE3-CBC")) + digest_len = 24; + else if (!strcmp (cipher, "AES-128-CBC")) + digest_len = 16; + key = g_malloc0 (digest_len + 1); if (!crypto_md5_hash (salt, salt_len, password, strlen (password), key, digest_len, error)) { @@ -1544,7 +1550,8 @@ make_key (const char *salt, } /** - * nm_utils_rsa_key_encrypt: + * nm_utils_rsa_key_encrypt_helper: + * @cipher: cipher to use for encryption ("DES-EDE3-CBC" or "AES-128-CBC") * @data: RSA private key data to be encrypted * @in_password: (allow-none): existing password to use, if any * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated @@ -1558,13 +1565,15 @@ make_key (const char *salt, * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted * certificate/private key file. **/ -GByteArray * -nm_utils_rsa_key_encrypt (const GByteArray *data, - const char *in_password, - char **out_password, - GError **error) +static GByteArray * +nm_utils_rsa_key_encrypt_helper (const char *cipher, + const GByteArray *data, + const char *in_password, + char **out_password, + GError **error) { - char salt[8]; + char salt[16]; + int salt_len; char *key = NULL, *enc = NULL, *pw_buf[32]; gsize key_len = 0, enc_len = 0; GString *pem = NULL; @@ -1573,6 +1582,7 @@ nm_utils_rsa_key_encrypt (const GByteArray *data, const char *p; GByteArray *ret = NULL; + g_return_val_if_fail (!g_strcmp0 (cipher, CIPHER_DES_EDE3_CBC) || !g_strcmp0 (cipher, CIPHER_AES_CBC), NULL); g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (data->len > 0, NULL); if (out_password) @@ -1585,14 +1595,19 @@ nm_utils_rsa_key_encrypt (const GByteArray *data, in_password = tmp_password = nm_utils_bin2hexstr ((const char *) pw_buf, sizeof (pw_buf), -1); } - if (!crypto_randomize (salt, sizeof (salt), error)) + if (g_strcmp0 (cipher, CIPHER_AES_CBC) == 0) + salt_len = 16; + else + salt_len = 8; + + if (!crypto_randomize (salt, salt_len, error)) goto out; - key = make_key (&salt[0], sizeof (salt), in_password, &key_len, error); + key = make_key (cipher, &salt[0], salt_len, in_password, &key_len, error); if (!key) goto out; - enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, salt, sizeof (salt), key, key_len, &enc_len, error); + enc = crypto_encrypt (cipher, data, salt, salt_len, key, key_len, &enc_len, error); if (!enc) goto out; @@ -1601,8 +1616,8 @@ nm_utils_rsa_key_encrypt (const GByteArray *data, g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n"); /* Convert the salt to a hex string */ - tmp = nm_utils_bin2hexstr ((const char *) salt, sizeof (salt), 16); - g_string_append_printf (pem, "DEK-Info: DES-EDE3-CBC,%s\n\n", tmp); + tmp = nm_utils_bin2hexstr ((const char *) salt, salt_len, salt_len * 2); + g_string_append_printf (pem, "DEK-Info: %s,%s\n\n", cipher, tmp); g_free (tmp); /* Convert the encrypted key to a base64 string */ @@ -1643,6 +1658,65 @@ out: return ret; } +/** + * nm_utils_rsa_key_encrypt: + * @data: RSA private key data to be encrypted + * @in_password: (allow-none): existing password to use, if any + * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated + * and returned in this argument + * @error: detailed error information on return, if an error occurred + * + * Encrypts the given RSA private key data with the given password (or generates + * a password if no password was given) and converts the data to PEM format + * suitable for writing to a file. It uses Triple DES cipher for the encryption. + * + * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted + * certificate/private key file. + **/ +GByteArray * +nm_utils_rsa_key_encrypt (const GByteArray *data, + const char *in_password, + char **out_password, + GError **error) +{ + + + return nm_utils_rsa_key_encrypt_helper (CIPHER_DES_EDE3_CBC, + data, + in_password, + out_password, + error); +} + +/** + * nm_utils_rsa_key_encrypt_aes: + * @data: RSA private key data to be encrypted + * @in_password: (allow-none): existing password to use, if any + * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated + * and returned in this argument + * @error: detailed error information on return, if an error occurred + * + * Encrypts the given RSA private key data with the given password (or generates + * a password if no password was given) and converts the data to PEM format + * suitable for writing to a file. It uses AES cipher for the encryption. + * + * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted + * certificate/private key file. + **/ +GByteArray * +nm_utils_rsa_key_encrypt_aes (const GByteArray *data, + const char *in_password, + char **out_password, + GError **error) +{ + + return nm_utils_rsa_key_encrypt_helper (CIPHER_AES_CBC, + data, + in_password, + out_password, + error); +} + /** * nm_utils_file_is_pkcs12: * @filename: name of the file to test diff --git a/libnm-util/nm-utils.h b/libnm-util/nm-utils.h index 582600420b..bb8786a144 100644 --- a/libnm-util/nm-utils.h +++ b/libnm-util/nm-utils.h @@ -120,6 +120,10 @@ GByteArray *nm_utils_rsa_key_encrypt (const GByteArray *data, const char *in_password, char **out_password, GError **error); +GByteArray *nm_utils_rsa_key_encrypt_aes (const GByteArray *data, + const char *in_password, + char **out_password, + GError **error); gboolean nm_utils_file_is_pkcs12 (const char *filename); guint32 nm_utils_wifi_freq_to_channel (guint32 freq); diff --git a/libnm-util/tests/test-crypto.c b/libnm-util/tests/test-crypto.c index 684de4680c..223f407d94 100644 --- a/libnm-util/tests/test-crypto.c +++ b/libnm-util/tests/test-crypto.c @@ -255,6 +255,28 @@ test_load_pkcs8 (const char *path, } } +static gboolean +is_cipher_aes (const char *path) +{ + char *contents; + gsize length = 0; + const char *cipher; + gboolean is_aes = FALSE; + + if (!g_file_get_contents (path, &contents, &length, NULL)) + return FALSE; + + cipher = strstr (contents, "DEK-Info: "); + if (cipher) { + cipher += strlen ("DEK-Info: "); + if (g_str_has_prefix (cipher, "AES-128-CBC")) + is_aes = TRUE; + } + + g_free (contents); + return is_aes; +} + static void test_encrypt_private_key (const char *path, const char *password, @@ -274,7 +296,10 @@ test_encrypt_private_key (const char *path, path, NM_CRYPTO_KEY_TYPE_RSA, key_type); /* Now re-encrypt the private key */ - encrypted = nm_utils_rsa_key_encrypt (array, password, NULL, &error); + if (is_cipher_aes (path)) + encrypted = nm_utils_rsa_key_encrypt_aes (array, password, NULL, &error); + else + encrypted = nm_utils_rsa_key_encrypt (array, password, NULL, &error); ASSERT (encrypted != NULL, desc, "couldn't re-encrypt private key file '%s': %d %s", path, error->code, error->message);