public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } ThrowIfDisposed(); // The size of encrypt is always the keysize (in ceiling-bytes) int outputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] output = new byte[outputSize]; if (!TryEncrypt(data, output, padding, out int bytesWritten)) { Debug.Fail($"TryEncrypt with a preallocated buffer should not fail"); throw new CryptographicException(); } Debug.Assert(bytesWritten == outputSize); return(output); }
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } SecKeyPair keys = GetKeys(); if (keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (data.Length != modulusSizeInBytes) { throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } return(Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding)); }
public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (hash == null) { throw new ArgumentNullException(nameof(hash)); } if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1) { SecKeyPair keys = GetKeys(); if (keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } int expectedSize; Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out expectedSize); if (hash.Length != expectedSize) { // Windows: NTE_BAD_DATA ("Bad Data.") // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length") throw new CryptographicException( SR.Format( SR.Cryptography_BadHashSize_ForAlgorithm, hash.Length, expectedSize, hashAlgorithm.Name)); } return(Interop.AppleCrypto.GenerateSignature( keys.PrivateKey, hash, palAlgId)); } // A signature will always be the keysize (in ceiling-bytes) in length. int outputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] output = new byte[outputSize]; if (!TrySignHash(hash, output, hashAlgorithm, padding, out int bytesWritten)) { Debug.Fail("TrySignHash failed with a pre-allocated buffer"); throw new CryptographicException(); } Debug.Assert(bytesWritten == outputSize); return(output); }
public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1) { int algorithmNid = GetAlgorithmNid(hashAlgorithm); SafeRsaHandle rsa = _key.Value; return(Interop.Crypto.RsaVerify(algorithmNid, hash, hash.Length, signature, signature.Length, rsa)); } else if (padding == RSASignaturePadding.Pss) { RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); SafeRsaHandle rsa = _key.Value; int requiredBytes = Interop.Crypto.RsaSize(rsa); if (signature.Length != requiredBytes) { return(false); } if (hash.Length != processor.HashLength) { return(false); } byte[] rented = ArrayPool <byte> .Shared.Rent(requiredBytes); Span <byte> unwrapped = new Span <byte>(rented, 0, requiredBytes); try { int ret = Interop.Crypto.RsaVerificationPrimitive(signature, unwrapped, rsa); CheckReturn(ret); Debug.Assert( ret == requiredBytes, $"RSA_private_encrypt returned {ret} when {requiredBytes} was expected"); return(processor.VerifyPss(hash, unwrapped, KeySize)); } finally { unwrapped.Clear(); ArrayPool <byte> .Shared.Return(rented); } } throw PaddingModeNotSupported(); }
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 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); } }
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } SecKeyPair keys = GetKeys(); if (keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1) { int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (data.Length > modulusSizeInBytes) { throw new CryptographicException( SR.Format(SR.Cryptography_Padding_DecDataTooBig, modulusSizeInBytes)); } return(Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding)); } int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] rented = ArrayPool <byte> .Shared.Rent(maxOutputSize); Span <byte> contentsSpan = Span <byte> .Empty; try { if (!TryDecrypt(keys.PrivateKey, data, rented, padding, out int bytesWritten)) { Debug.Fail($"TryDecrypt returned false with a modulus-sized destination"); throw new CryptographicException(); } contentsSpan = new Span <byte>(rented, 0, bytesWritten); return(contentsSpan.ToArray()); } finally { CryptographicOperations.ZeroMemory(contentsSpan); ArrayPool <byte> .Shared.Return(rented); } }
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); }
private static Interop.AndroidCrypto.RsaPadding GetInteropPadding( RSAEncryptionPadding padding, out RsaPaddingProcessor?rsaPaddingProcessor) { if (padding == RSAEncryptionPadding.Pkcs1) { rsaPaddingProcessor = null; return(Interop.AndroidCrypto.RsaPadding.Pkcs1); } if (padding == RSAEncryptionPadding.OaepSHA1) { rsaPaddingProcessor = null; return(Interop.AndroidCrypto.RsaPadding.OaepSHA1); } if (padding.Mode == RSAEncryptionPaddingMode.Oaep) { rsaPaddingProcessor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); return(Interop.AndroidCrypto.RsaPadding.NoPadding); } throw PaddingModeNotSupported(); }
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.Cryptography_RSA_DecryptWrongSize); } return(Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten)); }
private bool TrySignHash( ReadOnlySpan <byte> hash, Span <byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, bool allocateSignature, out int bytesWritten, out byte[] signature) { Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); Debug.Assert(padding != null); signature = null; // Do not factor out getting _key.Value, since the key creation should not happen on // invalid padding modes. if (padding.Mode == RSASignaturePaddingMode.Pkcs1) { int algorithmNid = GetAlgorithmNid(hashAlgorithm); SafeRsaHandle rsa = _key.Value; int bytesRequired = Interop.Crypto.RsaSize(rsa); if (allocateSignature) { Debug.Assert(destination.Length == 0); signature = new byte[bytesRequired]; destination = signature; } if (destination.Length < bytesRequired) { bytesWritten = 0; return(false); } if (!Interop.Crypto.RsaSign(algorithmNid, hash, hash.Length, destination, out int signatureSize, rsa)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } Debug.Assert( signatureSize == bytesRequired, $"RSA_sign reported signatureSize was {signatureSize}, when {bytesRequired} was expected"); bytesWritten = signatureSize; return(true); } else if (padding.Mode == RSASignaturePaddingMode.Pss) { RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); SafeRsaHandle rsa = _key.Value; int bytesRequired = Interop.Crypto.RsaSize(rsa); if (allocateSignature) { Debug.Assert(destination.Length == 0); signature = new byte[bytesRequired]; destination = signature; } if (destination.Length < bytesRequired) { bytesWritten = 0; return(false); } byte[] pssRented = CryptoPool.Rent(bytesRequired); Span <byte> pssBytes = new Span <byte>(pssRented, 0, bytesRequired); processor.EncodePss(hash, pssBytes, KeySize); int ret = Interop.Crypto.RsaSignPrimitive(pssBytes, destination, rsa); CryptoPool.Return(pssRented, bytesRequired); CheckReturn(ret); Debug.Assert( ret == bytesRequired, $"RSA_private_encrypt returned {ret} when {bytesRequired} was expected"); bytesWritten = ret; return(true); } throw PaddingModeNotSupported(); }
public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); ArgumentNullException.ThrowIfNull(padding); ThrowIfDisposed(); if (padding == RSASignaturePadding.Pkcs1) { Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out _); return(Interop.AppleCrypto.VerifySignature( GetKeys().PublicKey, hash, signature, palAlgId, Interop.AppleCrypto.PAL_SignatureAlgorithm.RsaPkcs1)); } else if (padding.Mode == RSASignaturePaddingMode.Pss) { SafeSecKeyRefHandle publicKey = GetKeys().PublicKey; int keySize = KeySize; int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(keySize); if (signature.Length != rsaSize) { return(false); } if (hash.Length != RsaPaddingProcessor.HashLength(hashAlgorithm)) { return(false); } byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> unwrapped = new Span <byte>(rented, 0, rsaSize); try { if (!Interop.AppleCrypto.TryRsaVerificationPrimitive( publicKey, signature, unwrapped, out int bytesWritten)) { Debug.Fail($"TryRsaVerificationPrimitive with a pre-allocated buffer"); throw new CryptographicException(); } Debug.Assert(bytesWritten == rsaSize); return(RsaPaddingProcessor.VerifyPss(hashAlgorithm, hash, unwrapped, keySize)); } finally { CryptographicOperations.ZeroMemory(unwrapped); CryptoPool.Return(rented, clearSize: 0); } } throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); }
public override bool TrySignHash(ReadOnlySpan <byte> hash, Span <byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) { ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm)); ArgumentNullException.ThrowIfNull(padding); ThrowIfDisposed(); bool pssPadding = padding.Mode switch { RSASignaturePaddingMode.Pss => true, RSASignaturePaddingMode.Pkcs1 => false, _ => throw new CryptographicException(SR.Cryptography_InvalidPaddingMode) }; SecKeyPair keys = GetKeys(); if (keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } int keySize = KeySize; int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(keySize); if (!pssPadding) { Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize); if (hash.Length != expectedSize) { // Windows: NTE_BAD_DATA ("Bad Data.") // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length") throw new CryptographicException( SR.Format( SR.Cryptography_BadHashSize_ForAlgorithm, hash.Length, expectedSize, hashAlgorithm.Name)); } if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } return(Interop.AppleCrypto.TryCreateSignature( keys.PrivateKey, hash, destination, palAlgId, Interop.AppleCrypto.PAL_SignatureAlgorithm.RsaPkcs1, out bytesWritten)); } Debug.Assert(padding.Mode == RSASignaturePaddingMode.Pss); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> buf = new Span <byte>(rented, 0, rsaSize); RsaPaddingProcessor.EncodePss(hashAlgorithm, hash, buf, keySize); try { return(Interop.AppleCrypto.TryRsaSignaturePrimitive(keys.PrivateKey, buf, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(buf); CryptoPool.Return(rented, clearSize: 0); } }
// 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); } } }
public override bool TryEncrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { if (padding == null) { throw new ArgumentNullException(nameof(padding)); } int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } if (padding == RSAEncryptionPadding.Pkcs1 && data.Length > 0) { return(Interop.AppleCrypto.TryRsaEncrypt( GetKeys().PublicKey, data, destination, padding, out bytesWritten)); } RsaPaddingProcessor processor; switch (padding.Mode) { case RSAEncryptionPaddingMode.Pkcs1: processor = null; break; case RSAEncryptionPaddingMode.Oaep: processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); break; default: throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } byte[] rented = ArrayPool <byte> .Shared.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { if (processor != null) { processor.PadOaep(data, tmp); } else { Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Pkcs1); RsaPaddingProcessor.PadPkcs1Encryption(data, tmp); } return(Interop.AppleCrypto.TryRsaEncryptionPrimitive( GetKeys().PublicKey, tmp, destination, out bytesWritten)); } finally { tmp.Clear(); ArrayPool <byte> .Shared.Return(rented); } }
public override bool TrySignHash(ReadOnlySpan <byte> hash, Span <byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } RsaPaddingProcessor processor = null; if (padding.Mode == RSASignaturePaddingMode.Pss) { processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); } else if (padding != RSASignaturePadding.Pkcs1) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } SecKeyPair keys = GetKeys(); if (keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } int keySize = KeySize; int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(keySize); if (processor == null) { Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize); if (hash.Length != expectedSize) { // Windows: NTE_BAD_DATA ("Bad Data.") // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length") throw new CryptographicException( SR.Format( SR.Cryptography_BadHashSize_ForAlgorithm, hash.Length, expectedSize, hashAlgorithm.Name)); } if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } return(Interop.AppleCrypto.TryGenerateSignature( keys.PrivateKey, hash, destination, palAlgId, out bytesWritten)); } Debug.Assert(padding.Mode == RSASignaturePaddingMode.Pss); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } byte[] rented = ArrayPool <byte> .Shared.Rent(rsaSize); Span <byte> buf = new Span <byte>(rented, 0, rsaSize); processor.EncodePss(hash, buf, keySize); try { return(Interop.AppleCrypto.TryRsaSignaturePrimitive(keys.PrivateKey, buf, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(buf); ArrayPool <byte> .Shared.Return(rented); } }
// 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); } } }
public override bool TryEncrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { if (padding == null) { throw new ArgumentNullException(nameof(padding)); } ThrowIfDisposed(); int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } if (padding == RSAEncryptionPadding.Pkcs1 && data.Length > 0) { const int Pkcs1PaddingOverhead = 11; int maxAllowed = rsaSize - Pkcs1PaddingOverhead; if (data.Length > maxAllowed) { throw new CryptographicException( SR.Format(SR.Cryptography_Encryption_MessageTooLong, maxAllowed)); } return(Interop.AppleCrypto.TryRsaEncrypt( GetKeys().PublicKey, data, destination, padding, out bytesWritten)); } RsaPaddingProcessor?processor; switch (padding.Mode) { case RSAEncryptionPaddingMode.Pkcs1: processor = null; break; case RSAEncryptionPaddingMode.Oaep: processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); break; default: throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { if (processor != null) { processor.PadOaep(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); } }
public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1 && padding == RSASignaturePadding.Pss) { throw PaddingModeNotSupported(); } RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); SafeRsaHandle rsa = GetKey(); int requiredBytes = Interop.AndroidCrypto.RsaSize(rsa); if (signature.Length != requiredBytes) { return(false); } if (hash.Length != processor.HashLength) { return(false); } byte[] rented = CryptoPool.Rent(requiredBytes); Span <byte> unwrapped = new Span <byte>(rented, 0, requiredBytes); try { int ret = Interop.AndroidCrypto.RsaVerificationPrimitive(signature, unwrapped, rsa); CheckReturn(ret); if (ret == 0) { // Return value of 0 from RsaVerificationPrimitive indicates the signature could not be decrypted. return(false); } Debug.Assert( ret == requiredBytes, $"RsaVerificationPrimitive returned {ret} when {requiredBytes} was expected"); if (padding == RSASignaturePadding.Pkcs1) { byte[] repadRent = CryptoPool.Rent(unwrapped.Length); Span <byte> repadded = repadRent.AsSpan(0, requiredBytes); processor.PadPkcs1Signature(hash, repadded); bool valid = CryptographicOperations.FixedTimeEquals(repadded, unwrapped); CryptoPool.Return(repadRent, requiredBytes); return(valid); } else if (padding == RSASignaturePadding.Pss) { return(processor.VerifyPss(hash, unwrapped, KeySize)); } else { Debug.Fail("Padding mode should be checked prior to this point."); throw PaddingModeNotSupported(); } } finally { CryptoPool.Return(rented, requiredBytes); } throw PaddingModeNotSupported(); }
private bool TrySignHash( ReadOnlySpan <byte> hash, Span <byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, bool allocateSignature, out int bytesWritten, out byte[]?signature) { Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); Debug.Assert(padding != null); signature = null; if (padding == RSASignaturePadding.Pkcs1 && padding == RSASignaturePadding.Pss) { throw PaddingModeNotSupported(); } RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); SafeRsaHandle rsa = GetKey(); int bytesRequired = Interop.AndroidCrypto.RsaSize(rsa); if (allocateSignature) { Debug.Assert(destination.Length == 0); signature = new byte[bytesRequired]; destination = signature; } if (destination.Length < bytesRequired) { bytesWritten = 0; return(false); } byte[] encodedRented = CryptoPool.Rent(bytesRequired); Span <byte> encodedBytes = new Span <byte>(encodedRented, 0, bytesRequired); if (padding.Mode == RSASignaturePaddingMode.Pkcs1) { processor.PadPkcs1Signature(hash, encodedBytes); } else if (padding.Mode == RSASignaturePaddingMode.Pss) { processor.EncodePss(hash, encodedBytes, KeySize); } else { Debug.Fail("Padding mode should be checked prior to this point."); throw PaddingModeNotSupported(); } int ret = Interop.AndroidCrypto.RsaSignPrimitive(encodedBytes, destination, rsa); CryptoPool.Return(encodedRented, bytesRequired); CheckReturn(ret); Debug.Assert( ret == bytesRequired, $"RsaSignPrimitive returned {ret} when {bytesRequired} was expected"); bytesWritten = ret; return(true); }
public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1) { Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize); return(Interop.AppleCrypto.VerifySignature(GetKeys().PublicKey, hash, signature, palAlgId)); } else if (padding.Mode == RSASignaturePaddingMode.Pss) { RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); SafeSecKeyRefHandle publicKey = GetKeys().PublicKey; int keySize = KeySize; int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(keySize); if (signature.Length != rsaSize) { return(false); } if (hash.Length != processor.HashLength) { return(false); } byte[] rented = ArrayPool <byte> .Shared.Rent(rsaSize); Span <byte> unwrapped = new Span <byte>(rented, 0, rsaSize); try { if (!Interop.AppleCrypto.TryRsaVerificationPrimitive( publicKey, signature, unwrapped, out int bytesWritten)) { Debug.Fail($"TryRsaVerificationPrimitive with a pre-allocated buffer"); throw new CryptographicException(); } Debug.Assert(bytesWritten == rsaSize); return(processor.VerifyPss(hash, unwrapped, keySize)); } finally { unwrapped.Clear(); ArrayPool <byte> .Shared.Return(rented); } } throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); }
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); } } }