private static UniversalCryptoTransform CreateTransformCore( CipherMode cipherMode, PaddingMode paddingMode, byte[] key, byte[]?iv, int blockSize, int paddingSize, int feedbackSize, bool encrypting) { ValidateCipherMode(cipherMode); if (iv is null) { throw new CryptographicException(SR.Cryptography_MissingIV); } Debug.Assert(blockSize == BlockSizeBytes); Debug.Assert(paddingSize == blockSize); BasicSymmetricCipher cipher = Interop.BrowserCrypto.CanUseSubtleCrypto ? new AesSubtleCryptoTransform(key, iv, encrypting) : new AesManagedTransform(key, iv, encrypting); return(UniversalCryptoTransform.Create(paddingMode, cipher, encrypting)); }
protected virtual void Dispose(bool disposing) { if (disposing) { BasicSymmetricCipher.Dispose(); } }
public static UniversalCryptoTransform Create( PaddingMode paddingMode, BasicSymmetricCipher cipher, bool encrypting) { if (encrypting) { return(new UniversalCryptoEncryptor(paddingMode, cipher)); } else { return(new UniversalCryptoDecryptor(paddingMode, cipher)); } }
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 int UncheckedTransformBlock(ReadOnlySpan <byte> inputBuffer, Span <byte> outputBuffer) { // // If we're decrypting, it's possible to be called with the last blocks of the data, and then // have TransformFinalBlock called with an empty array. Since we don't know if this is the case, // we won't decrypt the last block of the input until either TransformBlock or // TransformFinalBlock is next called. // // We don't need to do this for PaddingMode.None because there is no padding to strip, and // we also don't do this for PaddingMode.Zeros since there is no way for us to tell if the // zeros at the end of a block are part of the plaintext or the padding. // int decryptedBytes = 0; if (SymmetricPadding.DepaddingRequired(PaddingMode)) { // If we have data saved from a previous call, decrypt that into the output first if (_heldoverCipher != null) { int depadDecryptLength = BasicSymmetricCipher.Transform(_heldoverCipher, outputBuffer); outputBuffer = outputBuffer.Slice(depadDecryptLength); decryptedBytes += depadDecryptLength; } else { _heldoverCipher = new byte[InputBlockSize]; } // Postpone the last block to the next round. Debug.Assert(inputBuffer.Length >= _heldoverCipher.Length, "inputBuffer.Length >= _heldoverCipher.Length"); inputBuffer.Slice(inputBuffer.Length - _heldoverCipher.Length).CopyTo(_heldoverCipher); inputBuffer = inputBuffer.Slice(0, inputBuffer.Length - _heldoverCipher.Length); Debug.Assert(inputBuffer.Length % InputBlockSize == 0, "Did not remove whole blocks for depadding"); } if (inputBuffer.Length > 0) { decryptedBytes += BasicSymmetricCipher.Transform(inputBuffer, outputBuffer); } return(decryptedBytes); }
protected UniversalCryptoTransform(PaddingMode paddingMode, BasicSymmetricCipher basicSymmetricCipher) { PaddingMode = paddingMode; BasicSymmetricCipher = basicSymmetricCipher; }
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); } } }
public UniversalCryptoDecryptor(PaddingMode paddingMode, BasicSymmetricCipher basicSymmetricCipher) : base(paddingMode, basicSymmetricCipher) { }
protected override int UncheckedTransformBlock(ReadOnlySpan <byte> inputBuffer, Span <byte> outputBuffer) { return(BasicSymmetricCipher.Transform(inputBuffer, outputBuffer)); }