/** * Initialize the state descriptor for the specified hash algorithm. * * An internal routine to allocate the hash-specific state in \a hdesc for * use with cfs_crypto_hash_digest() to compute the hash of a single message, * though possibly in multiple chunks. The descriptor internal state should * be freed with cfs_crypto_hash_final(). * * \param[in] hash_alg hash algorithm id (CFS_HASH_ALG_*) * \param[out] type pointer to the hash description in hash_types[] array * \param[in,out] req ahash request to be initialized * \param[in] key initial hash value/state, NULL to use default value * \param[in] key_len length of \a key * * \retval 0 on success * \retval negative errno on failure */ static int cfs_crypto_hash_alloc(enum cfs_crypto_hash_alg hash_alg, const struct cfs_crypto_hash_type **type, struct ahash_request **req, unsigned char *key, unsigned int key_len) { struct crypto_ahash *tfm; int err = 0; *type = cfs_crypto_hash_type(hash_alg); if (*type == NULL) { CWARN("Unsupported hash algorithm id = %d, max id is %d\n", hash_alg, CFS_HASH_ALG_MAX); return -EINVAL; } tfm = crypto_alloc_ahash((*type)->cht_name, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { CDEBUG(D_INFO, "Failed to alloc crypto hash %s\n", (*type)->cht_name); return PTR_ERR(tfm); } *req = ahash_request_alloc(tfm, GFP_KERNEL); if (!*req) { CDEBUG(D_INFO, "Failed to alloc ahash_request for %s\n", (*type)->cht_name); crypto_free_ahash(tfm); return -ENOMEM; } ahash_request_set_callback(*req, 0, NULL, NULL); if (key) err = crypto_ahash_setkey(tfm, key, key_len); else if ((*type)->cht_key != 0) err = crypto_ahash_setkey(tfm, (unsigned char *)&((*type)->cht_key), (*type)->cht_size); if (err != 0) { ahash_request_free(*req); crypto_free_ahash(tfm); return err; } CDEBUG(D_INFO, "Using crypto hash: %s (%s) speed %d MB/s\n", crypto_ahash_alg_name(tfm), crypto_ahash_driver_name(tfm), cfs_crypto_hash_speeds[hash_alg]); err = crypto_ahash_init(*req); if (err) { ahash_request_free(*req); crypto_free_ahash(tfm); } return err; }
/** * Initialize the state descriptor for the specified hash algorithm. * * An internal routine to allocate the hash-specific state in \a hdesc for * use with cfs_crypto_hash_digest() to compute the hash of a single message, * though possibly in multiple chunks. The descriptor internal state should * be freed with cfs_crypto_hash_final(). * * \param[in] hash_alg hash algorithm id (CFS_HASH_ALG_*) * \param[out] type pointer to the hash description in hash_types[] array * \param[in,out] req ahash request to be initialized * \param[in] key initial hash value/state, NULL to use default value * \param[in] key_len length of \a key * * \retval 0 on success * \retval negative errno on failure */ static int cfs_crypto_hash_alloc(enum cfs_crypto_hash_alg hash_alg, const struct cfs_crypto_hash_type **type, struct ahash_request **req, unsigned char *key, unsigned int key_len) { struct crypto_ahash *tfm; int err = 0; *type = cfs_crypto_hash_type(hash_alg); if (!*type) { CWARN("Unsupported hash algorithm id = %d, max id is %d\n", hash_alg, CFS_HASH_ALG_MAX); return -EINVAL; } /* Keys are only supported for the hmac version */ if (key && key_len > 0) { char *algo_name; algo_name = kasprintf(GFP_KERNEL, "hmac(%s)", (*type)->cht_name); if (!algo_name) return -ENOMEM; tfm = crypto_alloc_ahash(algo_name, 0, CRYPTO_ALG_ASYNC); kfree(algo_name); } else { tfm = crypto_alloc_ahash((*type)->cht_name, 0, CRYPTO_ALG_ASYNC); } if (IS_ERR(tfm)) { CDEBUG(D_INFO, "Failed to alloc crypto hash %s\n", (*type)->cht_name); return PTR_ERR(tfm); } *req = ahash_request_alloc(tfm, GFP_KERNEL); if (!*req) { CDEBUG(D_INFO, "Failed to alloc ahash_request for %s\n", (*type)->cht_name); GOTO(out_free_tfm, err = -ENOMEM); } ahash_request_set_callback(*req, 0, NULL, NULL); if (key) err = crypto_ahash_setkey(tfm, key, key_len); else if ((*type)->cht_key != 0) err = crypto_ahash_setkey(tfm, (unsigned char *)&((*type)->cht_key), (*type)->cht_size); if (err) GOTO(out_free_req, err); CDEBUG(D_INFO, "Using crypto hash: %s (%s) speed %d MB/s\n", crypto_ahash_alg_name(tfm), crypto_ahash_driver_name(tfm), cfs_crypto_hash_speeds[hash_alg]); err = crypto_ahash_init(*req); if (err) { out_free_req: ahash_request_free(*req); out_free_tfm: crypto_free_ahash(tfm); } return err; }