예제 #1
0
        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 (destination.Length < rsaSize)
            {
                bytesWritten = 0;
                return(false);
            }

            Span <byte> decryptBuf = destination;

            byte[] paddingBuf = null;

            if (rsaPaddingProcessor != null)
            {
                paddingBuf = ArrayPool <byte> .Shared.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);
                    ArrayPool <byte> .Shared.Return(paddingBuf);
                }
            }
        }
예제 #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 = ArrayPool <byte> .Shared.Rent(bytesRequired);

                Span <byte> pssBytes = new Span <byte>(pssRented, 0, bytesRequired);

                processor.EncodePss(hash, pssBytes, KeySize);

                int ret = Interop.Crypto.RsaSignPrimitive(pssBytes, destination, rsa);

                pssBytes.Clear();
                ArrayPool <byte> .Shared.Return(pssRented);

                CheckReturn(ret);

                Debug.Assert(
                    ret == bytesRequired,
                    $"RSA_private_encrypt returned {ret} when {bytesRequired} was expected");

                bytesWritten = ret;
                return(true);
            }

            throw PaddingModeNotSupported();
        }
예제 #3
0
 internal RSAAndroid(SafeRsaHandle key)
 {
     _key = new Lazy <SafeRsaHandle>(key.DuplicateHandle());
     SetKeySizeFromHandle(key);
 }
예제 #4
0
        public override bool TryDecrypt(
            ReadOnlySpan <byte> data,
            Span <byte> destination,
            RSAEncryptionPadding padding,
            out int bytesWritten)
        {
            if (padding == null)
            {
                throw new ArgumentNullException(nameof(padding));
            }

            Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor? oaepProcessor);
            SafeRsaHandle             key        = GetKey();

            int keySizeBytes = Interop.Crypto.RsaSize(key);

            // OpenSSL does not take a length value for the destination, so it can write out of bounds.
            // To prevent the OOB write, decrypt into a temporary buffer.
            if (destination.Length < keySizeBytes)
            {
                Span <byte> tmp = stackalloc byte[0];
                byte[]? rent = null;

                // RSA up through 4096 stackalloc
                if (keySizeBytes <= 512)
                {
                    tmp = stackalloc byte[keySizeBytes];
                }
                else
                {
                    rent = ArrayPool <byte> .Shared.Rent(keySizeBytes);

                    tmp = rent;
                }

                bool ret = TryDecrypt(key, data, tmp, rsaPadding, oaepProcessor, out bytesWritten);

                if (ret)
                {
                    tmp = tmp.Slice(0, bytesWritten);

                    if (bytesWritten > destination.Length)
                    {
                        ret          = false;
                        bytesWritten = 0;
                    }
                    else
                    {
                        tmp.CopyTo(destination);
                    }

                    CryptographicOperations.ZeroMemory(tmp);
                }

                if (rent != null)
                {
                    // Already cleared
                    ArrayPool <byte> .Shared.Return(rent);
                }

                return(ret);
            }

            return(TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten));
        }
예제 #5
0
            public override void ImportParameters(RSAParameters parameters)
            {
                ValidateParameters(ref parameters);
                ThrowIfDisposed();

                if (parameters.Exponent == null || parameters.Modulus == null)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                }

                // Check that either all parameters are not null or all are null, if a subset were set, then the parameters are invalid.
                // If the parameters are all not null, verify the integrity of their lengths.
                if (parameters.D == null)
                {
                    if (parameters.P != null ||
                        parameters.DP != null ||
                        parameters.Q != null ||
                        parameters.DQ != null ||
                        parameters.InverseQ != null)
                    {
                        throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                    }
                }
                else
                {
                    if (parameters.P == null ||
                        parameters.DP == null ||
                        parameters.Q == null ||
                        parameters.DQ == null ||
                        parameters.InverseQ == null)
                    {
                        throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                    }

                    // Half, rounded up.
                    int halfModulusLength = (parameters.Modulus.Length + 1) / 2;

                    // Matching the .NET Framework RSACryptoServiceProvider behavior, as that's the .NET de facto standard
                    if (parameters.D.Length != parameters.Modulus.Length ||
                        parameters.P.Length != halfModulusLength ||
                        parameters.Q.Length != halfModulusLength ||
                        parameters.DP.Length != halfModulusLength ||
                        parameters.DQ.Length != halfModulusLength ||
                        parameters.InverseQ.Length != halfModulusLength)
                    {
                        throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                    }
                }

                SafeRsaHandle key      = Interop.AndroidCrypto.RsaCreate();
                bool          imported = false;

                if (key is null || key.IsInvalid)
                {
                    throw new CryptographicException();
                }

                try
                {
                    if (!Interop.AndroidCrypto.SetRsaParameters(
                            key,
                            parameters.Modulus,
                            parameters.Modulus != null ? parameters.Modulus.Length : 0,
                            parameters.Exponent,
                            parameters.Exponent != null ? parameters.Exponent.Length : 0,
                            parameters.D,
                            parameters.D != null ? parameters.D.Length : 0,
                            parameters.P,
                            parameters.P != null ? parameters.P.Length : 0,
                            parameters.DP,
                            parameters.DP != null ? parameters.DP.Length : 0,
                            parameters.Q,
                            parameters.Q != null ? parameters.Q.Length : 0,
                            parameters.DQ,
                            parameters.DQ != null ? parameters.DQ.Length : 0,
                            parameters.InverseQ,
                            parameters.InverseQ != null ? parameters.InverseQ.Length : 0))
                    {
                        throw new CryptographicException();
                    }

                    imported = true;
                }
                finally
                {
                    if (!imported)
                    {
                        key.Dispose();
                    }
                }

                FreeKey();
                _key = new Lazy <SafeRsaHandle>(key);
                SetKeySizeFromHandle(key);
            }
예제 #6
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();
            }
예제 #7
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);
            }