OSDN Git Service

crypto: talitos - HMAC SNOOP NO AFEU mode requires SW icv checking.
[android-x86/kernel.git] / crypto / drbg.c
index fb33f7d..4bb5f93 100644 (file)
@@ -262,6 +262,7 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                              u8 *inbuf, u32 inbuflen,
                              u8 *outbuf, u32 outlen);
 #define DRBG_CTR_NULL_LEN 128
+#define DRBG_OUTSCRATCHLEN DRBG_CTR_NULL_LEN
 
 /* BCC function for CTR DRBG as defined in 10.4.3 */
 static int drbg_ctr_bcc(struct drbg_state *drbg,
@@ -1132,10 +1133,12 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
 {
        if (!drbg)
                return;
-       kzfree(drbg->V);
+       kzfree(drbg->Vbuf);
        drbg->Vbuf = NULL;
-       kzfree(drbg->C);
+       drbg->V = NULL;
+       kzfree(drbg->Cbuf);
        drbg->Cbuf = NULL;
+       drbg->C = NULL;
        kzfree(drbg->scratchpadbuf);
        drbg->scratchpadbuf = NULL;
        drbg->reseed_ctr = 0;
@@ -1644,6 +1647,9 @@ static int drbg_fini_sym_kernel(struct drbg_state *drbg)
        kfree(drbg->ctr_null_value_buf);
        drbg->ctr_null_value = NULL;
 
+       kfree(drbg->outscratchpadbuf);
+       drbg->outscratchpadbuf = NULL;
+
        return 0;
 }
 
@@ -1687,6 +1693,7 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
                return PTR_ERR(sk_tfm);
        }
        drbg->ctr_handle = sk_tfm;
+       init_completion(&drbg->ctr_completion);
 
        req = skcipher_request_alloc(sk_tfm, GFP_KERNEL);
        if (!req) {
@@ -1708,6 +1715,15 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
        drbg->ctr_null_value = (u8 *)PTR_ALIGN(drbg->ctr_null_value_buf,
                                               alignmask + 1);
 
+       drbg->outscratchpadbuf = kmalloc(DRBG_OUTSCRATCHLEN + alignmask,
+                                        GFP_KERNEL);
+       if (!drbg->outscratchpadbuf) {
+               drbg_fini_sym_kernel(drbg);
+               return -ENOMEM;
+       }
+       drbg->outscratchpad = (u8 *)PTR_ALIGN(drbg->outscratchpadbuf,
+                                             alignmask + 1);
+
        return alignmask;
 }
 
@@ -1737,15 +1753,16 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                              u8 *outbuf, u32 outlen)
 {
        struct scatterlist sg_in;
+       int ret;
 
        sg_init_one(&sg_in, inbuf, inlen);
 
        while (outlen) {
-               u32 cryptlen = min_t(u32, inlen, outlen);
+               u32 cryptlen = min3(inlen, outlen, (u32)DRBG_OUTSCRATCHLEN);
                struct scatterlist sg_out;
-               int ret;
 
-               sg_init_one(&sg_out, outbuf, cryptlen);
+               /* Output buffer may not be valid for SGL, use scratchpad */
+               sg_init_one(&sg_out, drbg->outscratchpad, cryptlen);
                skcipher_request_set_crypt(drbg->ctr_req, &sg_in, &sg_out,
                                           cryptlen, drbg->V);
                ret = crypto_skcipher_encrypt(drbg->ctr_req);
@@ -1754,21 +1771,25 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                        break;
                case -EINPROGRESS:
                case -EBUSY:
-                       ret = wait_for_completion_interruptible(
-                               &drbg->ctr_completion);
-                       if (!ret && !drbg->ctr_async_err) {
+                       wait_for_completion(&drbg->ctr_completion);
+                       if (!drbg->ctr_async_err) {
                                reinit_completion(&drbg->ctr_completion);
                                break;
                        }
                default:
-                       return ret;
+                       goto out;
                }
                init_completion(&drbg->ctr_completion);
 
+               memcpy(outbuf, drbg->outscratchpad, cryptlen);
+
                outlen -= cryptlen;
        }
+       ret = 0;
 
-       return 0;
+out:
+       memzero_explicit(drbg->outscratchpad, DRBG_OUTSCRATCHLEN);
+       return ret;
 }
 #endif /* CONFIG_CRYPTO_DRBG_CTR */