summaryrefslogtreecommitdiff
path: root/crypto/adiantum.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/adiantum.c')
-rw-r--r--crypto/adiantum.c442
1 files changed, 243 insertions, 199 deletions
diff --git a/crypto/adiantum.c b/crypto/adiantum.c
index a6bca877c3c7..5ddf585abb66 100644
--- a/crypto/adiantum.c
+++ b/crypto/adiantum.c
@@ -20,23 +20,14 @@
*
* - Stream cipher: XChaCha12 or XChaCha20
* - Block cipher: any with a 128-bit block size and 256-bit key
- *
- * This implementation doesn't currently allow other ε-∆U hash functions, i.e.
- * HPolyC is not supported. This is because Adiantum is ~20% faster than HPolyC
- * but still provably as secure, and also the ε-∆U hash function of HBSH is
- * formally defined to take two inputs (tweak, message) which makes it difficult
- * to wrap with the crypto_shash API. Rather, some details need to be handled
- * here. Nevertheless, if needed in the future, support for other ε-∆U hash
- * functions could be added here.
*/
#include <crypto/b128ops.h>
#include <crypto/chacha.h>
#include <crypto/internal/cipher.h>
-#include <crypto/internal/hash.h>
#include <crypto/internal/poly1305.h>
#include <crypto/internal/skcipher.h>
-#include <crypto/nhpoly1305.h>
+#include <crypto/nh.h>
#include <crypto/scatterwalk.h>
#include <linux/module.h>
@@ -50,7 +41,7 @@
#define BLOCKCIPHER_KEY_SIZE 32
/* Size of the hash key (K_H) in bytes */
-#define HASH_KEY_SIZE (POLY1305_BLOCK_SIZE + NHPOLY1305_KEY_SIZE)
+#define HASH_KEY_SIZE (2 * POLY1305_BLOCK_SIZE + NH_KEY_BYTES)
/*
* The specification allows variable-length tweaks, but Linux's crypto API
@@ -64,43 +55,40 @@
struct adiantum_instance_ctx {
struct crypto_skcipher_spawn streamcipher_spawn;
struct crypto_cipher_spawn blockcipher_spawn;
- struct crypto_shash_spawn hash_spawn;
};
struct adiantum_tfm_ctx {
struct crypto_skcipher *streamcipher;
struct crypto_cipher *blockcipher;
- struct crypto_shash *hash;
struct poly1305_core_key header_hash_key;
+ struct poly1305_core_key msg_poly_key;
+ u32 nh_key[NH_KEY_WORDS];
};
-struct adiantum_request_ctx {
+struct nhpoly1305_ctx {
+ /* Running total of polynomial evaluation */
+ struct poly1305_state poly_state;
+
+ /* Partial block buffer */
+ u8 buffer[NH_MESSAGE_UNIT];
+ unsigned int buflen;
/*
- * Buffer for right-hand part of data, i.e.
- *
- * P_L => P_M => C_M => C_R when encrypting, or
- * C_R => C_M => P_M => P_L when decrypting.
- *
- * Also used to build the IV for the stream cipher.
+ * Number of bytes remaining until the current NH message reaches
+ * NH_MESSAGE_BYTES. When nonzero, 'nh_hash' holds the partial NH hash.
*/
- union {
- u8 bytes[XCHACHA_IV_SIZE];
- __le32 words[XCHACHA_IV_SIZE / sizeof(__le32)];
- le128 bignum; /* interpret as element of Z/(2^{128}Z) */
- } rbuf;
+ unsigned int nh_remaining;
- bool enc; /* true if encrypting, false if decrypting */
+ __le64 nh_hash[NH_NUM_PASSES];
+};
+struct adiantum_request_ctx {
/*
- * The result of the Poly1305 ε-∆U hash function applied to
- * (bulk length, tweak)
+ * skcipher sub-request size is unknown at compile-time, so it needs to
+ * go after the members with known sizes.
*/
- le128 header_hash;
-
- /* Sub-requests, must be last */
union {
- struct shash_desc hash_desc;
+ struct nhpoly1305_ctx hash_ctx;
struct skcipher_request streamcipher_req;
} u;
};
@@ -170,12 +158,11 @@ static int adiantum_setkey(struct crypto_skcipher *tfm, const u8 *key,
/* Set the hash key (K_H) */
poly1305_core_setkey(&tctx->header_hash_key, keyp);
keyp += POLY1305_BLOCK_SIZE;
-
- crypto_shash_clear_flags(tctx->hash, CRYPTO_TFM_REQ_MASK);
- crypto_shash_set_flags(tctx->hash, crypto_skcipher_get_flags(tfm) &
- CRYPTO_TFM_REQ_MASK);
- err = crypto_shash_setkey(tctx->hash, keyp, NHPOLY1305_KEY_SIZE);
- keyp += NHPOLY1305_KEY_SIZE;
+ poly1305_core_setkey(&tctx->msg_poly_key, keyp);
+ keyp += POLY1305_BLOCK_SIZE;
+ for (int i = 0; i < NH_KEY_WORDS; i++)
+ tctx->nh_key[i] = get_unaligned_le32(&keyp[i * 4]);
+ keyp += NH_KEY_BYTES;
WARN_ON(keyp != &data->derived_keys[ARRAY_SIZE(data->derived_keys)]);
out:
kfree_sensitive(data);
@@ -206,7 +193,7 @@ static inline void le128_sub(le128 *r, const le128 *v1, const le128 *v2)
/*
* Apply the Poly1305 ε-∆U hash function to (bulk length, tweak) and save the
- * result to rctx->header_hash. This is the calculation
+ * result to @out. This is the calculation
*
* H_T ← Poly1305_{K_T}(bin_{128}(|L|) || T)
*
@@ -216,11 +203,10 @@ static inline void le128_sub(le128 *r, const le128 *v1, const le128 *v2)
* inputs only) taken over the left-hand part (the "bulk") of the message, to
* give the overall Adiantum hash of the (tweak, left-hand part) pair.
*/
-static void adiantum_hash_header(struct skcipher_request *req)
+static void adiantum_hash_header(struct skcipher_request *req, le128 *out)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
- struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
struct {
__le64 message_bits;
@@ -240,99 +226,143 @@ static void adiantum_hash_header(struct skcipher_request *req)
poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv,
TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1);
- poly1305_core_emit(&state, NULL, &rctx->header_hash);
+ poly1305_core_emit(&state, NULL, out);
}
-/* Hash the left-hand part (the "bulk") of the message using NHPoly1305 */
-static int adiantum_hash_message(struct skcipher_request *req,
- struct scatterlist *sgl, unsigned int nents,
- le128 *digest)
+/* Pass the next NH hash value through Poly1305 */
+static void process_nh_hash_value(struct nhpoly1305_ctx *ctx,
+ const struct adiantum_tfm_ctx *key)
{
- struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
- const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
- struct shash_desc *hash_desc = &rctx->u.hash_desc;
- struct sg_mapping_iter miter;
- unsigned int i, n;
- int err;
+ static_assert(NH_HASH_BYTES % POLY1305_BLOCK_SIZE == 0);
- err = crypto_shash_init(hash_desc);
- if (err)
- return err;
+ poly1305_core_blocks(&ctx->poly_state, &key->msg_poly_key, ctx->nh_hash,
+ NH_HASH_BYTES / POLY1305_BLOCK_SIZE, 1);
+}
- sg_miter_start(&miter, sgl, nents, SG_MITER_FROM_SG | SG_MITER_ATOMIC);
- for (i = 0; i < bulk_len; i += n) {
- sg_miter_next(&miter);
- n = min_t(unsigned int, miter.length, bulk_len - i);
- err = crypto_shash_update(hash_desc, miter.addr, n);
- if (err)
- break;
- }
- sg_miter_stop(&miter);
- if (err)
- return err;
+/*
+ * Feed the next portion of the message data, as a whole number of 16-byte
+ * "NH message units", through NH and Poly1305. Each NH hash is taken over
+ * 1024 bytes, except possibly the final one which is taken over a multiple of
+ * 16 bytes up to 1024. Also, in the case where data is passed in misaligned
+ * chunks, we combine partial hashes; the end result is the same either way.
+ */
+static void nhpoly1305_units(struct nhpoly1305_ctx *ctx,
+ const struct adiantum_tfm_ctx *key,
+ const u8 *data, size_t len)
+{
+ do {
+ unsigned int bytes;
+
+ if (ctx->nh_remaining == 0) {
+ /* Starting a new NH message */
+ bytes = min(len, NH_MESSAGE_BYTES);
+ nh(key->nh_key, data, bytes, ctx->nh_hash);
+ ctx->nh_remaining = NH_MESSAGE_BYTES - bytes;
+ } else {
+ /* Continuing a previous NH message */
+ __le64 tmp_hash[NH_NUM_PASSES];
+ unsigned int pos;
+
+ pos = NH_MESSAGE_BYTES - ctx->nh_remaining;
+ bytes = min(len, ctx->nh_remaining);
+ nh(&key->nh_key[pos / 4], data, bytes, tmp_hash);
+ for (int i = 0; i < NH_NUM_PASSES; i++)
+ le64_add_cpu(&ctx->nh_hash[i],
+ le64_to_cpu(tmp_hash[i]));
+ ctx->nh_remaining -= bytes;
+ }
+ if (ctx->nh_remaining == 0)
+ process_nh_hash_value(ctx, key);
+ data += bytes;
+ len -= bytes;
+ } while (len);
+}
- return crypto_shash_final(hash_desc, (u8 *)digest);
+static void nhpoly1305_init(struct nhpoly1305_ctx *ctx)
+{
+ poly1305_core_init(&ctx->poly_state);
+ ctx->buflen = 0;
+ ctx->nh_remaining = 0;
}
-/* Continue Adiantum encryption/decryption after the stream cipher step */
-static int adiantum_finish(struct skcipher_request *req)
+static void nhpoly1305_update(struct nhpoly1305_ctx *ctx,
+ const struct adiantum_tfm_ctx *key,
+ const u8 *data, size_t len)
{
- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
- const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
- struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
- const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
- struct scatterlist *dst = req->dst;
- const unsigned int dst_nents = sg_nents(dst);
- le128 digest;
- int err;
+ unsigned int bytes;
+
+ if (ctx->buflen) {
+ bytes = min(len, (int)NH_MESSAGE_UNIT - ctx->buflen);
+ memcpy(&ctx->buffer[ctx->buflen], data, bytes);
+ ctx->buflen += bytes;
+ if (ctx->buflen < NH_MESSAGE_UNIT)
+ return;
+ nhpoly1305_units(ctx, key, ctx->buffer, NH_MESSAGE_UNIT);
+ ctx->buflen = 0;
+ data += bytes;
+ len -= bytes;
+ }
- /* If decrypting, decrypt C_M with the block cipher to get P_M */
- if (!rctx->enc)
- crypto_cipher_decrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
- rctx->rbuf.bytes);
+ if (len >= NH_MESSAGE_UNIT) {
+ bytes = round_down(len, NH_MESSAGE_UNIT);
+ nhpoly1305_units(ctx, key, data, bytes);
+ data += bytes;
+ len -= bytes;
+ }
- /*
- * Second hash step
- * enc: C_R = C_M - H_{K_H}(T, C_L)
- * dec: P_R = P_M - H_{K_H}(T, P_L)
- */
- rctx->u.hash_desc.tfm = tctx->hash;
- le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
- if (dst_nents == 1 && dst->offset + req->cryptlen <= PAGE_SIZE) {
- /* Fast path for single-page destination */
- struct page *page = sg_page(dst);
- void *virt = kmap_local_page(page) + dst->offset;
+ if (len) {
+ memcpy(ctx->buffer, data, len);
+ ctx->buflen = len;
+ }
+}
- err = crypto_shash_digest(&rctx->u.hash_desc, virt, bulk_len,
- (u8 *)&digest);
- if (err) {
- kunmap_local(virt);
- return err;
- }
- le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
- memcpy(virt + bulk_len, &rctx->rbuf.bignum, sizeof(le128));
- flush_dcache_page(page);
- kunmap_local(virt);
- } else {
- /* Slow path that works for any destination scatterlist */
- err = adiantum_hash_message(req, dst, dst_nents, &digest);
- if (err)
- return err;
- le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
- scatterwalk_map_and_copy(&rctx->rbuf.bignum, dst,
- bulk_len, sizeof(le128), 1);
+static void nhpoly1305_final(struct nhpoly1305_ctx *ctx,
+ const struct adiantum_tfm_ctx *key, le128 *out)
+{
+ if (ctx->buflen) {
+ memset(&ctx->buffer[ctx->buflen], 0,
+ NH_MESSAGE_UNIT - ctx->buflen);
+ nhpoly1305_units(ctx, key, ctx->buffer, NH_MESSAGE_UNIT);
}
- return 0;
+
+ if (ctx->nh_remaining)
+ process_nh_hash_value(ctx, key);
+
+ poly1305_core_emit(&ctx->poly_state, NULL, out);
}
-static void adiantum_streamcipher_done(void *data, int err)
+/*
+ * Hash the left-hand part (the "bulk") of the message as follows:
+ *
+ * H_L ← Poly1305_{K_L}(NH_{K_N}(pad_{128}(L)))
+ *
+ * See section 6.4 of the Adiantum paper. This is an ε-almost-∆-universal
+ * (ε-∆U) hash function for equal-length inputs over Z/(2^{128}Z), where the "∆"
+ * operation is addition. It hashes 1024-byte chunks of the input with the NH
+ * hash function, reducing the input length by 32x. The resulting NH hashes are
+ * evaluated as a polynomial in GF(2^{130}-5), like in the Poly1305 MAC. Note
+ * that the polynomial evaluation by itself would suffice to achieve the ε-∆U
+ * property; NH is used for performance since it's much faster than Poly1305.
+ */
+static void adiantum_hash_message(struct skcipher_request *req,
+ struct scatterlist *sgl, le128 *out)
{
- struct skcipher_request *req = data;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
+ struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
+ unsigned int len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
+ struct scatter_walk walk;
- if (!err)
- err = adiantum_finish(req);
+ nhpoly1305_init(&rctx->u.hash_ctx);
+ scatterwalk_start(&walk, sgl);
+ while (len) {
+ unsigned int n = scatterwalk_next(&walk, len);
- skcipher_request_complete(req, err);
+ nhpoly1305_update(&rctx->u.hash_ctx, tctx, walk.addr, n);
+ scatterwalk_done_src(&walk, n);
+ len -= n;
+ }
+ nhpoly1305_final(&rctx->u.hash_ctx, tctx, out);
}
static int adiantum_crypt(struct skcipher_request *req, bool enc)
@@ -341,55 +371,63 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
const struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
struct adiantum_request_ctx *rctx = skcipher_request_ctx(req);
const unsigned int bulk_len = req->cryptlen - BLOCKCIPHER_BLOCK_SIZE;
- struct scatterlist *src = req->src;
- const unsigned int src_nents = sg_nents(src);
+ struct scatterlist *src = req->src, *dst = req->dst;
+ /*
+ * Buffer for right-hand part of data, i.e.
+ *
+ * P_L => P_M => C_M => C_R when encrypting, or
+ * C_R => C_M => P_M => P_L when decrypting.
+ *
+ * Also used to build the IV for the stream cipher.
+ */
+ union {
+ u8 bytes[XCHACHA_IV_SIZE];
+ __le32 words[XCHACHA_IV_SIZE / sizeof(__le32)];
+ le128 bignum; /* interpret as element of Z/(2^{128}Z) */
+ } rbuf;
+ le128 header_hash, msg_hash;
unsigned int stream_len;
- le128 digest;
int err;
if (req->cryptlen < BLOCKCIPHER_BLOCK_SIZE)
return -EINVAL;
- rctx->enc = enc;
-
/*
* First hash step
* enc: P_M = P_R + H_{K_H}(T, P_L)
* dec: C_M = C_R + H_{K_H}(T, C_L)
*/
- adiantum_hash_header(req);
- rctx->u.hash_desc.tfm = tctx->hash;
- if (src_nents == 1 && src->offset + req->cryptlen <= PAGE_SIZE) {
+ adiantum_hash_header(req, &header_hash);
+ if (src->length >= req->cryptlen &&
+ src->offset + req->cryptlen <= PAGE_SIZE) {
/* Fast path for single-page source */
void *virt = kmap_local_page(sg_page(src)) + src->offset;
- err = crypto_shash_digest(&rctx->u.hash_desc, virt, bulk_len,
- (u8 *)&digest);
- memcpy(&rctx->rbuf.bignum, virt + bulk_len, sizeof(le128));
+ nhpoly1305_init(&rctx->u.hash_ctx);
+ nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
+ nhpoly1305_final(&rctx->u.hash_ctx, tctx, &msg_hash);
+ memcpy(&rbuf.bignum, virt + bulk_len, sizeof(le128));
kunmap_local(virt);
} else {
/* Slow path that works for any source scatterlist */
- err = adiantum_hash_message(req, src, src_nents, &digest);
- scatterwalk_map_and_copy(&rctx->rbuf.bignum, src,
- bulk_len, sizeof(le128), 0);
+ adiantum_hash_message(req, src, &msg_hash);
+ memcpy_from_sglist(&rbuf.bignum, src, bulk_len, sizeof(le128));
}
- if (err)
- return err;
- le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &rctx->header_hash);
- le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest);
+ le128_add(&rbuf.bignum, &rbuf.bignum, &header_hash);
+ le128_add(&rbuf.bignum, &rbuf.bignum, &msg_hash);
/* If encrypting, encrypt P_M with the block cipher to get C_M */
if (enc)
- crypto_cipher_encrypt_one(tctx->blockcipher, rctx->rbuf.bytes,
- rctx->rbuf.bytes);
+ crypto_cipher_encrypt_one(tctx->blockcipher, rbuf.bytes,
+ rbuf.bytes);
/* Initialize the rest of the XChaCha IV (first part is C_M) */
BUILD_BUG_ON(BLOCKCIPHER_BLOCK_SIZE != 16);
BUILD_BUG_ON(XCHACHA_IV_SIZE != 32); /* nonce || stream position */
- rctx->rbuf.words[4] = cpu_to_le32(1);
- rctx->rbuf.words[5] = 0;
- rctx->rbuf.words[6] = 0;
- rctx->rbuf.words[7] = 0;
+ rbuf.words[4] = cpu_to_le32(1);
+ rbuf.words[5] = 0;
+ rbuf.words[6] = 0;
+ rbuf.words[7] = 0;
/*
* XChaCha needs to be done on all the data except the last 16 bytes;
@@ -406,12 +444,44 @@ static int adiantum_crypt(struct skcipher_request *req, bool enc)
skcipher_request_set_tfm(&rctx->u.streamcipher_req, tctx->streamcipher);
skcipher_request_set_crypt(&rctx->u.streamcipher_req, req->src,
- req->dst, stream_len, &rctx->rbuf);
+ req->dst, stream_len, &rbuf);
skcipher_request_set_callback(&rctx->u.streamcipher_req,
- req->base.flags,
- adiantum_streamcipher_done, req);
- return crypto_skcipher_encrypt(&rctx->u.streamcipher_req) ?:
- adiantum_finish(req);
+ req->base.flags, NULL, NULL);
+ err = crypto_skcipher_encrypt(&rctx->u.streamcipher_req);
+ if (err)
+ return err;
+
+ /* If decrypting, decrypt C_M with the block cipher to get P_M */
+ if (!enc)
+ crypto_cipher_decrypt_one(tctx->blockcipher, rbuf.bytes,
+ rbuf.bytes);
+
+ /*
+ * Second hash step
+ * enc: C_R = C_M - H_{K_H}(T, C_L)
+ * dec: P_R = P_M - H_{K_H}(T, P_L)
+ */
+ le128_sub(&rbuf.bignum, &rbuf.bignum, &header_hash);
+ if (dst->length >= req->cryptlen &&
+ dst->offset + req->cryptlen <= PAGE_SIZE) {
+ /* Fast path for single-page destination */
+ struct page *page = sg_page(dst);
+ void *virt = kmap_local_page(page) + dst->offset;
+
+ nhpoly1305_init(&rctx->u.hash_ctx);
+ nhpoly1305_update(&rctx->u.hash_ctx, tctx, virt, bulk_len);
+ nhpoly1305_final(&rctx->u.hash_ctx, tctx, &msg_hash);
+ le128_sub(&rbuf.bignum, &rbuf.bignum, &msg_hash);
+ memcpy(virt + bulk_len, &rbuf.bignum, sizeof(le128));
+ flush_dcache_page(page);
+ kunmap_local(virt);
+ } else {
+ /* Slow path that works for any destination scatterlist */
+ adiantum_hash_message(req, dst, &msg_hash);
+ le128_sub(&rbuf.bignum, &rbuf.bignum, &msg_hash);
+ memcpy_to_sglist(dst, bulk_len, &rbuf.bignum, sizeof(le128));
+ }
+ return 0;
}
static int adiantum_encrypt(struct skcipher_request *req)
@@ -431,8 +501,6 @@ static int adiantum_init_tfm(struct crypto_skcipher *tfm)
struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm);
struct crypto_skcipher *streamcipher;
struct crypto_cipher *blockcipher;
- struct crypto_shash *hash;
- unsigned int subreq_size;
int err;
streamcipher = crypto_spawn_skcipher(&ictx->streamcipher_spawn);
@@ -445,32 +513,18 @@ static int adiantum_init_tfm(struct crypto_skcipher *tfm)
goto err_free_streamcipher;
}
- hash = crypto_spawn_shash(&ictx->hash_spawn);
- if (IS_ERR(hash)) {
- err = PTR_ERR(hash);
- goto err_free_blockcipher;
- }
-
tctx->streamcipher = streamcipher;
tctx->blockcipher = blockcipher;
- tctx->hash = hash;
BUILD_BUG_ON(offsetofend(struct adiantum_request_ctx, u) !=
sizeof(struct adiantum_request_ctx));
- subreq_size = max(sizeof_field(struct adiantum_request_ctx,
- u.hash_desc) +
- crypto_shash_descsize(hash),
- sizeof_field(struct adiantum_request_ctx,
- u.streamcipher_req) +
- crypto_skcipher_reqsize(streamcipher));
-
- crypto_skcipher_set_reqsize(tfm,
- offsetof(struct adiantum_request_ctx, u) +
- subreq_size);
+ crypto_skcipher_set_reqsize(
+ tfm, max(sizeof(struct adiantum_request_ctx),
+ offsetofend(struct adiantum_request_ctx,
+ u.streamcipher_req) +
+ crypto_skcipher_reqsize(streamcipher)));
return 0;
-err_free_blockcipher:
- crypto_free_cipher(blockcipher);
err_free_streamcipher:
crypto_free_skcipher(streamcipher);
return err;
@@ -482,7 +536,6 @@ static void adiantum_exit_tfm(struct crypto_skcipher *tfm)
crypto_free_skcipher(tctx->streamcipher);
crypto_free_cipher(tctx->blockcipher);
- crypto_free_shash(tctx->hash);
}
static void adiantum_free_instance(struct skcipher_instance *inst)
@@ -491,7 +544,6 @@ static void adiantum_free_instance(struct skcipher_instance *inst)
crypto_drop_skcipher(&ictx->streamcipher_spawn);
crypto_drop_cipher(&ictx->blockcipher_spawn);
- crypto_drop_shash(&ictx->hash_spawn);
kfree(inst);
}
@@ -499,9 +551,9 @@ static void adiantum_free_instance(struct skcipher_instance *inst)
* Check for a supported set of inner algorithms.
* See the comment at the beginning of this file.
*/
-static bool adiantum_supported_algorithms(struct skcipher_alg_common *streamcipher_alg,
- struct crypto_alg *blockcipher_alg,
- struct shash_alg *hash_alg)
+static bool
+adiantum_supported_algorithms(struct skcipher_alg_common *streamcipher_alg,
+ struct crypto_alg *blockcipher_alg)
{
if (strcmp(streamcipher_alg->base.cra_name, "xchacha12") != 0 &&
strcmp(streamcipher_alg->base.cra_name, "xchacha20") != 0)
@@ -513,21 +565,16 @@ static bool adiantum_supported_algorithms(struct skcipher_alg_common *streamciph
if (blockcipher_alg->cra_blocksize != BLOCKCIPHER_BLOCK_SIZE)
return false;
- if (strcmp(hash_alg->base.cra_name, "nhpoly1305") != 0)
- return false;
-
return true;
}
static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
{
u32 mask;
- const char *nhpoly1305_name;
struct skcipher_instance *inst;
struct adiantum_instance_ctx *ictx;
struct skcipher_alg_common *streamcipher_alg;
struct crypto_alg *blockcipher_alg;
- struct shash_alg *hash_alg;
int err;
err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER, &mask);
@@ -542,7 +589,8 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
/* Stream cipher, e.g. "xchacha12" */
err = crypto_grab_skcipher(&ictx->streamcipher_spawn,
skcipher_crypto_instance(inst),
- crypto_attr_alg_name(tb[1]), 0, mask);
+ crypto_attr_alg_name(tb[1]), 0,
+ mask | CRYPTO_ALG_ASYNC /* sync only */);
if (err)
goto err_free_inst;
streamcipher_alg = crypto_spawn_skcipher_alg_common(&ictx->streamcipher_spawn);
@@ -555,23 +603,21 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
goto err_free_inst;
blockcipher_alg = crypto_spawn_cipher_alg(&ictx->blockcipher_spawn);
- /* NHPoly1305 ε-∆U hash function */
- nhpoly1305_name = crypto_attr_alg_name(tb[3]);
- if (nhpoly1305_name == ERR_PTR(-ENOENT))
- nhpoly1305_name = "nhpoly1305";
- err = crypto_grab_shash(&ictx->hash_spawn,
- skcipher_crypto_instance(inst),
- nhpoly1305_name, 0, mask);
- if (err)
+ /*
+ * Originally there was an optional third parameter, for requesting a
+ * specific implementation of "nhpoly1305" for message hashing. This is
+ * no longer supported. The best implementation is just always used.
+ */
+ if (crypto_attr_alg_name(tb[3]) != ERR_PTR(-ENOENT)) {
+ err = -ENOENT;
goto err_free_inst;
- hash_alg = crypto_spawn_shash_alg(&ictx->hash_spawn);
+ }
/* Check the set of algorithms */
- if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg,
- hash_alg)) {
- pr_warn("Unsupported Adiantum instantiation: (%s,%s,%s)\n",
+ if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg)) {
+ pr_warn("Unsupported Adiantum instantiation: (%s,%s)\n",
streamcipher_alg->base.cra_name,
- blockcipher_alg->cra_name, hash_alg->base.cra_name);
+ blockcipher_alg->cra_name);
err = -EINVAL;
goto err_free_inst;
}
@@ -584,10 +630,8 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
blockcipher_alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
goto err_free_inst;
if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
- "adiantum(%s,%s,%s)",
- streamcipher_alg->base.cra_driver_name,
- blockcipher_alg->cra_driver_name,
- hash_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+ "adiantum(%s,%s)", streamcipher_alg->base.cra_driver_name,
+ blockcipher_alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
goto err_free_inst;
inst->alg.base.cra_blocksize = BLOCKCIPHER_BLOCK_SIZE;
@@ -596,12 +640,12 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
/*
* The block cipher is only invoked once per message, so for long
* messages (e.g. sectors for disk encryption) its performance doesn't
- * matter as much as that of the stream cipher and hash function. Thus,
- * weigh the block cipher's ->cra_priority less.
+ * matter as much as that of the stream cipher. Thus, weigh the block
+ * cipher's ->cra_priority less.
*/
inst->alg.base.cra_priority = (4 * streamcipher_alg->base.cra_priority +
- 2 * hash_alg->base.cra_priority +
- blockcipher_alg->cra_priority) / 7;
+ blockcipher_alg->cra_priority) /
+ 5;
inst->alg.setkey = adiantum_setkey;
inst->alg.encrypt = adiantum_encrypt;
@@ -622,7 +666,7 @@ err_free_inst:
return err;
}
-/* adiantum(streamcipher_name, blockcipher_name [, nhpoly1305_name]) */
+/* adiantum(streamcipher_name, blockcipher_name) */
static struct crypto_template adiantum_tmpl = {
.name = "adiantum",
.create = adiantum_create,