Пример #1
0
        public void HashAes()
        {
            using var cmac = new CMAC(Aes.Create(), Convert.FromHexString("2b7e151628aed2a6abf7158809cf4f3c"));
            cmac.TransformBlock(Convert.FromHexString("6bc1bee22e409f96e93d7e117393172a"), 0, 16, null, 0);
            cmac.TransformBlock(Convert.FromHexString("ae2d8a571e03ac9c9eb76fac45af8e51"), 0, 16, null, 0);
            cmac.TransformFinalBlock(Convert.FromHexString("30c81c46a35ce411"), 0, 8);
            var tag = cmac.Hash;

            Assert.AreEqual("dfa66747de9ae63030ca32611497c827", Convert.ToHexString(tag).ToLowerInvariant());
        }
Пример #2
0
        private void Process(ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> input, Span <byte> output, Span <byte> tag, ReadOnlySpan <byte> associatedData, bool outputIsCiphertext)
        {
            using var encryptor = aes.CreateEncryptor();
            var tmp               = CryptoPool.Rent(16);
            var counter           = CryptoPool.Rent(16);
            var counterEnc        = CryptoPool.Rent(16);
            var nonceMac          = CryptoPool.Rent(16);
            var associatedDataMac = CryptoPool.Rent(16);
            var ciphertextMac     = CryptoPool.Rent(16);

            try
            {
                CryptographicOperations.ZeroMemory(tmp.AsSpan(0, 15));
                tmp[15] = 0; // N tag
                cmac.TransformBlock(tmp, 0, 16, null, 0);
                cmac.TryComputeHash(nonce, nonceMac, out var _);

                tmp[15] = 1; // H tag
                cmac.TransformBlock(tmp, 0, 16, null, 0);
                cmac.TryComputeHash(associatedData, associatedDataMac, out var _);

                cmac.Initialize();
                tmp[15] = 2; // C tag
                cmac.TransformBlock(tmp, 0, 16, null, 0);

                nonceMac.AsSpan().CopyTo(counter);
                while (input.Length >= 16)
                {
                    encryptor.TransformBlock(counter, 0, 16, counterEnc, 0);
                    if (outputIsCiphertext)
                    {
                        for (int i = 0; i < 16; i++)
                        {
                            tmp[i] = (byte)(input[i] ^ counterEnc[i]);
                        }
                        cmac.TransformBlock(tmp, 0, 16, null, 0);
                        tmp.AsSpan(0, 16).CopyTo(output);
                    }
                    else
                    {
                        input.Slice(0, 16).CopyTo(tmp);
                        cmac.TransformBlock(tmp, 0, 16, null, 0);
                        for (int i = 0; i < 16; i++)
                        {
                            output[i] = (byte)(input[i] ^ counterEnc[i]);
                        }
                    }
                    byte add = 1;
                    for (int i = 15; i >= 0; i--)
                    {
                        counter[i] += add;
                        add         = counter[i] == 0 ? 1 : 0;
                    }
                    input  = input.Slice(16);
                    output = output.Slice(16);
                }

                if (input.Length > 0)
                {
                    encryptor.TransformBlock(counter, 0, 16, counterEnc, 0);
                    if (outputIsCiphertext)
                    {
                        for (int i = 0; i < input.Length; i++)
                        {
                            tmp[i] = (byte)(input[i] ^ counterEnc[i]);
                        }
                        cmac.TransformBlock(tmp, 0, input.Length, null, 0);
                        tmp.AsSpan(0, input.Length).CopyTo(output);
                    }
                    else
                    {
                        input.CopyTo(tmp);
                        cmac.TransformBlock(tmp, 0, input.Length, null, 0);
                        for (int i = 0; i < input.Length; i++)
                        {
                            output[i] = (byte)(input[i] ^ counterEnc[i]);
                        }
                    }
                }

                cmac.TryComputeHash(Array.Empty <byte>(), ciphertextMac, out var _);

                for (int i = 0; i < tag.Length; i++)
                {
                    tag[i] = (byte)(nonceMac[i] ^ associatedDataMac[i] ^ ciphertextMac[i]);
                }
            }
            finally
            {
                cmac.Initialize();
                CryptoPool.Return(tmp, 16);
                CryptoPool.Return(counter, 16);
                CryptoPool.Return(counterEnc, 16);
                CryptoPool.Return(nonceMac, 16);
                CryptoPool.Return(associatedDataMac, 16);
                CryptoPool.Return(ciphertextMac, 16);
            }
        }