summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-05-06 20:46:49 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2008-05-07 21:08:56 +0800
commit67412f0e78dfbbbcb36e631d9df70c6c559d60d4 (patch)
tree92975160306147eeee8ecd09b0fa13f6ab5dd6ef
parentc0a18111e571138747a98af18b3a2124df56a0d1 (diff)
downloadlinux-67412f0e78dfbbbcb36e631d9df70c6c559d60d4.tar.gz
linux-67412f0e78dfbbbcb36e631d9df70c6c559d60d4.tar.bz2
linux-67412f0e78dfbbbcb36e631d9df70c6c559d60d4.zip
[CRYPTO] hmac: Avoid calling virt_to_page on key
When HMAC gets a key longer than the block size of the hash, it needs to feed it as input to the hash to reduce it to a fixed length. As it is HMAC converts the key to a scatter and gather list. However, this doesn't work on certain platforms if the key is not allocated via kmalloc. For example, the keys from tcrypt are stored in the rodata section and this causes it to fail with HMAC on x86-64. This patch fixes this by copying the key to memory obtained via kmalloc before hashing it. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/hmac.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/crypto/hmac.c b/crypto/hmac.c
index b60c3c7aa320..14c6351e639d 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -57,14 +57,35 @@ static int hmac_setkey(struct crypto_hash *parent,
if (keylen > bs) {
struct hash_desc desc;
struct scatterlist tmp;
+ int tmplen;
int err;
desc.tfm = tfm;
desc.flags = crypto_hash_get_flags(parent);
desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
- sg_init_one(&tmp, inkey, keylen);
- err = crypto_hash_digest(&desc, &tmp, keylen, digest);
+ err = crypto_hash_init(&desc);
+ if (err)
+ return err;
+
+ tmplen = bs * 2 + ds;
+ sg_init_one(&tmp, ipad, tmplen);
+
+ for (; keylen > tmplen; inkey += tmplen, keylen -= tmplen) {
+ memcpy(ipad, inkey, tmplen);
+ err = crypto_hash_update(&desc, &tmp, tmplen);
+ if (err)
+ return err;
+ }
+
+ if (keylen) {
+ memcpy(ipad, inkey, keylen);
+ err = crypto_hash_update(&desc, &tmp, keylen);
+ if (err)
+ return err;
+ }
+
+ err = crypto_hash_final(&desc, digest);
if (err)
return err;