Browse Source

(1) Mask bit 31 of AES-CTR nonce to disallow uint32 overflow, (2) get rid of handling of uint32/uint64 overflow in our AES-CTR code to optimize, (3) optimize AES software a bit

Adam Ierymenko 5 years ago
parent
commit
d151d731a6
2 changed files with 167 additions and 287 deletions
  1. 147 286
      node/AES.cpp
  2. 20 1
      node/AES.hpp

File diff suppressed because it is too large
+ 147 - 286
node/AES.cpp


+ 20 - 1
node/AES.hpp

@@ -259,7 +259,10 @@ public:
 		 */
 		ZT_INLINE void init(const uint64_t iv,void *const output) noexcept
 		{
+			// Output buffer to receive the result of AES-CTR encryption.
 			_output = output;
+
+			// Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero).
 			_iv[0] = iv;
 			_iv[1] = 0;
 			_gmac.init(reinterpret_cast<const uint8_t *>(_iv));
@@ -276,7 +279,11 @@ public:
 		 */
 		ZT_INLINE void aad(const void *const aad,unsigned int len) noexcept
 		{
+			// Feed ADD into GMAC first
 			_gmac.update(aad,len);
+
+			// End of AAD is padded to a multiple of 16 bytes to ensure unique encoding vs. plaintext.
+			// AES-GCM-SIV does this as well for the same reason.
 			len &= 0xfU;
 			if (len != 0)
 				_gmac.update(Utils::ZERO256,16 - len);
@@ -298,11 +305,23 @@ public:
 		 */
 		ZT_INLINE void finish1() noexcept
 		{
+			// Compute GMAC tag, then encrypt the original 64-bit IV and the first 64 bits
+			// of the GMAC tag with AES (single block) and use this to initialize AES-CTR.
 			uint64_t gmacTag[2];
 			_gmac.finish(reinterpret_cast<uint8_t *>(gmacTag));
 			_iv[1] = gmacTag[0];
 			_ctr._aes.encrypt(_iv,_iv);
-			_ctr.init(reinterpret_cast<const uint8_t *>(_iv),_output);
+
+			// Bit 31 of the CTR IV is masked to (1) allow us to optimize by forgetting
+			// about integer overflow for less than 2^31 bytes (which is far less than
+			// this system's max message size), and (2) ensure interoperability with any
+			// future FIPS-compliant or other cryptographic libraries that may or may not
+			// handle 32-bit integer overflow of the least significant 32 bits in the
+			// counter in the expected way.
+			uint64_t ctrIv[2];
+			ctrIv[0] = _iv[0];
+			ctrIv[1] = _iv[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
+			_ctr.init(reinterpret_cast<const uint8_t *>(ctrIv),_output);
 		}
 
 		/**

Some files were not shown because too many files changed in this diff