/// <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); }
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)); }
/// <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); }