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; }
static gboolean decrypt_buffer (EggBuffer *buffer, GkmSecret *master, guchar salt[8], int iterations) { const gchar *password = NULL; gcry_cipher_hd_t cih; gcry_error_t gerr; guchar *key, *iv; gsize n_password = 0; size_t pos; g_assert (buffer->len % 16 == 0); g_assert (16 == gcry_cipher_get_algo_blklen (GCRY_CIPHER_AES128)); g_assert (16 == gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES128)); /* No password is set, try an null password */ if (master == NULL) { password = NULL; n_password = 0; } else { password = gkm_secret_get_password (master, &n_password); } if (!egg_symkey_generate_simple (GCRY_CIPHER_AES128, GCRY_MD_SHA256, password, n_password, salt, 8, iterations, &key, &iv)) return FALSE; gerr = gcry_cipher_open (&cih, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0); if (gerr) { g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gerr)); egg_secure_free (key); g_free (iv); return FALSE; } /* 16 = 128 bits */ gerr = gcry_cipher_setkey (cih, key, 16); g_return_val_if_fail (!gerr, FALSE); egg_secure_free (key); /* 16 = 128 bits */ gerr = gcry_cipher_setiv (cih, iv, 16); g_return_val_if_fail (!gerr, FALSE); g_free (iv); for (pos = 0; pos < buffer->len; pos += 16) { /* In place encryption */ gerr = gcry_cipher_decrypt (cih, buffer->buf + pos, 16, NULL, 0); g_return_val_if_fail (!gerr, FALSE); } gcry_cipher_close (cih); return TRUE; }
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 gboolean gkm_mate2_private_key_real_save (GkmSerializable *base, GkmSecret *login, gpointer *data, gsize *n_data) { GkmMate2PrivateKey *self = GKM_MATE2_PRIVATE_KEY (base); const gchar *password; gsize n_password; GkmSexp *sexp; guchar *key; g_return_val_if_fail (GKM_IS_MATE2_PRIVATE_KEY (self), FALSE); g_return_val_if_fail (data, FALSE); g_return_val_if_fail (n_data, FALSE); sexp = gkm_mate2_private_key_real_acquire_crypto_sexp (GKM_SEXP_KEY (self), NULL); g_return_val_if_fail (sexp, FALSE); password = gkm_secret_get_password (login, &n_password); if (password == NULL) { key = gkm_data_der_write_private_pkcs8_plain (gkm_sexp_get (sexp), n_data); /* * Caller is expecting normal memory buffer, which makes sense since * this is being written to disk, and won't be 'secure' anyway. */ *data = g_memdup (key, *n_data); egg_secure_free (key); } else { *data = gkm_data_der_write_private_pkcs8_crypted (gkm_sexp_get (sexp), password, n_password, n_data); } gkm_sexp_unref (sexp); return *data != NULL; }
static gboolean gcr_secret_exchange_default_generate_exchange_key (GcrSecretExchange *exchange, const gchar *scheme, guchar **public_key, gsize *n_public_key) { GcrSecretExchangeDefault *data = exchange->pv->default_exchange; if (data == NULL) { data = g_new0 (GcrSecretExchangeDefault, 1); if (!egg_dh_default_params (EXCHANGE_1_IKE_NAME, &data->prime, &data->base)) g_return_val_if_reached (FALSE); exchange->pv->default_exchange = data; exchange->pv->destroy_exchange = gcr_secret_exchange_default_free; } gcry_mpi_release (data->priv); data->priv = NULL; gcry_mpi_release (data->pub); data->pub = NULL; egg_secure_free (data->key); data->key = NULL; if (!egg_dh_gen_pair (data->prime, data->base, 0, &data->pub, &data->priv)) g_return_val_if_reached (FALSE); *public_key = mpi_to_data (data->pub, n_public_key); return *public_key != NULL; }
/** * gcr_secret_exchange_receive: * @self: a #GcrSecretExchange object * @exchange: the string received * * Receive a string from the other side of secret exchange. This string will * have been created by gcr_secret_exchange_begin() or gcr_secret_exchange_send(). * * After this call completes successfully the value returned from * gcr_secret_exchange_get_secret() will have changed. * * Returns: whether the string was successfully parsed and received */ gboolean gcr_secret_exchange_receive (GcrSecretExchange *self, const gchar *exchange) { GcrSecretExchangeClass *klass; gchar *secret = NULL; gsize n_secret = 0; GKeyFile *input; gboolean ret; g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), FALSE); g_return_val_if_fail (exchange != NULL, FALSE); klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); g_return_val_if_fail (klass->generate_exchange_key, FALSE); g_return_val_if_fail (klass->derive_transport_key, FALSE); gchar *string = g_strescape (exchange, ""); g_debug ("receiving secret exchange: %s", string); g_free (string); /* Parse the input */ input = g_key_file_new (); if (!g_key_file_load_from_data (input, exchange, strlen (exchange), G_KEY_FILE_NONE, NULL)) { g_key_file_free (input); g_message ("couldn't parse secret exchange data"); return FALSE; } if (!self->pv->generated) { if (!(klass->generate_exchange_key) (self, GCR_SECRET_EXCHANGE_PROTOCOL_1, &self->pv->publi, &self->pv->n_publi)) g_return_val_if_reached (FALSE); self->pv->generated = TRUE; } ret = TRUE; if (!self->pv->derived) { if (!derive_key (self, input)) ret = FALSE; } if (ret && g_key_file_has_key (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", NULL)) ret = perform_decrypt (self, input, (guchar **)&secret, &n_secret); if (ret) { egg_secure_free (self->pv->secret); self->pv->secret = secret; self->pv->n_secret = n_secret; } g_key_file_free (input); return ret; }
static void clear_secret_exchange (GcrSecretExchange *self) { g_free (self->pv->publi); self->pv->publi = NULL; self->pv->n_publi = 0; self->pv->derived = FALSE; self->pv->generated = TRUE; egg_secure_free (self->pv->secret); self->pv->secret = NULL; self->pv->n_secret = 0; }
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 void gcr_secret_exchange_default_free (gpointer to_free) { GcrSecretExchangeDefault *data = to_free; gcry_mpi_release (data->prime); gcry_mpi_release (data->base); gcry_mpi_release (data->pub); gcry_mpi_release (data->priv); if (data->key) { egg_secure_clear (data->key, EXCHANGE_1_KEY_LENGTH); egg_secure_free (data->key); } g_free (data); }
guint egg_openssl_pem_parse (const guchar *data, gsize n_data, EggOpensslPemCallback callback, gpointer user_data) { const gchar *beg, *end; guint nfound = 0; guchar *decoded = NULL; gsize n_decoded = 0; GHashTable *headers = NULL; GQuark type; g_return_val_if_fail (data, 0); g_return_val_if_fail (n_data, 0); g_return_val_if_fail (callback, 0); while (n_data > 0) { /* This returns the first character after the PEM BEGIN header */ beg = pem_find_begin ((const gchar*)data, n_data, &type); if (!beg) break; g_assert (type); /* This returns the character position before the PEM END header */ end = pem_find_end ((const gchar*)beg, n_data - ((const guchar*)beg - data), type); if (!end) break; if (beg != end) { if (pem_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) { (callback) (type, decoded, n_decoded, headers, user_data); ++nfound; egg_secure_free (decoded); if (headers) g_hash_table_remove_all (headers); } } /* Try for another block */ end += PEM_SUFF_L; n_data -= (const guchar*)end - data; data = (const guchar*)end; } if (headers) g_hash_table_destroy (headers); return nfound; }
static void gkm_generic_key_finalize (GObject *obj) { GkmGenericKey *self = GKM_GENERIC_KEY (obj); if (self->value) { egg_secure_clear (self->value, self->n_value); egg_secure_free (self->value); self->value = NULL; self->n_value = 0; } G_OBJECT_CLASS (gkm_generic_key_parent_class)->finalize (obj); }
void _secret_session_free (gpointer data) { SecretSession *session = data; if (session == NULL) return; g_free (session->path); #ifdef WITH_GCRYPT gcry_mpi_release (session->publi); gcry_mpi_release (session->privat); gcry_mpi_release (session->prime); #endif egg_secure_free (session->key); g_free (session); }
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; }
static void test_der_private (gcry_sexp_t key) { guchar *data; gsize n_data; GkmDataResult ret; gcry_sexp_t sexp; /* Encode it */ data = gkm_data_der_write_private_key (key, &n_data); g_assert ("couldn't encode private key" && data != NULL); g_assert ("encoding is empty" && n_data > 0); /* Now parse it */ ret = gkm_data_der_read_private_key (data, n_data, &sexp); g_assert ("couldn't decode private key" && ret == GKM_DATA_SUCCESS); g_assert ("parsed key is empty" && sexp != NULL); /* Now compare them */ g_assert ("key parsed differently" && compare_keys (key, sexp)); egg_secure_free (data); }
CK_RV gkm_aes_mechanism_wrap (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *wrapper, GkmObject *wrapped, CK_BYTE_PTR output, CK_ULONG_PTR n_output) { gcry_cipher_hd_t cih; gcry_error_t gcry; GkmAesKey *key; gpointer value, padded; gsize n_value, n_padded; gsize block, pos; gboolean ret; CK_RV rv; 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 (wrapped), CKR_GENERAL_ERROR); g_return_val_if_fail (n_output, 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); /* They just want the length */ if (!output) { rv = retrieve_length (session, wrapped, &n_value); if (rv != CKR_OK) return rv; if (!egg_padding_pkcs7_pad (NULL, block, NULL, n_value, NULL, &n_padded)) return CKR_KEY_SIZE_RANGE; *n_output = n_padded; return CKR_OK; } 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; } rv = retrieve_value (session, wrapped, &value, &n_value); if (rv != CKR_OK) { gcry_cipher_close (cih); return rv; } ret = egg_padding_pkcs7_pad (egg_secure_realloc, block, value, n_value, &padded, &n_padded); egg_secure_free (value); if (ret == FALSE) { gcry_cipher_close (cih); return CKR_KEY_SIZE_RANGE; } /* In place encryption */ for (pos = 0; pos < n_padded; pos += block) { gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, block, NULL, 0); g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR); } gcry_cipher_close (cih); rv = gkm_util_return_data (output, n_output, padded, n_padded); egg_secure_free (padded); return rv; }
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; }
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 gcry_cipher_hd_t prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password, gsize n_password, gsize *n_block) { GNode *asn1_params = NULL; gcry_cipher_hd_t cih; guchar *salt; gsize n_salt; gcry_error_t gcry; guchar *key, *iv; gsize n_key; int iterations; init_quarks (); /* Make sure the encryption algorithm works */ g_return_val_if_fail (gcry_cipher_algo_info (gcry_cipher_map_name (g_quark_to_string (OID_PKCS12_PBE_3DES_SHA1)), GCRYCTL_TEST_ALGO, NULL, 0) == 0, NULL); /* The encryption algorithm */ if(!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL), OID_PKCS12_PBE_3DES_SHA1)) g_return_val_if_reached (NULL); /* Randomize some input for the password based secret */ iterations = g_random_int_range (1000, 4096); n_salt = 8; salt = g_malloc (n_salt); gcry_create_nonce (salt, n_salt); /* Allocate space for the key and iv */ n_key = gcry_cipher_get_algo_keylen (GCRY_CIPHER_3DES); *n_block = gcry_cipher_get_algo_blklen (GCRY_MD_SHA1); g_return_val_if_fail (n_key && *n_block, NULL); if (!egg_symkey_generate_pkcs12 (GCRY_CIPHER_3DES, GCRY_MD_SHA1, password, n_password, salt, sizeof (salt), iterations, &key, &iv)) g_return_val_if_reached (NULL); /* Now write out the parameters */ asn1_params = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PbeParams"); g_return_val_if_fail (asn1_params, NULL); egg_asn1x_set_string_as_raw (egg_asn1x_node (asn1_params, "salt", NULL), salt, n_salt, g_free); egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations); egg_asn1x_set_any_from (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), asn1_params); /* Now make a cipher that matches what we wrote out */ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0); g_return_val_if_fail (gcry == 0, NULL); g_return_val_if_fail (cih, NULL); gcry_cipher_setiv (cih, iv, *n_block); gcry_cipher_setkey (cih, key, n_key); g_free (iv); egg_secure_free (key); egg_asn1x_destroy (asn1_params); return cih; }
/** * main: * @argc: * @argv[]: Sent to gtk_init * * Prompt for GnuPG and SSH. Communicates using stdin/stdout. Communication data * is in ini-file structures * * Returns: 0 */ int main (int argc, char *argv[]) { GError *err = NULL; gchar *data; gboolean ret; gsize length; /* Exit on HUP signal */ signal(SIGINT, hup_handler); prepare_logging (); egg_libgcrypt_initialize (); input_data = g_key_file_new (); output_data = g_key_file_new (); gtk_init (&argc, &argv); #ifdef HAVE_LOCALE_H /* internationalisation */ setlocale (LC_ALL, ""); #endif #ifdef HAVE_GETTEXT bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); textdomain (GETTEXT_PACKAGE); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif data = read_all_input (); g_assert (data); if (!data[0]) fatal ("no auth dialog instructions", NULL); ret = g_key_file_load_from_data (input_data, data, strlen (data), G_KEY_FILE_NONE, &err); g_free (data); if (!ret) fatal ("couldn't parse auth dialog instructions", egg_error_message (err)); run_dialog (); /* Cleanup after any key */ if (the_key) { egg_secure_clear (the_key, n_the_key); egg_secure_free (the_key); the_key = NULL; n_the_key = 0; } g_key_file_free (input_data); data = g_key_file_to_data (output_data, &length, &err); g_key_file_free (output_data); if (!data) fatal ("couldn't format auth dialog response: %s", egg_error_message (err)); write_all_output (data, length); g_free (data); return 0; }
GkmDataResult gkm_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const gchar *password, gsize n_password, gcry_sexp_t *s_key) { GNode *asn = NULL; gcry_cipher_hd_t cih = NULL; gcry_error_t gcry; GkmDataResult ret, r; GQuark scheme; guchar *crypted = NULL; const guchar *params; gsize n_crypted, n_params; gint l; init_quarks (); ret = GKM_DATA_UNRECOGNIZED; asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data); if (!asn) goto done; ret = GKM_DATA_FAILURE; /* Figure out the type of encryption */ scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL)); if (!scheme) goto done; params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params); if (!params) goto done; /* * Parse the encryption stuff into a cipher. */ r = egg_symkey_read_cipher (scheme, password, n_password, params, n_params, &cih); if (r == GKM_DATA_UNRECOGNIZED) { ret = GKM_DATA_FAILURE; goto done; } else if (r != GKM_DATA_SUCCESS) { ret = r; goto done; } crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL), egg_secure_realloc, &n_crypted); if (!crypted) goto done; gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0); gcry_cipher_close (cih); cih = NULL; if (gcry != 0) { g_warning ("couldn't decrypt pkcs8 data: %s", gcry_strerror (gcry)); goto done; } /* Unpad the DER data */ l = egg_asn1x_element_length (crypted, n_crypted); if (l <= 0 || l > n_crypted) { ret = GKM_DATA_LOCKED; goto done; } n_crypted = l; /* Try to parse the resulting key */ ret = gkm_data_der_read_private_pkcs8_plain (crypted, n_crypted, s_key); egg_secure_free (crypted); crypted = NULL; /* If unrecognized we assume bad password */ if (ret == GKM_DATA_UNRECOGNIZED) ret = GKM_DATA_LOCKED; done: if (cih) gcry_cipher_close (cih); egg_asn1x_destroy (asn); egg_secure_free (crypted); return ret; }
static gcry_cipher_hd_t prepare_and_encode_pkcs8_cipher (GNode *asn, const gchar *password, gsize n_password, gsize *n_block) { GNode *asn1_params = NULL; gcry_cipher_hd_t cih; guchar salt[8]; gcry_error_t gcry; guchar *key, *iv, *portion; gsize n_key, n_portion; int iterations; init_quarks (); /* Make sure the encryption algorithm works */ g_return_val_if_fail (gcry_cipher_algo_info (OID_PKCS12_PBE_3DES_SHA1, GCRYCTL_TEST_ALGO, NULL, 0), NULL); /* The encryption algorithm */ if(!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL), OID_PKCS12_PBE_3DES_SHA1)) g_return_val_if_reached (NULL); /* Randomize some input for the password based secret */ iterations = 1000 + (int) (1000.0 * rand () / (RAND_MAX + 1.0)); gcry_create_nonce (salt, sizeof (salt)); /* Allocate space for the key and iv */ n_key = gcry_cipher_get_algo_keylen (GCRY_CIPHER_3DES); *n_block = gcry_cipher_get_algo_blklen (GCRY_MD_SHA1); g_return_val_if_fail (n_key && *n_block, NULL); if (!egg_symkey_generate_pkcs12 (GCRY_CIPHER_3DES, GCRY_MD_SHA1, password, n_password, salt, sizeof (salt), iterations, &key, &iv)) g_return_val_if_reached (NULL); /* Now write out the parameters */ asn1_params = egg_asn1x_create (pkix_asn1_tab, "pkcs-12-PbeParams"); g_return_val_if_fail (asn1_params, NULL); if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn1_params, "salt", NULL), salt, sizeof (salt), NULL)) g_return_val_if_reached (NULL); if (!egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn1_params, "iterations", NULL), iterations)) g_return_val_if_reached (NULL); portion = egg_asn1x_encode (asn1_params, NULL, &n_portion); if (portion == NULL) { g_warning ("couldn't encode pkcs8 params key: %s", egg_asn1x_message (asn1_params)); g_return_val_if_reached (NULL); } if (!egg_asn1x_set_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), portion, n_portion, g_free)) g_return_val_if_reached (NULL); /* Now make a cipher that matches what we wrote out */ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0); g_return_val_if_fail (gcry == 0, NULL); g_return_val_if_fail (cih, NULL); gcry_cipher_setiv (cih, iv, *n_block); gcry_cipher_setkey (cih, key, n_key); g_free (iv); egg_secure_free (key); egg_asn1x_destroy (asn1_params); return cih; }
static gboolean gcr_secret_exchange_default_encrypt_transport_data (GcrSecretExchange *exchange, GckAllocator allocator, const guchar *plain_text, gsize n_plain_text, guchar **iv, gsize *n_iv, guchar **cipher_text, gsize *n_cipher_text) { GcrSecretExchangeDefault *data = exchange->pv->default_exchange; gcry_cipher_hd_t cih; gcry_error_t gcry; guchar *padded; gsize n_result; guchar *result; gsize pos; g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (data->key != NULL, FALSE); gcry = gcry_cipher_open (&cih, EXCHANGE_1_CIPHER_ALGO, EXCHANGE_1_CIPHER_MODE, 0); if (gcry != 0) { g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gcry)); g_free (iv); return FALSE; } *iv = (allocator) (NULL, EXCHANGE_1_IV_LENGTH); g_return_val_if_fail (*iv != NULL, FALSE); gcry_create_nonce (*iv, EXCHANGE_1_IV_LENGTH); *n_iv = EXCHANGE_1_IV_LENGTH; /* 16 = 128 bits */ gcry = gcry_cipher_setkey (cih, data->key, EXCHANGE_1_KEY_LENGTH); g_return_val_if_fail (gcry == 0, FALSE); /* 16 = 128 bits */ gcry = gcry_cipher_setiv (cih, *iv, EXCHANGE_1_IV_LENGTH); g_return_val_if_fail (gcry == 0, FALSE); /* Pad the text properly */ if (!egg_padding_pkcs7_pad (egg_secure_realloc, 16, plain_text, n_plain_text, (gpointer*)&padded, &n_result)) g_return_val_if_reached (FALSE); result = (allocator) (NULL, n_result); g_return_val_if_fail (result != NULL, FALSE); for (pos = 0; pos < n_result; pos += 16) { gcry = gcry_cipher_encrypt (cih, result + pos, 16, padded + pos, 16); g_return_val_if_fail (gcry == 0, FALSE); } gcry_cipher_close (cih); egg_secure_clear (padded, n_result); egg_secure_free (padded); *cipher_text = result; *n_cipher_text = n_result; 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); }