private byte[] CngTransform(byte[] input, int inputOffset, int inputCount) { Debug.Assert(m_key != null, "key != null"); Debug.Assert(!m_key.IsClosed && !m_key.IsInvalid, "!m_key.IsClosed && !m_key.IsInvalid"); Debug.Assert(input != null, "input != null"); Debug.Assert(inputOffset >= 0, "inputOffset >= 0"); Debug.Assert(inputCount >= 0, "inputCount >= 0"); Debug.Assert(inputCount <= input.Length - inputOffset, "inputCount <= input.Length - inputOffset"); byte[] inputBuffer = null; try { // Build up a buffer of the only portion of the input we should be transforming inputBuffer = input; if (inputOffset > 0 || inputCount != input.Length) { inputBuffer = new byte[inputCount]; Array.Copy(input, inputOffset, inputBuffer, 0, inputBuffer.Length); } if (m_encrypting) { return(BCryptNative.SymmetricEncrypt(m_key, inputBuffer, m_chainData, ref m_authInfo)); } else { return(BCryptNative.SymmetricDecrypt(m_key, inputBuffer, this.m_chainData, ref m_authInfo)); } } finally { if (inputBuffer != input) { // Zeroize the input buffer if we allocated one Array.Clear(inputBuffer, 0, inputBuffer.Length); } } }
private int DecryptBlocks(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, bool bufferLastBlock) { Debug.Assert(inputBuffer != null, "inputBuffer != null"); Debug.Assert(inputOffset >= 0, "inputOffset >= 0"); Debug.Assert(inputCount >= 0 && inputCount <= inputBuffer.Length - inputOffset, "inputCount >= 0 && inputCount <= inputBuffer.Length - inputOffset"); Debug.Assert(inputCount % InputBlockSize == 0, "inputCount % InputBlockSize == 0"); Debug.Assert(outputBuffer != null, "outputBuffer != null"); Debug.Assert(inputCount <= outputBuffer.Length - outputOffset, "inputCount <= outputBuffer.Length - outputOffset"); int decryptedBytes = 0; byte[] ciphertext = null; // // When decrypting, it's possible for us to be called with the final blocks of data in // TransformBlock, and then called with an empty TransformFinalBlock. This means that we always // need to keep the last block of data we see in a depad buffer and not decrypt it until the // next TransformBlock or TransformFinalBlock is called. Otherwise, we could end up decrypting // the padding bytes on the last call to TransformBlock and passing them out to our caller as // plaintext, when in fact we should have stripped them. // // If the padding cannot be removed, then we don't need to buffer the final block. if (!m_paddingMode.CanRemovePadding) { bufferLastBlock = false; } // If we've previously saved data to decrypt, we need to do that first. Otherwise, we need // to allocate a buffer to save the last block of the incoming data in. if (m_depadBuffer != null) { byte[] decryptedDepad = BCryptNative.SymmetricDecrypt(m_key, m_iv, m_depadBuffer); Buffer.BlockCopy(decryptedDepad, 0, outputBuffer, outputOffset, decryptedDepad.Length); decryptedBytes += decryptedDepad.Length; outputOffset += decryptedDepad.Length; } // If we need to save the last block of data, do that now if (bufferLastBlock) { if (m_depadBuffer == null) { m_depadBuffer = new byte[InputBlockSize]; } // Copy the last block of data to the depad buffer, and decrypt the first blocks now. ciphertext = new byte[inputCount - m_depadBuffer.Length]; Buffer.BlockCopy(inputBuffer, inputOffset, ciphertext, 0, ciphertext.Length); Buffer.BlockCopy(inputBuffer, inputOffset + inputCount - m_depadBuffer.Length, m_depadBuffer, 0, m_depadBuffer.Length); } else { // No depadding is necessary, so we can decrypt the entire input now m_depadBuffer = null; ciphertext = new byte[inputCount]; Buffer.BlockCopy(inputBuffer, inputOffset, ciphertext, 0, ciphertext.Length); } // Decrypt the input that's not been saved in the depad buffer Debug.Assert(ciphertext != null, "ciphertext != null"); if (ciphertext.Length > 0) { byte[] plaintext = BCryptNative.SymmetricDecrypt(m_key, m_iv, ciphertext); Buffer.BlockCopy(plaintext, 0, outputBuffer, outputOffset, plaintext.Length); decryptedBytes += plaintext.Length; } return(decryptedBytes); }