summary refs log tree commit diff
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
parentPut zero-length extensions first in the ClientHello (diff)
downloadBouncyCastle.NET-ed25519-27ce448162521ace7bc4c0520458ee3dd5665f53.tar.xz
Update Poly1305 to comply with RFC 7539
-rw-r--r--crypto/Readme.html9
-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
-rw-r--r--crypto/test/src/crypto/test/Poly1305Test.cs350
5 files changed, 300 insertions, 205 deletions
diff --git a/crypto/Readme.html b/crypto/Readme.html
index 7af1bbaf0..0cbd91daa 100644
--- a/crypto/Readme.html
+++ b/crypto/Readme.html
@@ -294,6 +294,15 @@ We state, where EC MQV has not otherwise been disabled or removed:
 
         <h4><a class="mozTocH4" name="mozTocId85316"></a>Release 1.8.2, Release Date TBD</h4>
 
+        <h5>IMPORTANT</h5>
+        <ul>
+            <li>
+                This release brings our Poly1305 implementation into line wih RFC 7539, which breaks backward compatibility. The essential
+                difference from 1.8.1 is that the two halves of the 32-byte Poly1305 key have swapped places. If you have persisted Poly1305
+                keys, or are interoperating with other Poly1305 implementations, you may need to account for this change when migrating to 1.8.2.
+            </li>
+        </ul>
+
         <h5>Additional Features and Functionality</h5>
         <ul>
             <li>TLS: support for ClientHello Padding Extension (RFC 7685).</li>
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;
         }
diff --git a/crypto/test/src/crypto/test/Poly1305Test.cs b/crypto/test/src/crypto/test/Poly1305Test.cs
index a1513165b..17c4289aa 100644
--- a/crypto/test/src/crypto/test/Poly1305Test.cs
+++ b/crypto/test/src/crypto/test/Poly1305Test.cs
@@ -20,54 +20,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 	{
 		private const int MAXLEN = 1000;
 
-		private class KeyEngine
-			: IBlockCipher
-		{
-
-			private byte[] key;
-			private int blockSize;
-
-			public KeyEngine(int blockSize)
-			{
-				this.blockSize = blockSize;
-			}
-
-			public void Init(bool forEncryption, ICipherParameters parameters)
-			{
-				if (parameters is KeyParameter)
-				{
-					this.key = ((KeyParameter)parameters).GetKey();
-				}
-			}
-
-			public bool IsPartialBlockOkay 
-			{ 
-				get { return false; } 
-			}
-
-			public string AlgorithmName
-			{
-				get { return "Key"; }
-			}
-
-			public int GetBlockSize()
-			{
-				return blockSize;
-			}
-
-			public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
-			{
-				Array.Copy(key, 0, output, outOff, key.Length);
-				return key.Length;
-			}
-
-			public void Reset()
-			{
-			}
-
-		}
-
-		private class TestCase
+        private class TestCase
 		{
 			internal byte[] key;
 			internal byte[] nonce;
@@ -85,57 +38,54 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 		}
 
-		private static TestCase[] CASES = {
-			// Raw Poly1305
-			// onetimeauth.c from nacl-20110221
-			new TestCase("2539121d8e234e652d651fa4c8cff880eea6a7251c1e72916d11c2cb214d3c25", null,
-			             "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
-			             + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
-			             + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
-			             + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
-			             "f3ffc7703f9400e52a7dfb4b3d3305d9"),
-
-			// Poly1305-AES
-			// Loop 1 of test-poly1305aes from poly1305aes-20050218
-			new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
-			             "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
-			new TestCase("f795bd4a52e29ed713d313fa20e98dbcf795bd0a50e29e0710d3130a20e98d0c",
-			             "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
-			new TestCase("e69dae0aab9f91c03a325dcc9436fa903ef49901c8e11c000430d90ad45e7603",
-			             "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
-			new TestCase("85a4ea91a7de0b0d96eed0d4bf6ecf1cda4afc035087d90e503f8f0ea08c3e0d",
-			             "0b6ef7a0b8f8c738b0f8d5995415271f",
-			             "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
-			             "3c5a13adb18d31c64cc29972030c917d"),
-			new TestCase(
-				"25eb69bac5cdf7d6bfcee4d9d5507b82ca3c6a0da0a864024ca3090628c28e0d",
-				"046772a4f0a8de92e4f0d628cdb04484",
-				"66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
-				"fc5fb58dc65daf19b14d1d05da1064e8"),
-
-			// Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
-			// expose Java unsigned integer problems
-			new TestCase(
-				"95cc0e44d0b79a8856afcae1bec4fe3c" + "01bcb20bfc8b6e03609ddd09f44b060f",
-				null,
-				"66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
-				+ "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
-				+ "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
-				+ "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
-				+ "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
-				+ "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
-				+ "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
-				+ "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
-				+ "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
-				+ "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
-				+ "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
-				+ "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
-			new TestCase(
-				"76fb3635a2dc92a1f768163ab12f2187" + "cd07fd0ef8c0be0afcbdb30af4af0009",
-				null,
-				"f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
-				"045be28cc52009f506bdbfabedacf0b4"),
-
+        private static TestCase[] CASES = {
+            // Raw Poly1305
+            // onetimeauth.c from nacl-20110221
+            new TestCase("eea6a7251c1e72916d11c2cb214d3c25" + "2539121d8e234e652d651fa4c8cff880", null,
+                "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
+                    + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
+                    + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
+                    + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
+                "f3ffc7703f9400e52a7dfb4b3d3305d9"),
+            // Poly1305-AES
+            // Loop 1 of test-poly1305aes from poly1305aes-20050218
+            new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
+                "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
+            new TestCase("f795bd0a50e29e0710d3130a20e98d0c" + "f795bd4a52e29ed713d313fa20e98dbc",
+                "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
+            new TestCase("3ef49901c8e11c000430d90ad45e7603" + "e69dae0aab9f91c03a325dcc9436fa90",
+                "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
+            new TestCase("da4afc035087d90e503f8f0ea08c3e0d" + "85a4ea91a7de0b0d96eed0d4bf6ecf1c",
+                "0b6ef7a0b8f8c738b0f8d5995415271f",
+                "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
+                "3c5a13adb18d31c64cc29972030c917d"),
+            new TestCase(
+                "ca3c6a0da0a864024ca3090628c28e0d" + "25eb69bac5cdf7d6bfcee4d9d5507b82",
+                "046772a4f0a8de92e4f0d628cdb04484",
+                "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
+                "fc5fb58dc65daf19b14d1d05da1064e8"),
+            // Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
+            // expose Java unsigned integer problems
+            new TestCase(
+                "01bcb20bfc8b6e03609ddd09f44b060f" + "95cc0e44d0b79a8856afcae1bec4fe3c",
+                null,
+                "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
+                    + "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
+                    + "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
+                    + "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
+                    + "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
+                    + "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
+                    + "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
+                    + "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
+                    + "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
+                    + "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
+                    + "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
+                    + "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
+            new TestCase(
+                "cd07fd0ef8c0be0afcbdb30af4af0009" + "76fb3635a2dc92a1f768163ab12f2187",
+                null,
+                "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
+                "045be28cc52009f506bdbfabedacf0b4"),
 		};
 
 		public override string Name
@@ -153,6 +103,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 			testSequential();
 			testReset();
+            rfc7539Test();
 		}
 
 		private void testCase(int i)
@@ -164,8 +115,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 			if (tc.nonce == null)
 			{
 				// Raw Poly1305 test - don't do any transform on AES key part
-				mac = new Poly1305(new KeyEngine(16));
-				mac.Init(new ParametersWithIV(new KeyParameter(tc.key), new byte[16]));
+                mac = new Poly1305();
+                mac.Init(new KeyParameter(tc.key));
 			}
 			else
 			{
@@ -228,23 +179,33 @@ namespace Org.BouncyCastle.Crypto.Tests
 					if (len >= MAXLEN)
 						break;
 					n[0] = (byte)(n[0] ^ loop);
-					for (int i = 0; i < 16; ++i)
-						n[i] ^= output[i];
-					if (len % 2 != 0)
-						for (int i = 0; i < 16; ++i)
-							kr[i] ^= output[i];
+                    for (int i = 0; i < 16; ++i)
+                    {
+                        n[i] ^= output[i];
+                    }
+                    if (len % 2 != 0)
+                    {
+                        for (int i = 0; i < 16; ++i)
+                        {
+                            kr[i] ^= output[i];
+                        }
+                    }
 					if (len % 3 != 0)
+                    {
 						for (int i = 0; i < 16; ++i)
+                        {
 							kr[i + 16] ^= output[i];
-					Poly1305KeyGenerator.Clamp(kr);
+                        }
+                    }
+                    Poly1305KeyGenerator.Clamp(kr);
 					m[len++] ^= output[0];
 				}
 			}
 			// Output after 13 loops as generated by poly1305 ref
-			if (c != 13013 || !Arrays.AreEqual(output, Hex.Decode("c96f60a23701a5b0fd2016f58cbe4f7e")))
-			{
-				Fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", Hex.ToHexString(output));
-			}
+            if (c != 13013 || !Arrays.AreEqual(output, Hex.Decode("89824ddf0816481051f4a82731cd56d5")))
+            {
+                Fail("Sequential Poly1305 " + c, "89824ddf0816481051f4a82731cd56d5", Hex.ToHexString(output));
+            }
 		}
 
 		private void testReset()
@@ -311,7 +272,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 			{
 				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[15]));
 				Fail("16 byte nonce required");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
@@ -322,21 +284,24 @@ namespace Org.BouncyCastle.Crypto.Tests
 				Array.Copy(k, 0, k2, 0, k2.Length);
 				poly.Init(new ParametersWithIV(new KeyParameter(k2), new byte[16]));
 				Fail("32 byte key required");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
 
+            /*
 			try
 			{
 				k[19] = (byte)0xFF;
 				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
 				Fail("UnClamped key should not be accepted.");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
-
+            */
 		}
 
 		private void testKeyGenerator()
@@ -353,7 +318,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 			try
 			{
 				Poly1305KeyGenerator.CheckKey(k);
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				Fail("Poly1305 key should be Clamped on generation.");
 			}
@@ -366,17 +332,167 @@ namespace Org.BouncyCastle.Crypto.Tests
 				Fail("Poly1305 key should be Clamped on generation.");
 			}
 
+            /*
 			try
 			{
 				k2[19] = (byte)0xff;
 				Poly1305KeyGenerator.CheckKey(k2);
 				Fail("UnClamped key should fail check.");
-			} catch (ArgumentException)
+			}
+            catch (ArgumentException)
 			{
 				// Expected
 			}
+            */
 		}
 
+        public void rfc7539Test()
+        {
+            // From RFC 7539
+            byte[] keyMaterial = Hex.Decode("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b");
+            byte[] data = Hex.Decode("43727970746f677261706869 63 20 46 6f 72 75 6d 20 52 65 73 65 61 72 63 68 20 47 72 6f7570");
+            byte[] expected = Hex.Decode("a8061dc1305136c6c22b8baf0c0127a9");
+
+            CheckVector(keyMaterial, data, expected);
+
+            data = Hex.Decode("48656c6c6f20776f726c6421");
+            keyMaterial = Hex.Decode(
+                "746869732069732033322d6279746520" +
+                    "6b657920666f7220506f6c7931333035");
+
+            CheckVector(keyMaterial, data, Hex.Decode("a6f745008f81c916a20dcc74eef2b2f0"));
+
+            // A.3 #1
+            keyMaterial = Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            data = Hex.Decode(
+                "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #2
+            keyMaterial = Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0036 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e");
+
+            data = Hex.Decode(
+                "41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74"
+                    + "6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e"
+                    + "64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72"
+                    + "69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69"
+                    + "63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72"
+                    + "20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46"
+                    + "20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20"
+                    + "6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73"
+                    + "74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69"
+                    + "74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74"
+                    + "20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69"
+                    + "76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72"
+                    + "65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74"
+                    + "72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20"
+                    + "73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75"
+                    + "64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e"
+                    + "74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69"
+                    + "6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20"
+                    + "77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63"
+                    + "74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61"
+                    + "74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e"
+                    + "79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c"
+                    + "20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65"
+                    + "73 73 65 64 20 74 6f");
+
+            CheckVector(keyMaterial, data, Hex.Decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e"));
+
+            // A.3 #3
+            keyMaterial = Hex.Decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0"));
+
+            // A.3 #4
+
+            keyMaterial = Hex.Decode("1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0");
+
+            data = Hex.Decode(
+                "27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61"
+                    + "6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f"
+                    + "76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64"
+                    + "20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77"
+                    + "61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77"
+                    + "65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65"
+                    + "73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20"
+                    + "72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e");
+
+            CheckVector(keyMaterial, data, Hex.Decode("45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62"));
+
+            // A.3 #5
+            keyMaterial = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+
+            CheckVector(keyMaterial, data, Hex.Decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #6
+            keyMaterial = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+            data = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #7
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFF0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #8
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFFB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01");
+
+            CheckVector(keyMaterial, data, Hex.Decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+
+            // A.3 #9
+            keyMaterial = Hex.Decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode("FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
+
+            CheckVector(keyMaterial, data, Hex.Decode("FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"));
+
+            // A.3 #10
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode(
+                "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
+                    + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
+                    + "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00"));
+
+            // A.3 #11
+            keyMaterial = Hex.Decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+            data = Hex.Decode(
+                "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00"
+                    + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00"
+                    + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+
+            CheckVector(keyMaterial, data, Hex.Decode("13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"));
+        }
+
+        private void CheckVector(byte[] keyMaterial, byte[] input, byte[] tag)
+        {
+            Poly1305 poly1305 = new Poly1305();
+
+            poly1305.Init(new KeyParameter(keyMaterial));
+
+            poly1305.BlockUpdate(input, 0, input.Length);
+
+            byte[] mac = new byte[poly1305.GetMacSize()];
+
+            poly1305.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(tag, mac))
+            {
+                Fail("rfc7539", Hex.ToHexString(tag), Hex.ToHexString(mac));
+            }
+       }
+
 		public static void Main(
 			string[] args)
 		{