crypto: gcmaes - Provide minimal library implementation
Subsystems (3)
Ard Biesheuvel
maintainerPATCH v2 1/1 crypto: gcmaes - Provide minimal library implementation
Implement a minimal library version of GCM based on the existing library implementations of AES and multiplication in GF(2^128). Using these primitives, GCM can be implemented in a straight-forward manner.
GCM has a couple of sharp edges, i.e., the amount of input data processed with the same initialization vector (IV) should be capped to protect the counter from 32-bit rollover (or carry), and the size of the authentication tag should be fixed for a given key. [0]
The former concern is addressed trivially, given that the function call API uses 32-bit signed types for the input lengths. It is still up to the caller to avoid IV reuse in general, but this is not something we can police at the implementation level.
As for the latter concern, let's make the authentication tag size part of the key schedule, and only permit it to be configured as part of the key expansion routine.
Note that table based AES implementations are susceptible to known plaintext timing attacks on the encryption key. The AES library already attempts to mitigate this to some extent, but given that the counter mode encryption used by GCM operates exclusively on known plaintext by construction (the IV and therefore the initial counter value are known to an attacker), let's take some extra care to mitigate this, by calling the AES library with interrupts disabled.
[0] https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38d.pdf
---
v2: - rename gcm to gcmaes to reflect that GCM is also used in
combination with other symmetric ciphers (Jason)
- add Nikunj's Tested-by
arch/x86/crypto/aesni-intel_glue.c | 24 +- include/crypto/gcm.h | 66 ++ lib/crypto/Kconfig | 6 + lib/crypto/Makefile | 3 + lib/crypto/gcmaes.c | 720 ++++++++++++++++++++ 5 files changed, 807 insertions(+), 12 deletions(-)
arch/x86/crypto/aesni-intel_glue.c +12 -12
@@ -778,8 +778,8 @@ static int gcmaes_crypt_by_sg(bool enc, struct aead_request *req,return 0 ; } -static int gcmaes_encrypt (struct aead_request *req,unsigned int assoclen, -u8 *hash_subkey,u8 *iv,void *aes_ctx) +static int gcmaesni_encrypt (struct aead_request *req,unsigned int assoclen, +u8 *hash_subkey,u8 *iv,void *aes_ctx) {struct crypto_aead *tfm =crypto_aead_reqtfm (req);unsigned long auth_tag_len =crypto_aead_authsize (tfm);
@@ -797,8 +797,8 @@ static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen,return 0 ; } -static int gcmaes_decrypt (struct aead_request *req,unsigned int assoclen, -u8 *hash_subkey,u8 *iv,void *aes_ctx) +static int gcmaesni_decrypt (struct aead_request *req,unsigned int assoclen, +u8 *hash_subkey,u8 *iv,void *aes_ctx) {struct crypto_aead *tfm =crypto_aead_reqtfm (req);unsigned long auth_tag_len =crypto_aead_authsize (tfm);
@@ -847,8 +847,8 @@ static int helper_rfc4106_encrypt(struct aead_request *req) *(iv+4 +i) = req->iv[i]; *((__be32 *)(iv+12 )) = counter; -return gcmaes_encrypt (req, req->assoclen -8 , ctx->hash_subkey, iv, - aes_ctx); +return gcmaesni_encrypt (req, req->assoclen -8 , ctx->hash_subkey, iv, + aes_ctx); }static int helper_rfc4106_decrypt (struct aead_request *req)
@@ -875,8 +875,8 @@ static int helper_rfc4106_decrypt(struct aead_request *req) *(iv+4 +i) = req->iv[i]; *((__be32 *)(iv+12 )) = counter; -return gcmaes_decrypt (req, req->assoclen -8 , ctx->hash_subkey, iv, - aes_ctx); +return gcmaesni_decrypt (req, req->assoclen -8 , ctx->hash_subkey, iv, + aes_ctx); }#endif
@@ -1167,8 +1167,8 @@ static int generic_gcmaes_encrypt(struct aead_request *req)memcpy (iv, req->iv,12 ); *((__be32 *)(iv+12 )) = counter; -return gcmaes_encrypt (req, req->assoclen, ctx->hash_subkey, iv, - aes_ctx); +return gcmaesni_encrypt (req, req->assoclen, ctx->hash_subkey, iv, + aes_ctx); }static int generic_gcmaes_decrypt (struct aead_request *req)
@@ -1183,8 +1183,8 @@ static int generic_gcmaes_decrypt(struct aead_request *req)memcpy (iv, req->iv,12 ); *((__be32 *)(iv+12 )) = counter; -return gcmaes_decrypt (req, req->assoclen, ctx->hash_subkey, iv, - aes_ctx); +return gcmaesni_decrypt (req, req->assoclen, ctx->hash_subkey, iv, + aes_ctx); }static struct aead_alg aesni_aeads[] = { {
include/crypto/gcm.h +66 -0
76 lines not on this page · raw message
lib/crypto/Kconfig +6 -0
@@ -8,6 +8,12 @@ config CRYPTO_LIB_UTILS config CRYPTO_LIB_AES tristate +config CRYPTO_LIB_GCMAES + tristate + select CRYPTO_GF128MUL + select CRYPTO_LIB_AES + select CRYPTO_LIB_UTILS + config CRYPTO_LIB_ARC4 tristate
lib/crypto/Makefile +3 -0
@@ -10,6 +10,9 @@ obj-$(CONFIG_CRYPTO_LIB_CHACHA_GENERIC) += libchacha.o obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o libaes-y := aes.o +obj-$(CONFIG_CRYPTO_LIB_GCMAES) += libgcmaes.o +libgcmaes-y := gcmaes.o + obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o libarc4-y := arc4.o
lib/crypto/gcmaes.c new file +720 -0
720 lines not on this page · raw message
Signature · 1 line
2.35.1
Eric Biggers
maintainerQuoted 7 lines · Ard Biesheuvel
Note that table based AES implementations are susceptible to known plaintext timing attacks on the encryption key. The AES library already attempts to mitigate this to some extent, but given that the counter mode encryption used by GCM operates exclusively on known plaintext by construction (the IV and therefore the initial counter value are known to an attacker), let's take some extra care to mitigate this, by calling the AES library with interrupts disabled.
Note that crypto/gf128mul.c has no mitigations against timing attacks. I take it that is something that needs to be tolerated here?
Quoted 29 lines
include/crypto/gcm.h +14
-0@@ -3,6 +3,9 @@#include <linux/errno.h> +#include <crypto/aes.h> +#include <crypto/gf128mul.h> +#define GCM_AES_IV_SIZE 12#define GCM_RFC4106_IV_SIZE 8#define GCM_RFC4543_IV_SIZE 8@@ -60,4 +63,67 @@ static inline int crypto_ipsec_check_assoclen(unsigned int assoclen)return 0 ; } + +struct gcmaes_ctx { +be128 ghash_key; +struct crypto_aes_ctx aes_ctx; +unsigned int authsize; +}; + +/** +* gcmaes_expandkey - Expands the AES and GHASH keys for the GCM-AES key +* schedule +*
include/crypto/gcm.h static inline int crypto_ipsec_check_assoclen(unsigned int assoclen) · line 86
Quoted 10 lines
include/crypto/gcm.h +10
-0+* @ctx: The data structure that will hold the GCM-AES key schedule +* @key: The AES encryption input key +* @keysize: The length in bytes of the input key +* @authsize: The size in bytes of the GCM authentication tag +* +* Returns 0 on success, or -EINVAL if @keysize or @authsize contain values +* that are not permitted by the GCM specification. +*/ +int gcmaes_expandkey (struct gcmaes_ctx *ctx,const u8 *key, +unsigned int keysize,unsigned int authsize);
These comments are duplicated in the .c file too. They should be in just one place, probably the .c file since that approach is more common in the kernel.
Also, this seems to be intended to be a kerneldoc comment, but the return value isn't documented in the correct format. It needs to be "Return:". Try this:
$ ./scripts/kernel-doc -v -none lib/crypto/gcmaes.c lib/crypto/gcmaes.c:35: info: Scanning doc for function gcmaes_expandkey lib/crypto/gcmaes.c:48: warning: No description found for return value of 'gcmaes_expandkey' lib/crypto/gcmaes.c:114: info: Scanning doc for function gcmaes_encrypt lib/crypto/gcmaes.c:142: info: Scanning doc for function gcmaes_decrypt lib/crypto/gcmaes.c:162: warning: No description found for return value of 'gcmaes_decrypt'
include/crypto/gcm.h static inline int crypto_ipsec_check_assoclen(unsigned int assoclen) · line 91
Quoted 5 lines
include/crypto/gcm.h +5
-0+config CRYPTO_LIB_GCMAES +tristate + select CRYPTO_GF128MUL + select CRYPTO_LIB_AES + select CRYPTO_LIB_UTILS
Doesn't this mean that crypto/gf128mul.c needs to be moved into lib/crypto/?
- Eric
Ard Biesheuvel
maintainerQuoted 10 lines · Eric Biggers
Quoted 7 lines · Ard Biesheuvel
Note that table based AES implementations are susceptible to known plaintext timing attacks on the encryption key. The AES library already attempts to mitigate this to some extent, but given that the counter mode encryption used by GCM operates exclusively on known plaintext by construction (the IV and therefore the initial counter value are known to an attacker), let's take some extra care to mitigate this, by calling the AES library with interrupts disabled.
Quoted 3 lines
Note that
crypto/gf128mul.chas no mitigations against timing attacks. I take it that is something that needs to be tolerated here?
Ah good point - I misremembered and thought that the 'slow' version without the expanded key uses not table lookups at all.
I can add a patch to address this, it doesn't seem all that difficult to remove the table lookups and data or key dependent conditionals.
Quoted 34 lines
Quoted 34 lines
include/crypto/gcm.h +19
-0@@ -3,6 +3,9 @@#include <linux/errno.h> +#include <crypto/aes.h> +#include <crypto/gf128mul.h> +#define GCM_AES_IV_SIZE 12#define GCM_RFC4106_IV_SIZE 8#define GCM_RFC4543_IV_SIZE 8@@ -60,4 +63,67 @@ static inline int crypto_ipsec_check_assoclen(unsigned int assoclen)return 0 ; } + +struct gcmaes_ctx { +be128 ghash_key; +struct crypto_aes_ctx aes_ctx; +unsigned int authsize; +}; + +/** +* gcmaes_expandkey - Expands the AES and GHASH keys for the GCM-AES key +* schedule +* +* @ctx: The data structure that will hold the GCM-AES key schedule +* @key: The AES encryption input key +* @keysize: The length in bytes of the input key +* @authsize: The size in bytes of the GCM authentication tag +*
Quoted 9 lines
include/crypto/gcm.h static inline int crypto_ipsec_check_assoclen(unsigned int assoclen) · line 86
Quoted 5 lines
include/crypto/gcm.h +5
-0+* Returns 0 on success, or -EINVAL if @keysize or @authsize contain values +* that are not permitted by the GCM specification. +*/ +int gcmaes_expandkey (struct gcmaes_ctx *ctx,const u8 *key, +unsigned int keysize,unsigned int authsize);These comments are duplicated in the .c file too. They should be in just one place, probably the .c file since that approach is more common in the kernel.
OK
Quoted 10 lines
Also, this seems to be intended to be a kerneldoc comment, but the return value isn't documented in the correct format. It needs to be "Return:". Try this:
$ ./scripts/kernel-doc -v -none lib/crypto/gcmaes.c lib/crypto/gcmaes.c:35: info: Scanning doc for function gcmaes_expandkey lib/crypto/gcmaes.c:48: warning: No description found for return value of 'gcmaes_expandkey' lib/crypto/gcmaes.c:114: info: Scanning doc for function gcmaes_encrypt lib/crypto/gcmaes.c:142: info: Scanning doc for function gcmaes_decrypt lib/crypto/gcmaes.c:162: warning: No description found for return value of 'gcmaes_decrypt'
OK, will fix.
Quoted 8 lines
include/crypto/gcm.h static inline int crypto_ipsec_check_assoclen(unsigned int assoclen) · line 91
Quoted 5 lines
include/crypto/gcm.h +5
-0+config CRYPTO_LIB_GCMAES +tristate + select CRYPTO_GF128MUL + select CRYPTO_LIB_AES + select CRYPTO_LIB_UTILSDoesn't this mean that
crypto/gf128mul.cneeds to be moved intolib/crypto/?
Probably, I'll address that as well in v3.
Thanks,
Ard.