예제 #1
0
파일: AesPmac.cs 프로젝트: zer09/miscreant
        /// <summary>
        /// Initializes a new instance of the <see cref="AesPmac"/> class with the specified key.
        /// </summary>
        /// <param name="key">The secret key for <see cref="AesPmac"> authentication.</param>
        public AesPmac(byte[] key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            aes       = Utils.CreateAes(CipherMode.ECB);
            encryptor = aes.CreateEncryptor(key, null);

            byte[] temp = new byte[BlockSize];
            encryptor.TransformBlock(temp, 0, BlockSize, temp, 0);

            for (int i = 0; i < l.Length; ++i)
            {
                l[i] = (byte[])temp.Clone();
                Utils.Multiply(temp);
            }

            inv = (byte[])l[0].Clone();
            int lastBit = inv[BlockSize - 1] & 1;

            for (int i = BlockSize - 1; i > 0; --i)
            {
                int carry = Subtle.ConstantTimeSelect(inv[i - 1] & 1, 0x80, 0);
                inv[i] = (byte)((inv[i] >> 1) | carry);
            }

            inv[0]            >>= 1;
            inv[0]             ^= (byte)Subtle.ConstantTimeSelect(lastBit, 0x80, 0);
            inv[BlockSize - 1] ^= (byte)Subtle.ConstantTimeSelect(lastBit, Constants.R >> 1, 0);
        }
예제 #2
0
        public static void Multiply(byte[] input)
        {
            Debug.Assert(input.Length == Constants.BlockSize);

            int carry = input[0] >> 7;

            for (int i = 0; i < Constants.BlockSize - 1; ++i)
            {
                input[i] = (byte)((input[i] << 1) | (input[i + 1] >> 7));
            }

            byte last = input[Constants.BlockSize - 1];

            input[Constants.BlockSize - 1] = (byte)((last << 1) ^ Subtle.ConstantTimeSelect(carry, Constants.R, 0));
        }
예제 #3
0
        /// <summary>
        /// Open decrypts ciphertext, authenticates the decrypted plaintext
        /// and the given associated data items and, if successful, returns
        /// the result. For nonce-based encryption, the nonce should be the
        /// last associated data item. In case of failed decryption, this
        /// method throws <see cref="CryptographicException">.
        /// </summary>
        /// <param name="ciphertext">The ciphertext to decrypt.</param>
        /// <param name="data">Associated data items to authenticate.</param>
        /// <returns>The decrypted plaintext.</returns>
        /// <exception cref="CryptographicException">Thrown when the ciphertext is invalid.</exception>
        public byte[] Open(byte[] ciphertext, params byte[][] data)
        {
            if (ciphertext == null)
            {
                throw new ArgumentNullException(nameof(ciphertext));
            }

            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (ciphertext.Length < BlockSize)
            {
                throw new CryptographicException("Malformed or corrupt ciphertext.");
            }

            if (data.Length > MaxAssociatedDataItems)
            {
                throw new CryptographicException($"Maximum number of associated data items is {MaxAssociatedDataItems}");
            }

            byte[] iv     = new byte[BlockSize];
            byte[] output = new byte[ciphertext.Length - iv.Length];

            Array.Copy(ciphertext, 0, iv, 0, BlockSize);
            ZeroIvBits(iv);

            ctr.Reset(iv);
            ctr.Encrypt(ciphertext, BlockSize, output.Length, output, 0);

            byte[] v = S2V(data, output);

            if (!Subtle.ConstantTimeEquals(ciphertext, v, BlockSize))
            {
                throw new CryptographicException("Malformed or corrupt ciphertext.");
            }

            return(output);
        }