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 }
@@ -1310,67 +1337,96 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out,
13101337 * @param [in, out] ctx AEAD context object.
13111338 * @param [out] out Buffer to hold decrypted/encrypted data.
13121339 * @param [out] outLen Length of data in output buffer.
1313- * @param [in] in Data to be encrypted/decrypted.
1314- * @param [in] inLen Length of data to be encrypted/decrypted.
1340+ * @param [in] offset Offset into the spooled data buffer.
1341+ * @param [in] done This is a final operation.
1342+ *
13151343 * @return 1 on success.
13161344 * @return 0 on failure.
13171345 */
1318- static int wp_aesgcm_encdec (wp_AeadCtx * ctx , unsigned char * out , size_t * outLen )
1346+ static int wp_aesgcm_encdec (wp_AeadCtx * ctx , unsigned char * out , size_t * outLen ,
1347+ size_t offset , int done )
13191348{
13201349 int ok = 1 ;
13211350 int rc ;
1351+ unsigned char * tmp = NULL ;
1352+ byte * iv = NULL ;
13221353
13231354 if (ctx -> tagLen == UNINITIALISED_SIZET ) {
13241355 ctx -> tagLen = EVP_GCM_TLS_TAG_LEN ;
13251356 }
13261357
1327- if (ctx -> enc ) {
1328- if (!ctx -> ivSet ) {
1329- rc = wc_AesGcmSetExtIV (& ctx -> aes , ctx -> iv , (word32 )ctx -> ivLen );
1330- if (rc != 0 ) {
1358+ if (ctx -> inLen > offset || (ctx -> tagAvail == 0 && done )) {
1359+ /* Prepare a temp buffer to store all the output */
1360+ if (ctx -> inLen > 0 ) {
1361+ tmp = OPENSSL_zalloc (ctx -> inLen );
1362+ if (tmp == NULL ) {
13311363 ok = 0 ;
13321364 }
13331365 }
1366+ /* Once loaded, always use original IV */
1367+ iv = ctx -> iv ;
1368+ if (ctx -> ivState == IV_STATE_COPIED ) {
1369+ iv = ctx -> origIv ;
1370+ }
13341371 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 );
1372+ rc = wc_AesGcmSetExtIV (& ctx -> aes , iv , (word32 )ctx -> ivLen );
13401373 if (rc != 0 ) {
13411374 ok = 0 ;
13421375 }
1343- if (ok ) {
1344- ctx -> tagAvail = 1 ;
1376+
1377+ if (ok && ctx -> ivState == IV_STATE_BUFFERED ) {
1378+ ctx -> ivState = IV_STATE_COPIED ;
1379+ XMEMCPY (ctx -> origIv , ctx -> iv , ctx -> ivLen );
13451380 }
13461381 }
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 ;
1382+ if (ctx -> enc ) {
1383+ if (ok ) {
1384+ ctx -> ivSet = 1 ;
1385+ /* IV coming out in this call. */
1386+ rc = wc_AesGcmEncrypt_ex (& ctx -> aes , tmp , ctx -> in ,
1387+ (word32 )ctx -> inLen , iv , (word32 )ctx -> ivLen , ctx -> buf ,
1388+ (word32 )ctx -> tagLen , ctx -> aad , (word32 )ctx -> aadLen );
1389+ if (rc != 0 ) {
1390+ ok = 0 ;
1391+ }
1392+ if (ok ) {
1393+ ctx -> tagAvail = 1 ;
1394+ }
1395+ }
13551396 }
1356- if (rc != 0 ) {
1357- ok = 0 ;
1397+ else {
1398+ /* Only the most recent auth err matters */
1399+ ctx -> authErr = 0 ;
1400+ rc = wc_AesGcmDecrypt (& ctx -> aes , tmp , ctx -> in , (word32 )ctx -> inLen ,
1401+ iv , (word32 )ctx -> ivLen , ctx -> buf , (word32 )ctx -> tagLen ,
1402+ ctx -> aad , (word32 )ctx -> aadLen );
1403+ if (rc == AES_GCM_AUTH_E ) {
1404+ ctx -> authErr = 1 ;
1405+ rc = 0 ;
1406+ }
1407+ if (rc != 0 ) {
1408+ ok = 0 ;
1409+ }
13581410 }
1411+ /* Copy out relevant portion of output */
13591412 if (ok ) {
1360- XMEMCPY (ctx -> iv , ctx -> aes .reg , ctx -> ivLen );
1413+ XMEMCPY (out , tmp + offset , (ctx -> inLen - offset ));
1414+ * outLen = (ctx -> inLen - offset );
13611415 }
1416+ OPENSSL_free (tmp );
13621417 }
1363- if (ok ) {
1364- * outLen = ctx -> inLen ;
1418+ else {
1419+ * outLen = 0 ;
1420+ }
1421+ if (done ) {
1422+ OPENSSL_free (ctx -> aad );
1423+ ctx -> aad = NULL ;
1424+ ctx -> aadLen = 0 ;
1425+ ctx -> aadSet = 0 ;
1426+ OPENSSL_free (ctx -> in );
1427+ ctx -> in = NULL ;
1428+ ctx -> inLen = 0 ;
13651429 }
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 ;
13741430
13751431 WOLFPROV_LEAVE (WP_LOG_CIPHER , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
13761432 return ok ;
@@ -1392,6 +1448,8 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out,
13921448 size_t * outLen , size_t outSize , const unsigned char * in , size_t inLen )
13931449{
13941450 int ok = 1 ;
1451+ int process = 0 ;
1452+ size_t curLen = 0 ;
13951453
13961454 if (ctx -> tlsAadLen != UNINITIALISED_SIZET ) {
13971455 ok = wp_aesgcm_tls_cipher (ctx , out , outLen , in , inLen );
@@ -1414,12 +1472,22 @@ static int wp_aesgcm_stream_update(wp_AeadCtx *ctx, unsigned char *out,
14141472 ok = 0 ;
14151473 }
14161474 else if (inLen > 0 ) {
1475+ curLen = ctx -> inLen ;
14171476 if (!wp_aead_cache_in (ctx , in , inLen )) {
14181477 ok = 0 ;
14191478 }
1479+ else {
1480+ process = 1 ;
1481+ }
14201482 }
14211483
1422- * outLen = oLen ;
1484+ /* If there is data to process, do it now */
1485+ if (process ) {
1486+ ok = wp_aesgcm_encdec (ctx , out , outLen , curLen , 0 );
1487+ }
1488+ else {
1489+ * outLen = oLen ;
1490+ }
14231491 }
14241492
14251493 WOLFPROV_LEAVE (WP_LOG_CIPHER , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
@@ -1449,7 +1517,7 @@ static int wp_aesgcm_stream_final(wp_AeadCtx *ctx, unsigned char *out,
14491517 ok = 0 ;
14501518 }
14511519 else {
1452- ok = wp_aesgcm_encdec (ctx , out , outLen );
1520+ ok = wp_aesgcm_encdec (ctx , out , outLen , ctx -> inLen , 1 );
14531521 ctx -> ivSet = 0 ;
14541522 }
14551523
0 commit comments