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); |
} |