static gboolean gcr_secret_exchange_default_derive_transport_key (GcrSecretExchange *exchange, const guchar *peer, gsize n_peer) { GcrSecretExchangeDefault *data = exchange->pv->default_exchange; gpointer ikm; gsize n_ikm; gcry_mpi_t mpi; g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data->priv != NULL, FALSE); mpi = mpi_from_data (peer, n_peer); if (mpi == NULL) return FALSE; /* Build up a key we can use */ ikm = egg_dh_gen_secret (mpi, data->priv, data->prime, &n_ikm); g_return_val_if_fail (ikm != NULL, FALSE); if (data->key == NULL) data->key = egg_secure_alloc (EXCHANGE_1_KEY_LENGTH); if (!egg_hkdf_perform (EXCHANGE_1_HASH_ALGO, ikm, n_ikm, NULL, 0, NULL, 0, data->key, EXCHANGE_1_KEY_LENGTH)) g_return_val_if_reached (FALSE); egg_secure_free (ikm); gcry_mpi_release (mpi); return TRUE; }
static GkmObject* factory_create_generic_key (GkmSession *session, GkmTransaction *transaction, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs) { GkmGenericKey *key; GkmManager *manager; CK_ATTRIBUTE_PTR value; value = gkm_attributes_find (attrs, n_attrs, CKA_VALUE); if (value == NULL) { gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE); return NULL; } if (gkm_attributes_find (attrs, n_attrs, CKA_VALUE_LEN)) { gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT); return NULL; } manager = gkm_manager_for_template (attrs, n_attrs, session); key = g_object_new (GKM_TYPE_GENERIC_KEY, "module", gkm_session_get_module (session), "manager", manager, NULL); key->value = egg_secure_alloc (value->ulValueLen); key->n_value = value->ulValueLen; memcpy (key->value, value->pValue, key->n_value); gkm_attribute_consume (value); gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (key), TRUE, attrs, n_attrs); return GKM_OBJECT (key); }
static gchar* uri_encode_password (const gchar *value) { gchar *p; gchar *result; /* Just allocate for worst case */ result = egg_secure_alloc ((strlen (value) * 3) + 1); /* Now loop through looking for escapes */ p = result; while (*value) { /* These characters we let through verbatim */ if (*value && (g_ascii_isalnum (*value) || strchr ("_-.", *value) != NULL)) { *(p++) = *(value++); /* All others get encoded */ } else { *(p++) = '%'; *(p++) = HEXC[((unsigned char)*value) >> 4]; *(p++) = HEXC[((unsigned char)*value) & 0x0F]; ++value; } } *p = 0; return result; }
guchar * egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, gssize n_password, GBytes *data, gsize *n_decrypted) { gcry_cipher_hd_t ch; guchar *key = NULL; guchar *iv = NULL; int gcry, ivlen; int algo = 0; int mode = 0; guchar *decrypted; if (!parse_dekinfo (dekinfo, &algo, &mode, &iv)) return FALSE; ivlen = gcry_cipher_get_algo_blklen (algo); /* We assume the iv is at least as long as at 8 byte salt */ g_return_val_if_fail (ivlen >= 8, FALSE); /* IV is already set from the DEK info */ if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password, n_password, iv, 8, 1, &key, NULL)) { g_free (iv); return NULL; } gcry = gcry_cipher_open (&ch, algo, mode, 0); g_return_val_if_fail (!gcry, NULL); gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo)); g_return_val_if_fail (!gcry, NULL); egg_secure_free (key); /* 16 = 128 bits */ gcry = gcry_cipher_setiv (ch, iv, ivlen); g_return_val_if_fail (!gcry, NULL); g_free (iv); /* Allocate output area */ *n_decrypted = g_bytes_get_size (data); decrypted = egg_secure_alloc (*n_decrypted); gcry = gcry_cipher_decrypt (ch, decrypted, *n_decrypted, g_bytes_get_data (data, NULL), g_bytes_get_size (data)); if (gcry) { egg_secure_free (decrypted); g_return_val_if_reached (NULL); } gcry_cipher_close (ch); return decrypted; }
char* egg_secure_strdup (const char *str) { size_t len; char *res; if (!str) return NULL; len = strlen (str) + 1; res = (char*)egg_secure_alloc (len); strcpy (res, str); return res; }
gpointer egg_dh_gen_secret (gcry_mpi_t peer, gcry_mpi_t priv, gcry_mpi_t prime, gsize *bytes) { gcry_error_t gcry; guchar *value; gsize n_value; gcry_mpi_t k; gint bits; g_return_val_if_fail (peer, NULL); g_return_val_if_fail (priv, NULL); g_return_val_if_fail (prime, NULL); bits = gcry_mpi_get_nbits (prime); g_return_val_if_fail (bits >= 0, NULL); k = gcry_mpi_snew (bits); g_return_val_if_fail (k, NULL); gcry_mpi_powm (k, peer, priv, prime); /* Write out the secret */ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_value, k); g_return_val_if_fail (gcry == 0, NULL); value = egg_secure_alloc (n_value); gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_value, &n_value, k); g_return_val_if_fail (gcry == 0, NULL); #if DEBUG_DH_SECRET g_printerr ("DH SECRET: "); gcry_mpi_dump (k); gcry_mpi_release (k); #endif *bytes = n_value; #if DEBUG_DH_SECRET gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, bytes, NULL); g_printerr ("RAW SECRET: "); gcry_mpi_dump (k); gcry_mpi_release (k); #endif return value; }
/** * Negotiates crypto between the calling programm and the prompt * * Reads data from the transport section of input_data and sends the public key back * in the transport section of the output_data. * * Returns TRUE on success **/ static gboolean negotiate_transport_crypto (void) { gcry_mpi_t base, prime, peer; gcry_mpi_t key, pub, priv; gboolean ret = FALSE; gpointer ikm; gsize n_ikm; g_assert (!the_key); base = prime = peer = NULL; key = pub = priv = NULL; /* The DH stuff coming in from our caller */ if (gku_prompt_util_decode_mpi (input_data, "transport", "prime", &prime) && gku_prompt_util_decode_mpi (input_data, "transport", "base", &base) && gku_prompt_util_decode_mpi (input_data, "transport", "public", &peer)) { /* Generate our own public/priv, and then a key, send it back */ if (egg_dh_gen_pair (prime, base, 0, &pub, &priv)) { gku_prompt_util_encode_mpi (output_data, "transport", "public", pub); /* Build up a key we can use */ ikm = egg_dh_gen_secret (peer, priv, prime, &n_ikm); if (ikm != NULL) { n_the_key = 16; the_key = egg_secure_alloc (n_the_key); if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0, the_key, n_the_key)) g_return_val_if_reached (FALSE); ret = TRUE; } } } gcry_mpi_release (base); gcry_mpi_release (prime); gcry_mpi_release (peer); gcry_mpi_release (key); gcry_mpi_release (pub); gcry_mpi_release (priv); return ret; }
static guchar* pkcs7_pad_bytes_in_secure_memory (gconstpointer secret, gsize length, gsize *n_padded) { gsize n_pad; guchar *padded; /* Pad the secret */ *n_padded = ((length + 16) / 16) * 16; g_assert (length < *n_padded); g_assert (*n_padded > 0); n_pad = *n_padded - length; g_assert (n_pad > 0 && n_pad <= 16); padded = egg_secure_alloc (*n_padded); memcpy (padded, secret, length); memset (padded + length, n_pad, n_pad); return padded; }
/* Encode a password in hex */ static gchar* hex_encode_password (const gchar *pass) { int j, c; gchar *enc, *k; /* Encode the password */ c = sizeof (gchar *) * ((strlen (pass) * 2) + 1); k = enc = egg_secure_alloc (c); /* Simple hex encoding */ while (*pass) { j = *(pass) >> 4 & 0xf; *(k++) = HEXC[j]; j = *(pass++) & 0xf; *(k++) = HEXC[j]; } return enc; }
static gchar* read_login_password (int fd) { /* We only accept a max of 8K as the login password */ #define MAX_LENGTH 8192 #define MAX_BLOCK 256 /* * When --login is specified then the login password is passed * in on stdin. All data (including newlines) are part of the * password. A zero length password is no password. */ gchar *buf = egg_secure_alloc (MAX_BLOCK); gchar *ret = NULL; int r, len = 0; for (;;) { r = read (fd, buf, MAX_BLOCK); if (r < 0) { if (errno == EAGAIN) continue; egg_secure_free (ret); egg_secure_free (buf); return NULL; } else if (r == 0 || len > MAX_LENGTH) { break; } else { ret = egg_secure_realloc (ret, len + r + 1); memset (ret + len, 0, r + 1); len = len + r; strncat (ret, buf, r); } } egg_secure_free (buf); return ret; }
static CK_RV retrieve_value (GkmSession *session, GkmObject *wrapped, gpointer *value, gsize *n_value) { CK_ATTRIBUTE attr; CK_RV rv; rv = retrieve_length (session, wrapped, n_value); if (rv != CKR_OK) return rv; attr.type = CKA_VALUE; attr.pValue = egg_secure_alloc (*n_value); attr.ulValueLen = *n_value; rv = gkm_object_get_attribute (wrapped, session, &attr); if (rv == CKR_OK) *value = attr.pValue; else egg_secure_free (attr.pValue); return rv; }
GBytes * gkm_data_der_write_private_pkcs8_crypted (gcry_sexp_t skey, const gchar *password, gsize n_password) { gcry_error_t gcry; gcry_cipher_hd_t cih; GNode *asn = NULL; GBytes *key, *data; guchar *raw; gsize n_raw, n_key; gsize block = 0; /* Encode the key in normal pkcs8 fashion */ key = gkm_data_der_write_private_pkcs8_plain (skey); if (key == NULL) return NULL; asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo"); g_return_val_if_fail (asn, NULL); /* Create a and write out a cipher used for encryption */ cih = prepare_and_encode_pkcs8_cipher (asn, password, n_password, &block); g_return_val_if_fail (cih, NULL); n_key = g_bytes_get_size (key); /* Pad the block of data */ if(block > 1) { gsize n_pad = block - (n_key % block); if (n_pad == 0) n_pad = block; raw = egg_secure_alloc (n_key + n_pad); memcpy (raw, g_bytes_get_data (key, NULL), n_key); memset (raw + n_key, (int)n_pad, n_pad); n_raw = n_key + n_pad; /* No padding, probably stream cipher */ } else { raw = egg_secure_alloc (n_key); memcpy (raw, g_bytes_get_data (key, NULL), n_key); n_raw = n_key; } g_bytes_unref (key); gcry = gcry_cipher_encrypt (cih, raw, n_raw, NULL, 0); g_return_val_if_fail (gcry == 0, NULL); gcry_cipher_close (cih); key = g_bytes_new_with_free_func (raw, n_raw, egg_secure_free, raw); egg_asn1x_set_string_as_bytes (egg_asn1x_node (asn, "encryptedData", NULL), key); g_bytes_unref (key); data = egg_asn1x_encode (asn, NULL); if (data == NULL) g_warning ("couldn't encode encrypted pkcs8 key: %s", egg_asn1x_message (asn)); egg_asn1x_destroy (asn); return data; }
gboolean egg_symkey_generate_simple (int cipher_algo, int hash_algo, const gchar *password, gssize n_password, const guchar *salt, gsize n_salt, int iterations, guchar **key, guchar **iv) { gcry_md_hd_t mdh; gcry_error_t gcry; guchar *digest; guchar *digested; guint n_digest; gint pass, i; gint needed_iv, needed_key; guchar *at_iv, *at_key; g_assert (cipher_algo); g_assert (hash_algo); g_return_val_if_fail (iterations >= 1, FALSE); if (!password) n_password = 0; if (n_password == -1) n_password = strlen (password); /* * If cipher algo needs more bytes than hash algo has available * then the entire hashing process is done again (with the previous * hash bytes as extra input), and so on until satisfied. */ needed_key = gcry_cipher_get_algo_keylen (cipher_algo); needed_iv = gcry_cipher_get_algo_blklen (cipher_algo); gcry = gcry_md_open (&mdh, hash_algo, 0); if (gcry) { g_warning ("couldn't create '%s' hash context: %s", gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); return FALSE; } n_digest = gcry_md_get_algo_dlen (hash_algo); g_return_val_if_fail (n_digest > 0, FALSE); digest = egg_secure_alloc (n_digest); g_return_val_if_fail (digest, FALSE); if (key) { *key = egg_secure_alloc (needed_key); g_return_val_if_fail (*key, FALSE); } if (iv) *iv = g_new0 (guchar, needed_iv); at_key = key ? *key : NULL; at_iv = iv ? *iv : NULL; for (pass = 0; TRUE; ++pass) { gcry_md_reset (mdh); /* Hash in the previous buffer on later passes */ if (pass > 0) gcry_md_write (mdh, digest, n_digest); if (password) gcry_md_write (mdh, password, n_password); if (salt && n_salt) gcry_md_write (mdh, salt, n_salt); gcry_md_final (mdh); digested = gcry_md_read (mdh, 0); g_return_val_if_fail (digested, FALSE); memcpy (digest, digested, n_digest); for (i = 1; i < iterations; ++i) { gcry_md_reset (mdh); gcry_md_write (mdh, digest, n_digest); gcry_md_final (mdh); digested = gcry_md_read (mdh, 0); g_return_val_if_fail (digested, FALSE); memcpy (digest, digested, n_digest); } /* Copy as much as possible into the destinations */ i = 0; while (needed_key && i < n_digest) { if (at_key) *(at_key++) = digest[i]; needed_key--; i++; } while (needed_iv && i < n_digest) { if (at_iv) *(at_iv++) = digest[i]; needed_iv--; i++; } if (needed_key == 0 && needed_iv == 0) break; } egg_secure_free (digest); gcry_md_close (mdh); return TRUE; }
static gboolean generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, gssize n_password, const guchar *salt, gsize n_salt, int iterations, guchar *output, gsize n_output) { gcry_mpi_t num_b1, num_ij; guchar *hash, *buf_i, *buf_b; const gchar *end_password; gcry_md_hd_t mdh; const gchar *p2; guchar *p; gsize n_hash, i; gunichar unich; gcry_error_t gcry; num_b1 = num_ij = NULL; n_hash = gcry_md_get_algo_dlen (hash_algo); g_return_val_if_fail (n_hash > 0, FALSE); if (!utf8_password) n_password = 0; if (n_password == -1) end_password = utf8_password + strlen (utf8_password); else end_password = utf8_password + n_password; gcry = gcry_md_open (&mdh, hash_algo, 0); if (gcry) { g_warning ("couldn't create '%s' hash context: %s", gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); return FALSE; } /* Reqisition me a buffer */ hash = egg_secure_alloc (n_hash); buf_i = egg_secure_alloc (128); buf_b = egg_secure_alloc (64); g_return_val_if_fail (hash && buf_i && buf_b, FALSE); /* Bring in the salt */ p = buf_i; if (salt) { for (i = 0; i < 64; ++i) *(p++) = salt[i % n_salt]; } else { memset (p, 0, 64); p += 64; } /* Bring in the password, as 16bits per character BMP string, ie: UCS2 */ if (utf8_password) { p2 = utf8_password; for (i = 0; i < 64; i += 2) { /* Get a character from the string */ if (p2 < end_password) { unich = g_utf8_get_char (p2); p2 = g_utf8_next_char (p2); /* Get zero null terminator, and loop back to beginning */ } else { unich = 0; p2 = utf8_password; } /* Encode the bytes received */ *(p++) = (unich & 0xFF00) >> 8; *(p++) = (unich & 0xFF); } } else {
gboolean egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, gssize n_password, const guchar *salt, gsize n_salt, int iterations, guchar **key, guchar **iv) { gcry_md_hd_t mdh; gcry_error_t gcry; guchar *digest; guchar *digested; guint i, n_digest; gint needed_iv, needed_key; g_assert (cipher_algo); g_assert (hash_algo); g_return_val_if_fail (iterations >= 1, FALSE); if (!password) n_password = 0; if (n_password == -1) n_password = strlen (password); /* * We only do one pass here. * * The key ends up as the first needed_key bytes of the hash buffer. * The iv ends up as the last needed_iv bytes of the hash buffer. * * The IV may overlap the key (which is stupid) if the wrong pair of * hash/cipher algorithms are chosen. */ n_digest = gcry_md_get_algo_dlen (hash_algo); g_return_val_if_fail (n_digest > 0, FALSE); needed_key = gcry_cipher_get_algo_keylen (cipher_algo); needed_iv = gcry_cipher_get_algo_blklen (cipher_algo); if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) { g_warning ("using PBE symkey generation with %s using an algorithm that needs " "too many bytes of key and/or IV: %s", gcry_cipher_algo_name (hash_algo), gcry_cipher_algo_name (cipher_algo)); return FALSE; } gcry = gcry_md_open (&mdh, hash_algo, 0); if (gcry) { g_warning ("couldn't create '%s' hash context: %s", gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); return FALSE; } digest = egg_secure_alloc (n_digest); g_return_val_if_fail (digest, FALSE); if (key) { *key = egg_secure_alloc (needed_key); g_return_val_if_fail (*key, FALSE); } if (iv) *iv = g_new0 (guchar, needed_iv); if (password) gcry_md_write (mdh, password, n_password); if (salt && n_salt) gcry_md_write (mdh, salt, n_salt); gcry_md_final (mdh); digested = gcry_md_read (mdh, 0); g_return_val_if_fail (digested, FALSE); memcpy (digest, digested, n_digest); for (i = 1; i < iterations; ++i) gcry_md_hash_buffer (hash_algo, digest, digest, n_digest); /* The first x bytes are the key */ if (key) { g_assert (needed_key <= n_digest); memcpy (*key, digest, needed_key); } /* The last 16 - x bytes are the iv */ if (iv) { g_assert (needed_iv <= n_digest && n_digest >= 16); memcpy (*iv, digest + (16 - needed_iv), needed_iv); } egg_secure_free (digest); gcry_md_close (mdh); return TRUE; }
static gboolean response_open_session_aes (SecretSession *session, GVariant *response) { gconstpointer buffer; GVariant *argument; const gchar *sig; gsize n_buffer; gcry_mpi_t peer; gcry_error_t gcry; gpointer ikm; gsize n_ikm; sig = g_variant_get_type_string (response); g_return_val_if_fail (sig != NULL, FALSE); if (!g_str_equal (sig, "(vo)")) { g_warning ("invalid OpenSession() response from daemon with signature: %s", sig); return FALSE; } g_assert (session->path == NULL); g_variant_get (response, "(vo)", &argument, &session->path); buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar)); gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL); g_return_val_if_fail (gcry == 0, FALSE); g_variant_unref (argument); #if 0 g_printerr (" lib publi: "); gcry_mpi_dump (session->publi); g_printerr ("\n lib peer: "); gcry_mpi_dump (peer); g_printerr ("\n"); #endif ikm = egg_dh_gen_secret (peer, session->privat, session->prime, &n_ikm); gcry_mpi_release (peer); #if 0 g_printerr (" lib ikm: %s\n", egg_hex_encode (ikm, n_ikm)); #endif if (ikm == NULL) { g_warning ("couldn't negotiate a valid AES session key"); g_free (session->path); session->path = NULL; return FALSE; } session->n_key = 16; session->key = egg_secure_alloc (session->n_key); if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0, session->key, session->n_key)) g_return_val_if_reached (FALSE); egg_secure_free (ikm); session->algorithms = ALGORITHMS_AES; return TRUE; }
static gboolean pem_parse_block (const gchar *data, gsize n_data, guchar **decoded, gsize *n_decoded, GHashTable **headers) { const gchar *x, *hbeg, *hend; const gchar *p, *end; gint state = 0; guint save = 0; g_assert (data); g_assert (n_data); g_assert (decoded); g_assert (n_decoded); p = data; end = p + n_data; hbeg = hend = NULL; /* Try and find a pair of blank lines with only white space between */ while (hend == NULL) { x = memchr (p, '\n', end - p); if (!x) break; ++x; while (isspace (*x)) { /* Found a second line, with only spaces between */ if (*x == '\n') { hbeg = data; hend = x; break; /* Found a space between two lines */ } else { ++x; } } /* Try next line */ p = x; } /* Headers found? */ if (hbeg && hend) { data = hend; n_data = end - data; } *n_decoded = (n_data * 3) / 4 + 1; if (egg_secure_check (data)) *decoded = egg_secure_alloc (*n_decoded); else *decoded = g_malloc0 (*n_decoded); g_return_val_if_fail (*decoded, FALSE); *n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save); if (!*n_decoded) { egg_secure_free (*decoded); return FALSE; } if (headers && hbeg && hend) parse_header_lines (hbeg, hend, headers); return TRUE; }
static SecretValue * service_decode_aes_secret (SecretSession *session, gconstpointer param, gsize n_param, gconstpointer value, gsize n_value, const gchar *content_type) { gcry_cipher_hd_t cih; gsize n_padded; gcry_error_t gcry; guchar *padded; gsize pos; if (n_param != 16) { g_message ("received an encrypted secret structure with invalid parameter"); return NULL; } if (n_value == 0 || n_value % 16 != 0) { g_message ("received an encrypted secret structure with bad secret length"); return NULL; } gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); if (gcry != 0) { g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry)); return NULL; } #if 0 g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param)); #endif gcry = gcry_cipher_setiv (cih, param, n_param); g_return_val_if_fail (gcry == 0, NULL); #if 0 g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key)); #endif gcry = gcry_cipher_setkey (cih, session->key, session->n_key); g_return_val_if_fail (gcry == 0, NULL); /* Copy the memory buffer */ n_padded = n_value; padded = egg_secure_alloc (n_padded); memcpy (padded, value, n_padded); /* Perform the decryption */ for (pos = 0; pos < n_padded; pos += 16) { gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0); g_return_val_if_fail (gcry == 0, FALSE); } gcry_cipher_close (cih); /* Unpad the resulting value */ if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) { egg_secure_clear (padded, n_padded); egg_secure_free (padded); g_message ("received an invalid or unencryptable secret"); return FALSE; } return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free); }
gboolean egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, gssize n_password, const guchar *data, gsize n_data, guchar **encrypted, gsize *n_encrypted) { gsize n_overflow, n_batch, n_padding; gcry_cipher_hd_t ch; guchar *key = NULL; guchar *iv = NULL; guchar *padded = NULL; int gcry, ivlen; int algo = 0; int mode = 0; if (!parse_dekinfo (dekinfo, &algo, &mode, &iv)) g_return_val_if_reached (FALSE); ivlen = gcry_cipher_get_algo_blklen (algo); /* We assume the iv is at least as long as at 8 byte salt */ g_return_val_if_fail (ivlen >= 8, FALSE); /* IV is already set from the DEK info */ if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password, n_password, iv, 8, 1, &key, NULL)) g_return_val_if_reached (FALSE); gcry = gcry_cipher_open (&ch, algo, mode, 0); g_return_val_if_fail (!gcry, FALSE); gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo)); g_return_val_if_fail (!gcry, FALSE); egg_secure_free (key); /* 16 = 128 bits */ gcry = gcry_cipher_setiv (ch, iv, ivlen); g_return_val_if_fail (!gcry, FALSE); g_free (iv); /* Allocate output area */ n_overflow = (n_data % ivlen); n_padding = n_overflow ? (ivlen - n_overflow) : 0; n_batch = n_data - n_overflow; *n_encrypted = n_data + n_padding; *encrypted = g_malloc0 (*n_encrypted); g_assert (*n_encrypted % ivlen == 0); g_assert (*n_encrypted >= n_data); g_assert (*n_encrypted == n_batch + n_overflow + n_padding); /* Encrypt everything but the last bit */ gcry = gcry_cipher_encrypt (ch, *encrypted, n_batch, (void*)data, n_batch); if (gcry) { g_free (*encrypted); g_return_val_if_reached (FALSE); } /* Encrypt the padded block */ if (n_overflow) { padded = egg_secure_alloc (ivlen); memset (padded, 0, ivlen); memcpy (padded, data + n_batch, n_overflow); gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen); egg_secure_free (padded); if (gcry) { g_free (*encrypted); g_return_val_if_reached (FALSE); } } gcry_cipher_close (ch); return TRUE; }
CK_RV gkm_aes_mechanism_unwrap (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *wrapper, CK_VOID_PTR input, CK_ULONG n_input, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GkmObject **unwrapped) { gcry_cipher_hd_t cih; gcry_error_t gcry; CK_ATTRIBUTE attr; GArray *array; GkmAesKey *key; gpointer padded, value; gsize n_padded, n_value; GkmTransaction *transaction; gsize block, pos; gboolean ret; g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR); g_return_val_if_fail (mech, CKR_GENERAL_ERROR); g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR); g_return_val_if_fail (GKM_IS_OBJECT (wrapper), CKR_GENERAL_ERROR); if (!GKM_IS_AES_KEY (wrapper)) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; key = GKM_AES_KEY (wrapper); block = gkm_aes_key_get_block_size (key); g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR); if (n_input == 0 || n_input % block != 0) return CKR_WRAPPED_KEY_LEN_RANGE; cih = gkm_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC); if (cih == NULL) return CKR_FUNCTION_FAILED; if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) { gcry_cipher_close (cih); return CKR_MECHANISM_PARAM_INVALID; } padded = egg_secure_alloc (n_input); memcpy (padded, input, n_input); n_padded = n_input; /* In place decryption */ for (pos = 0; pos < n_padded; pos += block) { gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, block, NULL, 0); g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR); } gcry_cipher_close (cih); /* Unpad the resulting value */ ret = egg_padding_pkcs7_unpad (egg_secure_realloc, block, padded, n_padded, &value, &n_value); egg_secure_free (padded); /* TODO: This is dubious, there doesn't seem to be an rv for 'bad decrypt' */ if (ret == FALSE) return CKR_WRAPPED_KEY_INVALID; /* Now setup the attributes with our new value */ array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE)); /* Prepend the value */ attr.type = CKA_VALUE; attr.pValue = value; attr.ulValueLen = n_value; g_array_append_val (array, attr); /* Add the remainder of the attributes */ g_array_append_vals (array, attrs, n_attrs); transaction = gkm_transaction_new (); /* Now create an object with these attributes */ *unwrapped = gkm_session_create_object_for_attributes (session, transaction, (CK_ATTRIBUTE_PTR)array->data, array->len); egg_secure_free (value); g_array_free (array, TRUE); return gkm_transaction_complete_and_unref (transaction); }