Exemple #1
0
        protected override int UncheckedTransformFinalBlock(ReadOnlySpan <byte> inputBuffer, Span <byte> outputBuffer)
        {
            // The only caller of this method is the array-allocating overload, outputBuffer is
            // always new memory, not a user-provided buffer.
            Debug.Assert(!inputBuffer.Overlaps(outputBuffer));

            int padWritten       = SymmetricPadding.PadBlock(inputBuffer, outputBuffer, PaddingSizeBytes, PaddingMode);
            int transformWritten = BasicSymmetricCipher.TransformFinal(outputBuffer.Slice(0, padWritten), outputBuffer);

            // After padding, we should have an even number of blocks, and the same applies
            // to the transform.
            Debug.Assert(padWritten == transformWritten);

            return(transformWritten);
        }
        protected override unsafe int UncheckedTransformFinalBlock(ReadOnlySpan <byte> inputBuffer, Span <byte> outputBuffer)
        {
            // We can't complete decryption on a partial block
            if (inputBuffer.Length % PaddingSizeBytes != 0)
            {
                throw new CryptographicException(SR.Cryptography_PartialBlock);
            }

            //
            // If we have postponed cipher bits from the prior round, copy that into the decryption buffer followed by the input data.
            // Otherwise the decryption buffer is just the input data.
            //

            ReadOnlySpan <byte> inputCiphertext;
            Span <byte>         ciphertext;

            byte[]? rentedCiphertext = null;
            int rentedCiphertextSize = 0;

            try
            {
                if (_heldoverCipher == null)
                {
                    rentedCiphertextSize = inputBuffer.Length;
                    rentedCiphertext     = CryptoPool.Rent(inputBuffer.Length);
                    ciphertext           = rentedCiphertext.AsSpan(0, inputBuffer.Length);
                    inputCiphertext      = inputBuffer;
                }
                else
                {
                    rentedCiphertextSize = _heldoverCipher.Length + inputBuffer.Length;
                    rentedCiphertext     = CryptoPool.Rent(rentedCiphertextSize);
                    ciphertext           = rentedCiphertext.AsSpan(0, rentedCiphertextSize);
                    _heldoverCipher.AsSpan().CopyTo(ciphertext);
                    inputBuffer.CopyTo(ciphertext.Slice(_heldoverCipher.Length));

                    // Decrypt in-place
                    inputCiphertext = ciphertext;
                }

                int unpaddedLength = 0;

                fixed(byte *pCiphertext = ciphertext)
                {
                    // Decrypt the data, then strip the padding to get the final decrypted data. Note that even if the cipherText length is 0, we must
                    // invoke TransformFinal() so that the cipher object knows to reset for the next cipher operation.
                    int         decryptWritten = BasicSymmetricCipher.TransformFinal(inputCiphertext, ciphertext);
                    Span <byte> decryptedBytes = ciphertext.Slice(0, decryptWritten);

                    if (decryptedBytes.Length > 0)
                    {
                        unpaddedLength = SymmetricPadding.GetPaddingLength(decryptedBytes, PaddingMode, InputBlockSize);
                        decryptedBytes.Slice(0, unpaddedLength).CopyTo(outputBuffer);
                    }
                }

                Reset();
                return(unpaddedLength);
            }
            finally
            {
                if (rentedCiphertext != null)
                {
                    CryptoPool.Return(rentedCiphertext, clearSize: rentedCiphertextSize);
                }
            }
        }