Chromium Code Reviews| Index: nss/mozilla/security/nss/lib/freebl/rijndael.c |
| =================================================================== |
| --- nss/mozilla/security/nss/lib/freebl/rijndael.c (revision 155503) |
| +++ nss/mozilla/security/nss/lib/freebl/rijndael.c (working copy) |
| @@ -47,6 +47,10 @@ |
| #include "blapi.h" |
| #include "rijndael.h" |
| +#include "cts.h" |
| +#include "ctr.h" |
| +#include "gcm.h" |
| + |
| #if USE_HW_AES |
| #include "intel-aes.h" |
| #include "mpi.h" |
| @@ -1050,18 +1054,20 @@ |
| memcpy(cx->iv, iv, blocksize); |
| #if USE_HW_AES |
| if (use_hw_aes) { |
| - cx->worker = intel_aes_cbc_worker(encrypt, keysize); |
| + cx->worker = (freeblCipherFunc) |
| + intel_aes_cbc_worker(encrypt, keysize); |
| } else |
| #endif |
| - cx->worker = (encrypt |
| + cx->worker = (freeblCipherFunc) (encrypt |
| ? &rijndael_encryptCBC : &rijndael_decryptCBC); |
| } else { |
| #if USE_HW_AES |
| if (use_hw_aes) { |
| - cx->worker = intel_aes_ecb_worker(encrypt, keysize); |
| + cx->worker = (freeblCipherFunc) |
| + intel_aes_ecb_worker(encrypt, keysize); |
| } else |
| #endif |
| - cx->worker = (encrypt |
| + cx->worker = (freeblCipherFunc) (encrypt |
| ? &rijndael_encryptECB : &rijndael_decryptECB); |
| } |
| PORT_Assert((cx->Nb * (cx->Nr + 1)) <= RIJNDAEL_MAX_EXP_KEY_SIZE); |
| @@ -1094,6 +1100,9 @@ |
| goto cleanup; |
| } |
| } |
| + cx->worker_cx = cx; |
| + cx->destroy = NULL; |
| + cx->isBlock = PR_TRUE; |
| return SECSuccess; |
| cleanup: |
| return SECFailure; |
| @@ -1110,17 +1119,68 @@ |
| unsigned int keysize, unsigned int blocksize) |
| { |
| AESContext *cx = AES_AllocateContext(); |
| - if (cx) { |
| - SECStatus rv = AES_InitContext(cx, key, keysize, iv, mode, encrypt, |
| - blocksize); |
| - if (rv != SECSuccess) { |
| - AES_DestroyContext(cx, PR_TRUE); |
| - cx = NULL; |
| - } |
| + int basemode = mode;; |
| + PRBool baseencrypt = encrypt; |
| + SECStatus rv; |
| + |
| + switch (mode) { |
| + case NSS_AES_CTS: |
| + basemode = NSS_AES_CBC; |
| + break; |
| + case NSS_AES_GCM: |
| + case NSS_AES_CTR: |
| + basemode = NSS_AES; |
| + baseencrypt = PR_TRUE; |
| + break; |
| } |
| + if (cx == NULL) { |
| + return NULL; |
| + } |
| + rv = AES_InitContext(cx, key, keysize, iv, basemode, |
| + baseencrypt, blocksize); |
| + if (rv != SECSuccess) { |
| + AES_DestroyContext(cx, PR_TRUE); |
| + return NULL; |
| + } |
| + |
| + /* finally, set up any mode specific contexts */ |
| + switch (mode) { |
| + case NSS_AES_CTS: |
| + cx->worker_cx = CTS_CreateContext(cx, cx->worker, iv, blocksize); |
| + cx->worker = (freeblCipherFunc) |
| + (encrypt ? CTS_EncryptUpdate : CTS_DecryptUpdate); |
| + cx->destroy = (freeblDestroyFunc) CTS_DestroyContext; |
| + cx->isBlock = PR_FALSE; |
| + break; |
| + case NSS_AES_GCM: |
| + cx->worker_cx = GCM_CreateContext(cx, cx->worker, iv, blocksize); |
| + cx->worker = (freeblCipherFunc) |
| + (encrypt ? GCM_EncryptUpdate : GCM_DecryptUpdate); |
| + cx->destroy = (freeblDestroyFunc) GCM_DestroyContext; |
| + cx->isBlock = PR_FALSE; |
| + break; |
| + case NSS_AES_CTR: |
| + cx->worker_cx = CTR_CreateContext(cx, cx->worker, iv, blocksize); |
| + cx->worker = (freeblCipherFunc) CTR_Update ; |
| + cx->destroy = (freeblDestroyFunc) CTR_DestroyContext; |
| + cx->isBlock = PR_FALSE; |
| + break; |
| + default: |
| + /* everything has already been set up by AES_InitContext, just return*/ |
| + return cx; |
| + } |
| + /* check to see if we succeeded in getting the worker context */ |
| + if (cx->worker_cx == NULL) { |
| + /* no, just destroy the existing context */ |
| + cx->destroy = NULL; /* paranoia, though you can see a dozen lines */ |
| + /* below that this isn't necessary */ |
| + AES_DestroyContext(cx, PR_TRUE); |
| + return NULL; |
| + } |
| return cx; |
| } |
| + |
| /* |
| * AES_DestroyContext |
| * |
| @@ -1131,6 +1191,9 @@ |
| AES_DestroyContext(AESContext *cx, PRBool freeit) |
| { |
| /* memset(cx, 0, sizeof *cx); */ |
| + if (freeit && cx->worker_cx && cx->destroy) { |
|
Ryan Sleevi
2012/09/11 19:34:30
It's not clear why you switch on freeit here.
My
rjrejyea
2012/09/19 22:19:33
It's ugly and has to do with psuedo private caller
|
| + (*cx->destroy)(cx->worker_cx, freeit); |
| + } |
| if (freeit) |
| PORT_Free(cx); |
| } |
| @@ -1153,7 +1216,7 @@ |
| return SECFailure; |
| } |
| blocksize = 4 * cx->Nb; |
| - if (inputLen % blocksize != 0) { |
| + if (cx->isBlock && (inputLen % blocksize != 0)) { |
| PORT_SetError(SEC_ERROR_INPUT_LEN); |
| return SECFailure; |
| } |
| @@ -1162,7 +1225,7 @@ |
| return SECFailure; |
| } |
| *outputLen = inputLen; |
| - return (*cx->worker)(cx, output, outputLen, maxOutputLen, |
| + return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, |
| input, inputLen, blocksize); |
| } |
| @@ -1184,7 +1247,7 @@ |
| return SECFailure; |
| } |
| blocksize = 4 * cx->Nb; |
| - if (inputLen % blocksize != 0) { |
| + if (cx->isBlock && (inputLen % blocksize != 0)) { |
| PORT_SetError(SEC_ERROR_INPUT_LEN); |
| return SECFailure; |
| } |
| @@ -1193,6 +1256,6 @@ |
| return SECFailure; |
| } |
| *outputLen = inputLen; |
| - return (*cx->worker)(cx, output, outputLen, maxOutputLen, |
| + return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, |
| input, inputLen, blocksize); |
| } |