linux/crypto/adiantum.c

// 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 (ε-∆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 ε-∆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/scatterwalk.h>
#include <linux/module.h>

/*
 * Size of right-hand part 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

/* Size of the block cipher key (K_E) in bytes */
#define BLOCKCIPHER_KEY_SIZE

/* Size of the hash key (K_H) in bytes */
#define HASH_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

struct adiantum_instance_ctx {};

struct adiantum_tfm_ctx {};

struct adiantum_request_ctx {};

/*
 * 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)
{}

/* Addition in Z/(2^{128}Z) */
static inline void le128_add(le128 *r, const le128 *v1, const le128 *v2)
{}

/* Subtraction in Z/(2^{128}Z) */
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
 *
 *	H_T ← Poly1305_{K_T}(bin_{128}(|L|) || T)
 *
 * from the procedure in section 6.4 of the Adiantum paper.  The resulting value
 * is reused in both the first and second hash steps.  Specifically, it's added
 * to the result of an independently keyed ε-∆U hash function (for equal length
 * 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)
{}

/* 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)
{}

/* Continue Adiantum encryption/decryption after the stream cipher step */
static int adiantum_finish(struct skcipher_request *req)
{}

static void adiantum_streamcipher_done(void *data, int err)
{}

static int adiantum_crypt(struct skcipher_request *req, bool enc)
{}

static int adiantum_encrypt(struct skcipher_request *req)
{}

static int adiantum_decrypt(struct skcipher_request *req)
{}

static int adiantum_init_tfm(struct crypto_skcipher *tfm)
{}

static void adiantum_exit_tfm(struct crypto_skcipher *tfm)
{}

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 int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb)
{}

/* adiantum(streamcipher_name, blockcipher_name [, nhpoly1305_name]) */
static struct crypto_template adiantum_tmpl =;

static int __init adiantum_module_init(void)
{}

static void __exit adiantum_module_exit(void)
{}

subsys_initcall(adiantum_module_init);
module_exit(adiantum_module_exit);

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_ALIAS_CRYPTO();
MODULE_IMPORT_NS();