Message ID | 20181117012631.23528-15-ebiggers@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | crypto: Adiantum support | expand |
On Fri, 16 Nov 2018 at 17:29, Eric Biggers <ebiggers@kernel.org> wrote: > > From: Eric Biggers <ebiggers@google.com> > > Add support for the Adiantum encryption mode. Adiantum was designed by > Paul Crowley and is specified by our paper: > > Adiantum: length-preserving encryption for entry-level processors > (https://eprint.iacr.org/2018/720.pdf) > > See our paper for full details; this patch only provides an overview. > > Adiantum is a tweakable, length-preserving encryption mode designed for > fast and secure disk encryption, especially on CPUs without dedicated > crypto instructions. Adiantum encrypts each sector using the XChaCha12 > stream cipher, two passes of an ε-almost-∆-universal (εA∆U) hash > function, and an invocation of the AES-256 block cipher on a single > 16-byte block. On CPUs without AES instructions, Adiantum is much > faster than AES-XTS; for example, on ARM Cortex-A7, on 4096-byte sectors > Adiantum encryption is about 4 times faster than AES-256-XTS encryption, > and decryption about 5 times faster. > > Adiantum is a specialization of the more general HBSH construction. Our > earlier proposal, HPolyC, was also a HBSH specialization, but it used a > different εA∆U hash function, one based on Poly1305 only. Adiantum's > εA∆U hash function, which is based primarily on the "NH" hash function > like that used in UMAC (RFC4418), is about twice as fast as HPolyC's; > consequently, Adiantum is about 20% faster than HPolyC. > > This speed comes with no loss of security: Adiantum is provably just as > secure as HPolyC, in fact slightly *more* secure. Like HPolyC, > Adiantum's security is reducible to that of XChaCha12 and AES-256, > subject to a security bound. XChaCha12 itself has a security reduction > to ChaCha12. Therefore, one need not "trust" Adiantum; one need only > trust ChaCha12 and AES-256. Note that the εA∆U hash function is only > used for its proven combinatorical properties so cannot be "broken". > > Adiantum is also a true wide-block encryption mode, so flipping any > plaintext bit in the sector scrambles the entire ciphertext, and vice > versa. No other such mode is available in the kernel currently; doing > the same with XTS scrambles only 16 bytes. Adiantum also supports > arbitrary-length tweaks and naturally supports any length input >= 16 > bytes without needing "ciphertext stealing". > > For the stream cipher, Adiantum uses XChaCha12 rather than XChaCha20 in > order to make encryption feasible on the widest range of devices. > Although the 20-round variant is quite popular, the best known attacks > on ChaCha are on only 7 rounds, so ChaCha12 still has a substantial > security margin; in fact, larger than AES-256's. 12-round Salsa20 is > also the eSTREAM recommendation. For the block cipher, Adiantum uses > AES-256, despite it having a lower security margin than XChaCha12 and > needing table lookups, due to AES's extensive adoption and analysis > making it the obvious first choice. Nevertheless, for flexibility this > patch also permits the "adiantum" template to be instantiated with > XChaCha20 and/or with an alternate block cipher. > > We need Adiantum support in the kernel for use in dm-crypt and fscrypt, > where currently the only other suitable options are block cipher modes > such as AES-XTS. A big problem with this is that many low-end mobile > devices (e.g. Android Go phones sold primarily in developing countries, > as well as some smartwatches) still have CPUs that lack AES > instructions, e.g. ARM Cortex-A7. Sadly, AES-XTS encryption is much too > slow to be viable on these devices. We did find that some "lightweight" > block ciphers are fast enough, but these suffer from problems such as > not having much cryptanalysis or being too controversial. > > The ChaCha stream cipher has excellent performance but is insecure to > use directly for disk encryption, since each sector's IV is reused each > time it is overwritten. Even restricting the threat model to offline > attacks only isn't enough, since modern flash storage devices don't > guarantee that "overwrites" are really overwrites, due to wear-leveling. > Adiantum avoids this problem by constructing a > "tweakable super-pseudorandom permutation"; this is the strongest > possible security model for length-preserving encryption. > > Of course, storing random nonces along with the ciphertext would be the > ideal solution. But doing that with existing hardware and filesystems > runs into major practical problems; in most cases it would require data > journaling (like dm-integrity) which severely degrades performance. > Thus, for now length-preserving encryption is still needed. > > Signed-off-by: Eric Biggers <ebiggers@google.com> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> > --- > crypto/Kconfig | 23 ++ > crypto/Makefile | 1 + > crypto/adiantum.c | 658 ++++++++++++++++++++++++++++++++++++++++++++++ > crypto/tcrypt.c | 12 + > crypto/testmgr.c | 12 + > crypto/testmgr.h | 461 ++++++++++++++++++++++++++++++++ > 6 files changed, 1167 insertions(+) > create mode 100644 crypto/adiantum.c > > diff --git a/crypto/Kconfig b/crypto/Kconfig > index eaeb8a986b7d..b6376d5d973e 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -501,6 +501,29 @@ config CRYPTO_NHPOLY1305 > select CRYPTO_HASH > select CRYPTO_POLY1305 > > +config CRYPTO_ADIANTUM > + tristate "Adiantum support" > + select CRYPTO_CHACHA20 > + select CRYPTO_POLY1305 > + select CRYPTO_NHPOLY1305 > + help > + Adiantum is a tweakable, length-preserving encryption mode > + designed for fast and secure disk encryption, especially on > + CPUs without dedicated crypto instructions. It encrypts > + each sector using the XChaCha12 stream cipher, two passes of > + an ε-almost-∆-universal hash function, and an invocation of > + the AES-256 block cipher on a single 16-byte block. On CPUs > + without AES instructions, Adiantum is much faster than > + AES-XTS. > + > + Adiantum's security is provably reducible to that of its > + underlying stream and block ciphers, subject to a security > + bound. Unlike XTS, Adiantum is a true wide-block encryption > + mode, so it actually provides an even stronger notion of > + security than XTS, subject to the security bound. > + > + If unsure, say N. > + > comment "Hash modes" > > config CRYPTO_CMAC > diff --git a/crypto/Makefile b/crypto/Makefile > index c3310c85f09f..5e789dc2d4fd 100644 > --- a/crypto/Makefile > +++ b/crypto/Makefile > @@ -85,6 +85,7 @@ obj-$(CONFIG_CRYPTO_LRW) += lrw.o > obj-$(CONFIG_CRYPTO_XTS) += xts.o > obj-$(CONFIG_CRYPTO_CTR) += ctr.o > obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o > +obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o > obj-$(CONFIG_CRYPTO_NHPOLY1305) += nhpoly1305.o > obj-$(CONFIG_CRYPTO_GCM) += gcm.o > obj-$(CONFIG_CRYPTO_CCM) += ccm.o > diff --git a/crypto/adiantum.c b/crypto/adiantum.c > new file mode 100644 > index 000000000000..2dfcf12fd452 > --- /dev/null > +++ b/crypto/adiantum.c > @@ -0,0 +1,658 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Adiantum length-preserving encryption mode > + * > + * Copyright 2018 Google LLC > + */ > + > +/* > + * Adiantum is a tweakable, length-preserving encryption mode designed for fast > + * and secure disk encryption, especially on CPUs without dedicated crypto > + * instructions. Adiantum encrypts each sector using the XChaCha12 stream > + * cipher, two passes of an ε-almost-∆-universal (εA∆U) hash function based on > + * NH and Poly1305, and an invocation of the AES-256 block cipher on a single > + * 16-byte block. See the paper for details: > + * > + * Adiantum: length-preserving encryption for entry-level processors > + * (https://eprint.iacr.org/2018/720.pdf) > + * > + * For flexibility, this implementation also allows other ciphers: > + * > + * - 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 εA∆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 εA∆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 εA∆U hash > + * functions could be added here. > + */ > + > +#include <crypto/b128ops.h> > +#include <crypto/chacha.h> > +#include <crypto/internal/hash.h> > +#include <crypto/internal/skcipher.h> > +#include <crypto/nhpoly1305.h> > +#include <crypto/scatterwalk.h> > +#include <linux/module.h> > + > +#include "internal.h" > + > +/* > + * Size of right-hand block of input data, in bytes; also the size of the block > + * cipher's block size and the hash function's output. > + */ > +#define BLOCKCIPHER_BLOCK_SIZE 16 > + > +/* Size of the block cipher key (K_E) in bytes */ > +#define BLOCKCIPHER_KEY_SIZE 32 > + > +/* Size of the hash key (K_H) in bytes */ > +#define HASH_KEY_SIZE (POLY1305_BLOCK_SIZE + NHPOLY1305_KEY_SIZE) > + > +/* > + * The specification allows variable-length tweaks, but Linux's crypto API > + * currently only allows algorithms to support a single length. The "natural" > + * tweak length for Adiantum is 16, since that fits into one Poly1305 block for > + * the best performance. But longer tweaks are useful for fscrypt, to avoid > + * needing to derive per-file keys. So instead we use two blocks, or 32 bytes. > + */ > +#define TWEAK_SIZE 32 > + > +struct adiantum_instance_ctx { > + struct crypto_skcipher_spawn streamcipher_spawn; > + struct crypto_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_key header_hash_key; > +}; > + > +struct adiantum_request_ctx { > + > + /* > + * Buffer for right-hand block 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; > + > + bool enc; /* true if encrypting, false if decrypting */ > + > + /* > + * The result of the Poly1305 εA∆U hash function applied to > + * (message length, tweak). > + */ > + le128 header_hash; > + > + /* Sub-requests, must be last */ > + union { > + struct shash_desc hash_desc; > + struct skcipher_request streamcipher_req; > + } u; > +}; > + > +/* > + * Given the XChaCha stream key K_S, derive the block cipher key K_E and the > + * hash key K_H as follows: > + * > + * K_E || K_H || ... = XChaCha(key=K_S, nonce=1||0^191) > + * > + * Note that this denotes using bits from the XChaCha keystream, which here we > + * get indirectly by encrypting a buffer containing all 0's. > + */ > +static int adiantum_setkey(struct crypto_skcipher *tfm, const u8 *key, > + unsigned int keylen) > +{ > + struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); > + struct { > + u8 iv[XCHACHA_IV_SIZE]; > + u8 derived_keys[BLOCKCIPHER_KEY_SIZE + HASH_KEY_SIZE]; > + struct scatterlist sg; > + struct crypto_wait wait; > + struct skcipher_request req; /* must be last */ > + } *data; > + u8 *keyp; > + int err; > + > + /* Set the stream cipher key (K_S) */ > + crypto_skcipher_clear_flags(tctx->streamcipher, CRYPTO_TFM_REQ_MASK); > + crypto_skcipher_set_flags(tctx->streamcipher, > + crypto_skcipher_get_flags(tfm) & > + CRYPTO_TFM_REQ_MASK); > + err = crypto_skcipher_setkey(tctx->streamcipher, key, keylen); > + crypto_skcipher_set_flags(tfm, > + crypto_skcipher_get_flags(tctx->streamcipher) & > + CRYPTO_TFM_RES_MASK); > + if (err) > + return err; > + > + /* Derive the subkeys */ > + data = kzalloc(sizeof(*data) + > + crypto_skcipher_reqsize(tctx->streamcipher), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + data->iv[0] = 1; > + sg_init_one(&data->sg, data->derived_keys, sizeof(data->derived_keys)); > + crypto_init_wait(&data->wait); > + skcipher_request_set_tfm(&data->req, tctx->streamcipher); > + skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP | > + CRYPTO_TFM_REQ_MAY_BACKLOG, > + crypto_req_done, &data->wait); > + skcipher_request_set_crypt(&data->req, &data->sg, &data->sg, > + sizeof(data->derived_keys), data->iv); > + err = crypto_wait_req(crypto_skcipher_encrypt(&data->req), &data->wait); > + if (err) > + goto out; > + keyp = data->derived_keys; > + > + /* Set the block cipher key (K_E) */ > + crypto_cipher_clear_flags(tctx->blockcipher, CRYPTO_TFM_REQ_MASK); > + crypto_cipher_set_flags(tctx->blockcipher, > + crypto_skcipher_get_flags(tfm) & > + CRYPTO_TFM_REQ_MASK); > + err = crypto_cipher_setkey(tctx->blockcipher, keyp, > + BLOCKCIPHER_KEY_SIZE); > + crypto_skcipher_set_flags(tfm, > + crypto_cipher_get_flags(tctx->blockcipher) & > + CRYPTO_TFM_RES_MASK); > + if (err) > + goto out; > + keyp += BLOCKCIPHER_KEY_SIZE; > + > + /* 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); > + crypto_skcipher_set_flags(tfm, crypto_shash_get_flags(tctx->hash) & > + CRYPTO_TFM_RES_MASK); > + keyp += NHPOLY1305_KEY_SIZE; > + WARN_ON(keyp != &data->derived_keys[ARRAY_SIZE(data->derived_keys)]); > +out: > + kzfree(data); > + return err; > +} > + > +/* Addition in Z/(2^{128}Z) */ > +static inline void le128_add(le128 *r, const le128 *v1, const le128 *v2) > +{ > + u64 x = le64_to_cpu(v1->b); > + u64 y = le64_to_cpu(v2->b); > + > + r->b = cpu_to_le64(x + y); > + r->a = cpu_to_le64(le64_to_cpu(v1->a) + le64_to_cpu(v2->a) + > + (x + y < x)); > +} > + > +/* Subtraction in Z/(2^{128}Z) */ > +static inline void le128_sub(le128 *r, const le128 *v1, const le128 *v2) > +{ > + u64 x = le64_to_cpu(v1->b); > + u64 y = le64_to_cpu(v2->b); > + > + r->b = cpu_to_le64(x - y); > + r->a = cpu_to_le64(le64_to_cpu(v1->a) - le64_to_cpu(v2->a) - > + (x - y > x)); > +} > + > +/* > + * Apply the Poly1305 εA∆U hash function to (message length, tweak) and save the > + * result to rctx->header_hash. > + * > + * This value is reused in both the first and second hash steps. Specifically, > + * it's added to the result of an independently keyed εA∆U hash function (for > + * equal length inputs only) taken over the message. This gives the overall > + * Adiantum hash of the (tweak, message) pair. > + */ > +static void adiantum_hash_header(struct skcipher_request *req) > +{ > + 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; > + __le64 padding; > + } header = { > + .message_bits = cpu_to_le64((u64)bulk_len * 8) > + }; > + struct poly1305_state state; > + > + poly1305_core_init(&state); > + > + BUILD_BUG_ON(sizeof(header) % POLY1305_BLOCK_SIZE != 0); > + poly1305_core_blocks(&state, &tctx->header_hash_key, > + &header, sizeof(header) / POLY1305_BLOCK_SIZE); > + > + BUILD_BUG_ON(TWEAK_SIZE % POLY1305_BLOCK_SIZE != 0); > + poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv, > + TWEAK_SIZE / POLY1305_BLOCK_SIZE); > + > + poly1305_core_emit(&state, &rctx->header_hash); > +} > + > +/* Hash the left-hand block (the "bulk") of the message using NHPoly1305 */ > +static int adiantum_hash_message(struct skcipher_request *req, > + struct scatterlist *sgl, le128 *digest) > +{ > + 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 shash_desc *hash_desc = &rctx->u.hash_desc; > + struct sg_mapping_iter miter; > + unsigned int i, n; > + int err; > + > + hash_desc->tfm = tctx->hash; > + hash_desc->flags = 0; > + > + err = crypto_shash_init(hash_desc); > + if (err) > + return err; > + > + sg_miter_start(&miter, sgl, sg_nents(sgl), > + 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; > + > + return crypto_shash_final(hash_desc, (u8 *)digest); > +} > + > +/* Continue Adiantum encryption/decryption after the stream cipher step */ > +static int adiantum_finish(struct skcipher_request *req) > +{ > + 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; > + le128 digest; > + int err; > + > + /* 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); > + > + /* > + * 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) > + */ > + err = adiantum_hash_message(req, req->dst, &digest); > + if (err) > + return err; > + le128_add(&digest, &digest, &rctx->header_hash); > + le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest); > + scatterwalk_map_and_copy(&rctx->rbuf.bignum, req->dst, > + bulk_len, BLOCKCIPHER_BLOCK_SIZE, 1); > + return 0; > +} > + > +static void adiantum_streamcipher_done(struct crypto_async_request *areq, > + int err) > +{ > + struct skcipher_request *req = areq->data; > + > + if (!err) > + err = adiantum_finish(req); > + > + skcipher_request_complete(req, err); > +} > + > +static int adiantum_crypt(struct skcipher_request *req, bool enc) > +{ > + 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; > + 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); > + err = adiantum_hash_message(req, req->src, &digest); > + if (err) > + return err; > + le128_add(&digest, &digest, &rctx->header_hash); > + scatterwalk_map_and_copy(&rctx->rbuf.bignum, req->src, > + bulk_len, BLOCKCIPHER_BLOCK_SIZE, 0); > + le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest); > + > + /* 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); > + > + /* 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; > + > + /* > + * XChaCha needs to be done on all the data except the last 16 bytes; > + * for disk encryption that usually means 4080 or 496 bytes. But ChaCha > + * implementations tend to be most efficient when passed a whole number > + * of 64-byte ChaCha blocks, or sometimes even a multiple of 256 bytes. > + * And here it doesn't matter whether the last 16 bytes are written to, > + * as the second hash step will overwrite them. Thus, round the XChaCha > + * length up to the next 64-byte boundary if possible. > + */ > + stream_len = bulk_len; > + if (round_up(stream_len, CHACHA_BLOCK_SIZE) <= req->cryptlen) > + stream_len = round_up(stream_len, CHACHA_BLOCK_SIZE); > + > + 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); > + 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); > +} > + > +static int adiantum_encrypt(struct skcipher_request *req) > +{ > + return adiantum_crypt(req, true); > +} > + > +static int adiantum_decrypt(struct skcipher_request *req) > +{ > + return adiantum_crypt(req, false); > +} > + > +static int adiantum_init_tfm(struct crypto_skcipher *tfm) > +{ > + struct skcipher_instance *inst = skcipher_alg_instance(tfm); > + struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst); > + 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); > + if (IS_ERR(streamcipher)) > + return PTR_ERR(streamcipher); > + > + blockcipher = crypto_spawn_cipher(&ictx->blockcipher_spawn); > + if (IS_ERR(blockcipher)) { > + err = PTR_ERR(blockcipher); > + 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(FIELD_SIZEOF(struct adiantum_request_ctx, > + u.hash_desc) + > + crypto_shash_descsize(hash), > + FIELD_SIZEOF(struct adiantum_request_ctx, > + u.streamcipher_req) + > + crypto_skcipher_reqsize(streamcipher)); > + > + crypto_skcipher_set_reqsize(tfm, > + offsetof(struct adiantum_request_ctx, u) + > + subreq_size); > + return 0; > + > +err_free_blockcipher: > + crypto_free_cipher(blockcipher); > +err_free_streamcipher: > + crypto_free_skcipher(streamcipher); > + return err; > +} > + > +static void adiantum_exit_tfm(struct crypto_skcipher *tfm) > +{ > + struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(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) > +{ > + struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst); > + > + crypto_drop_skcipher(&ictx->streamcipher_spawn); > + crypto_drop_spawn(&ictx->blockcipher_spawn); > + crypto_drop_shash(&ictx->hash_spawn); > + kfree(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 *streamcipher_alg, > + struct crypto_alg *blockcipher_alg, > + struct shash_alg *hash_alg) > +{ > + if (strcmp(streamcipher_alg->base.cra_name, "xchacha12") != 0 && > + strcmp(streamcipher_alg->base.cra_name, "xchacha20") != 0) > + return false; > + > + if (blockcipher_alg->cra_cipher.cia_min_keysize > BLOCKCIPHER_KEY_SIZE || > + blockcipher_alg->cra_cipher.cia_max_keysize < BLOCKCIPHER_KEY_SIZE) > + return false; > + 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) > +{ > + struct crypto_attr_type *algt; > + const char *streamcipher_name; > + const char *blockcipher_name; > + const char *nhpoly1305_name; > + struct skcipher_instance *inst; > + struct adiantum_instance_ctx *ictx; > + struct skcipher_alg *streamcipher_alg; > + struct crypto_alg *blockcipher_alg; > + struct crypto_alg *_hash_alg; > + struct shash_alg *hash_alg; > + int err; > + > + algt = crypto_get_attr_type(tb); > + if (IS_ERR(algt)) > + return PTR_ERR(algt); > + > + if ((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask) > + return -EINVAL; > + > + streamcipher_name = crypto_attr_alg_name(tb[1]); > + if (IS_ERR(streamcipher_name)) > + return PTR_ERR(streamcipher_name); > + > + blockcipher_name = crypto_attr_alg_name(tb[2]); > + if (IS_ERR(blockcipher_name)) > + return PTR_ERR(blockcipher_name); > + > + nhpoly1305_name = crypto_attr_alg_name(tb[3]); > + if (nhpoly1305_name == ERR_PTR(-ENOENT)) > + nhpoly1305_name = "nhpoly1305"; > + if (IS_ERR(nhpoly1305_name)) > + return PTR_ERR(nhpoly1305_name); > + > + inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); > + if (!inst) > + return -ENOMEM; > + ictx = skcipher_instance_ctx(inst); > + > + /* Stream cipher, e.g. "xchacha12" */ > + err = crypto_grab_skcipher(&ictx->streamcipher_spawn, streamcipher_name, > + 0, crypto_requires_sync(algt->type, > + algt->mask)); > + if (err) > + goto out_free_inst; > + streamcipher_alg = crypto_spawn_skcipher_alg(&ictx->streamcipher_spawn); > + > + /* Block cipher, e.g. "aes" */ > + err = crypto_grab_spawn(&ictx->blockcipher_spawn, blockcipher_name, > + CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_MASK); > + if (err) > + goto out_drop_streamcipher; > + blockcipher_alg = ictx->blockcipher_spawn.alg; > + > + /* NHPoly1305 εA∆U hash function */ > + _hash_alg = crypto_alg_mod_lookup(nhpoly1305_name, > + CRYPTO_ALG_TYPE_SHASH, > + CRYPTO_ALG_TYPE_MASK); > + if (IS_ERR(_hash_alg)) { > + err = PTR_ERR(_hash_alg); > + goto out_drop_blockcipher; > + } > + hash_alg = __crypto_shash_alg(_hash_alg); > + err = crypto_init_shash_spawn(&ictx->hash_spawn, hash_alg, > + skcipher_crypto_instance(inst)); > + if (err) { > + crypto_mod_put(_hash_alg); > + goto out_drop_blockcipher; > + } > + > + /* Check the set of algorithms */ > + if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg, > + hash_alg)) { > + pr_warn("Unsupported Adiantum instantiation: (%s,%s,%s)\n", > + streamcipher_alg->base.cra_name, > + blockcipher_alg->cra_name, hash_alg->base.cra_name); > + err = -EINVAL; > + goto out_drop_hash; > + } > + > + /* Instance fields */ > + > + err = -ENAMETOOLONG; > + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, > + "adiantum(%s,%s)", streamcipher_alg->base.cra_name, > + blockcipher_alg->cra_name) >= CRYPTO_MAX_ALG_NAME) > + goto out_drop_hash; > + 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) > + goto out_drop_hash; > + > + inst->alg.base.cra_blocksize = BLOCKCIPHER_BLOCK_SIZE; > + inst->alg.base.cra_ctxsize = sizeof(struct adiantum_tfm_ctx); > + inst->alg.base.cra_alignmask = streamcipher_alg->base.cra_alignmask | > + hash_alg->base.cra_alignmask; > + /* > + * 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. > + */ > + inst->alg.base.cra_priority = (4 * streamcipher_alg->base.cra_priority + > + 2 * hash_alg->base.cra_priority + > + blockcipher_alg->cra_priority) / 7; > + > + inst->alg.setkey = adiantum_setkey; > + inst->alg.encrypt = adiantum_encrypt; > + inst->alg.decrypt = adiantum_decrypt; > + inst->alg.init = adiantum_init_tfm; > + inst->alg.exit = adiantum_exit_tfm; > + inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(streamcipher_alg); > + inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(streamcipher_alg); > + inst->alg.ivsize = TWEAK_SIZE; > + > + inst->free = adiantum_free_instance; > + > + err = skcipher_register_instance(tmpl, inst); > + if (err) > + goto out_drop_hash; > + > + return 0; > + > +out_drop_hash: > + crypto_drop_shash(&ictx->hash_spawn); > +out_drop_blockcipher: > + crypto_drop_spawn(&ictx->blockcipher_spawn); > +out_drop_streamcipher: > + crypto_drop_skcipher(&ictx->streamcipher_spawn); > +out_free_inst: > + kfree(inst); > + return err; > +} > + > +/* adiantum(streamcipher_name, blockcipher_name [, nhpoly1305_name]) */ > +static struct crypto_template adiantum_tmpl = { > + .name = "adiantum", > + .create = adiantum_create, > + .module = THIS_MODULE, > +}; > + > +static int __init adiantum_module_init(void) > +{ > + return crypto_register_template(&adiantum_tmpl); > +} > + > +static void __exit adiantum_module_exit(void) > +{ > + crypto_unregister_template(&adiantum_tmpl); > +} > + > +module_init(adiantum_module_init); > +module_exit(adiantum_module_exit); > + > +MODULE_DESCRIPTION("Adiantum length-preserving encryption mode"); > +MODULE_LICENSE("GPL v2"); > +MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>"); > +MODULE_ALIAS_CRYPTO("adiantum"); > diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c > index 5fb120474902..0590a9204562 100644 > --- a/crypto/tcrypt.c > +++ b/crypto/tcrypt.c > @@ -2320,6 +2320,18 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) > test_cipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, > speed_template_16); > break; > + > + case 219: > + test_cipher_speed("adiantum(xchacha12,aes)", ENCRYPT, sec, NULL, > + 0, speed_template_32); > + test_cipher_speed("adiantum(xchacha12,aes)", DECRYPT, sec, NULL, > + 0, speed_template_32); > + test_cipher_speed("adiantum(xchacha20,aes)", ENCRYPT, sec, NULL, > + 0, speed_template_32); > + test_cipher_speed("adiantum(xchacha20,aes)", DECRYPT, sec, NULL, > + 0, speed_template_32); > + break; > + > case 300: > if (alg) { > test_hash_speed(alg, sec, generic_hash_speed_template); > diff --git a/crypto/testmgr.c b/crypto/testmgr.c > index 665911c24786..0f684a414acb 100644 > --- a/crypto/testmgr.c > +++ b/crypto/testmgr.c > @@ -2404,6 +2404,18 @@ static int alg_test_null(const struct alg_test_desc *desc, > /* Please keep this list sorted by algorithm name. */ > static const struct alg_test_desc alg_test_descs[] = { > { > + .alg = "adiantum(xchacha12,aes)", > + .test = alg_test_skcipher, > + .suite = { > + .cipher = __VECS(adiantum_xchacha12_aes_tv_template) > + }, > + }, { > + .alg = "adiantum(xchacha20,aes)", > + .test = alg_test_skcipher, > + .suite = { > + .cipher = __VECS(adiantum_xchacha20_aes_tv_template) > + }, > + }, { > .alg = "aegis128", > .test = alg_test_aead, > .suite = { > diff --git a/crypto/testmgr.h b/crypto/testmgr.h > index 50ea1f2705c7..e7e56a8febbc 100644 > --- a/crypto/testmgr.h > +++ b/crypto/testmgr.h > @@ -33381,6 +33381,467 @@ static const struct cipher_testvec xchacha12_tv_template[] = { > }, > }; > > +/* Adiantum test vectors from https://github.com/google/adiantum */ > +static const struct cipher_testvec adiantum_xchacha12_aes_tv_template[] = { > + { > + .key = "\x9e\xeb\xb2\x49\x3c\x1c\xf5\xf4" > + "\x6a\x99\xc2\xc4\xdf\xb1\xf4\xdd" > + "\x75\x20\x57\xea\x2c\x4f\xcd\xb2" > + "\xa5\x3d\x7b\x49\x1e\xab\xfd\x0f", > + .klen = 32, > + .iv = "\xdf\x63\xd4\xab\xd2\x49\xf3\xd8" > + "\x33\x81\x37\x60\x7d\xfa\x73\x08" > + "\xd8\x49\x6d\x80\xe8\x2f\x62\x54" > + "\xeb\x0e\xa9\x39\x5b\x45\x7f\x8a", > + .ptext = "\x67\xc9\xf2\x30\x84\x41\x8e\x43" > + "\xfb\xf3\xb3\x3e\x79\x36\x7f\xe8", > + .ctext = "\x6d\x32\x86\x18\x67\x86\x0f\x3f" > + "\x96\x7c\x9d\x28\x0d\x53\xec\x9f", > + .len = 16, > + .also_non_np = 1, > + .np = 2, > + .tap = { 14, 2 }, > + }, { > + .key = "\x36\x2b\x57\x97\xf8\x5d\xcd\x99" > + "\x5f\x1a\x5a\x44\x1d\x92\x0f\x27" > + "\xcc\x16\xd7\x2b\x85\x63\x99\xd3" > + "\xba\x96\xa1\xdb\xd2\x60\x68\xda", > + .klen = 32, > + .iv = "\xef\x58\x69\xb1\x2c\x5e\x9a\x47" > + "\x24\xc1\xb1\x69\xe1\x12\x93\x8f" > + "\x43\x3d\x6d\x00\xdb\x5e\xd8\xd9" > + "\x12\x9a\xfe\xd9\xff\x2d\xaa\xc4", > + .ptext = "\x5e\xa8\x68\x19\x85\x98\x12\x23" > + "\x26\x0a\xcc\xdb\x0a\x04\xb9\xdf" > + "\x4d\xb3\x48\x7b\xb0\xe3\xc8\x19" > + "\x43\x5a\x46\x06\x94\x2d\xf2", > + .ctext = "\xc7\xc6\xf1\x73\x8f\xc4\xff\x4a" > + "\x39\xbe\x78\xbe\x8d\x28\xc8\x89" > + "\x46\x63\xe7\x0c\x7d\x87\xe8\x4e" > + "\xc9\x18\x7b\xbe\x18\x60\x50", > + .len = 31, > + }, { > + .key = "\xa5\x28\x24\x34\x1a\x3c\xd8\xf7" > + "\x05\x91\x8f\xee\x85\x1f\x35\x7f" > + "\x80\x3d\xfc\x9b\x94\xf6\xfc\x9e" > + "\x19\x09\x00\xa9\x04\x31\x4f\x11", > + .klen = 32, > + .iv = "\xa1\xba\x49\x95\xff\x34\x6d\xb8" > + "\xcd\x87\x5d\x5e\xfd\xea\x85\xdb" > + "\x8a\x7b\x5e\xb2\x5d\x57\xdd\x62" > + "\xac\xa9\x8c\x41\x42\x94\x75\xb7", > + .ptext = "\x69\xb4\xe8\x8c\x37\xe8\x67\x82" > + "\xf1\xec\x5d\x04\xe5\x14\x91\x13" > + "\xdf\xf2\x87\x1b\x69\x81\x1d\x71" > + "\x70\x9e\x9c\x3b\xde\x49\x70\x11" > + "\xa0\xa3\xdb\x0d\x54\x4f\x66\x69" > + "\xd7\xdb\x80\xa7\x70\x92\x68\xce" > + "\x81\x04\x2c\xc6\xab\xae\xe5\x60" > + "\x15\xe9\x6f\xef\xaa\x8f\xa7\xa7" > + "\x63\x8f\xf2\xf0\x77\xf1\xa8\xea" > + "\xe1\xb7\x1f\x9e\xab\x9e\x4b\x3f" > + "\x07\x87\x5b\x6f\xcd\xa8\xaf\xb9" > + "\xfa\x70\x0b\x52\xb8\xa8\xa7\x9e" > + "\x07\x5f\xa6\x0e\xb3\x9b\x79\x13" > + "\x79\xc3\x3e\x8d\x1c\x2c\x68\xc8" > + "\x51\x1d\x3c\x7b\x7d\x79\x77\x2a" > + "\x56\x65\xc5\x54\x23\x28\xb0\x03", > + .ctext = "\x9e\x16\xab\xed\x4b\xa7\x42\x5a" > + "\xc6\xfb\x4e\x76\xff\xbe\x03\xa0" > + "\x0f\xe3\xad\xba\xe4\x98\x2b\x0e" > + "\x21\x48\xa0\xb8\x65\x48\x27\x48" > + "\x84\x54\x54\xb2\x9a\x94\x7b\xe6" > + "\x4b\x29\xe9\xcf\x05\x91\x80\x1a" > + "\x3a\xf3\x41\x96\x85\x1d\x9f\x74" > + "\x51\x56\x63\xfa\x7c\x28\x85\x49" > + "\xf7\x2f\xf9\xf2\x18\x46\xf5\x33" > + "\x80\xa3\x3c\xce\xb2\x57\x93\xf5" > + "\xae\xbd\xa9\xf5\x7b\x30\xc4\x93" > + "\x66\xe0\x30\x77\x16\xe4\xa0\x31" > + "\xba\x70\xbc\x68\x13\xf5\xb0\x9a" > + "\xc1\xfc\x7e\xfe\x55\x80\x5c\x48" > + "\x74\xa6\xaa\xa3\xac\xdc\xc2\xf5" > + "\x8d\xde\x34\x86\x78\x60\x75\x8d", > + .len = 128, > + .also_non_np = 1, > + .np = 4, > + .tap = { 104, 16, 4, 4 }, > + }, { > + .key = "\xd3\x81\x72\x18\x23\xff\x6f\x4a" > + "\x25\x74\x29\x0d\x51\x8a\x0e\x13" > + "\xc1\x53\x5d\x30\x8d\xee\x75\x0d" > + "\x14\xd6\x69\xc9\x15\xa9\x0c\x60", > + .klen = 32, > + .iv = "\x65\x9b\xd4\xa8\x7d\x29\x1d\xf4" > + "\xc4\xd6\x9b\x6a\x28\xab\x64\xe2" > + "\x62\x81\x97\xc5\x81\xaa\xf9\x44" > + "\xc1\x72\x59\x82\xaf\x16\xc8\x2c", > + .ptext = "\xc7\x6b\x52\x6a\x10\xf0\xcc\x09" > + "\xc1\x12\x1d\x6d\x21\xa6\x78\xf5" > + "\x05\xa3\x69\x60\x91\x36\x98\x57" > + "\xba\x0c\x14\xcc\xf3\x2d\x73\x03" > + "\xc6\xb2\x5f\xc8\x16\x27\x37\x5d" > + "\xd0\x0b\x87\xb2\x50\x94\x7b\x58" > + "\x04\xf4\xe0\x7f\x6e\x57\x8e\xc9" > + "\x41\x84\xc1\xb1\x7e\x4b\x91\x12" > + "\x3a\x8b\x5d\x50\x82\x7b\xcb\xd9" > + "\x9a\xd9\x4e\x18\x06\x23\x9e\xd4" > + "\xa5\x20\x98\xef\xb5\xda\xe5\xc0" > + "\x8a\x6a\x83\x77\x15\x84\x1e\xae" > + "\x78\x94\x9d\xdf\xb7\xd1\xea\x67" > + "\xaa\xb0\x14\x15\xfa\x67\x21\x84" > + "\xd3\x41\x2a\xce\xba\x4b\x4a\xe8" > + "\x95\x62\xa9\x55\xf0\x80\xad\xbd" > + "\xab\xaf\xdd\x4f\xa5\x7c\x13\x36" > + "\xed\x5e\x4f\x72\xad\x4b\xf1\xd0" > + "\x88\x4e\xec\x2c\x88\x10\x5e\xea" > + "\x12\xc0\x16\x01\x29\xa3\xa0\x55" > + "\xaa\x68\xf3\xe9\x9d\x3b\x0d\x3b" > + "\x6d\xec\xf8\xa0\x2d\xf0\x90\x8d" > + "\x1c\xe2\x88\xd4\x24\x71\xf9\xb3" > + "\xc1\x9f\xc5\xd6\x76\x70\xc5\x2e" > + "\x9c\xac\xdb\x90\xbd\x83\x72\xba" > + "\x6e\xb5\xa5\x53\x83\xa9\xa5\xbf" > + "\x7d\x06\x0e\x3c\x2a\xd2\x04\xb5" > + "\x1e\x19\x38\x09\x16\xd2\x82\x1f" > + "\x75\x18\x56\xb8\x96\x0b\xa6\xf9" > + "\xcf\x62\xd9\x32\x5d\xa9\xd7\x1d" > + "\xec\xe4\xdf\x1b\xbe\xf1\x36\xee" > + "\xe3\x7b\xb5\x2f\xee\xf8\x53\x3d" > + "\x6a\xb7\x70\xa9\xfc\x9c\x57\x25" > + "\xf2\x89\x10\xd3\xb8\xa8\x8c\x30" > + "\xae\x23\x4f\x0e\x13\x66\x4f\xe1" > + "\xb6\xc0\xe4\xf8\xef\x93\xbd\x6e" > + "\x15\x85\x6b\xe3\x60\x81\x1d\x68" > + "\xd7\x31\x87\x89\x09\xab\xd5\x96" > + "\x1d\xf3\x6d\x67\x80\xca\x07\x31" > + "\x5d\xa7\xe4\xfb\x3e\xf2\x9b\x33" > + "\x52\x18\xc8\x30\xfe\x2d\xca\x1e" > + "\x79\x92\x7a\x60\x5c\xb6\x58\x87" > + "\xa4\x36\xa2\x67\x92\x8b\xa4\xb7" > + "\xf1\x86\xdf\xdc\xc0\x7e\x8f\x63" > + "\xd2\xa2\xdc\x78\xeb\x4f\xd8\x96" > + "\x47\xca\xb8\x91\xf9\xf7\x94\x21" > + "\x5f\x9a\x9f\x5b\xb8\x40\x41\x4b" > + "\x66\x69\x6a\x72\xd0\xcb\x70\xb7" > + "\x93\xb5\x37\x96\x05\x37\x4f\xe5" > + "\x8c\xa7\x5a\x4e\x8b\xb7\x84\xea" > + "\xc7\xfc\x19\x6e\x1f\x5a\xa1\xac" > + "\x18\x7d\x52\x3b\xb3\x34\x62\x99" > + "\xe4\x9e\x31\x04\x3f\xc0\x8d\x84" > + "\x17\x7c\x25\x48\x52\x67\x11\x27" > + "\x67\xbb\x5a\x85\xca\x56\xb2\x5c" > + "\xe6\xec\xd5\x96\x3d\x15\xfc\xfb" > + "\x22\x25\xf4\x13\xe5\x93\x4b\x9a" > + "\x77\xf1\x52\x18\xfa\x16\x5e\x49" > + "\x03\x45\xa8\x08\xfa\xb3\x41\x92" > + "\x79\x50\x33\xca\xd0\xd7\x42\x55" > + "\xc3\x9a\x0c\x4e\xd9\xa4\x3c\x86" > + "\x80\x9f\x53\xd1\xa4\x2e\xd1\xbc" > + "\xf1\x54\x6e\x93\xa4\x65\x99\x8e" > + "\xdf\x29\xc0\x64\x63\x07\xbb\xea", > + .ctext = "\x15\x97\xd0\x86\x18\x03\x9c\x51" > + "\xc5\x11\x36\x62\x13\x92\xe6\x73" > + "\x29\x79\xde\xa1\x00\x3e\x08\x64" > + "\x17\x1a\xbc\xd5\xfe\x33\x0e\x0c" > + "\x7c\x94\xa7\xc6\x3c\xbe\xac\xa2" > + "\x89\xe6\xbc\xdf\x0c\x33\x27\x42" > + "\x46\x73\x2f\xba\x4e\xa6\x46\x8f" > + "\xe4\xee\x39\x63\x42\x65\xa3\x88" > + "\x7a\xad\x33\x23\xa9\xa7\x20\x7f" > + "\x0b\xe6\x6a\xc3\x60\xda\x9e\xb4" > + "\xd6\x07\x8a\x77\x26\xd1\xab\x44" > + "\x99\x55\x03\x5e\xed\x8d\x7b\xbd" > + "\xc8\x21\xb7\x21\x30\x3f\xc0\xb5" > + "\xc8\xec\x6c\x23\xa6\xa3\x6d\xf1" > + "\x30\x0a\xd0\xa6\xa9\x28\x69\xae" > + "\x2a\xe6\x54\xac\x82\x9d\x6a\x95" > + "\x6f\x06\x44\xc5\x5a\x77\x6e\xec" > + "\xf8\xf8\x63\xb2\xe6\xaa\xbd\x8e" > + "\x0e\x8a\x62\x00\x03\xc8\x84\xdd" > + "\x47\x4a\xc3\x55\xba\xb7\xe7\xdf" > + "\x08\xbf\x62\xf5\xe8\xbc\xb6\x11" > + "\xe4\xcb\xd0\x66\x74\x32\xcf\xd4" > + "\xf8\x51\x80\x39\x14\x05\x12\xdb" > + "\x87\x93\xe2\x26\x30\x9c\x3a\x21" > + "\xe5\xd0\x38\x57\x80\x15\xe4\x08" > + "\x58\x05\x49\x7d\xe6\x92\x77\x70" > + "\xfb\x1e\x2d\x6a\x84\x00\xc8\x68" > + "\xf7\x1a\xdd\xf0\x7b\x38\x1e\xd8" > + "\x2c\x78\x78\x61\xcf\xe3\xde\x69" > + "\x1f\xd5\x03\xd5\x1a\xb4\xcf\x03" > + "\xc8\x7a\x70\x68\x35\xb4\xf6\xbe" > + "\x90\x62\xb2\x28\x99\x86\xf5\x44" > + "\x99\xeb\x31\xcf\xca\xdf\xd0\x21" > + "\xd6\x60\xf7\x0f\x40\xb4\x80\xb7" > + "\xab\xe1\x9b\x45\xba\x66\xda\xee" > + "\xdd\x04\x12\x40\x98\xe1\x69\xe5" > + "\x2b\x9c\x59\x80\xe7\x7b\xcc\x63" > + "\xa6\xc0\x3a\xa9\xfe\x8a\xf9\x62" > + "\x11\x34\x61\x94\x35\xfe\xf2\x99" > + "\xfd\xee\x19\xea\x95\xb6\x12\xbf" > + "\x1b\xdf\x02\x1a\xcc\x3e\x7e\x65" > + "\x78\x74\x10\x50\x29\x63\x28\xea" > + "\x6b\xab\xd4\x06\x4d\x15\x24\x31" > + "\xc7\x0a\xc9\x16\xb6\x48\xf0\xbf" > + "\x49\xdb\x68\x71\x31\x8f\x87\xe2" > + "\x13\x05\x64\xd6\x22\x0c\xf8\x36" > + "\x84\x24\x3e\x69\x5e\xb8\x9e\x16" > + "\x73\x6c\x83\x1e\xe0\x9f\x9e\xba" > + "\xe5\x59\x21\x33\x1b\xa9\x26\xc2" > + "\xc7\xd9\x30\x73\xb6\xa6\x73\x82" > + "\x19\xfa\x44\x4d\x40\x8b\x69\x04" > + "\x94\x74\xea\x6e\xb3\x09\x47\x01" > + "\x2a\xb9\x78\x34\x43\x11\xed\xd6" > + "\x8c\x95\x65\x1b\x85\x67\xa5\x40" > + "\xac\x9c\x05\x4b\x57\x4a\xa9\x96" > + "\x0f\xdd\x4f\xa1\xe0\xcf\x6e\xc7" > + "\x1b\xed\xa2\xb4\x56\x8c\x09\x6e" > + "\xa6\x65\xd7\x55\x81\xb7\xed\x11" > + "\x9b\x40\x75\xa8\x6b\x56\xaf\x16" > + "\x8b\x3d\xf4\xcb\xfe\xd5\x1d\x3d" > + "\x85\xc2\xc0\xde\x43\x39\x4a\x96" > + "\xba\x88\x97\xc0\xd6\x00\x0e\x27" > + "\x21\xb0\x21\x52\xba\xa7\x37\xaa" > + "\xcc\xbf\x95\xa8\xf4\xd0\x91\xf6", > + .len = 512, > + .also_non_np = 1, > + .np = 2, > + .tap = { 144, 368 }, > + } > +}; > + > +/* Adiantum with XChaCha20 instead of XChaCha12 */ > +/* Test vectors from https://github.com/google/adiantum */ > +static const struct cipher_testvec adiantum_xchacha20_aes_tv_template[] = { > + { > + .key = "\x9e\xeb\xb2\x49\x3c\x1c\xf5\xf4" > + "\x6a\x99\xc2\xc4\xdf\xb1\xf4\xdd" > + "\x75\x20\x57\xea\x2c\x4f\xcd\xb2" > + "\xa5\x3d\x7b\x49\x1e\xab\xfd\x0f", > + .klen = 32, > + .iv = "\xdf\x63\xd4\xab\xd2\x49\xf3\xd8" > + "\x33\x81\x37\x60\x7d\xfa\x73\x08" > + "\xd8\x49\x6d\x80\xe8\x2f\x62\x54" > + "\xeb\x0e\xa9\x39\x5b\x45\x7f\x8a", > + .ptext = "\x67\xc9\xf2\x30\x84\x41\x8e\x43" > + "\xfb\xf3\xb3\x3e\x79\x36\x7f\xe8", > + .ctext = "\xf6\x78\x97\xd6\xaa\x94\x01\x27" > + "\x2e\x4d\x83\xe0\x6e\x64\x9a\xdf", > + .len = 16, > + .also_non_np = 1, > + .np = 3, > + .tap = { 5, 2, 9 }, > + }, { > + .key = "\x36\x2b\x57\x97\xf8\x5d\xcd\x99" > + "\x5f\x1a\x5a\x44\x1d\x92\x0f\x27" > + "\xcc\x16\xd7\x2b\x85\x63\x99\xd3" > + "\xba\x96\xa1\xdb\xd2\x60\x68\xda", > + .klen = 32, > + .iv = "\xef\x58\x69\xb1\x2c\x5e\x9a\x47" > + "\x24\xc1\xb1\x69\xe1\x12\x93\x8f" > + "\x43\x3d\x6d\x00\xdb\x5e\xd8\xd9" > + "\x12\x9a\xfe\xd9\xff\x2d\xaa\xc4", > + .ptext = "\x5e\xa8\x68\x19\x85\x98\x12\x23" > + "\x26\x0a\xcc\xdb\x0a\x04\xb9\xdf" > + "\x4d\xb3\x48\x7b\xb0\xe3\xc8\x19" > + "\x43\x5a\x46\x06\x94\x2d\xf2", > + .ctext = "\x4b\xb8\x90\x10\xdf\x7f\x64\x08" > + "\x0e\x14\x42\x5f\x00\x74\x09\x36" > + "\x57\x72\xb5\xfd\xb5\x5d\xb8\x28" > + "\x0c\x04\x91\x14\x91\xe9\x37", > + .len = 31, > + .also_non_np = 1, > + .np = 2, > + .tap = { 16, 15 }, > + }, { > + .key = "\xa5\x28\x24\x34\x1a\x3c\xd8\xf7" > + "\x05\x91\x8f\xee\x85\x1f\x35\x7f" > + "\x80\x3d\xfc\x9b\x94\xf6\xfc\x9e" > + "\x19\x09\x00\xa9\x04\x31\x4f\x11", > + .klen = 32, > + .iv = "\xa1\xba\x49\x95\xff\x34\x6d\xb8" > + "\xcd\x87\x5d\x5e\xfd\xea\x85\xdb" > + "\x8a\x7b\x5e\xb2\x5d\x57\xdd\x62" > + "\xac\xa9\x8c\x41\x42\x94\x75\xb7", > + .ptext = "\x69\xb4\xe8\x8c\x37\xe8\x67\x82" > + "\xf1\xec\x5d\x04\xe5\x14\x91\x13" > + "\xdf\xf2\x87\x1b\x69\x81\x1d\x71" > + "\x70\x9e\x9c\x3b\xde\x49\x70\x11" > + "\xa0\xa3\xdb\x0d\x54\x4f\x66\x69" > + "\xd7\xdb\x80\xa7\x70\x92\x68\xce" > + "\x81\x04\x2c\xc6\xab\xae\xe5\x60" > + "\x15\xe9\x6f\xef\xaa\x8f\xa7\xa7" > + "\x63\x8f\xf2\xf0\x77\xf1\xa8\xea" > + "\xe1\xb7\x1f\x9e\xab\x9e\x4b\x3f" > + "\x07\x87\x5b\x6f\xcd\xa8\xaf\xb9" > + "\xfa\x70\x0b\x52\xb8\xa8\xa7\x9e" > + "\x07\x5f\xa6\x0e\xb3\x9b\x79\x13" > + "\x79\xc3\x3e\x8d\x1c\x2c\x68\xc8" > + "\x51\x1d\x3c\x7b\x7d\x79\x77\x2a" > + "\x56\x65\xc5\x54\x23\x28\xb0\x03", > + .ctext = "\xb1\x8b\xa0\x05\x77\xa8\x4d\x59" > + "\x1b\x8e\x21\xfc\x3a\x49\xfa\xd4" > + "\xeb\x36\xf3\xc4\xdf\xdc\xae\x67" > + "\x07\x3f\x70\x0e\xe9\x66\xf5\x0c" > + "\x30\x4d\x66\xc9\xa4\x2f\x73\x9c" > + "\x13\xc8\x49\x44\xcc\x0a\x90\x9d" > + "\x7c\xdd\x19\x3f\xea\x72\x8d\x58" > + "\xab\xe7\x09\x2c\xec\xb5\x44\xd2" > + "\xca\xa6\x2d\x7a\x5c\x9c\x2b\x15" > + "\xec\x2a\xa6\x69\x91\xf9\xf3\x13" > + "\xf7\x72\xc1\xc1\x40\xd5\xe1\x94" > + "\xf4\x29\xa1\x3e\x25\x02\xa8\x3e" > + "\x94\xc1\x91\x14\xa1\x14\xcb\xbe" > + "\x67\x4c\xb9\x38\xfe\xa7\xaa\x32" > + "\x29\x62\x0d\xb2\xf6\x3c\x58\x57" > + "\xc1\xd5\x5a\xbb\xd6\xa6\x2a\xe5", > + .len = 128, > + .also_non_np = 1, > + .np = 4, > + .tap = { 112, 7, 8, 1 }, > + }, { > + .key = "\xd3\x81\x72\x18\x23\xff\x6f\x4a" > + "\x25\x74\x29\x0d\x51\x8a\x0e\x13" > + "\xc1\x53\x5d\x30\x8d\xee\x75\x0d" > + "\x14\xd6\x69\xc9\x15\xa9\x0c\x60", > + .klen = 32, > + .iv = "\x65\x9b\xd4\xa8\x7d\x29\x1d\xf4" > + "\xc4\xd6\x9b\x6a\x28\xab\x64\xe2" > + "\x62\x81\x97\xc5\x81\xaa\xf9\x44" > + "\xc1\x72\x59\x82\xaf\x16\xc8\x2c", > + .ptext = "\xc7\x6b\x52\x6a\x10\xf0\xcc\x09" > + "\xc1\x12\x1d\x6d\x21\xa6\x78\xf5" > + "\x05\xa3\x69\x60\x91\x36\x98\x57" > + "\xba\x0c\x14\xcc\xf3\x2d\x73\x03" > + "\xc6\xb2\x5f\xc8\x16\x27\x37\x5d" > + "\xd0\x0b\x87\xb2\x50\x94\x7b\x58" > + "\x04\xf4\xe0\x7f\x6e\x57\x8e\xc9" > + "\x41\x84\xc1\xb1\x7e\x4b\x91\x12" > + "\x3a\x8b\x5d\x50\x82\x7b\xcb\xd9" > + "\x9a\xd9\x4e\x18\x06\x23\x9e\xd4" > + "\xa5\x20\x98\xef\xb5\xda\xe5\xc0" > + "\x8a\x6a\x83\x77\x15\x84\x1e\xae" > + "\x78\x94\x9d\xdf\xb7\xd1\xea\x67" > + "\xaa\xb0\x14\x15\xfa\x67\x21\x84" > + "\xd3\x41\x2a\xce\xba\x4b\x4a\xe8" > + "\x95\x62\xa9\x55\xf0\x80\xad\xbd" > + "\xab\xaf\xdd\x4f\xa5\x7c\x13\x36" > + "\xed\x5e\x4f\x72\xad\x4b\xf1\xd0" > + "\x88\x4e\xec\x2c\x88\x10\x5e\xea" > + "\x12\xc0\x16\x01\x29\xa3\xa0\x55" > + "\xaa\x68\xf3\xe9\x9d\x3b\x0d\x3b" > + "\x6d\xec\xf8\xa0\x2d\xf0\x90\x8d" > + "\x1c\xe2\x88\xd4\x24\x71\xf9\xb3" > + "\xc1\x9f\xc5\xd6\x76\x70\xc5\x2e" > + "\x9c\xac\xdb\x90\xbd\x83\x72\xba" > + "\x6e\xb5\xa5\x53\x83\xa9\xa5\xbf" > + "\x7d\x06\x0e\x3c\x2a\xd2\x04\xb5" > + "\x1e\x19\x38\x09\x16\xd2\x82\x1f" > + "\x75\x18\x56\xb8\x96\x0b\xa6\xf9" > + "\xcf\x62\xd9\x32\x5d\xa9\xd7\x1d" > + "\xec\xe4\xdf\x1b\xbe\xf1\x36\xee" > + "\xe3\x7b\xb5\x2f\xee\xf8\x53\x3d" > + "\x6a\xb7\x70\xa9\xfc\x9c\x57\x25" > + "\xf2\x89\x10\xd3\xb8\xa8\x8c\x30" > + "\xae\x23\x4f\x0e\x13\x66\x4f\xe1" > + "\xb6\xc0\xe4\xf8\xef\x93\xbd\x6e" > + "\x15\x85\x6b\xe3\x60\x81\x1d\x68" > + "\xd7\x31\x87\x89\x09\xab\xd5\x96" > + "\x1d\xf3\x6d\x67\x80\xca\x07\x31" > + "\x5d\xa7\xe4\xfb\x3e\xf2\x9b\x33" > + "\x52\x18\xc8\x30\xfe\x2d\xca\x1e" > + "\x79\x92\x7a\x60\x5c\xb6\x58\x87" > + "\xa4\x36\xa2\x67\x92\x8b\xa4\xb7" > + "\xf1\x86\xdf\xdc\xc0\x7e\x8f\x63" > + "\xd2\xa2\xdc\x78\xeb\x4f\xd8\x96" > + "\x47\xca\xb8\x91\xf9\xf7\x94\x21" > + "\x5f\x9a\x9f\x5b\xb8\x40\x41\x4b" > + "\x66\x69\x6a\x72\xd0\xcb\x70\xb7" > + "\x93\xb5\x37\x96\x05\x37\x4f\xe5" > + "\x8c\xa7\x5a\x4e\x8b\xb7\x84\xea" > + "\xc7\xfc\x19\x6e\x1f\x5a\xa1\xac" > + "\x18\x7d\x52\x3b\xb3\x34\x62\x99" > + "\xe4\x9e\x31\x04\x3f\xc0\x8d\x84" > + "\x17\x7c\x25\x48\x52\x67\x11\x27" > + "\x67\xbb\x5a\x85\xca\x56\xb2\x5c" > + "\xe6\xec\xd5\x96\x3d\x15\xfc\xfb" > + "\x22\x25\xf4\x13\xe5\x93\x4b\x9a" > + "\x77\xf1\x52\x18\xfa\x16\x5e\x49" > + "\x03\x45\xa8\x08\xfa\xb3\x41\x92" > + "\x79\x50\x33\xca\xd0\xd7\x42\x55" > + "\xc3\x9a\x0c\x4e\xd9\xa4\x3c\x86" > + "\x80\x9f\x53\xd1\xa4\x2e\xd1\xbc" > + "\xf1\x54\x6e\x93\xa4\x65\x99\x8e" > + "\xdf\x29\xc0\x64\x63\x07\xbb\xea", > + .ctext = "\xe0\x33\xf6\xe0\xb4\xa5\xdd\x2b" > + "\xdd\xce\xfc\x12\x1e\xfc\x2d\xf2" > + "\x8b\xc7\xeb\xc1\xc4\x2a\xe8\x44" > + "\x0f\x3d\x97\x19\x2e\x6d\xa2\x38" > + "\x9d\xa6\xaa\xe1\x96\xb9\x08\xe8" > + "\x0b\x70\x48\x5c\xed\xb5\x9b\xcb" > + "\x8b\x40\x88\x7e\x69\x73\xf7\x16" > + "\x71\xbb\x5b\xfc\xa3\x47\x5d\xa6" > + "\xae\x3a\x64\xc4\xe7\xb8\xa8\xe7" > + "\xb1\x32\x19\xdb\xe3\x01\xb8\xf0" > + "\xa4\x86\xb4\x4c\xc2\xde\x5c\xd2" > + "\x6c\x77\xd2\xe8\x18\xb7\x0a\xc9" > + "\x3d\x53\xb5\xc4\x5c\xf0\x8c\x06" > + "\xdc\x90\xe0\x74\x47\x1b\x0b\xf6" > + "\xd2\x71\x6b\xc4\xf1\x97\x00\x2d" > + "\x63\x57\x44\x1f\x8c\xf4\xe6\x9b" > + "\xe0\x7a\xdd\xec\x32\x73\x42\x32" > + "\x7f\x35\x67\x60\x0d\xcf\x10\x52" > + "\x61\x22\x53\x8d\x8e\xbb\x33\x76" > + "\x59\xd9\x10\xce\xdf\xef\xc0\x41" > + "\xd5\x33\x29\x6a\xda\x46\xa4\x51" > + "\xf0\x99\x3d\x96\x31\xdd\xb5\xcb" > + "\x3e\x2a\x1f\xc7\x5c\x79\xd3\xc5" > + "\x20\xa1\xb1\x39\x1b\xc6\x0a\x70" > + "\x26\x39\x95\x07\xad\x7a\xc9\x69" > + "\xfe\x81\xc7\x88\x08\x38\xaf\xad" > + "\x9e\x8d\xfb\xe8\x24\x0d\x22\xb8" > + "\x0e\xed\xbe\x37\x53\x7c\xa6\xc6" > + "\x78\x62\xec\xa3\x59\xd9\xc6\x9d" > + "\xb8\x0e\x69\x77\x84\x2d\x6a\x4c" > + "\xc5\xd9\xb2\xa0\x2b\xa8\x80\xcc" > + "\xe9\x1e\x9c\x5a\xc4\xa1\xb2\x37" > + "\x06\x9b\x30\x32\x67\xf7\xe7\xd2" > + "\x42\xc7\xdf\x4e\xd4\xcb\xa0\x12" > + "\x94\xa1\x34\x85\x93\x50\x4b\x0a" > + "\x3c\x7d\x49\x25\x01\x41\x6b\x96" > + "\xa9\x12\xbb\x0b\xc0\xd7\xd0\x93" > + "\x1f\x70\x38\xb8\x21\xee\xf6\xa7" > + "\xee\xeb\xe7\x81\xa4\x13\xb4\x87" > + "\xfa\xc1\xb0\xb5\x37\x8b\x74\xa2" > + "\x4e\xc7\xc2\xad\x3d\x62\x3f\xf8" > + "\x34\x42\xe5\xae\x45\x13\x63\xfe" > + "\xfc\x2a\x17\x46\x61\xa9\xd3\x1c" > + "\x4c\xaf\xf0\x09\x62\x26\x66\x1e" > + "\x74\xcf\xd6\x68\x3d\x7d\xd8\xb7" > + "\xe7\xe6\xf8\xf0\x08\x20\xf7\x47" > + "\x1c\x52\xaa\x0f\x3e\x21\xa3\xf2" > + "\xbf\x2f\x95\x16\xa8\xc8\xc8\x8c" > + "\x99\x0f\x5d\xfb\xfa\x2b\x58\x8a" > + "\x7e\xd6\x74\x02\x60\xf0\xd0\x5b" > + "\x65\xa8\xac\xea\x8d\x68\x46\x34" > + "\x26\x9d\x4f\xb1\x9a\x8e\xc0\x1a" > + "\xf1\xed\xc6\x7a\x83\xfd\x8a\x57" > + "\xf2\xe6\xe4\xba\xfc\xc6\x3c\xad" > + "\x5b\x19\x50\x2f\x3a\xcc\x06\x46" > + "\x04\x51\x3f\x91\x97\xf0\xd2\x07" > + "\xe7\x93\x89\x7e\xb5\x32\x0f\x03" > + "\xe5\x58\x9e\x74\x72\xeb\xc2\x38" > + "\x00\x0c\x91\x72\x69\xed\x7d\x6d" > + "\xc8\x71\xf0\xec\xff\x80\xd9\x1c" > + "\x9e\xd2\xfa\x15\xfc\x6c\x4e\xbc" > + "\xb1\xa6\xbd\xbd\x70\x40\xca\x20" > + "\xb8\x78\xd2\xa3\xc6\xf3\x79\x9c" > + "\xc7\x27\xe1\x6a\x29\xad\xa4\x03", > + .len = 512, > + } > +}; > + > /* > * CTS (Cipher Text Stealing) mode tests > */ > -- > 2.19.1.1215.g8438c0b245-goog >
diff --git a/crypto/Kconfig b/crypto/Kconfig index eaeb8a986b7d..b6376d5d973e 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -501,6 +501,29 @@ config CRYPTO_NHPOLY1305 select CRYPTO_HASH select CRYPTO_POLY1305 +config CRYPTO_ADIANTUM + tristate "Adiantum support" + select CRYPTO_CHACHA20 + select CRYPTO_POLY1305 + select CRYPTO_NHPOLY1305 + help + Adiantum is a tweakable, length-preserving encryption mode + designed for fast and secure disk encryption, especially on + CPUs without dedicated crypto instructions. It encrypts + each sector using the XChaCha12 stream cipher, two passes of + an ε-almost-∆-universal hash function, and an invocation of + the AES-256 block cipher on a single 16-byte block. On CPUs + without AES instructions, Adiantum is much faster than + AES-XTS. + + Adiantum's security is provably reducible to that of its + underlying stream and block ciphers, subject to a security + bound. Unlike XTS, Adiantum is a true wide-block encryption + mode, so it actually provides an even stronger notion of + security than XTS, subject to the security bound. + + If unsure, say N. + comment "Hash modes" config CRYPTO_CMAC diff --git a/crypto/Makefile b/crypto/Makefile index c3310c85f09f..5e789dc2d4fd 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_XTS) += xts.o obj-$(CONFIG_CRYPTO_CTR) += ctr.o obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o +obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o obj-$(CONFIG_CRYPTO_NHPOLY1305) += nhpoly1305.o obj-$(CONFIG_CRYPTO_GCM) += gcm.o obj-$(CONFIG_CRYPTO_CCM) += ccm.o diff --git a/crypto/adiantum.c b/crypto/adiantum.c new file mode 100644 index 000000000000..2dfcf12fd452 --- /dev/null +++ b/crypto/adiantum.c @@ -0,0 +1,658 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Adiantum length-preserving encryption mode + * + * Copyright 2018 Google LLC + */ + +/* + * Adiantum is a tweakable, length-preserving encryption mode designed for fast + * and secure disk encryption, especially on CPUs without dedicated crypto + * instructions. Adiantum encrypts each sector using the XChaCha12 stream + * cipher, two passes of an ε-almost-∆-universal (εA∆U) hash function based on + * NH and Poly1305, and an invocation of the AES-256 block cipher on a single + * 16-byte block. See the paper for details: + * + * Adiantum: length-preserving encryption for entry-level processors + * (https://eprint.iacr.org/2018/720.pdf) + * + * For flexibility, this implementation also allows other ciphers: + * + * - 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 εA∆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 εA∆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 εA∆U hash + * functions could be added here. + */ + +#include <crypto/b128ops.h> +#include <crypto/chacha.h> +#include <crypto/internal/hash.h> +#include <crypto/internal/skcipher.h> +#include <crypto/nhpoly1305.h> +#include <crypto/scatterwalk.h> +#include <linux/module.h> + +#include "internal.h" + +/* + * Size of right-hand block of input data, in bytes; also the size of the block + * cipher's block size and the hash function's output. + */ +#define BLOCKCIPHER_BLOCK_SIZE 16 + +/* Size of the block cipher key (K_E) in bytes */ +#define BLOCKCIPHER_KEY_SIZE 32 + +/* Size of the hash key (K_H) in bytes */ +#define HASH_KEY_SIZE (POLY1305_BLOCK_SIZE + NHPOLY1305_KEY_SIZE) + +/* + * The specification allows variable-length tweaks, but Linux's crypto API + * currently only allows algorithms to support a single length. The "natural" + * tweak length for Adiantum is 16, since that fits into one Poly1305 block for + * the best performance. But longer tweaks are useful for fscrypt, to avoid + * needing to derive per-file keys. So instead we use two blocks, or 32 bytes. + */ +#define TWEAK_SIZE 32 + +struct adiantum_instance_ctx { + struct crypto_skcipher_spawn streamcipher_spawn; + struct crypto_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_key header_hash_key; +}; + +struct adiantum_request_ctx { + + /* + * Buffer for right-hand block 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; + + bool enc; /* true if encrypting, false if decrypting */ + + /* + * The result of the Poly1305 εA∆U hash function applied to + * (message length, tweak). + */ + le128 header_hash; + + /* Sub-requests, must be last */ + union { + struct shash_desc hash_desc; + struct skcipher_request streamcipher_req; + } u; +}; + +/* + * Given the XChaCha stream key K_S, derive the block cipher key K_E and the + * hash key K_H as follows: + * + * K_E || K_H || ... = XChaCha(key=K_S, nonce=1||0^191) + * + * Note that this denotes using bits from the XChaCha keystream, which here we + * get indirectly by encrypting a buffer containing all 0's. + */ +static int adiantum_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); + struct { + u8 iv[XCHACHA_IV_SIZE]; + u8 derived_keys[BLOCKCIPHER_KEY_SIZE + HASH_KEY_SIZE]; + struct scatterlist sg; + struct crypto_wait wait; + struct skcipher_request req; /* must be last */ + } *data; + u8 *keyp; + int err; + + /* Set the stream cipher key (K_S) */ + crypto_skcipher_clear_flags(tctx->streamcipher, CRYPTO_TFM_REQ_MASK); + crypto_skcipher_set_flags(tctx->streamcipher, + crypto_skcipher_get_flags(tfm) & + CRYPTO_TFM_REQ_MASK); + err = crypto_skcipher_setkey(tctx->streamcipher, key, keylen); + crypto_skcipher_set_flags(tfm, + crypto_skcipher_get_flags(tctx->streamcipher) & + CRYPTO_TFM_RES_MASK); + if (err) + return err; + + /* Derive the subkeys */ + data = kzalloc(sizeof(*data) + + crypto_skcipher_reqsize(tctx->streamcipher), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->iv[0] = 1; + sg_init_one(&data->sg, data->derived_keys, sizeof(data->derived_keys)); + crypto_init_wait(&data->wait); + skcipher_request_set_tfm(&data->req, tctx->streamcipher); + skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP | + CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &data->wait); + skcipher_request_set_crypt(&data->req, &data->sg, &data->sg, + sizeof(data->derived_keys), data->iv); + err = crypto_wait_req(crypto_skcipher_encrypt(&data->req), &data->wait); + if (err) + goto out; + keyp = data->derived_keys; + + /* Set the block cipher key (K_E) */ + crypto_cipher_clear_flags(tctx->blockcipher, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(tctx->blockcipher, + crypto_skcipher_get_flags(tfm) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(tctx->blockcipher, keyp, + BLOCKCIPHER_KEY_SIZE); + crypto_skcipher_set_flags(tfm, + crypto_cipher_get_flags(tctx->blockcipher) & + CRYPTO_TFM_RES_MASK); + if (err) + goto out; + keyp += BLOCKCIPHER_KEY_SIZE; + + /* 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); + crypto_skcipher_set_flags(tfm, crypto_shash_get_flags(tctx->hash) & + CRYPTO_TFM_RES_MASK); + keyp += NHPOLY1305_KEY_SIZE; + WARN_ON(keyp != &data->derived_keys[ARRAY_SIZE(data->derived_keys)]); +out: + kzfree(data); + return err; +} + +/* Addition in Z/(2^{128}Z) */ +static inline void le128_add(le128 *r, const le128 *v1, const le128 *v2) +{ + u64 x = le64_to_cpu(v1->b); + u64 y = le64_to_cpu(v2->b); + + r->b = cpu_to_le64(x + y); + r->a = cpu_to_le64(le64_to_cpu(v1->a) + le64_to_cpu(v2->a) + + (x + y < x)); +} + +/* Subtraction in Z/(2^{128}Z) */ +static inline void le128_sub(le128 *r, const le128 *v1, const le128 *v2) +{ + u64 x = le64_to_cpu(v1->b); + u64 y = le64_to_cpu(v2->b); + + r->b = cpu_to_le64(x - y); + r->a = cpu_to_le64(le64_to_cpu(v1->a) - le64_to_cpu(v2->a) - + (x - y > x)); +} + +/* + * Apply the Poly1305 εA∆U hash function to (message length, tweak) and save the + * result to rctx->header_hash. + * + * This value is reused in both the first and second hash steps. Specifically, + * it's added to the result of an independently keyed εA∆U hash function (for + * equal length inputs only) taken over the message. This gives the overall + * Adiantum hash of the (tweak, message) pair. + */ +static void adiantum_hash_header(struct skcipher_request *req) +{ + 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; + __le64 padding; + } header = { + .message_bits = cpu_to_le64((u64)bulk_len * 8) + }; + struct poly1305_state state; + + poly1305_core_init(&state); + + BUILD_BUG_ON(sizeof(header) % POLY1305_BLOCK_SIZE != 0); + poly1305_core_blocks(&state, &tctx->header_hash_key, + &header, sizeof(header) / POLY1305_BLOCK_SIZE); + + BUILD_BUG_ON(TWEAK_SIZE % POLY1305_BLOCK_SIZE != 0); + poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv, + TWEAK_SIZE / POLY1305_BLOCK_SIZE); + + poly1305_core_emit(&state, &rctx->header_hash); +} + +/* Hash the left-hand block (the "bulk") of the message using NHPoly1305 */ +static int adiantum_hash_message(struct skcipher_request *req, + struct scatterlist *sgl, le128 *digest) +{ + 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 shash_desc *hash_desc = &rctx->u.hash_desc; + struct sg_mapping_iter miter; + unsigned int i, n; + int err; + + hash_desc->tfm = tctx->hash; + hash_desc->flags = 0; + + err = crypto_shash_init(hash_desc); + if (err) + return err; + + sg_miter_start(&miter, sgl, sg_nents(sgl), + 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; + + return crypto_shash_final(hash_desc, (u8 *)digest); +} + +/* Continue Adiantum encryption/decryption after the stream cipher step */ +static int adiantum_finish(struct skcipher_request *req) +{ + 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; + le128 digest; + int err; + + /* 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); + + /* + * 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) + */ + err = adiantum_hash_message(req, req->dst, &digest); + if (err) + return err; + le128_add(&digest, &digest, &rctx->header_hash); + le128_sub(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest); + scatterwalk_map_and_copy(&rctx->rbuf.bignum, req->dst, + bulk_len, BLOCKCIPHER_BLOCK_SIZE, 1); + return 0; +} + +static void adiantum_streamcipher_done(struct crypto_async_request *areq, + int err) +{ + struct skcipher_request *req = areq->data; + + if (!err) + err = adiantum_finish(req); + + skcipher_request_complete(req, err); +} + +static int adiantum_crypt(struct skcipher_request *req, bool enc) +{ + 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; + 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); + err = adiantum_hash_message(req, req->src, &digest); + if (err) + return err; + le128_add(&digest, &digest, &rctx->header_hash); + scatterwalk_map_and_copy(&rctx->rbuf.bignum, req->src, + bulk_len, BLOCKCIPHER_BLOCK_SIZE, 0); + le128_add(&rctx->rbuf.bignum, &rctx->rbuf.bignum, &digest); + + /* 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); + + /* 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; + + /* + * XChaCha needs to be done on all the data except the last 16 bytes; + * for disk encryption that usually means 4080 or 496 bytes. But ChaCha + * implementations tend to be most efficient when passed a whole number + * of 64-byte ChaCha blocks, or sometimes even a multiple of 256 bytes. + * And here it doesn't matter whether the last 16 bytes are written to, + * as the second hash step will overwrite them. Thus, round the XChaCha + * length up to the next 64-byte boundary if possible. + */ + stream_len = bulk_len; + if (round_up(stream_len, CHACHA_BLOCK_SIZE) <= req->cryptlen) + stream_len = round_up(stream_len, CHACHA_BLOCK_SIZE); + + 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); + 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); +} + +static int adiantum_encrypt(struct skcipher_request *req) +{ + return adiantum_crypt(req, true); +} + +static int adiantum_decrypt(struct skcipher_request *req) +{ + return adiantum_crypt(req, false); +} + +static int adiantum_init_tfm(struct crypto_skcipher *tfm) +{ + struct skcipher_instance *inst = skcipher_alg_instance(tfm); + struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst); + 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); + if (IS_ERR(streamcipher)) + return PTR_ERR(streamcipher); + + blockcipher = crypto_spawn_cipher(&ictx->blockcipher_spawn); + if (IS_ERR(blockcipher)) { + err = PTR_ERR(blockcipher); + 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(FIELD_SIZEOF(struct adiantum_request_ctx, + u.hash_desc) + + crypto_shash_descsize(hash), + FIELD_SIZEOF(struct adiantum_request_ctx, + u.streamcipher_req) + + crypto_skcipher_reqsize(streamcipher)); + + crypto_skcipher_set_reqsize(tfm, + offsetof(struct adiantum_request_ctx, u) + + subreq_size); + return 0; + +err_free_blockcipher: + crypto_free_cipher(blockcipher); +err_free_streamcipher: + crypto_free_skcipher(streamcipher); + return err; +} + +static void adiantum_exit_tfm(struct crypto_skcipher *tfm) +{ + struct adiantum_tfm_ctx *tctx = crypto_skcipher_ctx(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) +{ + struct adiantum_instance_ctx *ictx = skcipher_instance_ctx(inst); + + crypto_drop_skcipher(&ictx->streamcipher_spawn); + crypto_drop_spawn(&ictx->blockcipher_spawn); + crypto_drop_shash(&ictx->hash_spawn); + kfree(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 *streamcipher_alg, + struct crypto_alg *blockcipher_alg, + struct shash_alg *hash_alg) +{ + if (strcmp(streamcipher_alg->base.cra_name, "xchacha12") != 0 && + strcmp(streamcipher_alg->base.cra_name, "xchacha20") != 0) + return false; + + if (blockcipher_alg->cra_cipher.cia_min_keysize > BLOCKCIPHER_KEY_SIZE || + blockcipher_alg->cra_cipher.cia_max_keysize < BLOCKCIPHER_KEY_SIZE) + return false; + 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) +{ + struct crypto_attr_type *algt; + const char *streamcipher_name; + const char *blockcipher_name; + const char *nhpoly1305_name; + struct skcipher_instance *inst; + struct adiantum_instance_ctx *ictx; + struct skcipher_alg *streamcipher_alg; + struct crypto_alg *blockcipher_alg; + struct crypto_alg *_hash_alg; + struct shash_alg *hash_alg; + int err; + + algt = crypto_get_attr_type(tb); + if (IS_ERR(algt)) + return PTR_ERR(algt); + + if ((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask) + return -EINVAL; + + streamcipher_name = crypto_attr_alg_name(tb[1]); + if (IS_ERR(streamcipher_name)) + return PTR_ERR(streamcipher_name); + + blockcipher_name = crypto_attr_alg_name(tb[2]); + if (IS_ERR(blockcipher_name)) + return PTR_ERR(blockcipher_name); + + nhpoly1305_name = crypto_attr_alg_name(tb[3]); + if (nhpoly1305_name == ERR_PTR(-ENOENT)) + nhpoly1305_name = "nhpoly1305"; + if (IS_ERR(nhpoly1305_name)) + return PTR_ERR(nhpoly1305_name); + + inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); + if (!inst) + return -ENOMEM; + ictx = skcipher_instance_ctx(inst); + + /* Stream cipher, e.g. "xchacha12" */ + err = crypto_grab_skcipher(&ictx->streamcipher_spawn, streamcipher_name, + 0, crypto_requires_sync(algt->type, + algt->mask)); + if (err) + goto out_free_inst; + streamcipher_alg = crypto_spawn_skcipher_alg(&ictx->streamcipher_spawn); + + /* Block cipher, e.g. "aes" */ + err = crypto_grab_spawn(&ictx->blockcipher_spawn, blockcipher_name, + CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_MASK); + if (err) + goto out_drop_streamcipher; + blockcipher_alg = ictx->blockcipher_spawn.alg; + + /* NHPoly1305 εA∆U hash function */ + _hash_alg = crypto_alg_mod_lookup(nhpoly1305_name, + CRYPTO_ALG_TYPE_SHASH, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(_hash_alg)) { + err = PTR_ERR(_hash_alg); + goto out_drop_blockcipher; + } + hash_alg = __crypto_shash_alg(_hash_alg); + err = crypto_init_shash_spawn(&ictx->hash_spawn, hash_alg, + skcipher_crypto_instance(inst)); + if (err) { + crypto_mod_put(_hash_alg); + goto out_drop_blockcipher; + } + + /* Check the set of algorithms */ + if (!adiantum_supported_algorithms(streamcipher_alg, blockcipher_alg, + hash_alg)) { + pr_warn("Unsupported Adiantum instantiation: (%s,%s,%s)\n", + streamcipher_alg->base.cra_name, + blockcipher_alg->cra_name, hash_alg->base.cra_name); + err = -EINVAL; + goto out_drop_hash; + } + + /* Instance fields */ + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, + "adiantum(%s,%s)", streamcipher_alg->base.cra_name, + blockcipher_alg->cra_name) >= CRYPTO_MAX_ALG_NAME) + goto out_drop_hash; + 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) + goto out_drop_hash; + + inst->alg.base.cra_blocksize = BLOCKCIPHER_BLOCK_SIZE; + inst->alg.base.cra_ctxsize = sizeof(struct adiantum_tfm_ctx); + inst->alg.base.cra_alignmask = streamcipher_alg->base.cra_alignmask | + hash_alg->base.cra_alignmask; + /* + * 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. + */ + inst->alg.base.cra_priority = (4 * streamcipher_alg->base.cra_priority + + 2 * hash_alg->base.cra_priority + + blockcipher_alg->cra_priority) / 7; + + inst->alg.setkey = adiantum_setkey; + inst->alg.encrypt = adiantum_encrypt; + inst->alg.decrypt = adiantum_decrypt; + inst->alg.init = adiantum_init_tfm; + inst->alg.exit = adiantum_exit_tfm; + inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(streamcipher_alg); + inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(streamcipher_alg); + inst->alg.ivsize = TWEAK_SIZE; + + inst->free = adiantum_free_instance; + + err = skcipher_register_instance(tmpl, inst); + if (err) + goto out_drop_hash; + + return 0; + +out_drop_hash: + crypto_drop_shash(&ictx->hash_spawn); +out_drop_blockcipher: + crypto_drop_spawn(&ictx->blockcipher_spawn); +out_drop_streamcipher: + crypto_drop_skcipher(&ictx->streamcipher_spawn); +out_free_inst: + kfree(inst); + return err; +} + +/* adiantum(streamcipher_name, blockcipher_name [, nhpoly1305_name]) */ +static struct crypto_template adiantum_tmpl = { + .name = "adiantum", + .create = adiantum_create, + .module = THIS_MODULE, +}; + +static int __init adiantum_module_init(void) +{ + return crypto_register_template(&adiantum_tmpl); +} + +static void __exit adiantum_module_exit(void) +{ + crypto_unregister_template(&adiantum_tmpl); +} + +module_init(adiantum_module_init); +module_exit(adiantum_module_exit); + +MODULE_DESCRIPTION("Adiantum length-preserving encryption mode"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>"); +MODULE_ALIAS_CRYPTO("adiantum"); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 5fb120474902..0590a9204562 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -2320,6 +2320,18 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_cipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, speed_template_16); break; + + case 219: + test_cipher_speed("adiantum(xchacha12,aes)", ENCRYPT, sec, NULL, + 0, speed_template_32); + test_cipher_speed("adiantum(xchacha12,aes)", DECRYPT, sec, NULL, + 0, speed_template_32); + test_cipher_speed("adiantum(xchacha20,aes)", ENCRYPT, sec, NULL, + 0, speed_template_32); + test_cipher_speed("adiantum(xchacha20,aes)", DECRYPT, sec, NULL, + 0, speed_template_32); + break; + case 300: if (alg) { test_hash_speed(alg, sec, generic_hash_speed_template); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 665911c24786..0f684a414acb 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2404,6 +2404,18 @@ static int alg_test_null(const struct alg_test_desc *desc, /* Please keep this list sorted by algorithm name. */ static const struct alg_test_desc alg_test_descs[] = { { + .alg = "adiantum(xchacha12,aes)", + .test = alg_test_skcipher, + .suite = { + .cipher = __VECS(adiantum_xchacha12_aes_tv_template) + }, + }, { + .alg = "adiantum(xchacha20,aes)", + .test = alg_test_skcipher, + .suite = { + .cipher = __VECS(adiantum_xchacha20_aes_tv_template) + }, + }, { .alg = "aegis128", .test = alg_test_aead, .suite = { diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 50ea1f2705c7..e7e56a8febbc 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -33381,6 +33381,467 @@ static const struct cipher_testvec xchacha12_tv_template[] = { }, }; +/* Adiantum test vectors from https://github.com/google/adiantum */ +static const struct cipher_testvec adiantum_xchacha12_aes_tv_template[] = { + { + .key = "\x9e\xeb\xb2\x49\x3c\x1c\xf5\xf4" + "\x6a\x99\xc2\xc4\xdf\xb1\xf4\xdd" + "\x75\x20\x57\xea\x2c\x4f\xcd\xb2" + "\xa5\x3d\x7b\x49\x1e\xab\xfd\x0f", + .klen = 32, + .iv = "\xdf\x63\xd4\xab\xd2\x49\xf3\xd8" + "\x33\x81\x37\x60\x7d\xfa\x73\x08" + "\xd8\x49\x6d\x80\xe8\x2f\x62\x54" + "\xeb\x0e\xa9\x39\x5b\x45\x7f\x8a", + .ptext = "\x67\xc9\xf2\x30\x84\x41\x8e\x43" + "\xfb\xf3\xb3\x3e\x79\x36\x7f\xe8", + .ctext = "\x6d\x32\x86\x18\x67\x86\x0f\x3f" + "\x96\x7c\x9d\x28\x0d\x53\xec\x9f", + .len = 16, + .also_non_np = 1, + .np = 2, + .tap = { 14, 2 }, + }, { + .key = "\x36\x2b\x57\x97\xf8\x5d\xcd\x99" + "\x5f\x1a\x5a\x44\x1d\x92\x0f\x27" + "\xcc\x16\xd7\x2b\x85\x63\x99\xd3" + "\xba\x96\xa1\xdb\xd2\x60\x68\xda", + .klen = 32, + .iv = "\xef\x58\x69\xb1\x2c\x5e\x9a\x47" + "\x24\xc1\xb1\x69\xe1\x12\x93\x8f" + "\x43\x3d\x6d\x00\xdb\x5e\xd8\xd9" + "\x12\x9a\xfe\xd9\xff\x2d\xaa\xc4", + .ptext = "\x5e\xa8\x68\x19\x85\x98\x12\x23" + "\x26\x0a\xcc\xdb\x0a\x04\xb9\xdf" + "\x4d\xb3\x48\x7b\xb0\xe3\xc8\x19" + "\x43\x5a\x46\x06\x94\x2d\xf2", + .ctext = "\xc7\xc6\xf1\x73\x8f\xc4\xff\x4a" + "\x39\xbe\x78\xbe\x8d\x28\xc8\x89" + "\x46\x63\xe7\x0c\x7d\x87\xe8\x4e" + "\xc9\x18\x7b\xbe\x18\x60\x50", + .len = 31, + }, { + .key = "\xa5\x28\x24\x34\x1a\x3c\xd8\xf7" + "\x05\x91\x8f\xee\x85\x1f\x35\x7f" + "\x80\x3d\xfc\x9b\x94\xf6\xfc\x9e" + "\x19\x09\x00\xa9\x04\x31\x4f\x11", + .klen = 32, + .iv = "\xa1\xba\x49\x95\xff\x34\x6d\xb8" + "\xcd\x87\x5d\x5e\xfd\xea\x85\xdb" + "\x8a\x7b\x5e\xb2\x5d\x57\xdd\x62" + "\xac\xa9\x8c\x41\x42\x94\x75\xb7", + .ptext = "\x69\xb4\xe8\x8c\x37\xe8\x67\x82" + "\xf1\xec\x5d\x04\xe5\x14\x91\x13" + "\xdf\xf2\x87\x1b\x69\x81\x1d\x71" + "\x70\x9e\x9c\x3b\xde\x49\x70\x11" + "\xa0\xa3\xdb\x0d\x54\x4f\x66\x69" + "\xd7\xdb\x80\xa7\x70\x92\x68\xce" + "\x81\x04\x2c\xc6\xab\xae\xe5\x60" + "\x15\xe9\x6f\xef\xaa\x8f\xa7\xa7" + "\x63\x8f\xf2\xf0\x77\xf1\xa8\xea" + "\xe1\xb7\x1f\x9e\xab\x9e\x4b\x3f" + "\x07\x87\x5b\x6f\xcd\xa8\xaf\xb9" + "\xfa\x70\x0b\x52\xb8\xa8\xa7\x9e" + "\x07\x5f\xa6\x0e\xb3\x9b\x79\x13" + "\x79\xc3\x3e\x8d\x1c\x2c\x68\xc8" + "\x51\x1d\x3c\x7b\x7d\x79\x77\x2a" + "\x56\x65\xc5\x54\x23\x28\xb0\x03", + .ctext = "\x9e\x16\xab\xed\x4b\xa7\x42\x5a" + "\xc6\xfb\x4e\x76\xff\xbe\x03\xa0" + "\x0f\xe3\xad\xba\xe4\x98\x2b\x0e" + "\x21\x48\xa0\xb8\x65\x48\x27\x48" + "\x84\x54\x54\xb2\x9a\x94\x7b\xe6" + "\x4b\x29\xe9\xcf\x05\x91\x80\x1a" + "\x3a\xf3\x41\x96\x85\x1d\x9f\x74" + "\x51\x56\x63\xfa\x7c\x28\x85\x49" + "\xf7\x2f\xf9\xf2\x18\x46\xf5\x33" + "\x80\xa3\x3c\xce\xb2\x57\x93\xf5" + "\xae\xbd\xa9\xf5\x7b\x30\xc4\x93" + "\x66\xe0\x30\x77\x16\xe4\xa0\x31" + "\xba\x70\xbc\x68\x13\xf5\xb0\x9a" + "\xc1\xfc\x7e\xfe\x55\x80\x5c\x48" + "\x74\xa6\xaa\xa3\xac\xdc\xc2\xf5" + "\x8d\xde\x34\x86\x78\x60\x75\x8d", + .len = 128, + .also_non_np = 1, + .np = 4, + .tap = { 104, 16, 4, 4 }, + }, { + .key = "\xd3\x81\x72\x18\x23\xff\x6f\x4a" + "\x25\x74\x29\x0d\x51\x8a\x0e\x13" + "\xc1\x53\x5d\x30\x8d\xee\x75\x0d" + "\x14\xd6\x69\xc9\x15\xa9\x0c\x60", + .klen = 32, + .iv = "\x65\x9b\xd4\xa8\x7d\x29\x1d\xf4" + "\xc4\xd6\x9b\x6a\x28\xab\x64\xe2" + "\x62\x81\x97\xc5\x81\xaa\xf9\x44" + "\xc1\x72\x59\x82\xaf\x16\xc8\x2c", + .ptext = "\xc7\x6b\x52\x6a\x10\xf0\xcc\x09" + "\xc1\x12\x1d\x6d\x21\xa6\x78\xf5" + "\x05\xa3\x69\x60\x91\x36\x98\x57" + "\xba\x0c\x14\xcc\xf3\x2d\x73\x03" + "\xc6\xb2\x5f\xc8\x16\x27\x37\x5d" + "\xd0\x0b\x87\xb2\x50\x94\x7b\x58" + "\x04\xf4\xe0\x7f\x6e\x57\x8e\xc9" + "\x41\x84\xc1\xb1\x7e\x4b\x91\x12" + "\x3a\x8b\x5d\x50\x82\x7b\xcb\xd9" + "\x9a\xd9\x4e\x18\x06\x23\x9e\xd4" + "\xa5\x20\x98\xef\xb5\xda\xe5\xc0" + "\x8a\x6a\x83\x77\x15\x84\x1e\xae" + "\x78\x94\x9d\xdf\xb7\xd1\xea\x67" + "\xaa\xb0\x14\x15\xfa\x67\x21\x84" + "\xd3\x41\x2a\xce\xba\x4b\x4a\xe8" + "\x95\x62\xa9\x55\xf0\x80\xad\xbd" + "\xab\xaf\xdd\x4f\xa5\x7c\x13\x36" + "\xed\x5e\x4f\x72\xad\x4b\xf1\xd0" + "\x88\x4e\xec\x2c\x88\x10\x5e\xea" + "\x12\xc0\x16\x01\x29\xa3\xa0\x55" + "\xaa\x68\xf3\xe9\x9d\x3b\x0d\x3b" + "\x6d\xec\xf8\xa0\x2d\xf0\x90\x8d" + "\x1c\xe2\x88\xd4\x24\x71\xf9\xb3" + "\xc1\x9f\xc5\xd6\x76\x70\xc5\x2e" + "\x9c\xac\xdb\x90\xbd\x83\x72\xba" + "\x6e\xb5\xa5\x53\x83\xa9\xa5\xbf" + "\x7d\x06\x0e\x3c\x2a\xd2\x04\xb5" + "\x1e\x19\x38\x09\x16\xd2\x82\x1f" + "\x75\x18\x56\xb8\x96\x0b\xa6\xf9" + "\xcf\x62\xd9\x32\x5d\xa9\xd7\x1d" + "\xec\xe4\xdf\x1b\xbe\xf1\x36\xee" + "\xe3\x7b\xb5\x2f\xee\xf8\x53\x3d" + "\x6a\xb7\x70\xa9\xfc\x9c\x57\x25" + "\xf2\x89\x10\xd3\xb8\xa8\x8c\x30" + "\xae\x23\x4f\x0e\x13\x66\x4f\xe1" + "\xb6\xc0\xe4\xf8\xef\x93\xbd\x6e" + "\x15\x85\x6b\xe3\x60\x81\x1d\x68" + "\xd7\x31\x87\x89\x09\xab\xd5\x96" + "\x1d\xf3\x6d\x67\x80\xca\x07\x31" + "\x5d\xa7\xe4\xfb\x3e\xf2\x9b\x33" + "\x52\x18\xc8\x30\xfe\x2d\xca\x1e" + "\x79\x92\x7a\x60\x5c\xb6\x58\x87" + "\xa4\x36\xa2\x67\x92\x8b\xa4\xb7" + "\xf1\x86\xdf\xdc\xc0\x7e\x8f\x63" + "\xd2\xa2\xdc\x78\xeb\x4f\xd8\x96" + "\x47\xca\xb8\x91\xf9\xf7\x94\x21" + "\x5f\x9a\x9f\x5b\xb8\x40\x41\x4b" + "\x66\x69\x6a\x72\xd0\xcb\x70\xb7" + "\x93\xb5\x37\x96\x05\x37\x4f\xe5" + "\x8c\xa7\x5a\x4e\x8b\xb7\x84\xea" + "\xc7\xfc\x19\x6e\x1f\x5a\xa1\xac" + "\x18\x7d\x52\x3b\xb3\x34\x62\x99" + "\xe4\x9e\x31\x04\x3f\xc0\x8d\x84" + "\x17\x7c\x25\x48\x52\x67\x11\x27" + "\x67\xbb\x5a\x85\xca\x56\xb2\x5c" + "\xe6\xec\xd5\x96\x3d\x15\xfc\xfb" + "\x22\x25\xf4\x13\xe5\x93\x4b\x9a" + "\x77\xf1\x52\x18\xfa\x16\x5e\x49" + "\x03\x45\xa8\x08\xfa\xb3\x41\x92" + "\x79\x50\x33\xca\xd0\xd7\x42\x55" + "\xc3\x9a\x0c\x4e\xd9\xa4\x3c\x86" + "\x80\x9f\x53\xd1\xa4\x2e\xd1\xbc" + "\xf1\x54\x6e\x93\xa4\x65\x99\x8e" + "\xdf\x29\xc0\x64\x63\x07\xbb\xea", + .ctext = "\x15\x97\xd0\x86\x18\x03\x9c\x51" + "\xc5\x11\x36\x62\x13\x92\xe6\x73" + "\x29\x79\xde\xa1\x00\x3e\x08\x64" + "\x17\x1a\xbc\xd5\xfe\x33\x0e\x0c" + "\x7c\x94\xa7\xc6\x3c\xbe\xac\xa2" + "\x89\xe6\xbc\xdf\x0c\x33\x27\x42" + "\x46\x73\x2f\xba\x4e\xa6\x46\x8f" + "\xe4\xee\x39\x63\x42\x65\xa3\x88" + "\x7a\xad\x33\x23\xa9\xa7\x20\x7f" + "\x0b\xe6\x6a\xc3\x60\xda\x9e\xb4" + "\xd6\x07\x8a\x77\x26\xd1\xab\x44" + "\x99\x55\x03\x5e\xed\x8d\x7b\xbd" + "\xc8\x21\xb7\x21\x30\x3f\xc0\xb5" + "\xc8\xec\x6c\x23\xa6\xa3\x6d\xf1" + "\x30\x0a\xd0\xa6\xa9\x28\x69\xae" + "\x2a\xe6\x54\xac\x82\x9d\x6a\x95" + "\x6f\x06\x44\xc5\x5a\x77\x6e\xec" + "\xf8\xf8\x63\xb2\xe6\xaa\xbd\x8e" + "\x0e\x8a\x62\x00\x03\xc8\x84\xdd" + "\x47\x4a\xc3\x55\xba\xb7\xe7\xdf" + "\x08\xbf\x62\xf5\xe8\xbc\xb6\x11" + "\xe4\xcb\xd0\x66\x74\x32\xcf\xd4" + "\xf8\x51\x80\x39\x14\x05\x12\xdb" + "\x87\x93\xe2\x26\x30\x9c\x3a\x21" + "\xe5\xd0\x38\x57\x80\x15\xe4\x08" + "\x58\x05\x49\x7d\xe6\x92\x77\x70" + "\xfb\x1e\x2d\x6a\x84\x00\xc8\x68" + "\xf7\x1a\xdd\xf0\x7b\x38\x1e\xd8" + "\x2c\x78\x78\x61\xcf\xe3\xde\x69" + "\x1f\xd5\x03\xd5\x1a\xb4\xcf\x03" + "\xc8\x7a\x70\x68\x35\xb4\xf6\xbe" + "\x90\x62\xb2\x28\x99\x86\xf5\x44" + "\x99\xeb\x31\xcf\xca\xdf\xd0\x21" + "\xd6\x60\xf7\x0f\x40\xb4\x80\xb7" + "\xab\xe1\x9b\x45\xba\x66\xda\xee" + "\xdd\x04\x12\x40\x98\xe1\x69\xe5" + "\x2b\x9c\x59\x80\xe7\x7b\xcc\x63" + "\xa6\xc0\x3a\xa9\xfe\x8a\xf9\x62" + "\x11\x34\x61\x94\x35\xfe\xf2\x99" + "\xfd\xee\x19\xea\x95\xb6\x12\xbf" + "\x1b\xdf\x02\x1a\xcc\x3e\x7e\x65" + "\x78\x74\x10\x50\x29\x63\x28\xea" + "\x6b\xab\xd4\x06\x4d\x15\x24\x31" + "\xc7\x0a\xc9\x16\xb6\x48\xf0\xbf" + "\x49\xdb\x68\x71\x31\x8f\x87\xe2" + "\x13\x05\x64\xd6\x22\x0c\xf8\x36" + "\x84\x24\x3e\x69\x5e\xb8\x9e\x16" + "\x73\x6c\x83\x1e\xe0\x9f\x9e\xba" + "\xe5\x59\x21\x33\x1b\xa9\x26\xc2" + "\xc7\xd9\x30\x73\xb6\xa6\x73\x82" + "\x19\xfa\x44\x4d\x40\x8b\x69\x04" + "\x94\x74\xea\x6e\xb3\x09\x47\x01" + "\x2a\xb9\x78\x34\x43\x11\xed\xd6" + "\x8c\x95\x65\x1b\x85\x67\xa5\x40" + "\xac\x9c\x05\x4b\x57\x4a\xa9\x96" + "\x0f\xdd\x4f\xa1\xe0\xcf\x6e\xc7" + "\x1b\xed\xa2\xb4\x56\x8c\x09\x6e" + "\xa6\x65\xd7\x55\x81\xb7\xed\x11" + "\x9b\x40\x75\xa8\x6b\x56\xaf\x16" + "\x8b\x3d\xf4\xcb\xfe\xd5\x1d\x3d" + "\x85\xc2\xc0\xde\x43\x39\x4a\x96" + "\xba\x88\x97\xc0\xd6\x00\x0e\x27" + "\x21\xb0\x21\x52\xba\xa7\x37\xaa" + "\xcc\xbf\x95\xa8\xf4\xd0\x91\xf6", + .len = 512, + .also_non_np = 1, + .np = 2, + .tap = { 144, 368 }, + } +}; + +/* Adiantum with XChaCha20 instead of XChaCha12 */ +/* Test vectors from https://github.com/google/adiantum */ +static const struct cipher_testvec adiantum_xchacha20_aes_tv_template[] = { + { + .key = "\x9e\xeb\xb2\x49\x3c\x1c\xf5\xf4" + "\x6a\x99\xc2\xc4\xdf\xb1\xf4\xdd" + "\x75\x20\x57\xea\x2c\x4f\xcd\xb2" + "\xa5\x3d\x7b\x49\x1e\xab\xfd\x0f", + .klen = 32, + .iv = "\xdf\x63\xd4\xab\xd2\x49\xf3\xd8" + "\x33\x81\x37\x60\x7d\xfa\x73\x08" + "\xd8\x49\x6d\x80\xe8\x2f\x62\x54" + "\xeb\x0e\xa9\x39\x5b\x45\x7f\x8a", + .ptext = "\x67\xc9\xf2\x30\x84\x41\x8e\x43" + "\xfb\xf3\xb3\x3e\x79\x36\x7f\xe8", + .ctext = "\xf6\x78\x97\xd6\xaa\x94\x01\x27" + "\x2e\x4d\x83\xe0\x6e\x64\x9a\xdf", + .len = 16, + .also_non_np = 1, + .np = 3, + .tap = { 5, 2, 9 }, + }, { + .key = "\x36\x2b\x57\x97\xf8\x5d\xcd\x99" + "\x5f\x1a\x5a\x44\x1d\x92\x0f\x27" + "\xcc\x16\xd7\x2b\x85\x63\x99\xd3" + "\xba\x96\xa1\xdb\xd2\x60\x68\xda", + .klen = 32, + .iv = "\xef\x58\x69\xb1\x2c\x5e\x9a\x47" + "\x24\xc1\xb1\x69\xe1\x12\x93\x8f" + "\x43\x3d\x6d\x00\xdb\x5e\xd8\xd9" + "\x12\x9a\xfe\xd9\xff\x2d\xaa\xc4", + .ptext = "\x5e\xa8\x68\x19\x85\x98\x12\x23" + "\x26\x0a\xcc\xdb\x0a\x04\xb9\xdf" + "\x4d\xb3\x48\x7b\xb0\xe3\xc8\x19" + "\x43\x5a\x46\x06\x94\x2d\xf2", + .ctext = "\x4b\xb8\x90\x10\xdf\x7f\x64\x08" + "\x0e\x14\x42\x5f\x00\x74\x09\x36" + "\x57\x72\xb5\xfd\xb5\x5d\xb8\x28" + "\x0c\x04\x91\x14\x91\xe9\x37", + .len = 31, + .also_non_np = 1, + .np = 2, + .tap = { 16, 15 }, + }, { + .key = "\xa5\x28\x24\x34\x1a\x3c\xd8\xf7" + "\x05\x91\x8f\xee\x85\x1f\x35\x7f" + "\x80\x3d\xfc\x9b\x94\xf6\xfc\x9e" + "\x19\x09\x00\xa9\x04\x31\x4f\x11", + .klen = 32, + .iv = "\xa1\xba\x49\x95\xff\x34\x6d\xb8" + "\xcd\x87\x5d\x5e\xfd\xea\x85\xdb" + "\x8a\x7b\x5e\xb2\x5d\x57\xdd\x62" + "\xac\xa9\x8c\x41\x42\x94\x75\xb7", + .ptext = "\x69\xb4\xe8\x8c\x37\xe8\x67\x82" + "\xf1\xec\x5d\x04\xe5\x14\x91\x13" + "\xdf\xf2\x87\x1b\x69\x81\x1d\x71" + "\x70\x9e\x9c\x3b\xde\x49\x70\x11" + "\xa0\xa3\xdb\x0d\x54\x4f\x66\x69" + "\xd7\xdb\x80\xa7\x70\x92\x68\xce" + "\x81\x04\x2c\xc6\xab\xae\xe5\x60" + "\x15\xe9\x6f\xef\xaa\x8f\xa7\xa7" + "\x63\x8f\xf2\xf0\x77\xf1\xa8\xea" + "\xe1\xb7\x1f\x9e\xab\x9e\x4b\x3f" + "\x07\x87\x5b\x6f\xcd\xa8\xaf\xb9" + "\xfa\x70\x0b\x52\xb8\xa8\xa7\x9e" + "\x07\x5f\xa6\x0e\xb3\x9b\x79\x13" + "\x79\xc3\x3e\x8d\x1c\x2c\x68\xc8" + "\x51\x1d\x3c\x7b\x7d\x79\x77\x2a" + "\x56\x65\xc5\x54\x23\x28\xb0\x03", + .ctext = "\xb1\x8b\xa0\x05\x77\xa8\x4d\x59" + "\x1b\x8e\x21\xfc\x3a\x49\xfa\xd4" + "\xeb\x36\xf3\xc4\xdf\xdc\xae\x67" + "\x07\x3f\x70\x0e\xe9\x66\xf5\x0c" + "\x30\x4d\x66\xc9\xa4\x2f\x73\x9c" + "\x13\xc8\x49\x44\xcc\x0a\x90\x9d" + "\x7c\xdd\x19\x3f\xea\x72\x8d\x58" + "\xab\xe7\x09\x2c\xec\xb5\x44\xd2" + "\xca\xa6\x2d\x7a\x5c\x9c\x2b\x15" + "\xec\x2a\xa6\x69\x91\xf9\xf3\x13" + "\xf7\x72\xc1\xc1\x40\xd5\xe1\x94" + "\xf4\x29\xa1\x3e\x25\x02\xa8\x3e" + "\x94\xc1\x91\x14\xa1\x14\xcb\xbe" + "\x67\x4c\xb9\x38\xfe\xa7\xaa\x32" + "\x29\x62\x0d\xb2\xf6\x3c\x58\x57" + "\xc1\xd5\x5a\xbb\xd6\xa6\x2a\xe5", + .len = 128, + .also_non_np = 1, + .np = 4, + .tap = { 112, 7, 8, 1 }, + }, { + .key = "\xd3\x81\x72\x18\x23\xff\x6f\x4a" + "\x25\x74\x29\x0d\x51\x8a\x0e\x13" + "\xc1\x53\x5d\x30\x8d\xee\x75\x0d" + "\x14\xd6\x69\xc9\x15\xa9\x0c\x60", + .klen = 32, + .iv = "\x65\x9b\xd4\xa8\x7d\x29\x1d\xf4" + "\xc4\xd6\x9b\x6a\x28\xab\x64\xe2" + "\x62\x81\x97\xc5\x81\xaa\xf9\x44" + "\xc1\x72\x59\x82\xaf\x16\xc8\x2c", + .ptext = "\xc7\x6b\x52\x6a\x10\xf0\xcc\x09" + "\xc1\x12\x1d\x6d\x21\xa6\x78\xf5" + "\x05\xa3\x69\x60\x91\x36\x98\x57" + "\xba\x0c\x14\xcc\xf3\x2d\x73\x03" + "\xc6\xb2\x5f\xc8\x16\x27\x37\x5d" + "\xd0\x0b\x87\xb2\x50\x94\x7b\x58" + "\x04\xf4\xe0\x7f\x6e\x57\x8e\xc9" + "\x41\x84\xc1\xb1\x7e\x4b\x91\x12" + "\x3a\x8b\x5d\x50\x82\x7b\xcb\xd9" + "\x9a\xd9\x4e\x18\x06\x23\x9e\xd4" + "\xa5\x20\x98\xef\xb5\xda\xe5\xc0" + "\x8a\x6a\x83\x77\x15\x84\x1e\xae" + "\x78\x94\x9d\xdf\xb7\xd1\xea\x67" + "\xaa\xb0\x14\x15\xfa\x67\x21\x84" + "\xd3\x41\x2a\xce\xba\x4b\x4a\xe8" + "\x95\x62\xa9\x55\xf0\x80\xad\xbd" + "\xab\xaf\xdd\x4f\xa5\x7c\x13\x36" + "\xed\x5e\x4f\x72\xad\x4b\xf1\xd0" + "\x88\x4e\xec\x2c\x88\x10\x5e\xea" + "\x12\xc0\x16\x01\x29\xa3\xa0\x55" + "\xaa\x68\xf3\xe9\x9d\x3b\x0d\x3b" + "\x6d\xec\xf8\xa0\x2d\xf0\x90\x8d" + "\x1c\xe2\x88\xd4\x24\x71\xf9\xb3" + "\xc1\x9f\xc5\xd6\x76\x70\xc5\x2e" + "\x9c\xac\xdb\x90\xbd\x83\x72\xba" + "\x6e\xb5\xa5\x53\x83\xa9\xa5\xbf" + "\x7d\x06\x0e\x3c\x2a\xd2\x04\xb5" + "\x1e\x19\x38\x09\x16\xd2\x82\x1f" + "\x75\x18\x56\xb8\x96\x0b\xa6\xf9" + "\xcf\x62\xd9\x32\x5d\xa9\xd7\x1d" + "\xec\xe4\xdf\x1b\xbe\xf1\x36\xee" + "\xe3\x7b\xb5\x2f\xee\xf8\x53\x3d" + "\x6a\xb7\x70\xa9\xfc\x9c\x57\x25" + "\xf2\x89\x10\xd3\xb8\xa8\x8c\x30" + "\xae\x23\x4f\x0e\x13\x66\x4f\xe1" + "\xb6\xc0\xe4\xf8\xef\x93\xbd\x6e" + "\x15\x85\x6b\xe3\x60\x81\x1d\x68" + "\xd7\x31\x87\x89\x09\xab\xd5\x96" + "\x1d\xf3\x6d\x67\x80\xca\x07\x31" + "\x5d\xa7\xe4\xfb\x3e\xf2\x9b\x33" + "\x52\x18\xc8\x30\xfe\x2d\xca\x1e" + "\x79\x92\x7a\x60\x5c\xb6\x58\x87" + "\xa4\x36\xa2\x67\x92\x8b\xa4\xb7" + "\xf1\x86\xdf\xdc\xc0\x7e\x8f\x63" + "\xd2\xa2\xdc\x78\xeb\x4f\xd8\x96" + "\x47\xca\xb8\x91\xf9\xf7\x94\x21" + "\x5f\x9a\x9f\x5b\xb8\x40\x41\x4b" + "\x66\x69\x6a\x72\xd0\xcb\x70\xb7" + "\x93\xb5\x37\x96\x05\x37\x4f\xe5" + "\x8c\xa7\x5a\x4e\x8b\xb7\x84\xea" + "\xc7\xfc\x19\x6e\x1f\x5a\xa1\xac" + "\x18\x7d\x52\x3b\xb3\x34\x62\x99" + "\xe4\x9e\x31\x04\x3f\xc0\x8d\x84" + "\x17\x7c\x25\x48\x52\x67\x11\x27" + "\x67\xbb\x5a\x85\xca\x56\xb2\x5c" + "\xe6\xec\xd5\x96\x3d\x15\xfc\xfb" + "\x22\x25\xf4\x13\xe5\x93\x4b\x9a" + "\x77\xf1\x52\x18\xfa\x16\x5e\x49" + "\x03\x45\xa8\x08\xfa\xb3\x41\x92" + "\x79\x50\x33\xca\xd0\xd7\x42\x55" + "\xc3\x9a\x0c\x4e\xd9\xa4\x3c\x86" + "\x80\x9f\x53\xd1\xa4\x2e\xd1\xbc" + "\xf1\x54\x6e\x93\xa4\x65\x99\x8e" + "\xdf\x29\xc0\x64\x63\x07\xbb\xea", + .ctext = "\xe0\x33\xf6\xe0\xb4\xa5\xdd\x2b" + "\xdd\xce\xfc\x12\x1e\xfc\x2d\xf2" + "\x8b\xc7\xeb\xc1\xc4\x2a\xe8\x44" + "\x0f\x3d\x97\x19\x2e\x6d\xa2\x38" + "\x9d\xa6\xaa\xe1\x96\xb9\x08\xe8" + "\x0b\x70\x48\x5c\xed\xb5\x9b\xcb" + "\x8b\x40\x88\x7e\x69\x73\xf7\x16" + "\x71\xbb\x5b\xfc\xa3\x47\x5d\xa6" + "\xae\x3a\x64\xc4\xe7\xb8\xa8\xe7" + "\xb1\x32\x19\xdb\xe3\x01\xb8\xf0" + "\xa4\x86\xb4\x4c\xc2\xde\x5c\xd2" + "\x6c\x77\xd2\xe8\x18\xb7\x0a\xc9" + "\x3d\x53\xb5\xc4\x5c\xf0\x8c\x06" + "\xdc\x90\xe0\x74\x47\x1b\x0b\xf6" + "\xd2\x71\x6b\xc4\xf1\x97\x00\x2d" + "\x63\x57\x44\x1f\x8c\xf4\xe6\x9b" + "\xe0\x7a\xdd\xec\x32\x73\x42\x32" + "\x7f\x35\x67\x60\x0d\xcf\x10\x52" + "\x61\x22\x53\x8d\x8e\xbb\x33\x76" + "\x59\xd9\x10\xce\xdf\xef\xc0\x41" + "\xd5\x33\x29\x6a\xda\x46\xa4\x51" + "\xf0\x99\x3d\x96\x31\xdd\xb5\xcb" + "\x3e\x2a\x1f\xc7\x5c\x79\xd3\xc5" + "\x20\xa1\xb1\x39\x1b\xc6\x0a\x70" + "\x26\x39\x95\x07\xad\x7a\xc9\x69" + "\xfe\x81\xc7\x88\x08\x38\xaf\xad" + "\x9e\x8d\xfb\xe8\x24\x0d\x22\xb8" + "\x0e\xed\xbe\x37\x53\x7c\xa6\xc6" + "\x78\x62\xec\xa3\x59\xd9\xc6\x9d" + "\xb8\x0e\x69\x77\x84\x2d\x6a\x4c" + "\xc5\xd9\xb2\xa0\x2b\xa8\x80\xcc" + "\xe9\x1e\x9c\x5a\xc4\xa1\xb2\x37" + "\x06\x9b\x30\x32\x67\xf7\xe7\xd2" + "\x42\xc7\xdf\x4e\xd4\xcb\xa0\x12" + "\x94\xa1\x34\x85\x93\x50\x4b\x0a" + "\x3c\x7d\x49\x25\x01\x41\x6b\x96" + "\xa9\x12\xbb\x0b\xc0\xd7\xd0\x93" + "\x1f\x70\x38\xb8\x21\xee\xf6\xa7" + "\xee\xeb\xe7\x81\xa4\x13\xb4\x87" + "\xfa\xc1\xb0\xb5\x37\x8b\x74\xa2" + "\x4e\xc7\xc2\xad\x3d\x62\x3f\xf8" + "\x34\x42\xe5\xae\x45\x13\x63\xfe" + "\xfc\x2a\x17\x46\x61\xa9\xd3\x1c" + "\x4c\xaf\xf0\x09\x62\x26\x66\x1e" + "\x74\xcf\xd6\x68\x3d\x7d\xd8\xb7" + "\xe7\xe6\xf8\xf0\x08\x20\xf7\x47" + "\x1c\x52\xaa\x0f\x3e\x21\xa3\xf2" + "\xbf\x2f\x95\x16\xa8\xc8\xc8\x8c" + "\x99\x0f\x5d\xfb\xfa\x2b\x58\x8a" + "\x7e\xd6\x74\x02\x60\xf0\xd0\x5b" + "\x65\xa8\xac\xea\x8d\x68\x46\x34" + "\x26\x9d\x4f\xb1\x9a\x8e\xc0\x1a" + "\xf1\xed\xc6\x7a\x83\xfd\x8a\x57" + "\xf2\xe6\xe4\xba\xfc\xc6\x3c\xad" + "\x5b\x19\x50\x2f\x3a\xcc\x06\x46" + "\x04\x51\x3f\x91\x97\xf0\xd2\x07" + "\xe7\x93\x89\x7e\xb5\x32\x0f\x03" + "\xe5\x58\x9e\x74\x72\xeb\xc2\x38" + "\x00\x0c\x91\x72\x69\xed\x7d\x6d" + "\xc8\x71\xf0\xec\xff\x80\xd9\x1c" + "\x9e\xd2\xfa\x15\xfc\x6c\x4e\xbc" + "\xb1\xa6\xbd\xbd\x70\x40\xca\x20" + "\xb8\x78\xd2\xa3\xc6\xf3\x79\x9c" + "\xc7\x27\xe1\x6a\x29\xad\xa4\x03", + .len = 512, + } +}; + /* * CTS (Cipher Text Stealing) mode tests */