18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This is an implementation of the ChaCha20Poly1305 AEAD construction. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Information: https://tools.ietf.org/html/rfc8439 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 118c2ecf20Sopenharmony_ci#include <crypto/chacha20poly1305.h> 128c2ecf20Sopenharmony_ci#include <crypto/chacha.h> 138c2ecf20Sopenharmony_ci#include <crypto/poly1305.h> 148c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define CHACHA_KEY_WORDS (CHACHA_KEY_SIZE / sizeof(u32)) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void chacha_load_key(u32 *k, const u8 *in) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci k[0] = get_unaligned_le32(in); 278c2ecf20Sopenharmony_ci k[1] = get_unaligned_le32(in + 4); 288c2ecf20Sopenharmony_ci k[2] = get_unaligned_le32(in + 8); 298c2ecf20Sopenharmony_ci k[3] = get_unaligned_le32(in + 12); 308c2ecf20Sopenharmony_ci k[4] = get_unaligned_le32(in + 16); 318c2ecf20Sopenharmony_ci k[5] = get_unaligned_le32(in + 20); 328c2ecf20Sopenharmony_ci k[6] = get_unaligned_le32(in + 24); 338c2ecf20Sopenharmony_ci k[7] = get_unaligned_le32(in + 28); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void xchacha_init(u32 *chacha_state, const u8 *key, const u8 *nonce) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 398c2ecf20Sopenharmony_ci u8 iv[CHACHA_IV_SIZE]; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci memset(iv, 0, 8); 428c2ecf20Sopenharmony_ci memcpy(iv + 8, nonce + 16, 8); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci chacha_load_key(k, key); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Compute the subkey given the original key and first 128 nonce bits */ 478c2ecf20Sopenharmony_ci chacha_init(chacha_state, k, nonce); 488c2ecf20Sopenharmony_ci hchacha_block(chacha_state, k, 20); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci chacha_init(chacha_state, k, iv); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci memzero_explicit(k, sizeof(k)); 538c2ecf20Sopenharmony_ci memzero_explicit(iv, sizeof(iv)); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void 578c2ecf20Sopenharmony_ci__chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 588c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, u32 *chacha_state) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci const u8 *pad0 = page_address(ZERO_PAGE(0)); 618c2ecf20Sopenharmony_ci struct poly1305_desc_ctx poly1305_state; 628c2ecf20Sopenharmony_ci union { 638c2ecf20Sopenharmony_ci u8 block0[POLY1305_KEY_SIZE]; 648c2ecf20Sopenharmony_ci __le64 lens[2]; 658c2ecf20Sopenharmony_ci } b; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); 688c2ecf20Sopenharmony_ci poly1305_init(&poly1305_state, b.block0); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, ad, ad_len); 718c2ecf20Sopenharmony_ci if (ad_len & 0xf) 728c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, dst, src, src_len); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, dst, src_len); 778c2ecf20Sopenharmony_ci if (src_len & 0xf) 788c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf)); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci b.lens[0] = cpu_to_le64(ad_len); 818c2ecf20Sopenharmony_ci b.lens[1] = cpu_to_le64(src_len); 828c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci poly1305_final(&poly1305_state, dst + src_len); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci memzero_explicit(chacha_state, CHACHA_STATE_WORDS * sizeof(u32)); 878c2ecf20Sopenharmony_ci memzero_explicit(&b, sizeof(b)); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 918c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 928c2ecf20Sopenharmony_ci const u64 nonce, 938c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 968c2ecf20Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 978c2ecf20Sopenharmony_ci __le64 iv[2]; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci chacha_load_key(k, key); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci iv[0] = 0; 1028c2ecf20Sopenharmony_ci iv[1] = cpu_to_le64(nonce); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci chacha_init(chacha_state, k, (u8 *)iv); 1058c2ecf20Sopenharmony_ci __chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci memzero_explicit(iv, sizeof(iv)); 1088c2ecf20Sopenharmony_ci memzero_explicit(k, sizeof(k)); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_encrypt); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_civoid xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 1138c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 1148c2ecf20Sopenharmony_ci const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], 1158c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci xchacha_init(chacha_state, key, nonce); 1208c2ecf20Sopenharmony_ci __chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xchacha20poly1305_encrypt); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic bool 1258c2ecf20Sopenharmony_ci__chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 1268c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, u32 *chacha_state) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci const u8 *pad0 = page_address(ZERO_PAGE(0)); 1298c2ecf20Sopenharmony_ci struct poly1305_desc_ctx poly1305_state; 1308c2ecf20Sopenharmony_ci size_t dst_len; 1318c2ecf20Sopenharmony_ci int ret; 1328c2ecf20Sopenharmony_ci union { 1338c2ecf20Sopenharmony_ci u8 block0[POLY1305_KEY_SIZE]; 1348c2ecf20Sopenharmony_ci u8 mac[POLY1305_DIGEST_SIZE]; 1358c2ecf20Sopenharmony_ci __le64 lens[2]; 1368c2ecf20Sopenharmony_ci } b; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (unlikely(src_len < POLY1305_DIGEST_SIZE)) 1398c2ecf20Sopenharmony_ci return false; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); 1428c2ecf20Sopenharmony_ci poly1305_init(&poly1305_state, b.block0); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, ad, ad_len); 1458c2ecf20Sopenharmony_ci if (ad_len & 0xf) 1468c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci dst_len = src_len - POLY1305_DIGEST_SIZE; 1498c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, src, dst_len); 1508c2ecf20Sopenharmony_ci if (dst_len & 0xf) 1518c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (dst_len & 0xf)); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci b.lens[0] = cpu_to_le64(ad_len); 1548c2ecf20Sopenharmony_ci b.lens[1] = cpu_to_le64(dst_len); 1558c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci poly1305_final(&poly1305_state, b.mac); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE); 1608c2ecf20Sopenharmony_ci if (likely(!ret)) 1618c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, dst, src, dst_len); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci memzero_explicit(&b, sizeof(b)); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return !ret; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cibool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 1698c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 1708c2ecf20Sopenharmony_ci const u64 nonce, 1718c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 1748c2ecf20Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 1758c2ecf20Sopenharmony_ci __le64 iv[2]; 1768c2ecf20Sopenharmony_ci bool ret; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci chacha_load_key(k, key); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci iv[0] = 0; 1818c2ecf20Sopenharmony_ci iv[1] = cpu_to_le64(nonce); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci chacha_init(chacha_state, k, (u8 *)iv); 1848c2ecf20Sopenharmony_ci ret = __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, 1858c2ecf20Sopenharmony_ci chacha_state); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci memzero_explicit(chacha_state, sizeof(chacha_state)); 1888c2ecf20Sopenharmony_ci memzero_explicit(iv, sizeof(iv)); 1898c2ecf20Sopenharmony_ci memzero_explicit(k, sizeof(k)); 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_decrypt); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cibool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 1958c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 1968c2ecf20Sopenharmony_ci const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], 1978c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci xchacha_init(chacha_state, key, nonce); 2028c2ecf20Sopenharmony_ci return __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, 2038c2ecf20Sopenharmony_ci chacha_state); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xchacha20poly1305_decrypt); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic 2088c2ecf20Sopenharmony_cibool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src, 2098c2ecf20Sopenharmony_ci const size_t src_len, 2108c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 2118c2ecf20Sopenharmony_ci const u64 nonce, 2128c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE], 2138c2ecf20Sopenharmony_ci int encrypt) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci const u8 *pad0 = page_address(ZERO_PAGE(0)); 2168c2ecf20Sopenharmony_ci struct poly1305_desc_ctx poly1305_state; 2178c2ecf20Sopenharmony_ci u32 chacha_state[CHACHA_STATE_WORDS]; 2188c2ecf20Sopenharmony_ci struct sg_mapping_iter miter; 2198c2ecf20Sopenharmony_ci size_t partial = 0; 2208c2ecf20Sopenharmony_ci unsigned int flags; 2218c2ecf20Sopenharmony_ci bool ret = true; 2228c2ecf20Sopenharmony_ci int sl; 2238c2ecf20Sopenharmony_ci union { 2248c2ecf20Sopenharmony_ci struct { 2258c2ecf20Sopenharmony_ci u32 k[CHACHA_KEY_WORDS]; 2268c2ecf20Sopenharmony_ci __le64 iv[2]; 2278c2ecf20Sopenharmony_ci }; 2288c2ecf20Sopenharmony_ci u8 block0[POLY1305_KEY_SIZE]; 2298c2ecf20Sopenharmony_ci u8 chacha_stream[CHACHA_BLOCK_SIZE]; 2308c2ecf20Sopenharmony_ci struct { 2318c2ecf20Sopenharmony_ci u8 mac[2][POLY1305_DIGEST_SIZE]; 2328c2ecf20Sopenharmony_ci }; 2338c2ecf20Sopenharmony_ci __le64 lens[2]; 2348c2ecf20Sopenharmony_ci } b __aligned(16); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (WARN_ON(src_len > INT_MAX)) 2378c2ecf20Sopenharmony_ci return false; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci chacha_load_key(b.k, key); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci b.iv[0] = 0; 2428c2ecf20Sopenharmony_ci b.iv[1] = cpu_to_le64(nonce); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci chacha_init(chacha_state, b.k, (u8 *)b.iv); 2458c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); 2468c2ecf20Sopenharmony_ci poly1305_init(&poly1305_state, b.block0); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (unlikely(ad_len)) { 2498c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, ad, ad_len); 2508c2ecf20Sopenharmony_ci if (ad_len & 0xf) 2518c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci flags = SG_MITER_TO_SG | SG_MITER_ATOMIC; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci sg_miter_start(&miter, src, sg_nents(src), flags); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci for (sl = src_len; sl > 0 && sg_miter_next(&miter); sl -= miter.length) { 2598c2ecf20Sopenharmony_ci u8 *addr = miter.addr; 2608c2ecf20Sopenharmony_ci size_t length = min_t(size_t, sl, miter.length); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!encrypt) 2638c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, addr, length); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (unlikely(partial)) { 2668c2ecf20Sopenharmony_ci size_t l = min(length, CHACHA_BLOCK_SIZE - partial); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci crypto_xor(addr, b.chacha_stream + partial, l); 2698c2ecf20Sopenharmony_ci partial = (partial + l) & (CHACHA_BLOCK_SIZE - 1); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci addr += l; 2728c2ecf20Sopenharmony_ci length -= l; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (likely(length >= CHACHA_BLOCK_SIZE || length == sl)) { 2768c2ecf20Sopenharmony_ci size_t l = length; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (unlikely(length < sl)) 2798c2ecf20Sopenharmony_ci l &= ~(CHACHA_BLOCK_SIZE - 1); 2808c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, addr, addr, l); 2818c2ecf20Sopenharmony_ci addr += l; 2828c2ecf20Sopenharmony_ci length -= l; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (unlikely(length > 0)) { 2868c2ecf20Sopenharmony_ci chacha20_crypt(chacha_state, b.chacha_stream, pad0, 2878c2ecf20Sopenharmony_ci CHACHA_BLOCK_SIZE); 2888c2ecf20Sopenharmony_ci crypto_xor(addr, b.chacha_stream, length); 2898c2ecf20Sopenharmony_ci partial = length; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (encrypt) 2938c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, miter.addr, 2948c2ecf20Sopenharmony_ci min_t(size_t, sl, miter.length)); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (src_len & 0xf) 2988c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci b.lens[0] = cpu_to_le64(ad_len); 3018c2ecf20Sopenharmony_ci b.lens[1] = cpu_to_le64(src_len); 3028c2ecf20Sopenharmony_ci poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (likely(sl <= -POLY1305_DIGEST_SIZE)) { 3058c2ecf20Sopenharmony_ci if (encrypt) { 3068c2ecf20Sopenharmony_ci poly1305_final(&poly1305_state, 3078c2ecf20Sopenharmony_ci miter.addr + miter.length + sl); 3088c2ecf20Sopenharmony_ci ret = true; 3098c2ecf20Sopenharmony_ci } else { 3108c2ecf20Sopenharmony_ci poly1305_final(&poly1305_state, b.mac[0]); 3118c2ecf20Sopenharmony_ci ret = !crypto_memneq(b.mac[0], 3128c2ecf20Sopenharmony_ci miter.addr + miter.length + sl, 3138c2ecf20Sopenharmony_ci POLY1305_DIGEST_SIZE); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci sg_miter_stop(&miter); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (unlikely(sl > -POLY1305_DIGEST_SIZE)) { 3208c2ecf20Sopenharmony_ci poly1305_final(&poly1305_state, b.mac[1]); 3218c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b.mac[encrypt], src, src_len, 3228c2ecf20Sopenharmony_ci sizeof(b.mac[1]), encrypt); 3238c2ecf20Sopenharmony_ci ret = encrypt || 3248c2ecf20Sopenharmony_ci !crypto_memneq(b.mac[0], b.mac[1], POLY1305_DIGEST_SIZE); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci memzero_explicit(chacha_state, sizeof(chacha_state)); 3288c2ecf20Sopenharmony_ci memzero_explicit(&b, sizeof(b)); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cibool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len, 3348c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 3358c2ecf20Sopenharmony_ci const u64 nonce, 3368c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci return chacha20poly1305_crypt_sg_inplace(src, src_len, ad, ad_len, 3398c2ecf20Sopenharmony_ci nonce, key, 1); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_encrypt_sg_inplace); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cibool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len, 3448c2ecf20Sopenharmony_ci const u8 *ad, const size_t ad_len, 3458c2ecf20Sopenharmony_ci const u64 nonce, 3468c2ecf20Sopenharmony_ci const u8 key[CHACHA20POLY1305_KEY_SIZE]) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci if (unlikely(src_len < POLY1305_DIGEST_SIZE)) 3498c2ecf20Sopenharmony_ci return false; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return chacha20poly1305_crypt_sg_inplace(src, 3528c2ecf20Sopenharmony_ci src_len - POLY1305_DIGEST_SIZE, 3538c2ecf20Sopenharmony_ci ad, ad_len, nonce, key, 0); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(chacha20poly1305_decrypt_sg_inplace); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int __init mod_init(void) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && 3608c2ecf20Sopenharmony_ci WARN_ON(!chacha20poly1305_selftest())) 3618c2ecf20Sopenharmony_ci return -ENODEV; 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cimodule_init(mod_init); 3668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction"); 3688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>"); 369