2 * Accelerated GHASH implementation with ARMv8 PMULL instructions.
4 * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
12 #include <asm/unaligned.h>
13 #include <crypto/internal/hash.h>
14 #include <linux/cpufeature.h>
15 #include <linux/crypto.h>
16 #include <linux/module.h>
18 MODULE_DESCRIPTION("GHASH secure hash using ARMv8 Crypto Extensions");
19 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
20 MODULE_LICENSE("GPL v2");
22 #define GHASH_BLOCK_SIZE 16
23 #define GHASH_DIGEST_SIZE 16
30 struct ghash_desc_ctx
{
31 u64 digest
[GHASH_DIGEST_SIZE
/sizeof(u64
)];
32 u8 buf
[GHASH_BLOCK_SIZE
];
36 asmlinkage
void pmull_ghash_update(int blocks
, u64 dg
[], const char *src
,
37 struct ghash_key
const *k
, const char *head
);
39 static int ghash_init(struct shash_desc
*desc
)
41 struct ghash_desc_ctx
*ctx
= shash_desc_ctx(desc
);
43 *ctx
= (struct ghash_desc_ctx
){};
47 static int ghash_update(struct shash_desc
*desc
, const u8
*src
,
50 struct ghash_desc_ctx
*ctx
= shash_desc_ctx(desc
);
51 unsigned int partial
= ctx
->count
% GHASH_BLOCK_SIZE
;
55 if ((partial
+ len
) >= GHASH_BLOCK_SIZE
) {
56 struct ghash_key
*key
= crypto_shash_ctx(desc
->tfm
);
60 int p
= GHASH_BLOCK_SIZE
- partial
;
62 memcpy(ctx
->buf
+ partial
, src
, p
);
67 blocks
= len
/ GHASH_BLOCK_SIZE
;
68 len
%= GHASH_BLOCK_SIZE
;
70 kernel_neon_begin_partial(8);
71 pmull_ghash_update(blocks
, ctx
->digest
, src
, key
,
72 partial
? ctx
->buf
: NULL
);
74 src
+= blocks
* GHASH_BLOCK_SIZE
;
78 memcpy(ctx
->buf
+ partial
, src
, len
);
82 static int ghash_final(struct shash_desc
*desc
, u8
*dst
)
84 struct ghash_desc_ctx
*ctx
= shash_desc_ctx(desc
);
85 unsigned int partial
= ctx
->count
% GHASH_BLOCK_SIZE
;
88 struct ghash_key
*key
= crypto_shash_ctx(desc
->tfm
);
90 memset(ctx
->buf
+ partial
, 0, GHASH_BLOCK_SIZE
- partial
);
92 kernel_neon_begin_partial(8);
93 pmull_ghash_update(1, ctx
->digest
, ctx
->buf
, key
, NULL
);
96 put_unaligned_be64(ctx
->digest
[1], dst
);
97 put_unaligned_be64(ctx
->digest
[0], dst
+ 8);
99 *ctx
= (struct ghash_desc_ctx
){};
103 static int ghash_setkey(struct crypto_shash
*tfm
,
104 const u8
*inkey
, unsigned int keylen
)
106 struct ghash_key
*key
= crypto_shash_ctx(tfm
);
109 if (keylen
!= GHASH_BLOCK_SIZE
) {
110 crypto_shash_set_flags(tfm
, CRYPTO_TFM_RES_BAD_KEY_LEN
);
114 /* perform multiplication by 'x' in GF(2^128) */
115 b
= get_unaligned_be64(inkey
);
116 a
= get_unaligned_be64(inkey
+ 8);
118 key
->a
= (a
<< 1) | (b
>> 63);
119 key
->b
= (b
<< 1) | (a
>> 63);
122 key
->b
^= 0xc200000000000000UL
;
127 static struct shash_alg ghash_alg
= {
128 .digestsize
= GHASH_DIGEST_SIZE
,
130 .update
= ghash_update
,
131 .final
= ghash_final
,
132 .setkey
= ghash_setkey
,
133 .descsize
= sizeof(struct ghash_desc_ctx
),
136 .cra_driver_name
= "ghash-ce",
138 .cra_flags
= CRYPTO_ALG_TYPE_SHASH
,
139 .cra_blocksize
= GHASH_BLOCK_SIZE
,
140 .cra_ctxsize
= sizeof(struct ghash_key
),
141 .cra_module
= THIS_MODULE
,
145 static int __init
ghash_ce_mod_init(void)
147 return crypto_register_shash(&ghash_alg
);
150 static void __exit
ghash_ce_mod_exit(void)
152 crypto_unregister_shash(&ghash_alg
);
155 module_cpu_feature_match(PMULL
, ghash_ce_mod_init
);
156 module_exit(ghash_ce_mod_exit
);