Index: nss/mozilla/security/nss/lib/freebl/rijndael.c |
=================================================================== |
--- nss/mozilla/security/nss/lib/freebl/rijndael.c (revision 162724) |
+++ nss/mozilla/security/nss/lib/freebl/rijndael.c (working copy) |
@@ -1,7 +1,7 @@ |
/* This Source Code Form is subject to the terms of the Mozilla Public |
* License, v. 2.0. If a copy of the MPL was not distributed with this |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
-/* $Id: rijndael.c,v 1.27 2012/04/25 14:49:43 gerv%gerv.net Exp $ */ |
+/* $Id: rijndael.c,v 1.28 2012/09/28 22:46:32 rrelyea%redhat.com Exp $ */ |
#ifdef FREEBL_NO_DEPEND |
#include "stubs.h" |
@@ -15,6 +15,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" |
@@ -956,8 +960,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) |
{ |
@@ -1018,18 +1027,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); |
@@ -1062,12 +1073,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 |
@@ -1099,6 +1176,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); |
} |
@@ -1121,7 +1201,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; |
} |
@@ -1130,7 +1210,7 @@ |
return SECFailure; |
} |
*outputLen = inputLen; |
- return (*cx->worker)(cx, output, outputLen, maxOutputLen, |
+ return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, |
input, inputLen, blocksize); |
} |
@@ -1152,7 +1232,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; |
} |
@@ -1161,6 +1241,6 @@ |
return SECFailure; |
} |
*outputLen = inputLen; |
- return (*cx->worker)(cx, output, outputLen, maxOutputLen, |
+ return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, |
input, inputLen, blocksize); |
} |