private bool TryDecrypt( SafeSecKeyRefHandle privateKey, ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { Debug.Assert(privateKey != null); if (padding.Mode != RSAEncryptionPaddingMode.Pkcs1 && padding.Mode != RSAEncryptionPaddingMode.Oaep) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (data.Length > modulusSizeInBytes) { throw new CryptographicException( SR.Format(SR.Cryptography_Padding_DecDataTooBig, modulusSizeInBytes)); } if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1 || padding == RSAEncryptionPadding.OaepSHA1) { return(Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten)); } Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Oaep); RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); byte[] rented = ArrayPool <byte> .Shared.Rent(modulusSizeInBytes); Span <byte> unpaddedData = Span <byte> .Empty; try { if (!Interop.AppleCrypto.TryRsaDecryptionPrimitive(privateKey, data, rented, out int paddedSize)) { Debug.Fail($"Raw decryption failed with KeySize={KeySize} and a buffer length {rented.Length}"); throw new CryptographicException(); } Debug.Assert(modulusSizeInBytes == paddedSize); unpaddedData = new Span <byte>(rented, 0, paddedSize); return(processor.DepadOaep(unpaddedData, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(unpaddedData); ArrayPool <byte> .Shared.Return(rented); } }
private static bool TryDecrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.Crypto.RsaPadding rsaPadding, RsaPaddingProcessor rsaPaddingProcessor, out int bytesWritten) { // If rsaPadding is PKCS1 or OAEP-SHA1 then no depadding method should be present. // If rsaPadding is NoPadding then a depadding method should be present. Debug.Assert( (rsaPadding == Interop.Crypto.RsaPadding.NoPadding) == (rsaPaddingProcessor != null)); // Caller should have already checked this. Debug.Assert(!key.IsInvalid); int rsaSize = Interop.Crypto.RsaSize(key); if (data.Length != rsaSize) { throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } Span <byte> decryptBuf = destination; byte[] paddingBuf = null; if (rsaPaddingProcessor != null) { paddingBuf = CryptoPool.Rent(rsaSize); decryptBuf = paddingBuf; } try { int returnValue = Interop.Crypto.RsaPrivateDecrypt(data.Length, data, decryptBuf, key, rsaPadding); CheckReturn(returnValue); if (rsaPaddingProcessor != null) { return(rsaPaddingProcessor.DepadOaep(paddingBuf, destination, out bytesWritten)); } else { // If the padding mode is RSA_NO_PADDING then the size of the decrypted block // will be RSA_size. If any padding was used, then some amount (determined by the padding algorithm) // will have been reduced, and only returnValue bytes were part of the decrypted // body. Either way, we can just use returnValue, but some additional bytes may have been overwritten // in the destination span. bytesWritten = returnValue; } return(true); } finally { if (paddingBuf != null) { // DecryptBuf is paddingBuf if paddingBuf is not null, erase it before returning it. // If paddingBuf IS null then decryptBuf was destination, and shouldn't be cleared. CryptographicOperations.ZeroMemory(decryptBuf); CryptoPool.Return(paddingBuf, clearSize: 0); } } }