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);
                }
            }
Exemple #2
0
        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();
        }
Exemple #3
0
            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);
            }
Exemple #4
0
            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);
                }
            }