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); }