Example #1
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);
        }