cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

chacha20poly1305.c (10157B)


      1// SPDX-License-Identifier: GPL-2.0 OR MIT
      2/*
      3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
      4 *
      5 * This is an implementation of the ChaCha20Poly1305 AEAD construction.
      6 *
      7 * Information: https://tools.ietf.org/html/rfc8439
      8 */
      9
     10#include <crypto/algapi.h>
     11#include <crypto/chacha20poly1305.h>
     12#include <crypto/chacha.h>
     13#include <crypto/poly1305.h>
     14#include <crypto/scatterwalk.h>
     15
     16#include <asm/unaligned.h>
     17#include <linux/kernel.h>
     18#include <linux/init.h>
     19#include <linux/mm.h>
     20#include <linux/module.h>
     21
     22#define CHACHA_KEY_WORDS	(CHACHA_KEY_SIZE / sizeof(u32))
     23
     24static void chacha_load_key(u32 *k, const u8 *in)
     25{
     26	k[0] = get_unaligned_le32(in);
     27	k[1] = get_unaligned_le32(in + 4);
     28	k[2] = get_unaligned_le32(in + 8);
     29	k[3] = get_unaligned_le32(in + 12);
     30	k[4] = get_unaligned_le32(in + 16);
     31	k[5] = get_unaligned_le32(in + 20);
     32	k[6] = get_unaligned_le32(in + 24);
     33	k[7] = get_unaligned_le32(in + 28);
     34}
     35
     36static void xchacha_init(u32 *chacha_state, const u8 *key, const u8 *nonce)
     37{
     38	u32 k[CHACHA_KEY_WORDS];
     39	u8 iv[CHACHA_IV_SIZE];
     40
     41	memset(iv, 0, 8);
     42	memcpy(iv + 8, nonce + 16, 8);
     43
     44	chacha_load_key(k, key);
     45
     46	/* Compute the subkey given the original key and first 128 nonce bits */
     47	chacha_init(chacha_state, k, nonce);
     48	hchacha_block(chacha_state, k, 20);
     49
     50	chacha_init(chacha_state, k, iv);
     51
     52	memzero_explicit(k, sizeof(k));
     53	memzero_explicit(iv, sizeof(iv));
     54}
     55
     56static void
     57__chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
     58			   const u8 *ad, const size_t ad_len, u32 *chacha_state)
     59{
     60	const u8 *pad0 = page_address(ZERO_PAGE(0));
     61	struct poly1305_desc_ctx poly1305_state;
     62	union {
     63		u8 block0[POLY1305_KEY_SIZE];
     64		__le64 lens[2];
     65	} b;
     66
     67	chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0));
     68	poly1305_init(&poly1305_state, b.block0);
     69
     70	poly1305_update(&poly1305_state, ad, ad_len);
     71	if (ad_len & 0xf)
     72		poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
     73
     74	chacha20_crypt(chacha_state, dst, src, src_len);
     75
     76	poly1305_update(&poly1305_state, dst, src_len);
     77	if (src_len & 0xf)
     78		poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf));
     79
     80	b.lens[0] = cpu_to_le64(ad_len);
     81	b.lens[1] = cpu_to_le64(src_len);
     82	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
     83
     84	poly1305_final(&poly1305_state, dst + src_len);
     85
     86	memzero_explicit(chacha_state, CHACHA_STATE_WORDS * sizeof(u32));
     87	memzero_explicit(&b, sizeof(b));
     88}
     89
     90void chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
     91			      const u8 *ad, const size_t ad_len,
     92			      const u64 nonce,
     93			      const u8 key[CHACHA20POLY1305_KEY_SIZE])
     94{
     95	u32 chacha_state[CHACHA_STATE_WORDS];
     96	u32 k[CHACHA_KEY_WORDS];
     97	__le64 iv[2];
     98
     99	chacha_load_key(k, key);
    100
    101	iv[0] = 0;
    102	iv[1] = cpu_to_le64(nonce);
    103
    104	chacha_init(chacha_state, k, (u8 *)iv);
    105	__chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state);
    106
    107	memzero_explicit(iv, sizeof(iv));
    108	memzero_explicit(k, sizeof(k));
    109}
    110EXPORT_SYMBOL(chacha20poly1305_encrypt);
    111
    112void xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
    113			       const u8 *ad, const size_t ad_len,
    114			       const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
    115			       const u8 key[CHACHA20POLY1305_KEY_SIZE])
    116{
    117	u32 chacha_state[CHACHA_STATE_WORDS];
    118
    119	xchacha_init(chacha_state, key, nonce);
    120	__chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state);
    121}
    122EXPORT_SYMBOL(xchacha20poly1305_encrypt);
    123
    124static bool
    125__chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
    126			   const u8 *ad, const size_t ad_len, u32 *chacha_state)
    127{
    128	const u8 *pad0 = page_address(ZERO_PAGE(0));
    129	struct poly1305_desc_ctx poly1305_state;
    130	size_t dst_len;
    131	int ret;
    132	union {
    133		u8 block0[POLY1305_KEY_SIZE];
    134		u8 mac[POLY1305_DIGEST_SIZE];
    135		__le64 lens[2];
    136	} b;
    137
    138	if (unlikely(src_len < POLY1305_DIGEST_SIZE))
    139		return false;
    140
    141	chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0));
    142	poly1305_init(&poly1305_state, b.block0);
    143
    144	poly1305_update(&poly1305_state, ad, ad_len);
    145	if (ad_len & 0xf)
    146		poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
    147
    148	dst_len = src_len - POLY1305_DIGEST_SIZE;
    149	poly1305_update(&poly1305_state, src, dst_len);
    150	if (dst_len & 0xf)
    151		poly1305_update(&poly1305_state, pad0, 0x10 - (dst_len & 0xf));
    152
    153	b.lens[0] = cpu_to_le64(ad_len);
    154	b.lens[1] = cpu_to_le64(dst_len);
    155	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
    156
    157	poly1305_final(&poly1305_state, b.mac);
    158
    159	ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE);
    160	if (likely(!ret))
    161		chacha20_crypt(chacha_state, dst, src, dst_len);
    162
    163	memzero_explicit(&b, sizeof(b));
    164
    165	return !ret;
    166}
    167
    168bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
    169			      const u8 *ad, const size_t ad_len,
    170			      const u64 nonce,
    171			      const u8 key[CHACHA20POLY1305_KEY_SIZE])
    172{
    173	u32 chacha_state[CHACHA_STATE_WORDS];
    174	u32 k[CHACHA_KEY_WORDS];
    175	__le64 iv[2];
    176	bool ret;
    177
    178	chacha_load_key(k, key);
    179
    180	iv[0] = 0;
    181	iv[1] = cpu_to_le64(nonce);
    182
    183	chacha_init(chacha_state, k, (u8 *)iv);
    184	ret = __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len,
    185					 chacha_state);
    186
    187	memzero_explicit(chacha_state, sizeof(chacha_state));
    188	memzero_explicit(iv, sizeof(iv));
    189	memzero_explicit(k, sizeof(k));
    190	return ret;
    191}
    192EXPORT_SYMBOL(chacha20poly1305_decrypt);
    193
    194bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
    195			       const u8 *ad, const size_t ad_len,
    196			       const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
    197			       const u8 key[CHACHA20POLY1305_KEY_SIZE])
    198{
    199	u32 chacha_state[CHACHA_STATE_WORDS];
    200
    201	xchacha_init(chacha_state, key, nonce);
    202	return __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len,
    203					  chacha_state);
    204}
    205EXPORT_SYMBOL(xchacha20poly1305_decrypt);
    206
    207static
    208bool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src,
    209				       const size_t src_len,
    210				       const u8 *ad, const size_t ad_len,
    211				       const u64 nonce,
    212				       const u8 key[CHACHA20POLY1305_KEY_SIZE],
    213				       int encrypt)
    214{
    215	const u8 *pad0 = page_address(ZERO_PAGE(0));
    216	struct poly1305_desc_ctx poly1305_state;
    217	u32 chacha_state[CHACHA_STATE_WORDS];
    218	struct sg_mapping_iter miter;
    219	size_t partial = 0;
    220	unsigned int flags;
    221	bool ret = true;
    222	int sl;
    223	union {
    224		struct {
    225			u32 k[CHACHA_KEY_WORDS];
    226			__le64 iv[2];
    227		};
    228		u8 block0[POLY1305_KEY_SIZE];
    229		u8 chacha_stream[CHACHA_BLOCK_SIZE];
    230		struct {
    231			u8 mac[2][POLY1305_DIGEST_SIZE];
    232		};
    233		__le64 lens[2];
    234	} b __aligned(16);
    235
    236	if (WARN_ON(src_len > INT_MAX))
    237		return false;
    238
    239	chacha_load_key(b.k, key);
    240
    241	b.iv[0] = 0;
    242	b.iv[1] = cpu_to_le64(nonce);
    243
    244	chacha_init(chacha_state, b.k, (u8 *)b.iv);
    245	chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0));
    246	poly1305_init(&poly1305_state, b.block0);
    247
    248	if (unlikely(ad_len)) {
    249		poly1305_update(&poly1305_state, ad, ad_len);
    250		if (ad_len & 0xf)
    251			poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
    252	}
    253
    254	flags = SG_MITER_TO_SG | SG_MITER_ATOMIC;
    255
    256	sg_miter_start(&miter, src, sg_nents(src), flags);
    257
    258	for (sl = src_len; sl > 0 && sg_miter_next(&miter); sl -= miter.length) {
    259		u8 *addr = miter.addr;
    260		size_t length = min_t(size_t, sl, miter.length);
    261
    262		if (!encrypt)
    263			poly1305_update(&poly1305_state, addr, length);
    264
    265		if (unlikely(partial)) {
    266			size_t l = min(length, CHACHA_BLOCK_SIZE - partial);
    267
    268			crypto_xor(addr, b.chacha_stream + partial, l);
    269			partial = (partial + l) & (CHACHA_BLOCK_SIZE - 1);
    270
    271			addr += l;
    272			length -= l;
    273		}
    274
    275		if (likely(length >= CHACHA_BLOCK_SIZE || length == sl)) {
    276			size_t l = length;
    277
    278			if (unlikely(length < sl))
    279				l &= ~(CHACHA_BLOCK_SIZE - 1);
    280			chacha20_crypt(chacha_state, addr, addr, l);
    281			addr += l;
    282			length -= l;
    283		}
    284
    285		if (unlikely(length > 0)) {
    286			chacha20_crypt(chacha_state, b.chacha_stream, pad0,
    287				       CHACHA_BLOCK_SIZE);
    288			crypto_xor(addr, b.chacha_stream, length);
    289			partial = length;
    290		}
    291
    292		if (encrypt)
    293			poly1305_update(&poly1305_state, miter.addr,
    294					min_t(size_t, sl, miter.length));
    295	}
    296
    297	if (src_len & 0xf)
    298		poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf));
    299
    300	b.lens[0] = cpu_to_le64(ad_len);
    301	b.lens[1] = cpu_to_le64(src_len);
    302	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
    303
    304	if (likely(sl <= -POLY1305_DIGEST_SIZE)) {
    305		if (encrypt) {
    306			poly1305_final(&poly1305_state,
    307				       miter.addr + miter.length + sl);
    308			ret = true;
    309		} else {
    310			poly1305_final(&poly1305_state, b.mac[0]);
    311			ret = !crypto_memneq(b.mac[0],
    312					     miter.addr + miter.length + sl,
    313					     POLY1305_DIGEST_SIZE);
    314		}
    315	}
    316
    317	sg_miter_stop(&miter);
    318
    319	if (unlikely(sl > -POLY1305_DIGEST_SIZE)) {
    320		poly1305_final(&poly1305_state, b.mac[1]);
    321		scatterwalk_map_and_copy(b.mac[encrypt], src, src_len,
    322					 sizeof(b.mac[1]), encrypt);
    323		ret = encrypt ||
    324		      !crypto_memneq(b.mac[0], b.mac[1], POLY1305_DIGEST_SIZE);
    325	}
    326
    327	memzero_explicit(chacha_state, sizeof(chacha_state));
    328	memzero_explicit(&b, sizeof(b));
    329
    330	return ret;
    331}
    332
    333bool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len,
    334					 const u8 *ad, const size_t ad_len,
    335					 const u64 nonce,
    336					 const u8 key[CHACHA20POLY1305_KEY_SIZE])
    337{
    338	return chacha20poly1305_crypt_sg_inplace(src, src_len, ad, ad_len,
    339						 nonce, key, 1);
    340}
    341EXPORT_SYMBOL(chacha20poly1305_encrypt_sg_inplace);
    342
    343bool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len,
    344					 const u8 *ad, const size_t ad_len,
    345					 const u64 nonce,
    346					 const u8 key[CHACHA20POLY1305_KEY_SIZE])
    347{
    348	if (unlikely(src_len < POLY1305_DIGEST_SIZE))
    349		return false;
    350
    351	return chacha20poly1305_crypt_sg_inplace(src,
    352						 src_len - POLY1305_DIGEST_SIZE,
    353						 ad, ad_len, nonce, key, 0);
    354}
    355EXPORT_SYMBOL(chacha20poly1305_decrypt_sg_inplace);
    356
    357static int __init chacha20poly1305_init(void)
    358{
    359	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) &&
    360	    WARN_ON(!chacha20poly1305_selftest()))
    361		return -ENODEV;
    362	return 0;
    363}
    364
    365static void __exit chacha20poly1305_exit(void)
    366{
    367}
    368
    369module_init(chacha20poly1305_init);
    370module_exit(chacha20poly1305_exit);
    371MODULE_LICENSE("GPL v2");
    372MODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction");
    373MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");