public override bool TryEncrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { ArgumentNullException.ThrowIfNull(padding); ThrowIfDisposed(); int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } if (data.Length == 0) { if (padding.Mode != RSAEncryptionPaddingMode.Pkcs1 && padding.Mode != RSAEncryptionPaddingMode.Oaep) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { if (padding.Mode == RSAEncryptionPaddingMode.Oaep) { RsaPaddingProcessor.PadOaep(padding.OaepHashAlgorithm, data, tmp); } else { Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Pkcs1); RsaPaddingProcessor.PadPkcs1Encryption(data, tmp); } return(Interop.AppleCrypto.TryRsaEncryptionPrimitive( GetKeys().PublicKey, tmp, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(tmp); CryptoPool.Return(rented, clearSize: 0); } } return(Interop.AppleCrypto.TryRsaEncrypt( GetKeys().PublicKey, data, destination, padding, out bytesWritten)); }
private static bool TryEncrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.Crypto.RsaPadding rsaPadding, RsaPaddingProcessor rsaPaddingProcessor, out int bytesWritten) { int rsaSize = Interop.Crypto.RsaSize(key); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } int returnValue; if (rsaPaddingProcessor != null) { Debug.Assert(rsaPadding == Interop.Crypto.RsaPadding.NoPadding); byte[] rented = ArrayPool <byte> .Shared.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { rsaPaddingProcessor.PadOaep(data, tmp); returnValue = Interop.Crypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding); } finally { CryptographicOperations.ZeroMemory(tmp); ArrayPool <byte> .Shared.Return(rented); } } else { Debug.Assert(rsaPadding != Interop.Crypto.RsaPadding.NoPadding); returnValue = Interop.Crypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding); } CheckReturn(returnValue); bytesWritten = returnValue; Debug.Assert(returnValue == rsaSize); return(true); }
private static bool TryEncrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.AndroidCrypto.RsaPadding rsaPadding, HashAlgorithmName?oaepHashAlgorithmName, out int bytesWritten) { int rsaSize = Interop.AndroidCrypto.RsaSize(key); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } int returnValue; if (oaepHashAlgorithmName != null) { Debug.Assert(rsaPadding == Interop.AndroidCrypto.RsaPadding.NoPadding); byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { RsaPaddingProcessor.PadOaep(oaepHashAlgorithmName.Value, data, tmp); returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding); } finally { CryptographicOperations.ZeroMemory(tmp); CryptoPool.Return(rented, clearSize: 0); } } else { Debug.Assert(rsaPadding != Interop.AndroidCrypto.RsaPadding.NoPadding); returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding); } CheckReturn(returnValue); bytesWritten = returnValue; Debug.Assert(returnValue == rsaSize, $"{returnValue} != {rsaSize}"); return(true); }
// Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both // array-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done. private unsafe byte[] EncryptOrDecrypt(byte[] data, RSAEncryptionPadding padding, bool encrypt) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (!encrypt && data.Length != modulusSizeInBytes) { throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } if (encrypt && padding.Mode == RSAEncryptionPaddingMode.Pkcs1 && data.Length > modulusSizeInBytes - Pkcs1PaddingOverhead) { throw new CryptographicException( SR.Format(SR.Cryptography_Encryption_MessageTooLong, modulusSizeInBytes - Pkcs1PaddingOverhead)); } using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { if (encrypt && data.Length == 0) { byte[] rented = CryptoPool.Rent(modulusSizeInBytes); Span <byte> paddedMessage = new Span <byte>(rented, 0, modulusSizeInBytes); try { if (padding == RSAEncryptionPadding.Pkcs1) { RsaPaddingProcessor.PadPkcs1Encryption(data, paddedMessage); } else if (padding.Mode == RSAEncryptionPaddingMode.Oaep) { RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); processor.PadOaep(data, paddedMessage); } else { throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } return(EncryptOrDecrypt(keyHandle, paddedMessage, AsymmetricPaddingMode.NCRYPT_NO_PADDING_FLAG, null, encrypt)); } finally { CryptographicOperations.ZeroMemory(paddedMessage); CryptoPool.Return(rented, clearSize: 0); } } switch (padding.Mode) { case RSAEncryptionPaddingMode.Pkcs1: return(EncryptOrDecrypt(keyHandle, data, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt)); case RSAEncryptionPaddingMode.Oaep: IntPtr namePtr = Marshal.StringToHGlobalUni(padding.OaepHashAlgorithm.Name); try { var paddingInfo = new BCRYPT_OAEP_PADDING_INFO() { pszAlgId = namePtr, // It would nice to put randomized data here but RSAEncryptionPadding does not at this point provide support for this. pbLabel = IntPtr.Zero, cbLabel = 0, }; return(EncryptOrDecrypt(keyHandle, data, AsymmetricPaddingMode.NCRYPT_PAD_OAEP_FLAG, &paddingInfo, encrypt)); } finally { Marshal.FreeHGlobal(namePtr); } default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } } }
// Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both // span-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done. private unsafe bool TryEncryptOrDecrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, bool encrypt, out int bytesWritten) { if (padding == null) { throw new ArgumentNullException(nameof(padding)); } using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) { if (encrypt && data.Length == 0) { int bufSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] rented = ArrayPool <byte> .Shared.Rent(bufSize); Span <byte> paddedMessage = new Span <byte>(rented, 0, bufSize); try { if (padding == RSAEncryptionPadding.Pkcs1) { RsaPaddingProcessor.PadPkcs1Encryption(data, paddedMessage); } else if (padding.Mode == RSAEncryptionPaddingMode.Oaep) { RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); processor.PadOaep(data, paddedMessage); } else { throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } return(TryEncryptOrDecrypt(keyHandle, paddedMessage, destination, AsymmetricPaddingMode.NCRYPT_NO_PADDING_FLAG, null, encrypt, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(paddedMessage); ArrayPool <byte> .Shared.Return(rented); } } switch (padding.Mode) { case RSAEncryptionPaddingMode.Pkcs1: return(TryEncryptOrDecrypt(keyHandle, data, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt, out bytesWritten)); case RSAEncryptionPaddingMode.Oaep: IntPtr namePtr = Marshal.StringToHGlobalUni(padding.OaepHashAlgorithm.Name); try { var paddingInfo = new BCRYPT_OAEP_PADDING_INFO() { pszAlgId = namePtr, pbLabel = IntPtr.Zero, // It would nice to put randomized data here but RSAEncryptionPadding does not at this point provide support for this. cbLabel = 0, }; return(TryEncryptOrDecrypt(keyHandle, data, destination, AsymmetricPaddingMode.NCRYPT_PAD_OAEP_FLAG, &paddingInfo, encrypt, out bytesWritten)); } finally { Marshal.FreeHGlobal(namePtr); } default: throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode); } } }