162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This is an implementation of the ChaCha20Poly1305 AEAD construction. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Information: https://tools.ietf.org/html/rfc8439 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/algapi.h> 1162306a36Sopenharmony_ci#include <crypto/chacha20poly1305.h> 1262306a36Sopenharmony_ci#include <crypto/chacha.h> 1362306a36Sopenharmony_ci#include <crypto/poly1305.h> 1462306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/unaligned.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define CHACHA_KEY_WORDS (CHACHA_KEY_SIZE / sizeof(u32)) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void chacha_load_key(u32 *k, const u8 *in) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci k[0] = get_unaligned_le32(in); 2762306a36Sopenharmony_ci k[1] = get_unaligned_le32(in + 4); 2862306a36Sopenharmony_ci k[2] = get_unaligned_le32(in + 8); 2962306a36Sopenharmony_ci k[3] = get_unaligned_le32(in + 12); 3062306a36Sopenharmony_ci k[4] = get_unaligned_le32(in + 16); 3162306a36Sopenharmony_ci k[5] = get_unaligned_le32(in + 20); 3262306a36Sopenharmony_ci k[6] = get_unaligned_le32(in + 24); 3362306a36Sopenharmony_ci k[7] = get_unaligned_le32(in + 28); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void xchacha_init(u32 *chacha_state, const u8 *key, const u8 *nonce) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 3962306a36Sopenharmony_ci u8 iv[CHACHA_IV_SIZE]; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci memset(iv, 0, 8); 4262306a36Sopenharmony_ci memcpy(iv + 8, nonce + 16, 8); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci chacha_load_key(k, key); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Compute the subkey given the original key and first 128 nonce bits */ 4762306a36Sopenharmony_ci chacha_init(chacha_state, k, nonce); 4862306a36Sopenharmony_ci hchacha_block(chacha_state, k, 20); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci chacha_init(chacha_state, k, iv); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci memzero_explicit(k, sizeof(k)); 5362306a36Sopenharmony_ci memzero_explicit(iv, sizeof(iv)); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void 5762306a36Sopenharmony_ci__chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 5862306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, u32 *chacha_state) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci const u8 *pad0 = page_address(ZERO_PAGE(0)); 6162306a36Sopenharmony_ci struct poly1305_desc_ctx poly1305_state; 6262306a36Sopenharmony_ci union { 6362306a36Sopenharmony_ci u8 block0[POLY1305_KEY_SIZE]; 6462306a36Sopenharmony_ci __le64 lens[2]; 6562306a36Sopenharmony_ci } b; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); 6862306a36Sopenharmony_ci poly1305_init(&poly1305_state, b.block0); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci poly1305_update(&poly1305_state, ad, ad_len); 7162306a36Sopenharmony_ci if (ad_len & 0xf) 7262306a36Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci chacha20_crypt(chacha_state, dst, src, src_len); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci poly1305_update(&poly1305_state, dst, src_len); 7762306a36Sopenharmony_ci if (src_len & 0xf) 7862306a36Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci b.lens[0] = cpu_to_le64(ad_len); 8162306a36Sopenharmony_ci b.lens[1] = cpu_to_le64(src_len); 8262306a36Sopenharmony_ci poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci poly1305_final(&poly1305_state, dst + src_len); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci memzero_explicit(chacha_state, CHACHA_STATE_WORDS * sizeof(u32)); 8762306a36Sopenharmony_ci memzero_explicit(&b, sizeof(b)); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 9162306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 9262306a36Sopenharmony_ci const u64 nonce, 9362306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 9662306a36Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 9762306a36Sopenharmony_ci __le64 iv[2]; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci chacha_load_key(k, key); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci iv[0] = 0; 10262306a36Sopenharmony_ci iv[1] = cpu_to_le64(nonce); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci chacha_init(chacha_state, k, (u8 *)iv); 10562306a36Sopenharmony_ci __chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci memzero_explicit(iv, sizeof(iv)); 10862306a36Sopenharmony_ci memzero_explicit(k, sizeof(k)); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_encrypt); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_civoid xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 11362306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 11462306a36Sopenharmony_ci const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], 11562306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci xchacha_init(chacha_state, key, nonce); 12062306a36Sopenharmony_ci __chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ciEXPORT_SYMBOL(xchacha20poly1305_encrypt); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic bool 12562306a36Sopenharmony_ci__chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 12662306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, u32 *chacha_state) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci const u8 *pad0 = page_address(ZERO_PAGE(0)); 12962306a36Sopenharmony_ci struct poly1305_desc_ctx poly1305_state; 13062306a36Sopenharmony_ci size_t dst_len; 13162306a36Sopenharmony_ci int ret; 13262306a36Sopenharmony_ci union { 13362306a36Sopenharmony_ci u8 block0[POLY1305_KEY_SIZE]; 13462306a36Sopenharmony_ci u8 mac[POLY1305_DIGEST_SIZE]; 13562306a36Sopenharmony_ci __le64 lens[2]; 13662306a36Sopenharmony_ci } b; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (unlikely(src_len < POLY1305_DIGEST_SIZE)) 13962306a36Sopenharmony_ci return false; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); 14262306a36Sopenharmony_ci poly1305_init(&poly1305_state, b.block0); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci poly1305_update(&poly1305_state, ad, ad_len); 14562306a36Sopenharmony_ci if (ad_len & 0xf) 14662306a36Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci dst_len = src_len - POLY1305_DIGEST_SIZE; 14962306a36Sopenharmony_ci poly1305_update(&poly1305_state, src, dst_len); 15062306a36Sopenharmony_ci if (dst_len & 0xf) 15162306a36Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (dst_len & 0xf)); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci b.lens[0] = cpu_to_le64(ad_len); 15462306a36Sopenharmony_ci b.lens[1] = cpu_to_le64(dst_len); 15562306a36Sopenharmony_ci poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci poly1305_final(&poly1305_state, b.mac); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE); 16062306a36Sopenharmony_ci if (likely(!ret)) 16162306a36Sopenharmony_ci chacha20_crypt(chacha_state, dst, src, dst_len); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci memzero_explicit(&b, sizeof(b)); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return !ret; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cibool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 16962306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 17062306a36Sopenharmony_ci const u64 nonce, 17162306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 17462306a36Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 17562306a36Sopenharmony_ci __le64 iv[2]; 17662306a36Sopenharmony_ci bool ret; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci chacha_load_key(k, key); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci iv[0] = 0; 18162306a36Sopenharmony_ci iv[1] = cpu_to_le64(nonce); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci chacha_init(chacha_state, k, (u8 *)iv); 18462306a36Sopenharmony_ci ret = __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, 18562306a36Sopenharmony_ci chacha_state); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci memzero_explicit(chacha_state, sizeof(chacha_state)); 18862306a36Sopenharmony_ci memzero_explicit(iv, sizeof(iv)); 18962306a36Sopenharmony_ci memzero_explicit(k, sizeof(k)); 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_decrypt); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cibool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 19562306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 19662306a36Sopenharmony_ci const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], 19762306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci xchacha_init(chacha_state, key, nonce); 20262306a36Sopenharmony_ci return __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, 20362306a36Sopenharmony_ci chacha_state); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ciEXPORT_SYMBOL(xchacha20poly1305_decrypt); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic 20862306a36Sopenharmony_cibool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src, 20962306a36Sopenharmony_ci const size_t src_len, 21062306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 21162306a36Sopenharmony_ci const u64 nonce, 21262306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE], 21362306a36Sopenharmony_ci int encrypt) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci const u8 *pad0 = page_address(ZERO_PAGE(0)); 21662306a36Sopenharmony_ci struct poly1305_desc_ctx poly1305_state; 21762306a36Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 21862306a36Sopenharmony_ci struct sg_mapping_iter miter; 21962306a36Sopenharmony_ci size_t partial = 0; 22062306a36Sopenharmony_ci unsigned int flags; 22162306a36Sopenharmony_ci bool ret = true; 22262306a36Sopenharmony_ci int sl; 22362306a36Sopenharmony_ci union { 22462306a36Sopenharmony_ci struct { 22562306a36Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 22662306a36Sopenharmony_ci __le64 iv[2]; 22762306a36Sopenharmony_ci }; 22862306a36Sopenharmony_ci u8 block0[POLY1305_KEY_SIZE]; 22962306a36Sopenharmony_ci u8 chacha_stream[CHACHA_BLOCK_SIZE]; 23062306a36Sopenharmony_ci struct { 23162306a36Sopenharmony_ci u8 mac[2][POLY1305_DIGEST_SIZE]; 23262306a36Sopenharmony_ci }; 23362306a36Sopenharmony_ci __le64 lens[2]; 23462306a36Sopenharmony_ci } b __aligned(16); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (WARN_ON(src_len > INT_MAX)) 23762306a36Sopenharmony_ci return false; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci chacha_load_key(b.k, key); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci b.iv[0] = 0; 24262306a36Sopenharmony_ci b.iv[1] = cpu_to_le64(nonce); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci chacha_init(chacha_state, b.k, (u8 *)b.iv); 24562306a36Sopenharmony_ci chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); 24662306a36Sopenharmony_ci poly1305_init(&poly1305_state, b.block0); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (unlikely(ad_len)) { 24962306a36Sopenharmony_ci poly1305_update(&poly1305_state, ad, ad_len); 25062306a36Sopenharmony_ci if (ad_len & 0xf) 25162306a36Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci flags = SG_MITER_TO_SG | SG_MITER_ATOMIC; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci sg_miter_start(&miter, src, sg_nents(src), flags); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci for (sl = src_len; sl > 0 && sg_miter_next(&miter); sl -= miter.length) { 25962306a36Sopenharmony_ci u8 *addr = miter.addr; 26062306a36Sopenharmony_ci size_t length = min_t(size_t, sl, miter.length); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!encrypt) 26362306a36Sopenharmony_ci poly1305_update(&poly1305_state, addr, length); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (unlikely(partial)) { 26662306a36Sopenharmony_ci size_t l = min(length, CHACHA_BLOCK_SIZE - partial); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci crypto_xor(addr, b.chacha_stream + partial, l); 26962306a36Sopenharmony_ci partial = (partial + l) & (CHACHA_BLOCK_SIZE - 1); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci addr += l; 27262306a36Sopenharmony_ci length -= l; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (likely(length >= CHACHA_BLOCK_SIZE || length == sl)) { 27662306a36Sopenharmony_ci size_t l = length; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (unlikely(length < sl)) 27962306a36Sopenharmony_ci l &= ~(CHACHA_BLOCK_SIZE - 1); 28062306a36Sopenharmony_ci chacha20_crypt(chacha_state, addr, addr, l); 28162306a36Sopenharmony_ci addr += l; 28262306a36Sopenharmony_ci length -= l; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (unlikely(length > 0)) { 28662306a36Sopenharmony_ci chacha20_crypt(chacha_state, b.chacha_stream, pad0, 28762306a36Sopenharmony_ci CHACHA_BLOCK_SIZE); 28862306a36Sopenharmony_ci crypto_xor(addr, b.chacha_stream, length); 28962306a36Sopenharmony_ci partial = length; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (encrypt) 29362306a36Sopenharmony_ci poly1305_update(&poly1305_state, miter.addr, 29462306a36Sopenharmony_ci min_t(size_t, sl, miter.length)); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (src_len & 0xf) 29862306a36Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf)); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci b.lens[0] = cpu_to_le64(ad_len); 30162306a36Sopenharmony_ci b.lens[1] = cpu_to_le64(src_len); 30262306a36Sopenharmony_ci poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (likely(sl <= -POLY1305_DIGEST_SIZE)) { 30562306a36Sopenharmony_ci if (encrypt) { 30662306a36Sopenharmony_ci poly1305_final(&poly1305_state, 30762306a36Sopenharmony_ci miter.addr + miter.length + sl); 30862306a36Sopenharmony_ci ret = true; 30962306a36Sopenharmony_ci } else { 31062306a36Sopenharmony_ci poly1305_final(&poly1305_state, b.mac[0]); 31162306a36Sopenharmony_ci ret = !crypto_memneq(b.mac[0], 31262306a36Sopenharmony_ci miter.addr + miter.length + sl, 31362306a36Sopenharmony_ci POLY1305_DIGEST_SIZE); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci sg_miter_stop(&miter); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (unlikely(sl > -POLY1305_DIGEST_SIZE)) { 32062306a36Sopenharmony_ci poly1305_final(&poly1305_state, b.mac[1]); 32162306a36Sopenharmony_ci scatterwalk_map_and_copy(b.mac[encrypt], src, src_len, 32262306a36Sopenharmony_ci sizeof(b.mac[1]), encrypt); 32362306a36Sopenharmony_ci ret = encrypt || 32462306a36Sopenharmony_ci !crypto_memneq(b.mac[0], b.mac[1], POLY1305_DIGEST_SIZE); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci memzero_explicit(chacha_state, sizeof(chacha_state)); 32862306a36Sopenharmony_ci memzero_explicit(&b, sizeof(b)); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cibool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len, 33462306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 33562306a36Sopenharmony_ci const u64 nonce, 33662306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci return chacha20poly1305_crypt_sg_inplace(src, src_len, ad, ad_len, 33962306a36Sopenharmony_ci nonce, key, 1); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_encrypt_sg_inplace); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cibool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len, 34462306a36Sopenharmony_ci const u8 *ad, const size_t ad_len, 34562306a36Sopenharmony_ci const u64 nonce, 34662306a36Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci if (unlikely(src_len < POLY1305_DIGEST_SIZE)) 34962306a36Sopenharmony_ci return false; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return chacha20poly1305_crypt_sg_inplace(src, 35262306a36Sopenharmony_ci src_len - POLY1305_DIGEST_SIZE, 35362306a36Sopenharmony_ci ad, ad_len, nonce, key, 0); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_decrypt_sg_inplace); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int __init chacha20poly1305_init(void) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && 36062306a36Sopenharmony_ci WARN_ON(!chacha20poly1305_selftest())) 36162306a36Sopenharmony_ci return -ENODEV; 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void __exit chacha20poly1305_exit(void) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cimodule_init(chacha20poly1305_init); 37062306a36Sopenharmony_cimodule_exit(chacha20poly1305_exit); 37162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 37262306a36Sopenharmony_ciMODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction"); 37362306a36Sopenharmony_ciMODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>"); 374