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" |
@@ -988,8 +992,13 @@ |
} |
-SECStatus |
-AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, |
+/* |
+** Initialize a new AES context suitable for AES encryption/decryption in |
+** the ECB or CBC mode. |
+** "mode" the mode of operation, which must be NSS_AES or NSS_AES_CBC |
+*/ |
+static SECStatus |
+aes_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, |
const unsigned char *iv, int mode, unsigned int encrypt, |
unsigned int blocksize) |
{ |
@@ -1050,18 +1059,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,12 +1105,78 @@ |
goto cleanup; |
} |
} |
+ cx->worker_cx = cx; |
+ cx->destroy = NULL; |
+ cx->isBlock = PR_TRUE; |
return SECSuccess; |
cleanup: |
return SECFailure; |
} |
+SECStatus |
+AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, |
+ const unsigned char *iv, int mode, unsigned int encrypt, |
+ unsigned int blocksize) |
+{ |
+ 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; |
+ } |
+ rv = aes_InitContext(cx, key, keysize, iv, basemode, |
+ baseencrypt, blocksize); |
+ if (rv != SECSuccess) { |
+ AES_DestroyContext(cx, PR_TRUE); |
+ return rv; |
+ } |
+ |
+ /* 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 SECSuccess; |
+ } |
+ /* 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 SECFailure; |
+ } |
+ return SECSuccess; |
+} |
+ |
/* AES_CreateContext |
* |
* create a new context for Rijndael operations |
@@ -1131,6 +1208,9 @@ |
AES_DestroyContext(AESContext *cx, PRBool freeit) |
{ |
/* memset(cx, 0, sizeof *cx); */ |
+ if (cx->worker_cx && cx->destroy) { |
+ (*cx->destroy)(cx->worker_cx, PR_TRUE); |
+ } |
if (freeit) |
PORT_Free(cx); |
} |
@@ -1153,7 +1233,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 +1242,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 +1264,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 +1273,6 @@ |
return SECFailure; |
} |
*outputLen = inputLen; |
- return (*cx->worker)(cx, output, outputLen, maxOutputLen, |
+ return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, |
input, inputLen, blocksize); |
} |