summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2016-04-20 19:48:32 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2016-04-20 19:48:32 +0700
commit27ce448162521ace7bc4c0520458ee3dd5665f53 (patch)
tree83153c6fb753ff5b24f53bf3496b0d9af0286350 /crypto/src
parentPut zero-length extensions first in the ClientHello (diff)
downloadBouncyCastle.NET-ed25519-27ce448162521ace7bc4c0520458ee3dd5665f53.tar.xz
Update Poly1305 to comply with RFC 7539
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crypto/generators/Poly1305KeyGenerator.cs65
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs76
-rw-r--r--crypto/src/crypto/tls/Chacha20Poly1305.cs5
3 files changed, 58 insertions, 88 deletions
diff --git a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
index d05af0add..cdb24bfa0 100644
--- a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
+++ b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
@@ -66,51 +66,25 @@ namespace Org.BouncyCastle.Crypto.Generators
 	         * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
 	         */
 			if (key.Length != 32)
-			{
 				throw new ArgumentException("Poly1305 key must be 256 bits.");
-			}
 
-			/*
+            /*
 	         * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
 	         */
-			key[19] &= R_MASK_HIGH_4;
-			key[23] &= R_MASK_HIGH_4;
-			key[27] &= R_MASK_HIGH_4;
-			key[31] &= R_MASK_HIGH_4;
+			key[3] &= R_MASK_HIGH_4;
+			key[7] &= R_MASK_HIGH_4;
+			key[11] &= R_MASK_HIGH_4;
+			key[15] &= R_MASK_HIGH_4;
 
 			/*
 	         * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
 	         */
-			key[20] &= R_MASK_LOW_2;
-			key[24] &= R_MASK_LOW_2;
-			key[28] &= R_MASK_LOW_2;
+			key[4] &= R_MASK_LOW_2;
+			key[8] &= R_MASK_LOW_2;
+			key[12] &= R_MASK_LOW_2;
 		}
 
-        internal static void Clamp(byte[] key, int keyOff)
-        {
-            /*
-             * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
-             */
-            if (key.Length - 32 < keyOff)
-                throw new ArgumentException("Poly1305 key must be 256 bits.");
-
-            /*
-             * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
-             */
-            key[keyOff + 19] &= R_MASK_HIGH_4;
-            key[keyOff + 23] &= R_MASK_HIGH_4;
-            key[keyOff + 27] &= R_MASK_HIGH_4;
-            key[keyOff + 31] &= R_MASK_HIGH_4;
-
-            /*
-             * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
-             */
-            key[keyOff + 20] &= R_MASK_LOW_2;
-            key[keyOff + 24] &= R_MASK_LOW_2;
-            key[keyOff + 28] &= R_MASK_LOW_2;
-        }
-
-		/// <summary>
+        /// <summary>
 		/// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g.
 		/// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
 		/// as per <see cref="Clamp(byte[])"/>.
@@ -121,27 +95,22 @@ namespace Org.BouncyCastle.Crypto.Generators
 		public static void CheckKey(byte[] key)
 		{
 			if (key.Length != 32)
-			{
 				throw new ArgumentException("Poly1305 key must be 256 bits.");
-			}
 
-			checkMask(key[19], R_MASK_HIGH_4);
-			checkMask(key[23], R_MASK_HIGH_4);
-			checkMask(key[27], R_MASK_HIGH_4);
-			checkMask(key[31], R_MASK_HIGH_4);
+            CheckMask(key[3], R_MASK_HIGH_4);
+			CheckMask(key[7], R_MASK_HIGH_4);
+			CheckMask(key[11], R_MASK_HIGH_4);
+			CheckMask(key[15], R_MASK_HIGH_4);
 
-			checkMask(key[20], R_MASK_LOW_2);
-			checkMask(key[24], R_MASK_LOW_2);
-			checkMask(key[28], R_MASK_LOW_2);
+			CheckMask(key[4], R_MASK_LOW_2);
+			CheckMask(key[8], R_MASK_LOW_2);
+			CheckMask(key[12], R_MASK_LOW_2);
 		}
 
-		private static void checkMask(byte b, byte mask)
+        private static void CheckMask(byte b, byte mask)
 		{
 			if ((b & (~mask)) != 0)
-			{
 				throw new ArgumentException("Invalid format for r portion of Poly1305 key.");
-			}
 		}
-
 	}
 }
\ No newline at end of file
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 1a951ca04..0f66ccccc 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Crypto.Macs
     public class Poly1305
         : IMac
     {
-        private const int BLOCK_SIZE = 16;
+        private const int BlockSize = 16;
 
         private readonly IBlockCipher cipher;
 
@@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Crypto.Macs
         // Accumulating state
 
         /** Current block of buffered input */
-        private byte[] currentBlock = new byte[BLOCK_SIZE];
+        private byte[] currentBlock = new byte[BlockSize];
 
         /** Current offset in input buffer */
         private int currentBlockOffset = 0;
@@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Macs
          */
         public Poly1305(IBlockCipher cipher)
         {
-            if (cipher.GetBlockSize() != BLOCK_SIZE)
+            if (cipher.GetBlockSize() != BlockSize)
             {
                 throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
             }
@@ -102,22 +102,24 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         private void SetKey(byte[] key, byte[] nonce)
         {
-            if (cipher != null && (nonce == null || nonce.Length != BLOCK_SIZE))
-                throw new ArgumentException("Poly1305 requires a 128 bit IV.");
+            if (key.Length != 32)
+                throw new ArgumentException("Poly1305 key must be 256 bits.");
 
-            Poly1305KeyGenerator.CheckKey(key);
+            if (cipher != null && (nonce == null || nonce.Length != BlockSize))
+                throw new ArgumentException("Poly1305 requires a 128 bit IV.");
 
-            // Extract r portion of key
-            uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0);
-            uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4);
-            uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8);
-            uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12);
+            // Extract r portion of key (and "clamp" the values)
+            uint t0 = Pack.LE_To_UInt32(key, 0);
+            uint t1 = Pack.LE_To_UInt32(key, 4);
+            uint t2 = Pack.LE_To_UInt32(key, 8);
+            uint t3 = Pack.LE_To_UInt32(key, 12);
 
-            r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
-            r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
-            r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
-            r3 = t2 & 0x3f03fff; t3 >>= 8;
-            r4 = t3 & 0x00fffff;
+            // NOTE: The masks perform the key "clamping" implicitly
+            r0 =   t0                      & 0x03FFFFFFU;
+            r1 = ((t0 >> 26) | (t1 <<  6)) & 0x03FFFF03U;
+            r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU;
+            r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU;
+            r4 =  (t3 >>  8)               & 0x000FFFFFU;
 
             // Precompute multipliers
             s1 = r1 * 5;
@@ -126,22 +128,27 @@ namespace Org.BouncyCastle.Crypto.Macs
             s4 = r4 * 5;
 
             byte[] kBytes;
+            int kOff;
+
             if (cipher == null)
             {
                 kBytes = key;
+                kOff = BlockSize;
             }
             else
             {
                 // Compute encrypted nonce
-                kBytes = new byte[BLOCK_SIZE];
-                cipher.Init(true, new KeyParameter(key, 0, BLOCK_SIZE));
+                kBytes = new byte[BlockSize];
+                kOff = 0;
+
+                cipher.Init(true, new KeyParameter(key, BlockSize, BlockSize));
                 cipher.ProcessBlock(nonce, 0, kBytes, 0);
             }
 
-            k0 = Pack.LE_To_UInt32(kBytes, 0);
-            k1 = Pack.LE_To_UInt32(kBytes, 4);
-            k2 = Pack.LE_To_UInt32(kBytes, 8);
-            k3 = Pack.LE_To_UInt32(kBytes, 12);
+            k0 = Pack.LE_To_UInt32(kBytes, kOff + 0);
+            k1 = Pack.LE_To_UInt32(kBytes, kOff + 4);
+            k2 = Pack.LE_To_UInt32(kBytes, kOff + 8);
+            k3 = Pack.LE_To_UInt32(kBytes, kOff + 12);
         }
 
         public string AlgorithmName
@@ -151,7 +158,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public int GetMacSize()
         {
-            return BLOCK_SIZE;
+            return BlockSize;
         }
 
         public void Update(byte input)
@@ -165,13 +172,13 @@ namespace Org.BouncyCastle.Crypto.Macs
             int copied = 0;
             while (len > copied)
             {
-                if (currentBlockOffset == BLOCK_SIZE)
+                if (currentBlockOffset == BlockSize)
                 {
-                    processBlock();
+                    ProcessBlock();
                     currentBlockOffset = 0;
                 }
 
-                int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset);
+                int toCopy = System.Math.Min((len - copied), BlockSize - currentBlockOffset);
                 Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy);
                 copied += toCopy;
                 currentBlockOffset += toCopy;
@@ -179,12 +186,12 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         }
 
-        private void processBlock()
+        private void ProcessBlock()
         {
-            if (currentBlockOffset < BLOCK_SIZE)
+            if (currentBlockOffset < BlockSize)
             {
                 currentBlock[currentBlockOffset] = 1;
-                for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++)
+                for (int i = currentBlockOffset + 1; i < BlockSize; i++)
                 {
                     currentBlock[i] = 0;
                 }
@@ -201,7 +208,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff);
             h4 += (uint)(t3 >> 8);
 
-            if (currentBlockOffset == BLOCK_SIZE)
+            if (currentBlockOffset == BlockSize)
             {
                 h4 += (1 << 24);
             }
@@ -223,15 +230,12 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public int DoFinal(byte[] output, int outOff)
         {
-            if (outOff + BLOCK_SIZE > output.Length)
-            {
-                throw new DataLengthException("Output buffer is too short.");
-            }
+            Check.DataLength(output, outOff, BlockSize, "Output buffer is too short.");
 
             if (currentBlockOffset > 0)
             {
                 // Process padded block
-                processBlock();
+                ProcessBlock();
             }
 
             ulong f0, f1, f2, f3;
@@ -273,7 +277,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             Pack.UInt32_To_LE((uint)f3, output, outOff + 12);
 
             Reset();
-            return BLOCK_SIZE;
+            return BlockSize;
         }
 
         public void Reset()
diff --git a/crypto/src/crypto/tls/Chacha20Poly1305.cs b/crypto/src/crypto/tls/Chacha20Poly1305.cs
index 817e64b25..8687803b4 100644
--- a/crypto/src/crypto/tls/Chacha20Poly1305.cs
+++ b/crypto/src/crypto/tls/Chacha20Poly1305.cs
@@ -145,10 +145,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             byte[] firstBlock = new byte[64];
             cipher.ProcessBytes(firstBlock, 0, firstBlock.Length, firstBlock, 0);
 
-            // NOTE: The BC implementation puts 'r' after 'k'
-            Array.Copy(firstBlock, 0, firstBlock, 32, 16);
-            Poly1305KeyGenerator.Clamp(firstBlock, 16);
-            KeyParameter macKey = new KeyParameter(firstBlock, 16, 32);
+            KeyParameter macKey = new KeyParameter(firstBlock, 0, 32);
             Arrays.Fill(firstBlock, (byte)0);
             return macKey;
         }