~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/crypto/polyval-generic.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * POLYVAL: hash function for HCTR2.
  4  *
  5  * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
  6  * Copyright (c) 2009 Intel Corp.
  7  *   Author: Huang Ying <ying.huang@intel.com>
  8  * Copyright 2021 Google LLC
  9  */
 10 
 11 /*
 12  * Code based on crypto/ghash-generic.c
 13  *
 14  * POLYVAL is a keyed hash function similar to GHASH. POLYVAL uses a different
 15  * modulus for finite field multiplication which makes hardware accelerated
 16  * implementations on little-endian machines faster. POLYVAL is used in the
 17  * kernel to implement HCTR2, but was originally specified for AES-GCM-SIV
 18  * (RFC 8452).
 19  *
 20  * For more information see:
 21  * Length-preserving encryption with HCTR2:
 22  *   https://eprint.iacr.org/2021/1441.pdf
 23  * AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption:
 24  *   https://datatracker.ietf.org/doc/html/rfc8452
 25  *
 26  * Like GHASH, POLYVAL is not a cryptographic hash function and should
 27  * not be used outside of crypto modes explicitly designed to use POLYVAL.
 28  *
 29  * This implementation uses a convenient trick involving the GHASH and POLYVAL
 30  * fields. This trick allows multiplication in the POLYVAL field to be
 31  * implemented by using multiplication in the GHASH field as a subroutine. An
 32  * element of the POLYVAL field can be converted to an element of the GHASH
 33  * field by computing x*REVERSE(a), where REVERSE reverses the byte-ordering of
 34  * a. Similarly, an element of the GHASH field can be converted back to the
 35  * POLYVAL field by computing REVERSE(x^{-1}*a). For more information, see:
 36  * https://datatracker.ietf.org/doc/html/rfc8452#appendix-A
 37  *
 38  * By using this trick, we do not need to implement the POLYVAL field for the
 39  * generic implementation.
 40  *
 41  * Warning: this generic implementation is not intended to be used in practice
 42  * and is not constant time. For practical use, a hardware accelerated
 43  * implementation of POLYVAL should be used instead.
 44  *
 45  */
 46 
 47 #include <asm/unaligned.h>
 48 #include <crypto/algapi.h>
 49 #include <crypto/gf128mul.h>
 50 #include <crypto/polyval.h>
 51 #include <crypto/internal/hash.h>
 52 #include <linux/crypto.h>
 53 #include <linux/init.h>
 54 #include <linux/kernel.h>
 55 #include <linux/module.h>
 56 
 57 struct polyval_tfm_ctx {
 58         struct gf128mul_4k *gf128;
 59 };
 60 
 61 struct polyval_desc_ctx {
 62         union {
 63                 u8 buffer[POLYVAL_BLOCK_SIZE];
 64                 be128 buffer128;
 65         };
 66         u32 bytes;
 67 };
 68 
 69 static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE],
 70                              const u8 src[POLYVAL_BLOCK_SIZE])
 71 {
 72         u64 a = get_unaligned((const u64 *)&src[0]);
 73         u64 b = get_unaligned((const u64 *)&src[8]);
 74 
 75         put_unaligned(swab64(a), (u64 *)&dst[8]);
 76         put_unaligned(swab64(b), (u64 *)&dst[0]);
 77 }
 78 
 79 /*
 80  * Performs multiplication in the POLYVAL field using the GHASH field as a
 81  * subroutine.  This function is used as a fallback for hardware accelerated
 82  * implementations when simd registers are unavailable.
 83  *
 84  * Note: This function is not used for polyval-generic, instead we use the 4k
 85  * lookup table implementation for finite field multiplication.
 86  */
 87 void polyval_mul_non4k(u8 *op1, const u8 *op2)
 88 {
 89         be128 a, b;
 90 
 91         // Assume one argument is in Montgomery form and one is not.
 92         copy_and_reverse((u8 *)&a, op1);
 93         copy_and_reverse((u8 *)&b, op2);
 94         gf128mul_x_lle(&a, &a);
 95         gf128mul_lle(&a, &b);
 96         copy_and_reverse(op1, (u8 *)&a);
 97 }
 98 EXPORT_SYMBOL_GPL(polyval_mul_non4k);
 99 
100 /*
101  * Perform a POLYVAL update using non4k multiplication.  This function is used
102  * as a fallback for hardware accelerated implementations when simd registers
103  * are unavailable.
104  *
105  * Note: This function is not used for polyval-generic, instead we use the 4k
106  * lookup table implementation of finite field multiplication.
107  */
108 void polyval_update_non4k(const u8 *key, const u8 *in,
109                           size_t nblocks, u8 *accumulator)
110 {
111         while (nblocks--) {
112                 crypto_xor(accumulator, in, POLYVAL_BLOCK_SIZE);
113                 polyval_mul_non4k(accumulator, key);
114                 in += POLYVAL_BLOCK_SIZE;
115         }
116 }
117 EXPORT_SYMBOL_GPL(polyval_update_non4k);
118 
119 static int polyval_setkey(struct crypto_shash *tfm,
120                           const u8 *key, unsigned int keylen)
121 {
122         struct polyval_tfm_ctx *ctx = crypto_shash_ctx(tfm);
123         be128 k;
124 
125         if (keylen != POLYVAL_BLOCK_SIZE)
126                 return -EINVAL;
127 
128         gf128mul_free_4k(ctx->gf128);
129 
130         BUILD_BUG_ON(sizeof(k) != POLYVAL_BLOCK_SIZE);
131         copy_and_reverse((u8 *)&k, key);
132         gf128mul_x_lle(&k, &k);
133 
134         ctx->gf128 = gf128mul_init_4k_lle(&k);
135         memzero_explicit(&k, POLYVAL_BLOCK_SIZE);
136 
137         if (!ctx->gf128)
138                 return -ENOMEM;
139 
140         return 0;
141 }
142 
143 static int polyval_init(struct shash_desc *desc)
144 {
145         struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
146 
147         memset(dctx, 0, sizeof(*dctx));
148 
149         return 0;
150 }
151 
152 static int polyval_update(struct shash_desc *desc,
153                          const u8 *src, unsigned int srclen)
154 {
155         struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
156         const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
157         u8 *pos;
158         u8 tmp[POLYVAL_BLOCK_SIZE];
159         int n;
160 
161         if (dctx->bytes) {
162                 n = min(srclen, dctx->bytes);
163                 pos = dctx->buffer + dctx->bytes - 1;
164 
165                 dctx->bytes -= n;
166                 srclen -= n;
167 
168                 while (n--)
169                         *pos-- ^= *src++;
170 
171                 if (!dctx->bytes)
172                         gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
173         }
174 
175         while (srclen >= POLYVAL_BLOCK_SIZE) {
176                 copy_and_reverse(tmp, src);
177                 crypto_xor(dctx->buffer, tmp, POLYVAL_BLOCK_SIZE);
178                 gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
179                 src += POLYVAL_BLOCK_SIZE;
180                 srclen -= POLYVAL_BLOCK_SIZE;
181         }
182 
183         if (srclen) {
184                 dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
185                 pos = dctx->buffer + POLYVAL_BLOCK_SIZE - 1;
186                 while (srclen--)
187                         *pos-- ^= *src++;
188         }
189 
190         return 0;
191 }
192 
193 static int polyval_final(struct shash_desc *desc, u8 *dst)
194 {
195         struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
196         const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
197 
198         if (dctx->bytes)
199                 gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
200         copy_and_reverse(dst, dctx->buffer);
201         return 0;
202 }
203 
204 static void polyval_exit_tfm(struct crypto_tfm *tfm)
205 {
206         struct polyval_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
207 
208         gf128mul_free_4k(ctx->gf128);
209 }
210 
211 static struct shash_alg polyval_alg = {
212         .digestsize     = POLYVAL_DIGEST_SIZE,
213         .init           = polyval_init,
214         .update         = polyval_update,
215         .final          = polyval_final,
216         .setkey         = polyval_setkey,
217         .descsize       = sizeof(struct polyval_desc_ctx),
218         .base           = {
219                 .cra_name               = "polyval",
220                 .cra_driver_name        = "polyval-generic",
221                 .cra_priority           = 100,
222                 .cra_blocksize          = POLYVAL_BLOCK_SIZE,
223                 .cra_ctxsize            = sizeof(struct polyval_tfm_ctx),
224                 .cra_module             = THIS_MODULE,
225                 .cra_exit               = polyval_exit_tfm,
226         },
227 };
228 
229 static int __init polyval_mod_init(void)
230 {
231         return crypto_register_shash(&polyval_alg);
232 }
233 
234 static void __exit polyval_mod_exit(void)
235 {
236         crypto_unregister_shash(&polyval_alg);
237 }
238 
239 subsys_initcall(polyval_mod_init);
240 module_exit(polyval_mod_exit);
241 
242 MODULE_LICENSE("GPL");
243 MODULE_DESCRIPTION("POLYVAL hash function");
244 MODULE_ALIAS_CRYPTO("polyval");
245 MODULE_ALIAS_CRYPTO("polyval-generic");
246 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php