Poly1305 message authentication code, designed by D. J. Bernstein.
Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106 effective key bits) used in the authenticator. The polynomial calculation in this implementation is adapted from the public domain poly1305-donna-unrolled C implementation by Andrew M (@floodyberry).
Inheritance: IMac
Exemplo n.º 1
0
        static void PolyUpdateMacText(Macs.Poly1305 poly, byte[] buf)
        {
            poly.BlockUpdate(buf, 0, buf.Length);
            int partial = buf.Length % 16;

            if (partial != 0)
            {
                var zeroPadding = new byte[15];
                poly.BlockUpdate(zeroPadding, 0, 16 - partial);
            }
        }
Exemplo n.º 2
0
        public byte[] Decrypt(byte[] cipher, byte[] key, byte[] iv, byte[] aad = null, byte[] associated = null)
        {
            if (key.Length * 8 != this.KeySize)
            {
                throw new InvalidOperationException($"the given key has invalid size {key.Length * 8}, expect {this.KeySize}");
            }
            if (iv.Length != 12)
            {
                throw new InvalidOperationException($"chacha20 requires 96 bits IV, got {iv.Length * 8}");
            }
            if (cipher.Length <= 16)
            {
                throw new ArgumentException($"incorrect argument [cipher] size");
            }
            // split cipher and mac
            var cipherText = cipher.Take(cipher.Length - 16).ToArray();
            var macText    = cipher.Skip(cipher.Length - 16).ToArray();

            var engine = new Engines.ChaCha7539Engine();

            engine.Init(false, new Parameters.ParametersWithIV(new Parameters.KeyParameter(key), iv));
            // calculate mac key
            var mackeyBlock = new byte[64];

            engine.ProcessBytes(mackeyBlock, 0, mackeyBlock.Length, mackeyBlock, 0);
            var mackey = mackeyBlock.Take(32).ToArray();
            // calculate mac
            var poly = new Macs.Poly1305();

            poly.Init(new Parameters.KeyParameter(mackey));
            PolyUpdateMacText(poly, aad);
            PolyUpdateMacText(poly, cipherText);
            PolyUpdateMacLength(poly, aad.Length);
            PolyUpdateMacLength(poly, cipherText.Length);
            var myMac = PolyDoFinal(poly);

            if (!Utils.BytesEqual(myMac, macText))
            {
                throw new ArgumentException("bad record mac");
            }
            // decrypt
            var plain = new byte[cipherText.Length];

            engine.ProcessBytes(cipherText, 0, cipherText.Length, plain, 0);
            return(plain);
        }
Exemplo n.º 3
0
        public byte[] Encrypt(byte[] plain, byte[] key, byte[] iv, byte[] aad = null, byte[] associated = null)
        {
            if (key.Length * 8 != this.KeySize)
            {
                throw new InvalidOperationException($"the given key has invalid size {key.Length * 8}, expect {this.KeySize}");
            }
            if (iv.Length != 12)
            {
                throw new InvalidOperationException($"chacha20 requires 96 bits IV, got {iv.Length * 8}");
            }

            var engine = new Engines.ChaCha7539Engine();

            engine.Init(true, new Parameters.ParametersWithIV(new Parameters.KeyParameter(key), iv));
            // calculate mac key
            var mackeyBlock = new byte[64];

            engine.ProcessBytes(mackeyBlock, 0, mackeyBlock.Length, mackeyBlock, 0);
            var mackey = mackeyBlock.Take(32).ToArray();
            // encrypt
            var cipher = new byte[plain.Length];

            engine.ProcessBytes(plain, 0, plain.Length, cipher, 0);
            // calculate mac
            var poly = new Macs.Poly1305();

            poly.Init(new Parameters.KeyParameter(mackey));
            PolyUpdateMacText(poly, aad);
            PolyUpdateMacText(poly, cipher);
            PolyUpdateMacLength(poly, aad.Length);
            PolyUpdateMacLength(poly, cipher.Length);
            var myMac       = PolyDoFinal(poly);
            var cipherBlock = new byte[cipher.Length + myMac.Length];

            Buffer.BlockCopy(cipher, 0, cipherBlock, 0, cipher.Length);
            Buffer.BlockCopy(myMac, 0, cipherBlock, cipher.Length, myMac.Length);
            return(cipherBlock);
        }
Exemplo n.º 4
0
        protected virtual byte[] CalculateRecordMac(KeyParameter macKey, byte[] additionalData, byte[] buf, int off, int len)
        {
            IMac mac = new Poly1305();
            mac.Init(macKey);

            UpdateRecordMacText(mac, additionalData, 0, additionalData.Length);
            UpdateRecordMacText(mac, buf, off, len);
            UpdateRecordMacLength(mac, additionalData.Length);
            UpdateRecordMacLength(mac, len);

            return MacUtilities.DoFinal(mac);
        }
Exemplo n.º 5
0
 static byte[] PolyDoFinal(Macs.Poly1305 poly)
 {
     byte[] b = new byte[poly.GetMacSize()];
     poly.DoFinal(b, 0);
     return(b);
 }
Exemplo n.º 6
0
 static void PolyUpdateMacLength(Macs.Poly1305 poly, int len)
 {
     byte[] longLen = BitConverter.GetBytes((ulong)len);
     poly.BlockUpdate(longLen, 0, longLen.Length);
 }
Exemplo n.º 7
0
		private void testInit()
		{
			CipherKeyGenerator gen = new Poly1305KeyGenerator();
			gen.Init(new KeyGenerationParameters(new SecureRandom(), 256));
			byte[] k = gen.GenerateKey();

			IMac poly = new Poly1305(new AesFastEngine());
			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));

			try
			{
				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[15]));
				Fail("16 byte nonce required");
			} catch (ArgumentException)
			{
				// Expected
			}

			try
			{
				byte[] k2 = new byte[k.Length - 1];
				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)
			{
				// 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)
			{
				// Expected
			}

		}
Exemplo n.º 8
0
		private void testReset()
		{
			CipherKeyGenerator gen = new Poly1305KeyGenerator();
			gen.Init(new KeyGenerationParameters(new SecureRandom(), 256));
			byte[] k = gen.GenerateKey();

			byte[] m = new byte[10000];
			byte[] check = new byte[16];
			byte[] output = new byte[16];

			// Generate baseline
			IMac poly = new Poly1305(new AesFastEngine());
			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));

			poly.BlockUpdate(m, 0, m.Length);
			poly.DoFinal(check, 0);

			// Check reset after doFinal
			poly.BlockUpdate(m, 0, m.Length);
			poly.DoFinal(output, 0);

			if (!Arrays.AreEqual(check, output))
			{
				Fail("Mac not reset after doFinal");
			}

			// Check reset
			poly.Update((byte)1);
			poly.Update((byte)2);
			poly.Reset();
			poly.BlockUpdate(m, 0, m.Length);
			poly.DoFinal(output, 0);

			if (!Arrays.AreEqual(check, output))
			{
				Fail("Mac not reset after doFinal");
			}

			// Check init resets
			poly.Update((byte)1);
			poly.Update((byte)2);
			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
			poly.BlockUpdate(m, 0, m.Length);
			poly.DoFinal(output, 0);

			if (!Arrays.AreEqual(check, output))
			{
				Fail("Mac not reset after doFinal");
			}
		}
Exemplo n.º 9
0
		private void testSequential()
		{
			// Sequential test, adapted from test-poly1305aes
			int len;
			byte[] kr = new byte[32];
			byte[] m = new byte[MAXLEN];
			byte[] n = new byte[16];
			byte[] output = new byte[16];

			int c = 0;
			IMac mac = new Poly1305(new AesFastEngine());
			for (int loop = 0; loop < 13; loop++)
			{
				len = 0;
				for (;;)
				{
					c++;
					mac.Init(new ParametersWithIV(new KeyParameter(kr), n));
					mac.BlockUpdate(m, 0, len);
					mac.DoFinal(output, 0);

					// if (c == 678)
					// {
					// TestCase tc = CASES[0];
					//
					// if (!Arrays.AreEqual(tc.key, kr))
					// {
					// System.err.println("Key bad");
					// System.err.println(Hex.ToHexString(tc.key)));
					// System.err.println(Hex.ToHexString(kr)));
					// System.exit(1);
					// }
					// if (!Arrays.AreEqual(tc.nonce, n))
					// {
					// System.err.println("Nonce bad");
					// System.exit(1);
					// }
					// System.out.printf("[%d] m: %s\n", c, Hex.ToHexString(m, 0, len)));
					// System.out.printf("[%d] K: %s\n", c, new string(Hex.encodje(kr)));
					// System.out.printf("[%d] N: %s\n", c, Hex.ToHexString(n)));
					// System.out.printf("[%d] M: ", c);
					// }
					// System.out.printf("%d/%s\n", c, Hex.ToHexString(out)));

					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];
					if (len % 3 != 0)
						for (int i = 0; i < 16; ++i)
							kr[i + 16] ^= output[i];
					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));
			}
		}
Exemplo n.º 10
0
		private void testCase(int i)
		{
			byte[] output = new byte[16];
			TestCase tc = CASES[i];

			IMac mac;
			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]));
			}
			else
			{
				mac = new Poly1305(new AesFastEngine());
				mac.Init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce));
			}
			mac.BlockUpdate(tc.message, 0, tc.message.Length);
			mac.DoFinal(output, 0);

			if (!Arrays.AreEqual(output, tc.expectedMac))
			{
				Fail("Mismatched output " + i, Hex.ToHexString(tc.expectedMac), Hex.ToHexString(output));
			}
		}
Exemplo n.º 11
0
        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));
            }
       }