Пример #1
0
        protected virtual void Dispose(bool disposing)
        {
            // we always want to clear the input buffer
            if (disposing)
            {
                if (_inputBuffer != null)
                {
                    CryptographicOperations.ZeroMemory(_inputBuffer);
                    _inputBuffer = null;
                }

                Reset();
            }
        }
Пример #2
0
        private static bool TryEncrypt(
            SafeRsaHandle key,
            ReadOnlySpan <byte> data,
            Span <byte> destination,
            Interop.Crypto.RsaPadding rsaPadding,
            RsaPaddingProcessor rsaPaddingProcessor,
            out int bytesWritten)
        {
            int rsaSize = Interop.Crypto.RsaSize(key);

            if (destination.Length < rsaSize)
            {
                bytesWritten = 0;
                return(false);
            }

            int returnValue;

            if (rsaPaddingProcessor != null)
            {
                Debug.Assert(rsaPadding == Interop.Crypto.RsaPadding.NoPadding);
                byte[] rented = ArrayPool <byte> .Shared.Rent(rsaSize);

                Span <byte> tmp = new Span <byte>(rented, 0, rsaSize);

                try
                {
                    rsaPaddingProcessor.PadOaep(data, tmp);
                    returnValue = Interop.Crypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding);
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(tmp);
                    ArrayPool <byte> .Shared.Return(rented);
                }
            }
            else
            {
                Debug.Assert(rsaPadding != Interop.Crypto.RsaPadding.NoPadding);

                returnValue = Interop.Crypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding);
            }

            CheckReturn(returnValue);

            bytesWritten = returnValue;
            Debug.Assert(returnValue == rsaSize);
            return(true);
        }
Пример #3
0
        private void DecryptCore(
            ReadOnlySpan <byte> nonce,
            ReadOnlySpan <byte> ciphertext,
            ReadOnlySpan <byte> tag,
            Span <byte> plaintext,
            ReadOnlySpan <byte> associatedData)
        {
            Interop.Crypto.EvpCipherSetKeyAndIV(
                _ctxHandle,
                ReadOnlySpan <byte> .Empty,
                nonce,
                Interop.Crypto.EvpCipherDirection.Decrypt);

            if (!associatedData.IsEmpty)
            {
                Interop.Crypto.CipherUpdateAAD(_ctxHandle, associatedData);
            }

            if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext, out int plaintextBytesWritten, ciphertext))
            {
                CryptographicOperations.ZeroMemory(plaintext);
                throw new CryptographicException();
            }

            if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext.Slice(plaintextBytesWritten), out int bytesWritten, tag))
            {
                CryptographicOperations.ZeroMemory(plaintext);
                throw new CryptographicException();
            }

            plaintextBytesWritten += bytesWritten;

            if (!Interop.Crypto.EvpCipherFinalEx(
                    _ctxHandle,
                    plaintext.Slice(plaintextBytesWritten),
                    out bytesWritten))
            {
                CryptographicOperations.ZeroMemory(plaintext);
                throw new CryptographicException(SR.Cryptography_AuthTagMismatch);
            }

            plaintextBytesWritten += bytesWritten;

            if (plaintextBytesWritten != plaintext.Length)
            {
                Debug.Fail($"ChaCha20Poly1305 decrypt wrote {plaintextBytesWritten} of {plaintext.Length} bytes.");
                throw new CryptographicException();
            }
        }
Пример #4
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))
                {
                    // 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.EncodeAsSpan()));
                        }
                        catch (CryptographicException)
                        {
                            throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e);
                        }
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(decryptedSpan);
                        CryptoPool.Return(decrypted.Array !);
                    }
                }
            }
        }
Пример #5
0
            private static bool TryEncrypt(
                SafeRsaHandle key,
                ReadOnlySpan <byte> data,
                Span <byte> destination,
                Interop.AndroidCrypto.RsaPadding rsaPadding,
                HashAlgorithmName?oaepHashAlgorithmName,
                out int bytesWritten)
            {
                int rsaSize = Interop.AndroidCrypto.RsaSize(key);

                if (destination.Length < rsaSize)
                {
                    bytesWritten = 0;
                    return(false);
                }

                int returnValue;

                if (oaepHashAlgorithmName != 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(oaepHashAlgorithmName.Value, 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);
            }
Пример #6
0
        internal static void Return(byte[] array, int clearSize = ClearAll)
        {
            Debug.Assert(clearSize <= array.Length);
            bool clearWholeArray = clearSize < 0;

            if (!clearWholeArray && clearSize != 0)
            {
#if NETCOREAPP || NETSTANDARD2_1
                CryptographicOperations.ZeroMemory(array.AsSpan(0, clearSize));
#else
                Array.Clear(array, 0, clearSize);
#endif
            }

            ArrayPool <byte> .Shared.Return(array, clearWholeArray);
        }
Пример #7
0
        private unsafe AsnWriter WritePkcs8()
        {
            DSAParameters dsaParameters = ExportParameters(true);

            fixed(byte *privPin = dsaParameters.X)
            {
                try
                {
                    return(DSAKeyFormatHelper.WritePkcs8(dsaParameters));
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(dsaParameters.X);
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Exports the current key in the PKCS#1 RSAPrivateKey format, PEM encoded.
        /// </summary>
        /// <returns>A string containing the PEM-encoded PKCS#1 RSAPrivateKey.</returns>
        /// <exception cref="CryptographicException">
        /// The key could not be exported.
        /// </exception>
        /// <remarks>
        /// <p>
        ///   A PEM-encoded PKCS#1 RSAPrivateKey will begin with <c>-----BEGIN RSA PRIVATE KEY-----</c>
        ///   and end with <c>-----END RSA PRIVATE KEY-----</c>, with the base64 encoded DER
        ///   contents of the key between the PEM boundaries.
        /// </p>
        /// <p>
        ///   The PEM is encoded according to the IETF RFC 7468 &quot;strict&quot;
        ///   encoding rules.
        /// </p>
        /// </remarks>
        public unsafe string ExportRSAPrivateKeyPem()
        {
            byte[] exported = ExportRSAPrivateKey();

            // Fixed to prevent GC moves.
            fixed(byte *pExported = exported)
            {
                try
                {
                    return(PemKeyHelpers.CreatePemFromData(PemLabels.RsaPrivateKey, exported));
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(exported);
                }
            }
        }
Пример #9
0
        private static bool TryExportDataKeyParameters(
            SecKeyPair keys,
            bool includePrivateParameters,
            ref ECParameters ecParameters)
        {
            if (includePrivateParameters && keys.PrivateKey == null)
            {
                throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
            }

            bool gotKeyBlob = Interop.AppleCrypto.TrySecKeyCopyExternalRepresentation(
                includePrivateParameters ? keys.PrivateKey ! : keys.PublicKey,
                out byte[] keyBlob);

            if (!gotKeyBlob)
            {
                return(false);
            }

            try
            {
                AsymmetricAlgorithmHelpers.DecodeFromUncompressedAnsiX963Key(
                    keyBlob,
                    includePrivateParameters,
                    out ecParameters);

                switch (GetKeySize(keys))
                {
                case 256: ecParameters.Curve = ECCurve.NamedCurves.nistP256; break;

                case 384: ecParameters.Curve = ECCurve.NamedCurves.nistP384; break;

                case 521: ecParameters.Curve = ECCurve.NamedCurves.nistP521; break;

                default:
                    Debug.Fail("Unsupported curve");
                    throw new CryptographicException();
                }

                return(true);
            }
            finally
            {
                CryptographicOperations.ZeroMemory(keyBlob);
            }
        }
Пример #10
0
        /// <summary>
        /// Imports the public/private keypair from an ECPrivateKey structure,
        /// replacing the keys for this object.
        /// </summary>
        /// <param name="source">The bytes of an ECPrivateKey structure in the ASN.1-BER encoding.</param>
        /// <param name="bytesRead">
        /// When this method returns, contains a value that indicates the number
        /// of bytes read from <paramref name="source" />. This parameter is treated as uninitialized.
        /// </param>
        /// <exception cref="NotSupportedException">
        /// A derived class has not provided an implementation for <see cref="ImportParameters" />.
        /// </exception>
        /// <exception cref="CryptographicException">
        /// <p>
        ///   The contents of <paramref name="source" /> do not represent an
        ///   ASN.1-BER-encoded PKCS#8 ECPrivateKey structure.
        /// </p>
        /// <p>-or-</p>
        /// <p>The key import failed.</p>
        /// </exception>
        /// <remarks>
        /// This method only supports the binary (BER/CER/DER) encoding of ECPrivateKey.
        /// If the value is Base64-encoded, the caller must Base64-decode the contents before calling this method.
        /// If the value is PEM-encoded, <see cref="ImportFromPem" /> should be used.
        /// </remarks>
        public virtual unsafe void ImportECPrivateKey(ReadOnlySpan <byte> source, out int bytesRead)
        {
            ECParameters ecParameters = EccKeyFormatHelper.FromECPrivateKey(source, out int localRead);

            fixed(byte *privPin = ecParameters.D)
            {
                try
                {
                    ImportParameters(ecParameters);
                    bytesRead = localRead;
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
Пример #11
0
        /// <summary>Exports the current key in the ECPrivateKey format.</summary>
        /// <returns>A byte array containing the ECPrivateKey representation of this key.</returns>
        /// <exception cref="CryptographicException">The key could not be exported.</exception>
        public virtual unsafe byte[] ExportECPrivateKey()
        {
            ECParameters ecParameters = ExportParameters(true);

            fixed(byte *privPin = ecParameters.D)
            {
                try
                {
                    AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters);
                    return(writer.Encode());
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Exports the current key in the PKCS#8 EncryptedPrivateKeyInfo format
        /// with a char-based password, PEM encoded.
        /// </summary>
        /// <param name="password">
        /// The password to use when encrypting the key material.
        /// </param>
        /// <param name="pbeParameters">
        /// The password-based encryption (PBE) parameters to use when encrypting the key material.
        /// </param>
        /// <returns>A string containing the PEM-encoded PKCS#8 EncryptedPrivateKeyInfo.</returns>
        /// <exception cref="NotImplementedException">
        /// An implementation for <see cref="ExportEncryptedPkcs8PrivateKey(ReadOnlySpan{char}, PbeParameters)" /> or
        /// <see cref="TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan{char}, PbeParameters, Span{byte}, out int)" /> has not been provided.
        /// </exception>
        /// <exception cref="CryptographicException">
        /// The key could not be exported.
        /// </exception>
        /// <remarks>
        /// <p>
        ///   When <paramref name="pbeParameters" /> indicates an algorithm that
        ///   uses PBKDF2 (Password-Based Key Derivation Function 2), the password
        ///   is converted to bytes via the UTF-8 encoding.
        /// </p>
        /// <p>
        ///   A PEM-encoded PKCS#8 EncryptedPrivateKeyInfo will begin with
        ///  <c>-----BEGIN ENCRYPTED PRIVATE KEY-----</c> and end with
        ///  <c>-----END ENCRYPTED PRIVATE KEY-----</c>, with the base64 encoded DER
        ///   contents of the key between the PEM boundaries.
        /// </p>
        /// <p>
        ///   The PEM is encoded according to the IETF RFC 7468 &quot;strict&quot;
        ///   encoding rules.
        /// </p>
        /// </remarks>
        public unsafe string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan <char> password, PbeParameters pbeParameters)
        {
            byte[] exported = ExportEncryptedPkcs8PrivateKey(password, pbeParameters);

            // Fixed to prevent GC moves.
            fixed(byte *pExported = exported)
            {
                try
                {
                    return(PemKeyHelpers.CreatePemFromData(PemLabels.EncryptedPkcs8PrivateKey, exported));
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(exported);
                }
            }
        }
Пример #13
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 == RSAEncryptionPadding.OaepSHA1)
                {
                    return(Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten));
                }

                if (padding.Mode != RSAEncryptionPaddingMode.Oaep)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
                }

                RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);

                int bytesRequired = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);

                byte[] rented = ArrayPool <byte> .Shared.Rent(bytesRequired);

                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(bytesRequired == paddedSize);
                    unpaddedData = new Span <byte>(rented, 0, paddedSize);
                    return(processor.DepadOaep(unpaddedData, destination, out bytesWritten));
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(unpaddedData);
                    ArrayPool <byte> .Shared.Return(rented);
                }
            }
Пример #14
0
        /// <summary>
        /// Attempts to export the current key in the ECPrivateKey format into a provided buffer.
        /// </summary>
        /// <param name="destination">The byte span to receive the ECPrivateKey data.</param>
        /// <param name="bytesWritten">When this method returns, contains a value
        /// that indicates the number of bytes written to <paramref name="destination" />.
        /// This parameter is treated as uninitialized.
        /// </param>
        /// <returns>
        /// <see langword="true" /> if <paramref name="destination" /> is big enough
        /// to receive the output; otherwise, <see langword="false" />.
        /// </returns>
        /// <exception cref="CryptographicException">
        /// The key could not be exported.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// A derived class has not provided an implementation for <see cref="ExportParameters" />.
        /// </exception>
        public virtual unsafe bool TryExportECPrivateKey(Span <byte> destination, out int bytesWritten)
        {
            ECParameters ecParameters = ExportParameters(true);

            fixed(byte *privPin = ecParameters.D)
            {
                try
                {
                    AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters);
                    return(writer.TryEncode(destination, out bytesWritten));
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
Пример #15
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);
                }

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

                int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);

                byte[] rented = ArrayPool <byte> .Shared.Rent(maxOutputSize);

                Span <byte> contentsSpan = Span <byte> .Empty;

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

                    contentsSpan = new Span <byte>(rented, 0, bytesWritten);
                    return(contentsSpan.ToArray());
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(contentsSpan);
                    ArrayPool <byte> .Shared.Return(rented);
                }
            }
        private void DecryptInternal(
            ReadOnlySpan <byte> nonce,
            ReadOnlySpan <byte> ciphertext,
            ReadOnlySpan <byte> tag,
            Span <byte> plaintext,
            ReadOnlySpan <byte> associatedData)
        {
            Interop.Crypto.EvpCipherSetKeyAndIV(
                _ctxHandle,
                ReadOnlySpan <byte> .Empty,
                nonce,
                Interop.Crypto.EvpCipherDirection.Decrypt);

            if (associatedData.Length != 0)
            {
                if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, Span <byte> .Empty, out _, associatedData))
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }
            }

            if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext, out int plaintextBytesWritten, ciphertext))
            {
                throw Interop.Crypto.CreateOpenSslCryptographicException();
            }

            Interop.Crypto.EvpCipherSetGcmTag(_ctxHandle, tag);

            if (!Interop.Crypto.EvpCipherFinalEx(
                    _ctxHandle,
                    plaintext.Slice(plaintextBytesWritten),
                    out int bytesWritten))
            {
                CryptographicOperations.ZeroMemory(plaintext);
                throw new CryptographicException(SR.Cryptography_AuthTagMismatch);
            }

            plaintextBytesWritten += bytesWritten;

            if (plaintextBytesWritten != plaintext.Length)
            {
                Debug.Fail($"GCM decrypt wrote {plaintextBytesWritten} of {plaintext.Length} bytes.");
                throw new CryptographicException();
            }
        }
            public override DSAParameters ExportParameters(bool includePrivateParameters)
            {
                // Apple requires all private keys to be exported encrypted, but since we're trying to export
                // as parsed structures we will need to decrypt it for the user.
                const string ExportPassword = "******";
                SecKeyPair   keys           = GetKeys();

                if (keys.PublicKey == null ||
                    (includePrivateParameters && keys.PrivateKey == null))
                {
                    throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
                }

                byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
                    includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
                    exportPrivate: includePrivateParameters,
                    password: ExportPassword);

                try
                {
                    if (!includePrivateParameters)
                    {
                        DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(
                            keyBlob,
                            out int localRead,
                            out DSAParameters key);
                        Debug.Assert(localRead == keyBlob.Length);
                        return(key);
                    }
                    else
                    {
                        DSAKeyFormatHelper.ReadEncryptedPkcs8(
                            keyBlob,
                            ExportPassword,
                            out int localRead,
                            out DSAParameters key);
                        Debug.Assert(localRead == keyBlob.Length);
                        return(key);
                    }
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(keyBlob);
                }
            }
Пример #18
0
        /// <summary>
        ///   Computes the hash value of the specified data and signs it using the specified signature format.
        /// </summary>
        /// <param name="data">The data to sign.</param>
        /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param>
        /// <param name="signatureFormat">The encoding format to use for the signature.</param>
        /// <returns>
        ///   The ECDSA signature for the specified data.
        /// </returns>
        /// <exception cref="CryptographicException">
        ///   An error occurred in the hashing or signing operation.
        /// </exception>
        protected virtual byte[] SignDataCore(
            ReadOnlySpan <byte> data,
            HashAlgorithmName hashAlgorithm,
            DSASignatureFormat signatureFormat)
        {
            Span <byte> signature        = stackalloc byte[SignatureStackBufSize];
            int         maxSignatureSize = GetMaxSignatureSize(signatureFormat);

            byte[]? rented = null;
            bool returnArray  = false;
            int  bytesWritten = 0;

            if (maxSignatureSize > signature.Length)
            {
                // Use the shared pool because the buffer is passed out.
                rented = ArrayPool <byte> .Shared.Rent(maxSignatureSize);

                signature = rented;
            }

            try
            {
                if (!TrySignDataCore(data, signature, hashAlgorithm, signatureFormat, out bytesWritten))
                {
                    Debug.Fail($"GetMaxSignatureSize returned insufficient size for format {signatureFormat}");
                    throw new CryptographicException();
                }

                byte[] ret = signature.Slice(0, bytesWritten).ToArray();
                returnArray = true;
                return(ret);
            }
            finally
            {
                if (rented != null)
                {
                    CryptographicOperations.ZeroMemory(rented.AsSpan(0, bytesWritten));

                    if (returnArray)
                    {
                        ArrayPool <byte> .Shared.Return(rented);
                    }
                }
            }
        }
Пример #19
0
        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 = ArrayPool <byte> .Shared.Rent(rentSize);

                rentSize = rented.Length;
                int pkcs1Size = 0;

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

                        using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
                        {
                            writer.PushSequence();
                            WriteAlgorithmIdentifier(writer);
                            writer.WriteBitString(rented.AsSpan(0, pkcs1Size));
                            writer.PopSequence();

                            return(writer.TryEncode(destination, out bytesWritten));
                        }
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(rented.AsSpan(0, pkcs1Size));
                        ArrayPool <byte> .Shared.Return(rented);
                    }
                }
            }
        }
Пример #20
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));
            }

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

            CheckInvalidKey(key);

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

            byte[]      buf         = null;
            Span <byte> destination = default;

            try
            {
                buf = ArrayPool <byte> .Shared.Rent(rsaSize);

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

                if (!TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, 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);
                ArrayPool <byte> .Shared.Return(buf);
            }
        }
Пример #21
0
        public override unsafe bool TryExportPkcs8PrivateKey(
            Span <byte> destination,
            out int bytesWritten)
        {
            ECParameters ecParameters = ExportParameters(true);

            fixed(byte *privPtr = ecParameters.D)
            {
                try
                {
                    using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters))
                    {
                        return(writer.TryEncode(destination, out bytesWritten));
                    }
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
Пример #22
0
        private static void Pbkdf2Core(
            ReadOnlySpan <char> password,
            ReadOnlySpan <byte> salt,
            Span <byte> destination,
            int iterations,
            HashAlgorithmName hashAlgorithm)
        {
            Debug.Assert(hashAlgorithm.Name is not null);
            Debug.Assert(iterations > 0);

            if (destination.IsEmpty)
            {
                return;
            }

            const int MaxPasswordStackSize = 256;

            byte[]? rentedPasswordBuffer = null;
            int maxEncodedSize = s_throwingUtf8Encoding.GetMaxByteCount(password.Length);

            Span <byte> passwordBuffer = maxEncodedSize > MaxPasswordStackSize ?
                                         (rentedPasswordBuffer = CryptoPool.Rent(maxEncodedSize)) :
                                         stackalloc byte[MaxPasswordStackSize];
            int         passwordBytesWritten = s_throwingUtf8Encoding.GetBytes(password, passwordBuffer);
            Span <byte> passwordBytes        = passwordBuffer.Slice(0, passwordBytesWritten);

            try
            {
                Pbkdf2Implementation.Fill(passwordBytes, salt, iterations, hashAlgorithm, destination);
            }
            finally
            {
                CryptographicOperations.ZeroMemory(passwordBytes);
            }

            if (rentedPasswordBuffer is not null)
            {
                CryptoPool.Return(rentedPasswordBuffer, clearSize: 0); // manually cleared above.
            }
        }
Пример #23
0
        private static unsafe byte[] ExportArray <T>(
            ReadOnlySpan <T> password,
            PbeParameters pbeParameters,
            TryExportPbe <T> exporter)
        {
            int bufSize = 4096;

            while (true)
            {
                Span <byte> writtenSpan = Span <byte> .Empty;
                byte[]      buf         = ArrayPool <byte> .Shared.Rent(bufSize);

                bufSize = buf.Length;

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

                        ArrayPool <byte> .Shared.Return(buf);
                    }

                    bufSize = checked (bufSize * 2);
                }
            }
        }
Пример #24
0
        public override unsafe void ImportPkcs8PrivateKey(
            ReadOnlySpan <byte> source,
            out int bytesRead)
        {
            DSAKeyFormatHelper.ReadPkcs8(
                source,
                out int localRead,
                out DSAParameters key);

            fixed(byte *privPin = key.X)
            {
                try
                {
                    ImportParameters(key);
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(key.X);
                }
            }

            bytesRead = localRead;
        }
Пример #25
0
        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 = ArrayPool <byte> .Shared.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(rented.AsSpan(0, pkcs1Size)));
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(rented.AsSpan(0, pkcs1Size));
                        ArrayPool <byte> .Shared.Return(rented);
                    }
                }
            }
        }
Пример #26
0
        private static AsnWriter RewriteEncryptedPkcs8PrivateKey(
            AsymmetricAlgorithm key,
            ReadOnlySpan <char> password,
            PbeParameters pbeParameters)
        {
            Debug.Assert(pbeParameters != null);

            byte[] rented = ArrayPool <byte> .Shared.Rent(key.KeySize);

            int rentWritten = 0;

            try
            {
                while (!key.TryExportEncryptedPkcs8PrivateKey(
                           password,
                           s_platformParameters,
                           rented,
                           out rentWritten))
                {
                    int size = rented.Length;
                    ArrayPool <byte> .Shared.Return(rented);

                    rented = ArrayPool <byte> .Shared.Rent(checked (size * 2));
                }

                return(KeyFormatHelper.ReencryptPkcs8(
                           password,
                           rented.AsMemory(0, rentWritten),
                           password,
                           pbeParameters));
            }
            finally
            {
                CryptographicOperations.ZeroMemory(rented.AsSpan(0, rentWritten));
                ArrayPool <byte> .Shared.Return(rented);
            }
        }
Пример #27
0
        public override unsafe bool TryExportEncryptedPkcs8PrivateKey(
            ReadOnlySpan <char> password,
            PbeParameters pbeParameters,
            Span <byte> destination,
            out int bytesWritten)
        {
            if (pbeParameters == null)
            {
                throw new ArgumentNullException(nameof(pbeParameters));
            }

            PasswordBasedEncryption.ValidatePbeParameters(
                pbeParameters,
                password,
                ReadOnlySpan <byte> .Empty);

            ECParameters ecParameters = ExportParameters(true);

            fixed(byte *privPtr = ecParameters.D)
            {
                try
                {
                    AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters);

                    AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8(
                        password,
                        pkcs8PrivateKey,
                        pbeParameters);

                    return(writer.TryEncode(destination, out bytesWritten));
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
Пример #28
0
        /// <summary>
        /// Imports the public/private keypair from a PKCS#8 PrivateKeyInfo structure
        /// after decryption, replacing the keys for this object.
        /// </summary>
        /// <param name="source">The bytes of a PKCS#8 PrivateKeyInfo structure in the ASN.1-BER encoding.</param>
        /// <param name="bytesRead">
        /// When this method returns, contains a value that indicates the number
        /// of bytes read from <paramref name="source" />. This parameter is treated as uninitialized.
        /// </param>
        /// <exception cref="NotSupportedException">
        /// A derived class has not provided an implementation for <see cref="ImportParameters" />.
        /// </exception>
        /// <exception cref="CryptographicException">
        /// <p>
        ///   The contents of <paramref name="source" /> do not represent an ASN.1-BER-encoded
        ///   PKCS#8 PrivateKeyInfo structure.
        /// </p>
        /// <p>-or-</p>
        /// <p>
        ///   The contents of <paramref name="source" /> indicate the key is for an algorithm
        ///   other than the algorithm represented by this instance.
        /// </p>
        /// <p>-or-</p>
        /// <p>The contents of <paramref name="source" /> represent the key in a format that is not supported.</p>
        /// <p>-or-</p>
        /// <p>
        ///   The algorithm-specific key import failed.
        /// </p>
        /// </exception>
        /// <remarks>
        /// This method only supports the binary (BER/CER/DER) encoding of PrivateKeyInfo.
        /// If the value is Base64-encoded, the caller must Base64-decode the contents before calling this method.
        /// If the value is PEM-encoded, <see cref="ImportFromPem" /> should be used.
        /// </remarks>
        public override unsafe void ImportPkcs8PrivateKey(
            ReadOnlySpan <byte> source,
            out int bytesRead)
        {
            KeyFormatHelper.ReadPkcs8 <ECParameters>(
                s_validOids,
                source,
                EccKeyFormatHelper.FromECPrivateKey,
                out int localRead,
                out ECParameters key);

            fixed(byte *privPin = key.D)
            {
                try
                {
                    ImportParameters(key);
                    bytesRead = localRead;
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(key.D);
                }
            }
        }
Пример #29
0
        public Rfc2898DeriveBytes(string password, int saltSize, int iterations, HashAlgorithmName hashAlgorithm)
        {
            if (saltSize < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(saltSize), SR.ArgumentOutOfRange_NeedNonNegNum);
            }
            if (iterations <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(iterations), SR.ArgumentOutOfRange_NeedPosNum);
            }

            _salt = new byte[saltSize + sizeof(uint)];
            RandomNumberGenerator.Fill(_salt.AsSpan(0, saltSize));

            _iterations = (uint)iterations;
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
            HashAlgorithm = hashAlgorithm;
            _hmac         = OpenHmac(passwordBytes);
            CryptographicOperations.ZeroMemory(passwordBytes);
            // _blockSize is in bytes, HashSize is in bits.
            _blockSize = _hmac.HashSize >> 3;

            Initialize();
        }
Пример #30
0
        private static ECParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool includePrivateParameters)
        {
            // Apple requires all private keys to be exported encrypted, but since we're trying to export
            // as parsed structures we will need to decrypt it for the user.
            const string ExportPassword = "******";

            byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(
                includePrivateParameters ? keys.PrivateKey : keys.PublicKey,
                exportPrivate: includePrivateParameters,
                password: ExportPassword);

            try
            {
                if (!includePrivateParameters)
                {
                    EccKeyFormatHelper.ReadSubjectPublicKeyInfo(
                        keyBlob,
                        out int localRead,
                        out ECParameters key);
                    return(key);
                }
                else
                {
                    EccKeyFormatHelper.ReadEncryptedPkcs8(
                        keyBlob,
                        ExportPassword,
                        out int localRead,
                        out ECParameters key);
                    return(key);
                }
            }
            finally
            {
                CryptographicOperations.ZeroMemory(keyBlob);
            }
        }