diff --git a/ChangeLog b/ChangeLog index ee3d86567..6ea2dea61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,7 @@ Changes dynamically set (Better support for hardware acceleration) * Moved all OID functionality to a separate module. RSA function prototypes for the RSA sign and verify functions changed as a result + * Split up the GCM module into a starts/update/finish cycle Bugfix * Fix for MPI assembly for ARM diff --git a/include/polarssl/gcm.h b/include/polarssl/gcm.h index 77baa1756..c703f3bf0 100644 --- a/include/polarssl/gcm.h +++ b/include/polarssl/gcm.h @@ -49,6 +49,12 @@ typedef struct { aes_context aes_ctx; /*!< AES context used */ uint64_t HL[16]; /*!< Precalculated HTable */ uint64_t HH[16]; /*!< Precalculated HTable */ + uint64_t len; /*!< Total data length */ + uint64_t add_len; /*!< Total add length */ + unsigned char base_ectr[16];/*!< First ECTR for tag */ + unsigned char y[16]; /*!< Y working value */ + unsigned char buf[16]; /*!< buf working value */ + int mode; /*!< Encrypt or Decrypt */ } gcm_context; @@ -115,7 +121,7 @@ int gcm_crypt_and_tag( gcm_context *ctx, * \param add additional data * \param add_len length of additional data * \param tag buffer holding the tag - * \param tag_len length of the tag + * \param tag_len length of the tag * \param input buffer holding the input data * \param output buffer for holding the output data * @@ -128,11 +134,67 @@ int gcm_auth_decrypt( gcm_context *ctx, size_t iv_len, const unsigned char *add, size_t add_len, - const unsigned char *tag, + const unsigned char *tag, size_t tag_len, const unsigned char *input, unsigned char *output ); +/** + * \brief Generic GCM stream start function + * + * \param ctx GCM context + * \param mode GCM_ENCRYPT or GCM_DECRYPT + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * + * \return 0 if successful + */ +int gcm_starts( gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ); + +/** + * \brief Generic GCM update function. Encrypts/decrypts using the + * given GCM context. Expects input to be a multiple of 16 + * bytes! Only the last call before gcm_finish() can be less + * than 16 bytes! + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful or POLARSSL_ERR_GCM_BAD_INPUT + */ +int gcm_update( gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic GCM finalisation function. Wraps up the GCM stream + * and generated the tag. The tag can have a maximum length of + * 16 bytes. + * + * \param ctx GCM context + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate + * + * \return 0 if successful or POLARSSL_ERR_GCM_BAD_INPUT + */ +int gcm_finish( gcm_context *ctx, + unsigned char *tag, + size_t tag_len ); + /** * \brief Checkup routine * diff --git a/library/gcm.c b/library/gcm.c index f1daaff27..f0bacc618 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -169,41 +169,24 @@ static void gcm_mult( gcm_context *ctx, const unsigned char x[16], PUT_UINT32_BE( zl, output, 12 ); } -int gcm_crypt_and_tag( gcm_context *ctx, - int mode, - size_t length, - const unsigned char *iv, - size_t iv_len, - const unsigned char *add, - size_t add_len, - const unsigned char *input, - unsigned char *output, - size_t tag_len, - unsigned char *tag ) +int gcm_starts( gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ) { - unsigned char y[16]; - unsigned char ectr[16]; - unsigned char buf[16]; unsigned char work_buf[16]; size_t i; const unsigned char *p; - unsigned char *out_p = output; size_t use_len; - uint64_t orig_len = length * 8; - uint64_t orig_add_len = add_len * 8; - memset( y, 0x00, 16 ); - memset( work_buf, 0x00, 16 ); - memset( tag, 0x00, tag_len ); - memset( buf, 0x00, 16 ); - - if( output > input && (size_t) ( output - input ) < length ) - return( POLARSSL_ERR_GCM_BAD_INPUT ); + ctx->mode = mode; if( iv_len == 12 ) { - memcpy( y, iv, iv_len ); - y[15] = 1; + memcpy( ctx->y, iv, iv_len ); + ctx->y[15] = 1; } else { @@ -216,64 +199,100 @@ int gcm_crypt_and_tag( gcm_context *ctx, use_len = ( iv_len < 16 ) ? iv_len : 16; for( i = 0; i < use_len; i++ ) - y[i] ^= p[i]; + ctx->y[i] ^= p[i]; - gcm_mult( ctx, y, y ); + gcm_mult( ctx, ctx->y, ctx->y ); iv_len -= use_len; p += use_len; } for( i = 0; i < 16; i++ ) - y[i] ^= work_buf[i]; + ctx->y[i] ^= work_buf[i]; - gcm_mult( ctx, y, y ); + gcm_mult( ctx, ctx->y, ctx->y ); } - aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, y, ectr ); - memcpy( tag, ectr, tag_len ); + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->y, ctx->base_ectr ); + ctx->add_len = add_len; p = add; while( add_len > 0 ) { use_len = ( add_len < 16 ) ? add_len : 16; for( i = 0; i < use_len; i++ ) - buf[i] ^= p[i]; + ctx->buf[i] ^= p[i]; - gcm_mult( ctx, buf, buf ); + gcm_mult( ctx, ctx->buf, ctx->buf ); add_len -= use_len; p += use_len; } + return( 0 ); +} + +int gcm_update( gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ) +{ + unsigned char ectr[16]; + size_t i; + const unsigned char *p; + unsigned char *out_p = output; + size_t use_len; + + if( output > input && (size_t) ( output - input ) < length ) + return( POLARSSL_ERR_GCM_BAD_INPUT ); + + ctx->len += length; + p = input; while( length > 0 ) { use_len = ( length < 16 ) ? length : 16; for( i = 16; i > 12; i-- ) - if( ++y[i - 1] != 0 ) + if( ++ctx->y[i - 1] != 0 ) break; - aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, y, ectr ); + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->y, ectr ); for( i = 0; i < use_len; i++ ) { - if( mode == GCM_DECRYPT ) - buf[i] ^= p[i]; + if( ctx->mode == GCM_DECRYPT ) + ctx->buf[i] ^= p[i]; out_p[i] = ectr[i] ^ p[i]; - if( mode == GCM_ENCRYPT ) - buf[i] ^= out_p[i]; + if( ctx->mode == GCM_ENCRYPT ) + ctx->buf[i] ^= out_p[i]; } - gcm_mult( ctx, buf, buf ); + gcm_mult( ctx, ctx->buf, ctx->buf ); length -= use_len; p += use_len; out_p += use_len; } + return( 0 ); +} + +int gcm_finish( gcm_context *ctx, + unsigned char *tag, + size_t tag_len ) +{ + unsigned char work_buf[16]; + size_t i; + uint64_t orig_len = ctx->len * 8; + uint64_t orig_add_len = ctx->add_len * 8; + + memcpy( tag, ctx->base_ectr, tag_len ); + + if( tag_len > 16 ) + return( POLARSSL_ERR_GCM_BAD_INPUT ); + if( orig_len || orig_add_len ) { memset( work_buf, 0x00, 16 ); @@ -284,17 +303,43 @@ int gcm_crypt_and_tag( gcm_context *ctx, PUT_UINT32_BE( ( orig_len ), work_buf, 12 ); for( i = 0; i < 16; i++ ) - buf[i] ^= work_buf[i]; + ctx->buf[i] ^= work_buf[i]; - gcm_mult( ctx, buf, buf ); + gcm_mult( ctx, ctx->buf, ctx->buf ); for( i = 0; i < tag_len; i++ ) - tag[i] ^= buf[i]; + tag[i] ^= ctx->buf[i]; } return( 0 ); } +int gcm_crypt_and_tag( gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + int ret; + + if( ( ret = gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) + return( ret ); + + if( ( ret = gcm_update( ctx, length, input, output ) ) != 0 ) + return( ret ); + + if( ( ret = gcm_finish( ctx, tag, tag_len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + int gcm_auth_decrypt( gcm_context *ctx, size_t length, const unsigned char *iv, @@ -562,7 +607,9 @@ int gcm_self_test( int verbose ) for( i = 0; i < MAX_TESTS; i++ ) { - printf( " AES-GCM-%3d #%d (%s): ", key_len, i, "enc" ); + if( verbose != 0 ) + printf( " AES-GCM-%3d #%d (%s): ", key_len, i, "enc" ); + gcm_init( &ctx, key[key_index[i]], key_len ); ret = gcm_crypt_and_tag( &ctx, GCM_ENCRYPT, @@ -584,7 +631,9 @@ int gcm_self_test( int verbose ) if( verbose != 0 ) printf( "passed\n" ); - printf( " AES-GCM-%3d #%d (%s): ", key_len, i, "dec" ); + if( verbose != 0 ) + printf( " AES-GCM-%3d #%d (%s): ", key_len, i, "dec" ); + gcm_init( &ctx, key[key_index[i]], key_len ); ret = gcm_crypt_and_tag( &ctx, GCM_DECRYPT, @@ -605,10 +654,138 @@ int gcm_self_test( int verbose ) if( verbose != 0 ) printf( "passed\n" ); + + if( verbose != 0 ) + printf( " AES-GCM-%3d #%d split (%s): ", key_len, i, "enc" ); + + gcm_init( &ctx, key[key_index[i]], key_len ); + + ret = gcm_starts( &ctx, GCM_ENCRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = gcm_update( &ctx, 32, pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + ret = gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32, buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + ret = gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + if( verbose != 0 ) + printf( " AES-GCM-%3d #%d split (%s): ", key_len, i, "dec" ); + + gcm_init( &ctx, key[key_index[i]], key_len ); + + ret = gcm_starts( &ctx, GCM_DECRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = gcm_update( &ctx, 32, ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + ret = gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32, buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = gcm_update( &ctx, pt_len[i], ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + ret = gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } } - printf( "\n" ); + if( verbose != 0 ) + printf( "\n" ); return( 0 ); } diff --git a/tests/scripts/gen_gcm_decrypt.pl b/tests/scripts/gen_gcm_decrypt.pl index 2fb76c69f..6decac286 100755 --- a/tests/scripts/gen_gcm_decrypt.pl +++ b/tests/scripts/gen_gcm_decrypt.pl @@ -91,4 +91,8 @@ while (my $line = ) print("\n\n"); } } + +print("GCM Selftest\n"); +print("gcm_selftest:\n\n"); + close(TEST_DATA); diff --git a/tests/scripts/gen_gcm_encrypt.pl b/tests/scripts/gen_gcm_encrypt.pl index de179a98a..8adbbcefc 100755 --- a/tests/scripts/gen_gcm_encrypt.pl +++ b/tests/scripts/gen_gcm_encrypt.pl @@ -74,4 +74,8 @@ while (my $line = ) print("\n\n"); } } + +print("GCM Selftest\n"); +print("gcm_selftest:\n\n"); + close(TEST_DATA); diff --git a/tests/suites/test_suite_gcm.decrypt_128.data b/tests/suites/test_suite_gcm.decrypt_128.data index 0b714ab51..8e12296b3 100644 --- a/tests/suites/test_suite_gcm.decrypt_128.data +++ b/tests/suites/test_suite_gcm.decrypt_128.data @@ -502,3 +502,5 @@ gcm_decrypt_and_verify:"db68a96e216b0dd9945f14b878487e03":"5634196a32d4cbfa7a2f8 GCM NIST Validation (AES-128,128,1024,1024,32) #2 gcm_decrypt_and_verify:"659b9e729d12f68b73fdc2f7260ab114":"fd0732a38224c3f16f58de3a7f333da2ecdb6eec92b469544a891966dd4f8fb64a711a793f1ef6a90e49765eacaccdd8cc438c2b57c51902d27a82ee4f24925a864a9513a74e734ddbf77204a99a3c0060fcfbaccae48fe509bc95c3d6e1b1592889c489801265715e6e4355a45357ce467c1caa2f1c3071bd3a9168a7d223e3":"459df18e2dfbd66d6ad04978432a6d97":"ee0b0b52a729c45b899cc924f46eb1908e55aaaeeaa0c4cdaacf57948a7993a6debd7b6cd7aa426dc3b3b6f56522ba3d5700a820b1697b8170bad9ca7caf1050f13d54fb1ddeb111086cb650e1c5f4a14b6a927205a83bf49f357576fd0f884a83b068154352076a6e36a5369436d2c8351f3e6bfec65b4816e3eb3f144ed7f9":32:"8e5a6a79":"FAIL":0 +GCM Selftest +gcm_selftest: diff --git a/tests/suites/test_suite_gcm.decrypt_192.data b/tests/suites/test_suite_gcm.decrypt_192.data index cb57add36..476f8edee 100644 --- a/tests/suites/test_suite_gcm.decrypt_192.data +++ b/tests/suites/test_suite_gcm.decrypt_192.data @@ -501,3 +501,6 @@ gcm_decrypt_and_verify:"3fc76d627c775de2f789279dc7b67979a9f1cc23c8dcabc9":"92a60 GCM NIST Validation (AES-192,128,1024,1024,32) #2 gcm_decrypt_and_verify:"b10979797fb8f418a126120d45106e1779b4538751a19bf6":"e3dc64e3c02731fe6e6ec0e899183018da347bf8bd476aa7746d7a7729d83a95f64bb732ba987468d0cede154e28169f7bafa36559200795037ee38279e0e4ca40f9cfa85aa0c8035df9649345c8fdffd1c31528b485dfe443c1923180cc8fae5196d16f822be4ad07e3f1234e1d218e7c8fb37a0e4480dc6717c9c09ff5c45f":"ca362e615024a1fe11286668646cc1de":"237d95d86a5ad46035870f576a1757eded636c7234d5ed0f8039f6f59f1333cc31cb893170d1baa98bd4e79576de920120ead0fdecfb343edbc2fcc556540a91607388a05d43bdb8b55f1327552feed3b620614dfcccb2b342083896cbc81dc9670b761add998913ca813163708a45974e6d7b56dfd0511a72eb879f239d6a6d":32:"28d730ea":"dafde27aa8b3076bfa16ab1d89207d339c4997f8a756cc3eb62c0b023976de808ab640ba4467f2b2ea83d238861229c73387594cd43770386512ea595a70888b4c38863472279e06b923e7cf32438199b3e054ac4bc21baa8df39ddaa207ebb17fa4cad6e83ea58c3a92ec74e6e01b0a8979af145dd31d5df29750bb91b42d45":0 + +GCM Selftest +gcm_selftest: diff --git a/tests/suites/test_suite_gcm.decrypt_256.data b/tests/suites/test_suite_gcm.decrypt_256.data index 3542aaf90..24702b8ac 100644 --- a/tests/suites/test_suite_gcm.decrypt_256.data +++ b/tests/suites/test_suite_gcm.decrypt_256.data @@ -502,3 +502,5 @@ gcm_decrypt_and_verify:"9bb36fe25e966a075ae2c3bb43b5877679ebc379d5123c8eda3fa0e3 GCM NIST Validation (AES-256,128,1024,1024,32) #2 gcm_decrypt_and_verify:"ca264e7caecad56ee31c8bf8dde9592f753a6299e76c60ac1e93cff3b3de8ce9":"8d03cf6fac31182ad3e6f32e4c823e3b421aef786d5651afafbf70ef14c00524ab814bc421b1d4181b4d3d82d6ae4e8032e43a6c4e0691184425b37320798f865c88b9b306466311d79e3e42076837474c37c9f6336ed777f05f70b0c7d72bd4348a4cd754d0f0c3e4587f9a18313ea2d2bace502a24ea417d3041b709a0471f":"4763a4e37b806a5f4510f69fd8c63571":"07daeba37a66ebe15f3d6451d1176f3a7107a302da6966680c425377e621fd71610d1fc9c95122da5bf85f83b24c4b783b1dcd6b508d41e22c09b5c43693d072869601fc7e3f5a51dbd3bc6508e8d095b9130fb6a7f2a043f3a432e7ce68b7de06c1379e6bab5a1a48823b76762051b4e707ddc3201eb36456e3862425cb011a":32:"3105dddb":"FAIL":0 +GCM Selftest +gcm_selftest: diff --git a/tests/suites/test_suite_gcm.encrypt_128.data b/tests/suites/test_suite_gcm.encrypt_128.data index d617c4234..31cd37f35 100644 --- a/tests/suites/test_suite_gcm.encrypt_128.data +++ b/tests/suites/test_suite_gcm.encrypt_128.data @@ -501,3 +501,6 @@ gcm_encrypt_and_tag:"00d4bf20509a61bc76430ffa5f013589":"036a191a388cf3c57c9e6f0e GCM NIST Validation (AES-128,128,1024,1024,32) #2 gcm_encrypt_and_tag:"fe481476fce76efcfc78ed144b0756f1":"246e1f2babab8da98b17cc928bd49504d7d87ea2cc174f9ffb7dbafe5969ff824a0bcb52f35441d22f3edcd10fab0ec04c0bde5abd3624ca25cbb4541b5d62a3deb52c00b75d68aaf0504d51f95b8dcbebdd8433f4966c584ac7f8c19407ca927a79fa4ead2688c4a7baafb4c31ef83c05e8848ec2b4f657aab84c109c91c277":"1a2c18c6bf13b3b2785610c71ccd98ca":"b0ab3cb5256575774b8242b89badfbe0dfdfd04f5dd75a8e5f218b28d3f6bc085a013defa5f5b15dfb46132db58ed7a9ddb812d28ee2f962796ad988561a381c02d1cf37dca5fd33e081d61cc7b3ab0b477947524a4ca4cb48c36f48b302c440be6f5777518a60585a8a16cea510dbfc5580b0daac49a2b1242ff55e91a8eae8":"5587620bbb77f70afdf3cdb7ae390edd0473286d86d3f862ad70902d90ff1d315947c959f016257a8fe1f52cc22a54f21de8cb60b74808ac7b22ea7a15945371e18b77c9571aad631aa080c60c1e472019fa85625fc80ed32a51d05e397a8987c8fece197a566689d24d05361b6f3a75616c89db6123bf5902960b21a18bc03a":32:"bd4265a8":0 + +GCM Selftest +gcm_selftest: diff --git a/tests/suites/test_suite_gcm.encrypt_192.data b/tests/suites/test_suite_gcm.encrypt_192.data index 6ef7fc6ce..e2690aeaa 100644 --- a/tests/suites/test_suite_gcm.encrypt_192.data +++ b/tests/suites/test_suite_gcm.encrypt_192.data @@ -501,3 +501,6 @@ gcm_encrypt_and_tag:"8a7d8197d9ceebd8e3f6b3bfb74877ccf649ac91d7057af5":"37b01df3 GCM NIST Validation (AES-192,128,1024,1024,32) #2 gcm_encrypt_and_tag:"713358e746dd84ab27b8adb3b17ea59cd75fa6cb0c13d1a8":"35b8b655efdf2d09f5ed0233c9eeb0b6f85e513834848cd594dba3c6e64f78e7af4a7a6d53bba7b43764334d6373360ae3b73b1e765978dffa7dbd805fda7825b8e317e8d3f1314aa97f877be815439c5da845028d1686283735aefac79cdb9e02ec3590091cb507089b9174cd9a6111f446feead91f19b80fd222fc6299fd1c":"26ed909f5851961dd57fa950b437e17c":"c9469ad408764cb7d417f800d3d84f03080cee9bbd53f652763accde5fba13a53a12d990094d587345da2cdc99357b9afd63945ca07b760a2c2d4948dbadb1312670ccde87655a6a68edb5982d2fcf733bb4101d38cdb1a4942a5d410f4c45f5ddf00889bc1fe5ec69b40ae8aaee60ee97bea096eeef0ea71736efdb0d8a5ec9":"cc3f9983e1d673ec2c86ae4c1e1b04e30f9f395f67c36838e15ce825b05d37e9cd40041470224da345aa2da5dfb3e0c561dd05ba7984a1332541d58e8f9160e7e8457e717bab203de3161a72b7aedfa53616b16ca77fd28d566fbf7431be559caa1a129b2f29b9c5bbf3eaba594d6650c62907eb28e176f27c3be7a3aa24cef6":32:"5be7611b":0 + +GCM Selftest +gcm_selftest: diff --git a/tests/suites/test_suite_gcm.encrypt_256.data b/tests/suites/test_suite_gcm.encrypt_256.data index 68802c2cb..5d265ff46 100644 --- a/tests/suites/test_suite_gcm.encrypt_256.data +++ b/tests/suites/test_suite_gcm.encrypt_256.data @@ -502,3 +502,5 @@ gcm_encrypt_and_tag:"b55ac909e73989e310ae37d13c54bbd5a126f419a3b01a2ad8961d89bd2 GCM NIST Validation (AES-256,128,1024,1024,32) #2 gcm_encrypt_and_tag:"1477e189fb3546efac5cc144f25e132ffd0081be76e912e25cbce7ad63f1c2c4":"7bd3ea956f4b938ebe83ef9a75ddbda16717e924dd4e45202560bf5f0cffbffcdd23be3ae08ff30503d698ed08568ff6b3f6b9fdc9ea79c8e53a838cc8566a8b52ce7c21b2b067e778925a066c970a6c37b8a6cfc53145f24bf698c352078a7f0409b53196e00c619237454c190b970842bb6629c0def7f166d19565127cbce0":"c109f35893aff139db8ed51c85fee237":"8f7f9f71a4b2bb0aaf55fced4eb43c57415526162070919b5f8c08904942181820d5847dfd54d9ba707c5e893a888d5a38d0130f7f52c1f638b0119cf7bc5f2b68f51ff5168802e561dff2cf9c5310011c809eba002b2fa348718e8a5cb732056273cc7d01cce5f5837ab0b09b6c4c5321a7f30a3a3cd21f29da79fce3f3728b":"7841e3d78746f07e5614233df7175931e3c257e09ebd7b78545fae484d835ffe3db3825d3aa1e5cc1541fe6cac90769dc5aaeded0c148b5b4f397990eb34b39ee7881804e5a66ccc8d4afe907948780c4e646cc26479e1da874394cb3537a8f303e0aa13bd3cc36f6cc40438bcd41ef8b6a1cdee425175dcd17ee62611d09b02":32:"cb13ce59":0 +GCM Selftest +gcm_selftest: