3232
3333#if defined(WP_HAVE_AESGCM ) || defined(WP_HAVE_AESCCM )
3434
35+ /* For non-streaming AES-GCM, we have to spool all previous updates.
36+ * This is the number of extra bytes we add when allocating the internal
37+ * buffer used to spool the stream input. This way we if there is space
38+ * we can use the existing buffer, reducing the number of full realloc + copy
39+ * operations we need to do. Increase this number for better performance and
40+ * more memory usage, decrease for worse performance but less overhead */
41+ #ifndef WP_AES_GCM_EXTRA_BUF_LEN
42+ #define WP_AES_GCM_EXTRA_BUF_LEN 128
43+ #endif
44+
3545/**
3646 * Authenticated Encryption with Associated Data structure.
3747 */
@@ -94,10 +104,14 @@ typedef struct wp_AeadCtx {
94104 /** CCM is not streaming and needs to cache AAD data. */
95105 unsigned char * aad ;
96106#if defined(WP_HAVE_AESGCM ) && !defined(WOLFSSL_AESGCM_STREAM )
97- /** Length of AAD data cached. */
107+ /** Length of data cached. */
98108 size_t inLen ;
99109 /** CCM is not streaming and needs to cache AAD data. */
100110 unsigned char * in ;
111+ /* Total buffer size */
112+ size_t bufSize ;
113+ /* Original IV */
114+ unsigned char origIv [AES_BLOCK_SIZE ];
101115#endif
102116} wp_AeadCtx ;
103117
@@ -310,15 +324,24 @@ static int wp_aead_cache_in(wp_AeadCtx *ctx, const unsigned char *in,
310324 unsigned char * p ;
311325
312326 if (inLen > 0 ) {
313- p = (unsigned char * )OPENSSL_realloc (ctx -> in , ctx -> inLen + inLen );
314- if (p == NULL ) {
315- ok = 0 ;
316- }
317- if (ok ) {
318- ctx -> in = p ;
327+ if (inLen < (ctx -> bufSize - ctx -> inLen )) {
328+ /* We can fit this new data into the extra space, dont realloc */
319329 XMEMCPY (ctx -> in + ctx -> inLen , in , inLen );
320330 ctx -> inLen += inLen ;
321331 }
332+ else {
333+ p = (unsigned char * )OPENSSL_realloc (ctx -> in ,
334+ ctx -> inLen + inLen + WP_AES_GCM_EXTRA_BUF_LEN );
335+ if (p == NULL ) {
336+ ok = 0 ;
337+ }
338+ if (ok ) {
339+ ctx -> bufSize = ctx -> inLen + inLen + WP_AES_GCM_EXTRA_BUF_LEN ;
340+ ctx -> in = p ;
341+ XMEMCPY (ctx -> in + ctx -> inLen , in , inLen );
342+ ctx -> inLen += inLen ;
343+ }
344+ }
322345 }
323346
324347 WOLFPROV_LEAVE (WP_LOG_CIPHER , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
@@ -823,8 +846,6 @@ static int wp_aesgcm_get_rand_iv(wp_AeadCtx* ctx, unsigned char* out,
823846 if (rc != 0 ) {
824847 ok = 0 ;
825848 }
826- #else
827- XMEMCPY (ctx -> iv , ctx -> aes .reg , ctx -> ivLen );
828849 #endif
829850 }
830851 if (ok ) {
@@ -833,6 +854,9 @@ static int wp_aesgcm_get_rand_iv(wp_AeadCtx* ctx, unsigned char* out,
833854 olen = ctx -> ivLen ;
834855 }
835856 XMEMCPY (out , ctx -> iv + ctx -> ivLen - olen , olen );
857+ #ifndef WOLFSSL_AESGCM_STREAM
858+ XMEMCPY (ctx -> origIv , ctx -> iv , ctx -> ivLen );
859+ #endif
836860 if (inc ) {
837861 int i ;
838862 unsigned char * p = ctx -> iv + ctx -> ivLen - 8 ;
@@ -869,6 +893,9 @@ static int wp_aesgcm_set_rand_iv(wp_AeadCtx *ctx, unsigned char *in,
869893 ok = 0 ;
870894 }
871895 else {
896+ #ifndef WOLFSSL_AESGCM_STREAM
897+ XMEMCPY (ctx -> origIv , ctx -> iv , ctx -> ivLen );
898+ #endif
872899 XMEMCPY (ctx -> iv + ctx -> ivLen - inLen , in , inLen );
873900 ctx -> ivState = IV_STATE_COPIED ;
874901 }
@@ -1312,65 +1339,96 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out,
13121339 * @param [out] outLen Length of data in output buffer.
13131340 * @param [in] in Data to be encrypted/decrypted.
13141341 * @param [in] inLen Length of data to be encrypted/decrypted.
1342+ * @param [in] offset Offset into the spooled data buffer.
1343+ * @param [in] done This is a final operation.
1344+ *
13151345 * @return 1 on success.
13161346 * @return 0 on failure.
13171347 */
1318- static int wp_aesgcm_encdec (wp_AeadCtx * ctx , unsigned char * out , size_t * outLen )
1348+ static int wp_aesgcm_encdec (wp_AeadCtx * ctx , unsigned char * out , size_t * outLen ,
1349+ size_t offset , int done )
13191350{
13201351 int ok = 1 ;
13211352 int rc ;
1353+ unsigned char * tmp = NULL ;
1354+ byte * iv = NULL ;
13221355
13231356 if (ctx -> tagLen == UNINITIALISED_SIZET ) {
13241357 ctx -> tagLen = EVP_GCM_TLS_TAG_LEN ;
13251358 }
13261359
1327- if (ctx -> enc ) {
1328- if (!ctx -> ivSet ) {
1329- rc = wc_AesGcmSetExtIV (& ctx -> aes , ctx -> iv , (word32 )ctx -> ivLen );
1330- if (rc != 0 ) {
1360+ if (ctx -> inLen > offset || (ctx -> tagAvail == 0 && done )) {
1361+ /* Prepare a temp buffer to store all the output */
1362+ if (ctx -> inLen > 0 ) {
1363+ tmp = OPENSSL_zalloc (ctx -> inLen );
1364+ if (tmp == NULL ) {
13311365 ok = 0 ;
13321366 }
13331367 }
1368+ /* Once loaded, always use original IV */
1369+ iv = ctx -> iv ;
1370+ if (ctx -> ivState == IV_STATE_COPIED ) {
1371+ iv = ctx -> origIv ;
1372+ }
13341373 if (ok ) {
1335- ctx -> ivSet = 1 ;
1336- /* IV coming out in this call. */
1337- rc = wc_AesGcmEncrypt_ex (& ctx -> aes , out , ctx -> in ,
1338- (word32 )ctx -> inLen , ctx -> iv , (word32 )ctx -> ivLen , ctx -> buf ,
1339- (word32 )ctx -> tagLen , ctx -> aad , (word32 )ctx -> aadLen );
1374+ rc = wc_AesGcmSetExtIV (& ctx -> aes , iv , (word32 )ctx -> ivLen );
13401375 if (rc != 0 ) {
13411376 ok = 0 ;
13421377 }
1343- if (ok ) {
1344- ctx -> tagAvail = 1 ;
1378+
1379+ if (ok && ctx -> ivState == IV_STATE_BUFFERED ) {
1380+ ctx -> ivState = IV_STATE_COPIED ;
1381+ XMEMCPY (ctx -> origIv , ctx -> iv , ctx -> ivLen );
13451382 }
13461383 }
1347- }
1348- else {
1349- rc = wc_AesGcmDecrypt (& ctx -> aes , out , ctx -> in , (word32 )ctx -> inLen ,
1350- ctx -> iv , (word32 )ctx -> ivLen , ctx -> buf , (word32 )ctx -> tagLen ,
1351- ctx -> aad , (word32 )ctx -> aadLen );
1352- if (rc == AES_GCM_AUTH_E ) {
1353- ctx -> authErr = 1 ;
1354- rc = 0 ;
1384+ if (ctx -> enc ) {
1385+ if (ok ) {
1386+ ctx -> ivSet = 1 ;
1387+ /* IV coming out in this call. */
1388+ rc = wc_AesGcmEncrypt_ex (& ctx -> aes , tmp , ctx -> in ,
1389+ (word32 )ctx -> inLen , iv , (word32 )ctx -> ivLen , ctx -> buf ,
1390+ (word32 )ctx -> tagLen , ctx -> aad , (word32 )ctx -> aadLen );
1391+ if (rc != 0 ) {
1392+ ok = 0 ;
1393+ }
1394+ if (ok ) {
1395+ ctx -> tagAvail = 1 ;
1396+ }
1397+ }
13551398 }
1356- if (rc != 0 ) {
1357- ok = 0 ;
1399+ else {
1400+ /* Only the most recent auth err matters */
1401+ ctx -> authErr = 0 ;
1402+ rc = wc_AesGcmDecrypt (& ctx -> aes , tmp , ctx -> in , (word32 )ctx -> inLen ,
1403+ iv , (word32 )ctx -> ivLen , ctx -> buf , (word32 )ctx -> tagLen ,
1404+ ctx -> aad , (word32 )ctx -> aadLen );
1405+ if (rc == AES_GCM_AUTH_E ) {
1406+ ctx -> authErr = 1 ;
1407+ rc = 0 ;
1408+ }
1409+ if (rc != 0 ) {
1410+ ok = 0 ;
1411+ }
13581412 }
1413+ /* Copy out relevant portion of output */
13591414 if (ok ) {
1360- XMEMCPY (ctx -> iv , ctx -> aes .reg , ctx -> ivLen );
1415+ XMEMCPY (out , tmp + offset , (ctx -> inLen - offset ));
1416+ * outLen = (ctx -> inLen - offset );
13611417 }
1418+ OPENSSL_free (tmp );
13621419 }
1363- if (ok ) {
1364- * outLen = ctx -> inLen ;
1420+ else {
1421+ * outLen = 0 ;
1422+ }
1423+ if (done ) {
1424+ OPENSSL_free (ctx -> aad );
1425+ ctx -> aad = NULL ;
1426+ ctx -> aadLen = 0 ;
1427+ ctx -> aadSet = 0 ;
1428+ OPENSSL_free (ctx -> in );
1429+ ctx -> in = NULL ;
1430+ ctx -> inLen = 0 ;
13651431 }
1366-
1367- OPENSSL_free (ctx -> aad );
1368- ctx -> aad = NULL ;
1369- ctx -> aadLen = 0 ;
1370- ctx -> aadSet = 0 ;
1371- OPENSSL_free (ctx -> in );
1372- ctx -> in = NULL ;
1373- ctx -> inLen = 0 ;
13741432
13751433 WOLFPROV_LEAVE (WP_LOG_CIPHER , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
13761434 return ok ;
@@ -1392,6 +1450,8 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out,
13921450 size_t * outLen , size_t outSize , const unsigned char * in , size_t inLen )
13931451{
13941452 int ok = 1 ;
1453+ int process = 0 ;
1454+ size_t curLen = 0 ;
13951455
13961456 if (ctx -> tlsAadLen != UNINITIALISED_SIZET ) {
13971457 ok = wp_aesgcm_tls_cipher (ctx , out , outLen , in , inLen );
@@ -1414,12 +1474,22 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out,
14141474 ok = 0 ;
14151475 }
14161476 else if (inLen > 0 ) {
1477+ curLen = ctx -> inLen ;
14171478 if (!wp_aead_cache_in (ctx , in , inLen )) {
14181479 ok = 0 ;
14191480 }
1481+ else {
1482+ process = 1 ;
1483+ }
14201484 }
14211485
1422- * outLen = oLen ;
1486+ /* If there is data to process, do it now */
1487+ if (process ) {
1488+ ok = wp_aesgcm_encdec (ctx , out , outLen , curLen , 0 );
1489+ }
1490+ else {
1491+ * outLen = oLen ;
1492+ }
14231493 }
14241494
14251495 WOLFPROV_LEAVE (WP_LOG_CIPHER , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
@@ -1449,7 +1519,7 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out,
14491519 ok = 0 ;
14501520 }
14511521 else {
1452- ok = wp_aesgcm_encdec (ctx , out , outLen );
1522+ ok = wp_aesgcm_encdec (ctx , out , outLen , ctx -> inLen , 1 );
14531523 ctx -> ivSet = 0 ;
14541524 }
14551525
0 commit comments