Exemple #1
0
        private bool TryExportPublicKey(
            Func <ReadOnlyMemory <byte>, ReadOnlyMemory <byte> >?transform,
            Span <byte> destination,
            out int bytesWritten)
        {
            // It's entirely possible that this line will cause the key to be generated in the first place.
            SafeEvpPKeyHandle key = GetKey();

            ArraySegment <byte> spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key);

            try
            {
                ReadOnlyMemory <byte> data = spki;

                if (transform != null)
                {
                    data = transform(data);
                }

                return(data.Span.TryCopyToDestination(destination, out bytesWritten));
            }
            finally
            {
                CryptoPool.Return(spki);
            }
        }
Exemple #2
0
        public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            if (padding == null)
            {
                throw new ArgumentNullException(nameof(padding));
            }

            ValidatePadding(padding);
            SafeEvpPKeyHandle key   = GetKey();
            int         rsaSize     = Interop.Crypto.EvpPKeySize(key);
            Span <byte> destination = default;

            byte[] buf = CryptoPool.Rent(rsaSize);

            try
            {
                destination = new Span <byte>(buf, 0, rsaSize);

                int bytesWritten = Decrypt(key, data, destination, padding);
                return(destination.Slice(0, bytesWritten).ToArray());
            }
            finally
            {
                CryptographicOperations.ZeroMemory(destination);
                CryptoPool.Return(buf, clearSize: 0);
            }
        }
        private static unsafe byte[] ExportArray <T>(
            ReadOnlySpan <T> password,
            PbeParameters pbeParameters,
            TryExportPbe <T> exporter)
        {
            int bufSize = 4096;

            while (true)
            {
                byte[] buf          = CryptoPool.Rent(bufSize);
                int    bytesWritten = 0;
                bufSize = buf.Length;

                fixed(byte *bufPtr = buf)
                {
                    try
                    {
                        if (exporter(password, pbeParameters, buf, out bytesWritten))
                        {
                            Span <byte> writtenSpan = new Span <byte>(buf, 0, bytesWritten);
                            return(writtenSpan.ToArray());
                        }
                    }
                    finally
                    {
                        CryptoPool.Return(buf, bytesWritten);
                    }

                    bufSize = checked (bufSize * 2);
                }
            }
        }
        private static unsafe byte[] ExportArray(TryExport exporter)
        {
            int bufSize = 4096;

            while (true)
            {
                byte[] buf          = CryptoPool.Rent(bufSize);
                int    bytesWritten = 0;
                bufSize = buf.Length;

                fixed(byte *bufPtr = buf)
                {
                    try
                    {
                        if (exporter(buf, out bytesWritten))
                        {
                            Span <byte> writtenSpan = new Span <byte>(buf, 0, bytesWritten);
                            return(writtenSpan.ToArray());
                        }
                    }
                    finally
                    {
                        CryptoPool.Return(buf, bytesWritten);
                    }

                    bufSize = checked (bufSize * 2);
                }
            }
        }
Exemple #5
0
            public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
            {
                ArgumentNullException.ThrowIfNull(data);
                ArgumentNullException.ThrowIfNull(padding);

                Interop.AndroidCrypto.RsaPadding rsaPadding = GetInteropPadding(padding);
                SafeRsaHandle key = GetKey();

                int         rsaSize     = Interop.AndroidCrypto.RsaSize(key);
                Span <byte> destination = default;

                byte[] buf = CryptoPool.Rent(rsaSize);

                try
                {
                    destination = new Span <byte>(buf, 0, rsaSize);

                    if (!TryDecrypt(key, data, destination, rsaPadding, out int bytesWritten))
                    {
                        Debug.Fail($"{nameof(TryDecrypt)} should not return false for RSA_size buffer");
                        throw new CryptographicException();
                    }

                    return(destination.Slice(0, bytesWritten).ToArray());
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(destination);
                    CryptoPool.Return(buf, clearSize: 0);
                }
            }
            private static SafeSecKeyRefHandle ImportLegacyPrivateKey(RSAParameters parameters)
            {
                Debug.Assert(parameters.D != null);

                AsnWriter keyWriter = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters);

                byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength());

                if (!keyWriter.TryEncode(rented, out int written))
                {
                    Debug.Fail("TryEncode failed with a pre-allocated buffer");
                    throw new InvalidOperationException();
                }

                // Explicitly clear the inner buffer
                keyWriter.Reset();

                try
                {
                    return(Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), true));
                }
                finally
                {
                    CryptoPool.Return(rented, written);
                }
            }
        private static AsnWriter RewriteEncryptedPkcs8PrivateKey(
            AsymmetricAlgorithm key,
            ReadOnlySpan <char> password,
            PbeParameters pbeParameters)
        {
            Debug.Assert(pbeParameters != null);

            byte[] rented      = CryptoPool.Rent(key.KeySize);
            int    rentWritten = 0;

            try
            {
                while (!key.TryExportEncryptedPkcs8PrivateKey(
                           password,
                           s_platformParameters,
                           rented,
                           out rentWritten))
                {
                    int    size    = rented.Length;
                    byte[] current = rented;
                    rented = CryptoPool.Rent(checked (size * 2));
                    CryptoPool.Return(current, rentWritten);
                }

                return(KeyFormatHelper.ReencryptPkcs8(
                           password,
                           rented.AsMemory(0, rentWritten),
                           password,
                           pbeParameters));
            }
            finally
            {
                CryptoPool.Return(rented, rentWritten);
            }
        }
Exemple #8
0
        public unsafe int Transform(ReadOnlySpan <byte> input, Span <byte> output)
        {
#if DEBUG
            if (_isFinalized)
            {
                Debug.Fail("Cipher was reused without being reset.");
                throw new CryptographicException();
            }
#endif

            // OpenSSL 1.1 does not allow partial overlap.
            if (input.Overlaps(output, out int overlapOffset) && overlapOffset != 0)
            {
                byte[]      tmp     = CryptoPool.Rent(input.Length);
                Span <byte> tmpSpan = tmp;
                int         written = 0;

                try
                {
                    written = CipherUpdate(input, tmpSpan);
                    tmpSpan.Slice(0, written).CopyTo(output);
                    return(written);
                }
                finally
                {
                    CryptoPool.Return(tmp, written);
                }
            }

            return(CipherUpdate(input, output));
        }
Exemple #9
0
        public override byte[] CreateSignature(byte[] rgbHash)
        {
            if (rgbHash == null)
            {
                throw new ArgumentNullException(nameof(rgbHash));
            }

            SafeDsaHandle key           = GetKey();
            int           signatureSize = Interop.Crypto.DsaEncodedSignatureSize(key);

            byte[] signature = CryptoPool.Rent(signatureSize);
            try
            {
                bool success = Interop.Crypto.DsaSign(key, rgbHash, new Span <byte>(signature, 0, signatureSize), out signatureSize);
                if (!success)
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }

                Debug.Assert(
                    signatureSize <= signature.Length,
                    "DSA_sign reported an unexpected signature size",
                    "DSA_sign reported signatureSize was {0}, when <= {1} was expected",
                    signatureSize,
                    signature.Length);

                int signatureFieldSize = Interop.Crypto.DsaSignatureFieldSize(key) * BitsPerByte;
                return(AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureSize, signatureFieldSize));
            }
            finally
            {
                CryptoPool.Return(signature, signatureSize);
            }
        }
        protected override unsafe byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
            if (SymmetricPadding.DepaddingRequired(PaddingMode))
            {
                byte[] rented  = CryptoPool.Rent(inputCount + InputBlockSize);
                int    written = 0;

                fixed(byte *pRented = rented)
                {
                    try
                    {
                        written = UncheckedTransformFinalBlock(inputBuffer.AsSpan(inputOffset, inputCount), rented);
                        return(rented.AsSpan(0, written).ToArray());
                    }
                    finally
                    {
                        CryptoPool.Return(rented, clearSize: written);
                    }
                }
            }
            else
            {
                byte[] buffer  = GC.AllocateUninitializedArray <byte>(inputCount);
                int    written = UncheckedTransformFinalBlock(inputBuffer.AsSpan(inputOffset, inputCount), buffer);
                Debug.Assert(written == buffer.Length);
                return(buffer);
            }
        }
        private unsafe AsnWriter WritePkcs8PrivateKey()
        {
            // A PKCS1 RSAPrivateKey is the Modulus (KeySize bits), D (~KeySize bits)
            // P, Q, DP, DQ, InverseQ (all ~KeySize/2 bits)
            // Each field can have up to 7 bytes of overhead, and then another 9 bytes
            // of fixed overhead.
            // So it should fit in 5 * KeySizeInBytes, but Exponent is a wildcard.

            int rentSize = checked (5 * KeySize / 8);

            while (true)
            {
                byte[] rented = CryptoPool.Rent(rentSize);
                rentSize = rented.Length;
                int pkcs1Size = 0;

                fixed(byte *rentPtr = rented)
                {
                    try
                    {
                        if (!TryExportRSAPrivateKey(rented, out pkcs1Size))
                        {
                            rentSize = checked (rentSize * 2);
                            continue;
                        }

                        return(RSAKeyFormatHelper.WritePkcs8PrivateKey(new ReadOnlySpan <byte>(rented, 0, pkcs1Size)));
                    }
                    finally
                    {
                        CryptoPool.Return(rented, pkcs1Size);
                    }
                }
            }
        }
Exemple #12
0
        public override bool TrySignHash(ReadOnlySpan <byte> hash, Span <byte> destination, out int bytesWritten)
        {
            ThrowIfDisposed();
            SafeEcKeyHandle key = _key.Value;

            byte[] converted;
            int    signatureLength = Interop.Crypto.EcDsaSize(key);

            byte[] signature = CryptoPool.Rent(signatureLength);
            try
            {
                if (!Interop.Crypto.EcDsaSign(hash, new Span <byte>(signature, 0, signatureLength), ref signatureLength, key))
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }

                converted = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureLength, KeySize);
            }
            finally
            {
                CryptoPool.Return(signature, signatureLength);
            }

            if (converted.Length <= destination.Length)
            {
                new ReadOnlySpan <byte>(converted).CopyTo(destination);
                bytesWritten = converted.Length;
                return(true);
            }
            else
            {
                bytesWritten = 0;
                return(false);
            }
        }
        public override unsafe bool TryExportSubjectPublicKeyInfo(Span <byte> destination, out int bytesWritten)
        {
            // The PKCS1 RSAPublicKey format is just the modulus (KeySize bits) and Exponent (usually 3 bytes),
            // with each field having up to 7 bytes of overhead and then up to 6 extra bytes of overhead for the
            // SEQUENCE tag.
            //
            // So KeySize / 4 is ideally enough to start.
            int rentSize = KeySize / 4;

            while (true)
            {
                byte[] rented = CryptoPool.Rent(rentSize);
                rentSize = rented.Length;
                int pkcs1Size = 0;

                fixed(byte *rentPtr = rented)
                {
                    try
                    {
                        if (!TryExportRSAPublicKey(rented, out pkcs1Size))
                        {
                            rentSize = checked (rentSize * 2);
                            continue;
                        }

                        AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(rented.AsSpan(0, pkcs1Size));
                        return(writer.TryEncode(destination, out bytesWritten));
                    }
                    finally
                    {
                        CryptoPool.Return(rented, pkcs1Size);
                    }
                }
            }
        }
        public virtual bool VerifyData(ReadOnlySpan <byte> data, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
        {
            if (string.IsNullOrEmpty(hashAlgorithm.Name))
            {
                throw HashAlgorithmNameNullOrEmpty();
            }
            if (padding == null)
            {
                throw new ArgumentNullException(nameof(padding));
            }

            for (int i = 256; ; i = checked (i * 2))
            {
                int    hashLength = 0;
                byte[] hash       = CryptoPool.Rent(i);
                try
                {
                    if (TryHashData(data, hash, hashAlgorithm, out hashLength))
                    {
                        return(VerifyHash(new ReadOnlySpan <byte>(hash, 0, hashLength), signature, hashAlgorithm, padding));
                    }
                }
                finally
                {
                    CryptoPool.Return(hash, hashLength);
                }
            }
        }
Exemple #15
0
 private void ReturnToCryptoPool(byte[] array, int clearSize)
 {
     if (array != null)
     {
         CryptoPool.Return(array, clearSize);
     }
 }
Exemple #16
0
        public override bool TryDecrypt(
            ReadOnlySpan <byte> data,
            Span <byte> destination,
            RSAEncryptionPadding padding,
            out int bytesWritten)
        {
            ArgumentNullException.ThrowIfNull(padding);

            ValidatePadding(padding);
            SafeEvpPKeyHandle key = GetKey();
            int keySizeBytes      = Interop.Crypto.EvpPKeySize(key);

            // OpenSSL requires that the decryption buffer be at least as large as EVP_PKEY_size.
            // So if the destination is too small, use a temporary buffer so we can match
            // Windows behavior of succeeding so long as the buffer can hold the final output.
            if (destination.Length < keySizeBytes)
            {
                // RSA up through 4096 bits use a stackalloc
                Span <byte> tmp = stackalloc byte[512];
                byte[]? rent = null;

                if (keySizeBytes > tmp.Length)
                {
                    rent = CryptoPool.Rent(keySizeBytes);
                    tmp  = rent;
                }

                int  written = Decrypt(key, data, tmp, padding);
                bool ret;

                if (destination.Length < written)
                {
                    bytesWritten = 0;
                    ret          = false;
                }
                else
                {
                    tmp.Slice(0, written).CopyTo(destination);
                    bytesWritten = written;
                    ret          = true;
                }

                // Whether a stackalloc or a rented array, clear our copy of
                // the decrypted content.
                CryptographicOperations.ZeroMemory(tmp.Slice(0, written));

                if (rent != null)
                {
                    // Already cleared.
                    CryptoPool.Return(rent, clearSize: 0);
                }

                return(ret);
            }

            bytesWritten = Decrypt(key, data, destination, padding);
            return(true);
        }
Exemple #17
0
        private static AsnWriter RewriteEncryptedPkcs8PrivateKey(
            AsymmetricAlgorithm key,
            ReadOnlySpan <byte> passwordBytes,
            PbeParameters pbeParameters)
        {
            Debug.Assert(pbeParameters != null);

            // For RSA:
            //  * 512-bit key needs ~400 bytes
            //  * 16384-bit key needs ~10k bytes.
            //  * KeySize (bits) should avoid re-rent.
            //
            // For DSA:
            //  * 512-bit key needs ~300 bytes.
            //  * 1024-bit key needs ~400 bytes.
            //  * 2048-bit key needs ~700 bytes.
            //  * KeySize (bits) should avoid re-rent.
            //
            // For ECC:
            //  * secp256r1 needs ~200 bytes (named) or ~450 (explicit)
            //  * secp384r1 needs ~250 bytes (named) or ~600 (explicit)
            //  * secp521r1 needs ~300 bytes (named) or ~730 (explicit)
            //  * KeySize (bits) should avoid re-rent for named, and probably
            //    gets one re-rent for explicit.
            byte[] rented      = CryptoPool.Rent(key.KeySize);
            int    rentWritten = 0;

            // If we use 6 bits from each byte, that's 22 * 6 = 132
            Span <char> randomString = stackalloc char[22];

            try
            {
                FillRandomAsciiString(randomString);

                while (!key.TryExportEncryptedPkcs8PrivateKey(
                           randomString,
                           s_platformParameters,
                           rented,
                           out rentWritten))
                {
                    int    size    = rented.Length;
                    byte[] current = rented;
                    rented = CryptoPool.Rent(checked (size * 2));
                    CryptoPool.Return(current, rentWritten);
                }

                return(KeyFormatHelper.ReencryptPkcs8(
                           randomString,
                           rented.AsMemory(0, rentWritten),
                           passwordBytes,
                           pbeParameters));
            }
            finally
            {
                randomString.Clear();
                CryptoPool.Return(rented, rentWritten);
            }
        }
Exemple #18
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)
            {
                int           algorithmNid = GetAlgorithmNid(hashAlgorithm);
                SafeRsaHandle rsa          = _key.Value;
                return(Interop.Crypto.RsaVerify(algorithmNid, hash, signature, 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    = CryptoPool.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
                {
                    CryptoPool.Return(rented, requiredBytes);
                }
            }

            throw PaddingModeNotSupported();
        }
            private static SafeSecKeyRefHandle ImportKey(DSAParameters parameters)
            {
                AsnWriter keyWriter;
                bool      hasPrivateKey;

                if (parameters.X != null)
                {
                    // DSAPrivateKey ::= SEQUENCE(
                    //   version INTEGER,
                    //   p INTEGER,
                    //   q INTEGER,
                    //   g INTEGER,
                    //   y INTEGER,
                    //   x INTEGER,
                    // )

                    keyWriter = new AsnWriter(AsnEncodingRules.DER);

                    using (keyWriter.PushSequence())
                    {
                        keyWriter.WriteInteger(0);
                        keyWriter.WriteKeyParameterInteger(parameters.P);
                        keyWriter.WriteKeyParameterInteger(parameters.Q);
                        keyWriter.WriteKeyParameterInteger(parameters.G);
                        keyWriter.WriteKeyParameterInteger(parameters.Y);
                        keyWriter.WriteKeyParameterInteger(parameters.X);
                    }

                    hasPrivateKey = true;
                }
                else
                {
                    keyWriter     = DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters);
                    hasPrivateKey = false;
                }

                byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength());

                if (!keyWriter.TryEncode(rented, out int written))
                {
                    Debug.Fail("TryEncode failed with a pre-allocated buffer");
                    throw new InvalidOperationException();
                }

                // Explicitly clear the inner buffer
                keyWriter.Reset();

                try
                {
                    return(Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), hasPrivateKey));
                }
                finally
                {
                    CryptoPool.Return(rented, written);
                }
            }
            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));
            }
Exemple #21
0
        internal static unsafe Pkcs8Response ImportEncryptedPkcs8PrivateKey(
            ReadOnlySpan <byte> passwordBytes,
            ReadOnlySpan <byte> source,
            out int bytesRead)
        {
            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    try
                    {
                        // Since there's no bytes-based-password PKCS8 import in CNG, just do the decryption
                        // here and call the unencrypted PKCS8 import.
                        ArraySegment <byte> decrypted = KeyFormatHelper.DecryptPkcs8(
                            passwordBytes,
                            manager.Memory,
                            out bytesRead);

                        Span <byte> decryptedSpan = decrypted;

                        try
                        {
                            return(ImportPkcs8(decryptedSpan));
                        }
                        catch (CryptographicException e)
                        {
                            AsnWriter?pkcs8ZeroPublicKey = RewritePkcs8ECPrivateKeyWithZeroPublicKey(decryptedSpan);

                            if (pkcs8ZeroPublicKey == null)
                            {
                                throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e);
                            }

                            try
                            {
                                return(ImportPkcs8(pkcs8ZeroPublicKey));
                            }
                            catch (CryptographicException)
                            {
                                throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e);
                            }
                        }
                        finally
                        {
                            CryptoPool.Return(decrypted);
                        }
                    }
                    catch (AsnContentException e)
                    {
                        throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e);
                    }
                }
            }
        }
        public int TransformFinal(ReadOnlySpan <byte> input, Span <byte> output)
        {
#if DEBUG
            if (_isFinalized)
            {
                Debug.Fail("Cipher was reused without being reset.");
                throw new CryptographicException();
            }

            _isFinalized = true;
#endif

            // We just use CCCryptorUpdate instead of CCCryptorFinal. From the
            // Apple documentation:

            // In the following cases, the CCCryptorFinal() is superfluous as
            // it will not yield any data nor return an error:
            //     1. Encrypting or decrypting with a block cipher with padding
            //        disabled, when the total amount of data provided to
            //        CCCryptorUpdate() is an integral multiple of the block size.
            //     2. Encrypting or decrypting with a stream cipher.

            // For case 1, we do all of our padding manually and the cipher is opened with
            // PAL_PaddingMode.None. So that condition is met. For the second part, we always
            // submit data as a multiple of the block size, and is asserted below. So this condition
            // is met.

            Debug.Assert((input.Length % PaddingSizeInBytes) == 0);
            Debug.Assert(input.Length <= output.Length);

            int written = 0;

            if (input.Overlaps(output, out int offset) && offset != 0)
            {
                byte[] rented = CryptoPool.Rent(output.Length);

                try
                {
                    written = CipherUpdate(input, rented);
                    rented.AsSpan(0, written).CopyTo(output);
                }
                finally
                {
                    CryptoPool.Return(rented, clearSize: written);
                }
            }
            else
            {
                written = CipherUpdate(input, output);
            }

            return(written);
        }
Exemple #23
0
            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);
                }

                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       = CryptoPool.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);
                    CryptoPool.Return(rented, clearSize: 0);
                }
            }
Exemple #24
0
        internal static unsafe Pkcs8Response ImportEncryptedPkcs8PrivateKey(
            ReadOnlySpan <char> password,
            ReadOnlySpan <byte> source,
            out int bytesRead)
        {
            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER);
                    int       len    = reader.ReadEncodedValue().Length;
                    source = source.Slice(0, len);

                    try
                    {
                        bytesRead = len;
                        return(ImportPkcs8(source, password));
                    }
                    catch (CryptographicException)
                    {
                    }

                    ArraySegment <byte> decrypted = KeyFormatHelper.DecryptPkcs8(
                        password,
                        manager.Memory.Slice(0, len),
                        out int innerRead);

                    Span <byte> decryptedSpan = decrypted;

                    try
                    {
                        if (innerRead != len)
                        {
                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                        }

                        bytesRead = len;
                        return(ImportPkcs8(decryptedSpan));
                    }
                    catch (CryptographicException e)
                    {
                        throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e);
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(decryptedSpan);
                        CryptoPool.Return(decrypted.Array, clearSize: 0);
                    }
                }
            }
        }
Exemple #25
0
            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);
                }

                if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1)
                {
                    return(Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding));
                }

                int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);

                byte[] rented       = CryptoPool.Rent(maxOutputSize);
                int    bytesWritten = 0;

                try
                {
                    if (!TryDecrypt(keys.PrivateKey, data, rented, padding, out bytesWritten))
                    {
                        Debug.Fail($"TryDecrypt returned false with a modulus-sized destination");
                        throw new CryptographicException();
                    }

                    Span <byte> contentsSpan = new Span <byte>(rented, 0, bytesWritten);
                    return(contentsSpan.ToArray());
                }
                finally
                {
                    CryptoPool.Return(rented, bytesWritten);
                }
            }
Exemple #26
0
        private static Pkcs8Response ImportPkcs8(AsnWriter pkcs8Writer)
        {
            byte[] tmp = CryptoPool.Rent(pkcs8Writer.GetEncodedLength());

            if (!pkcs8Writer.TryEncode(tmp, out int written))
            {
                Debug.Fail("TryEncode failed with a pre-allocated buffer");
                throw new CryptographicException();
            }

            Pkcs8Response ret = ImportPkcs8(tmp.AsSpan(0, written));

            CryptoPool.Return(tmp, written);
            return(ret);
        }
Exemple #27
0
            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);
            }
Exemple #28
0
        private T ExportPublicKey <T>(Func <ReadOnlyMemory <byte>, T> exporter)
        {
            // It's entirely possible that this line will cause the key to be generated in the first place.
            SafeEvpPKeyHandle key = GetKey();

            ArraySegment <byte> spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key);

            try
            {
                return(exporter(spki));
            }
            finally
            {
                CryptoPool.Return(spki);
            }
        }
Exemple #29
0
        private T ExportPrivateKey <T>(ExportPrivateKeyFunc <T> exporter)
        {
            // It's entirely possible that this line will cause the key to be generated in the first place.
            SafeEvpPKeyHandle key = GetKey();

            ArraySegment <byte> p8 = Interop.Crypto.RentEncodePkcs8PrivateKey(key);

            try
            {
                ReadOnlyMemory <byte> pkcs1 = VerifyPkcs8(p8);
                return(exporter(p8, pkcs1));
            }
            finally
            {
                CryptoPool.Return(p8);
            }
        }
Exemple #30
0
        public int Transform(ReadOnlySpan <byte> input, Span <byte> output)
        {
            Debug.Assert(input.Length > 0);
            Debug.Assert((input.Length % PaddingSizeInBytes) == 0);

            int numBytesWritten = 0;

            // BCryptEncrypt and BCryptDecrypt can do in place encryption, but if the buffers overlap
            // the offset must be zero. In that case, we need to copy to a temporary location.
            if (input.Overlaps(output, out int offset) && offset != 0)
            {
                byte[] rented = CryptoPool.Rent(output.Length);

                try
                {
                    numBytesWritten = BCryptTransform(input, rented);
                    rented.AsSpan(0, numBytesWritten).CopyTo(output);
                }
                finally
                {
                    CryptoPool.Return(rented, clearSize: numBytesWritten);
                }
            }
            else
            {
                numBytesWritten = BCryptTransform(input, output);
            }

            if (numBytesWritten != input.Length)
            {
                // CNG gives us no way to tell BCryptDecrypt() that we're decrypting the final block, nor is it performing any
                // padding /depadding for us. So there's no excuse for a provider to hold back output for "future calls." Though
                // this isn't technically our problem to detect, we might as well detect it now for easier diagnosis.
                throw new CryptographicException(SR.Cryptography_UnexpectedTransformTruncation);
            }

            return(numBytesWritten);

            int BCryptTransform(ReadOnlySpan <byte> input, Span <byte> output)
            {
                return(_encrypting ?
                       Interop.BCrypt.BCryptEncrypt(_hKey, input, _currentIv, output) :
                       Interop.BCrypt.BCryptDecrypt(_hKey, input, _currentIv, output));
            }
        }