private static bool TryEncrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.AndroidCrypto.RsaPadding rsaPadding, RsaPaddingProcessor?rsaPaddingProcessor, out int bytesWritten) { int rsaSize = Interop.AndroidCrypto.RsaSize(key); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } int returnValue; if (rsaPaddingProcessor != 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(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 static bool TryDecrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.AndroidCrypto.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.AndroidCrypto.RsaPadding.NoPadding) == (rsaPaddingProcessor != null)); // Caller should have already checked this. Debug.Assert(!key.IsInvalid); int rsaSize = Interop.AndroidCrypto.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.AndroidCrypto.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); } } }
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(); 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.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); processor.EncodePss(hash, buf, keySize); try { return(Interop.AppleCrypto.TryRsaSignaturePrimitive(keys.PrivateKey, buf, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(buf); CryptoPool.Return(rented, clearSize: 0); } }