0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 #include <asm/unaligned.h>
0048 #include <crypto/algapi.h>
0049 #include <crypto/gf128mul.h>
0050 #include <crypto/polyval.h>
0051 #include <crypto/internal/hash.h>
0052 #include <linux/crypto.h>
0053 #include <linux/init.h>
0054 #include <linux/kernel.h>
0055 #include <linux/module.h>
0056
0057 struct polyval_tfm_ctx {
0058 struct gf128mul_4k *gf128;
0059 };
0060
0061 struct polyval_desc_ctx {
0062 union {
0063 u8 buffer[POLYVAL_BLOCK_SIZE];
0064 be128 buffer128;
0065 };
0066 u32 bytes;
0067 };
0068
0069 static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE],
0070 const u8 src[POLYVAL_BLOCK_SIZE])
0071 {
0072 u64 a = get_unaligned((const u64 *)&src[0]);
0073 u64 b = get_unaligned((const u64 *)&src[8]);
0074
0075 put_unaligned(swab64(a), (u64 *)&dst[8]);
0076 put_unaligned(swab64(b), (u64 *)&dst[0]);
0077 }
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 void polyval_mul_non4k(u8 *op1, const u8 *op2)
0088 {
0089 be128 a, b;
0090
0091
0092 copy_and_reverse((u8 *)&a, op1);
0093 copy_and_reverse((u8 *)&b, op2);
0094 gf128mul_x_lle(&a, &a);
0095 gf128mul_lle(&a, &b);
0096 copy_and_reverse(op1, (u8 *)&a);
0097 }
0098 EXPORT_SYMBOL_GPL(polyval_mul_non4k);
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108 void polyval_update_non4k(const u8 *key, const u8 *in,
0109 size_t nblocks, u8 *accumulator)
0110 {
0111 while (nblocks--) {
0112 crypto_xor(accumulator, in, POLYVAL_BLOCK_SIZE);
0113 polyval_mul_non4k(accumulator, key);
0114 in += POLYVAL_BLOCK_SIZE;
0115 }
0116 }
0117 EXPORT_SYMBOL_GPL(polyval_update_non4k);
0118
0119 static int polyval_setkey(struct crypto_shash *tfm,
0120 const u8 *key, unsigned int keylen)
0121 {
0122 struct polyval_tfm_ctx *ctx = crypto_shash_ctx(tfm);
0123 be128 k;
0124
0125 if (keylen != POLYVAL_BLOCK_SIZE)
0126 return -EINVAL;
0127
0128 gf128mul_free_4k(ctx->gf128);
0129
0130 BUILD_BUG_ON(sizeof(k) != POLYVAL_BLOCK_SIZE);
0131 copy_and_reverse((u8 *)&k, key);
0132 gf128mul_x_lle(&k, &k);
0133
0134 ctx->gf128 = gf128mul_init_4k_lle(&k);
0135 memzero_explicit(&k, POLYVAL_BLOCK_SIZE);
0136
0137 if (!ctx->gf128)
0138 return -ENOMEM;
0139
0140 return 0;
0141 }
0142
0143 static int polyval_init(struct shash_desc *desc)
0144 {
0145 struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
0146
0147 memset(dctx, 0, sizeof(*dctx));
0148
0149 return 0;
0150 }
0151
0152 static int polyval_update(struct shash_desc *desc,
0153 const u8 *src, unsigned int srclen)
0154 {
0155 struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
0156 const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
0157 u8 *pos;
0158 u8 tmp[POLYVAL_BLOCK_SIZE];
0159 int n;
0160
0161 if (dctx->bytes) {
0162 n = min(srclen, dctx->bytes);
0163 pos = dctx->buffer + dctx->bytes - 1;
0164
0165 dctx->bytes -= n;
0166 srclen -= n;
0167
0168 while (n--)
0169 *pos-- ^= *src++;
0170
0171 if (!dctx->bytes)
0172 gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
0173 }
0174
0175 while (srclen >= POLYVAL_BLOCK_SIZE) {
0176 copy_and_reverse(tmp, src);
0177 crypto_xor(dctx->buffer, tmp, POLYVAL_BLOCK_SIZE);
0178 gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
0179 src += POLYVAL_BLOCK_SIZE;
0180 srclen -= POLYVAL_BLOCK_SIZE;
0181 }
0182
0183 if (srclen) {
0184 dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
0185 pos = dctx->buffer + POLYVAL_BLOCK_SIZE - 1;
0186 while (srclen--)
0187 *pos-- ^= *src++;
0188 }
0189
0190 return 0;
0191 }
0192
0193 static int polyval_final(struct shash_desc *desc, u8 *dst)
0194 {
0195 struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
0196 const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
0197
0198 if (dctx->bytes)
0199 gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
0200 copy_and_reverse(dst, dctx->buffer);
0201 return 0;
0202 }
0203
0204 static void polyval_exit_tfm(struct crypto_tfm *tfm)
0205 {
0206 struct polyval_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
0207
0208 gf128mul_free_4k(ctx->gf128);
0209 }
0210
0211 static struct shash_alg polyval_alg = {
0212 .digestsize = POLYVAL_DIGEST_SIZE,
0213 .init = polyval_init,
0214 .update = polyval_update,
0215 .final = polyval_final,
0216 .setkey = polyval_setkey,
0217 .descsize = sizeof(struct polyval_desc_ctx),
0218 .base = {
0219 .cra_name = "polyval",
0220 .cra_driver_name = "polyval-generic",
0221 .cra_priority = 100,
0222 .cra_blocksize = POLYVAL_BLOCK_SIZE,
0223 .cra_ctxsize = sizeof(struct polyval_tfm_ctx),
0224 .cra_module = THIS_MODULE,
0225 .cra_exit = polyval_exit_tfm,
0226 },
0227 };
0228
0229 static int __init polyval_mod_init(void)
0230 {
0231 return crypto_register_shash(&polyval_alg);
0232 }
0233
0234 static void __exit polyval_mod_exit(void)
0235 {
0236 crypto_unregister_shash(&polyval_alg);
0237 }
0238
0239 subsys_initcall(polyval_mod_init);
0240 module_exit(polyval_mod_exit);
0241
0242 MODULE_LICENSE("GPL");
0243 MODULE_DESCRIPTION("POLYVAL hash function");
0244 MODULE_ALIAS_CRYPTO("polyval");
0245 MODULE_ALIAS_CRYPTO("polyval-generic");