Example #1
0
        private static unsafe AsnWriter?RewritePkcs8ECPrivateKeyWithZeroPublicKey(ReadOnlySpan <byte> source)
        {
            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    PrivateKeyInfoAsn      privateKeyInfo   = PrivateKeyInfoAsn.Decode(manager.Memory, AsnEncodingRules.BER);
                    AlgorithmIdentifierAsn privateAlgorithm = privateKeyInfo.PrivateKeyAlgorithm;

                    if (privateAlgorithm.Algorithm.Value != Oids.EcPublicKey)
                    {
                        return(null);
                    }

                    ECPrivateKey privateKey = ECPrivateKey.Decode(privateKeyInfo.PrivateKey, AsnEncodingRules.BER);
                    EccKeyFormatHelper.FromECPrivateKey(privateKey, privateAlgorithm, out ECParameters ecParameters);

                    fixed(byte *pD = ecParameters.D)
                    {
                        try
                        {
                            if (!ecParameters.Curve.IsExplicit || ecParameters.Q.X != null || ecParameters.Q.Y != null)
                            {
                                return(null);
                            }

                            byte[] zero = new byte[ecParameters.D !.Length];
Example #2
0
        /// <summary>
        /// Attempts to export the current key in the X.509 SubjectPublicKeyInfo format.
        /// </summary>
        /// <param name="destination">The byte span to receive the X.509 SubjectPublicKeyInfo 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="NotSupportedException">
        /// The member <see cref="ExportParameters" /> has not been overridden in a derived class.
        /// </exception>
        /// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
        /// <exception cref="CryptographicException">The key is invalid and could not be exported.</exception>
        public virtual bool TryExportSubjectPublicKeyInfo(Span <byte> destination, out int bytesWritten)
        {
            ECParameters ecParameters = ExportParameters();
            AsnWriter    writer       = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters);

            return(writer.TryEncode(destination, out bytesWritten));
        }
        internal unsafe int ImportSubjectPublicKeyInfo(
            ReadOnlySpan <byte> source,
            out int bytesRead)
        {
            ThrowIfDisposed();

            fixed(byte *ptr = &MemoryMarshal.GetReference(source))
            {
                using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length))
                {
                    // Validate the DER value and get the number of bytes.
                    EccKeyFormatHelper.ReadSubjectPublicKeyInfo(
                        manager.Memory,
                        out int localRead);

                    SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.ImportEphemeralKey(source.Slice(0, localRead), false);
                    SecKeyPair          newKeys   = SecKeyPair.PublicOnly(publicKey);
                    int size = GetKeySize(newKeys);
                    SetKey(newKeys);

                    bytesRead = localRead;
                    return(size);
                }
            }
        }
Example #4
0
        /// <summary>
        /// Exports the current key in the X.509 SubjectPublicKeyInfo format.
        /// </summary>
        /// <returns>
        /// A byte array containing the X.509 SubjectPublicKeyInfo representation of this key.
        /// </returns>
        /// <exception cref="NotSupportedException">
        /// The member <see cref="ExportParameters" /> has not been overridden in a derived class.
        /// </exception>
        /// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
        /// <exception cref="CryptographicException">The key is invalid and could not be exported.</exception>
        public virtual byte[] ExportSubjectPublicKeyInfo()
        {
            ECParameters ecParameters = ExportParameters();
            AsnWriter    writer       = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters);

            return(writer.Encode());
        }
Example #5
0
        /// <summary>
        /// Attempts to export the current key in the PKCS#8 EncryptedPrivateKeyInfo
        /// format into a provided buffer, using a char-based password.
        /// </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>
        /// <param name="destination">
        /// The byte span to receive the PKCS#8 EncryptedPrivateKeyInfo 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="ArgumentNullException">
        /// <paramref name="pbeParameters" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// A derived class has not provided an implementation for <see cref="ExportParameters" />.
        /// </exception>
        /// <exception cref="CryptographicException">
        /// The key could not be exported.
        /// </exception>
        /// <remarks>
        /// 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.
        /// </remarks>
        public override unsafe bool TryExportEncryptedPkcs8PrivateKey(
            ReadOnlySpan <char> password,
            PbeParameters pbeParameters,
            Span <byte> destination,
            out int bytesWritten)
        {
            ArgumentNullException.ThrowIfNull(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);
                }
            }
        }
Example #6
0
 private static void ExtractPublicKeyFromPrivateKey(ref ECParameters ecParameters)
 {
     using (SafeSecKeyRefHandle secPrivateKey = ImportLegacyPrivateKey(ref ecParameters))
     {
         const string ExportPassword = "******";
         byte[]       keyBlob        = Interop.AppleCrypto.SecKeyExport(secPrivateKey, exportPrivate: true, password: ExportPassword);
         EccKeyFormatHelper.ReadEncryptedPkcs8(keyBlob, ExportPassword, out _, out ecParameters);
         CryptographicOperations.ZeroMemory(keyBlob);
     }
 }
Example #7
0
        public override bool TryExportSubjectPublicKeyInfo(
            Span <byte> destination,
            out int bytesWritten)
        {
            ECParameters ecParameters = ExportParameters(false);

            using (AsnWriter writer = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(ecParameters))
            {
                return(writer.TryEncode(destination, out bytesWritten));
            }
        }
        internal static ECParameters ExportPublicParametersFromPrivateKey(SafeSecKeyRefHandle handle)
        {
            const string ExportPassword = "******";

            byte[] keyBlob = Interop.AppleCrypto.SecKeyExport(handle, exportPrivate: true, password: ExportPassword);
            EccKeyFormatHelper.ReadEncryptedPkcs8(keyBlob, ExportPassword, out _, out ECParameters key);
            CryptographicOperations.ZeroMemory(key.D);
            CryptographicOperations.ZeroMemory(keyBlob);
            key.D = null;
            return(key);
        }
 private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
 {
     if (parameters.D != null)
     {
         using (AsnWriter privateKey = EccKeyFormatHelper.WriteECPrivateKey(parameters))
         {
             return(Interop.AppleCrypto.ImportEphemeralKey(privateKey.EncodeAsSpan(), true));
         }
     }
     else
     {
         using (AsnWriter publicKey = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
         {
             return(Interop.AppleCrypto.ImportEphemeralKey(publicKey.EncodeAsSpan(), false));
         }
     }
 }
Example #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);
                }
            }
        }
Example #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);
                }
            }
        }
Example #12
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);
                }
            }
        }
        internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBits)
        {
            // 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           = GetOrGenerateKeys(keySizeInBits);

            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)
                {
                    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);
            }
        }
Example #14
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);
                }
            }
        }
Example #15
0
        private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
        {
            bool isPrivateKey = parameters.D != null;

            byte[] blob;

            if (isPrivateKey)
            {
                using (AsnWriter privateKey = EccKeyFormatHelper.WriteECPrivateKey(parameters))
                {
                    blob = privateKey.Encode();
                }
            }
            else
            {
                using (AsnWriter publicKey = EccKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters))
                {
                    blob = publicKey.Encode();
                }
            }

            return(Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey));
        }
        private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
        {
            AsnWriter keyWriter;
            bool      hasPrivateKey;

            if (parameters.D != null)
            {
                keyWriter     = EccKeyFormatHelper.WriteECPrivateKey(parameters);
                hasPrivateKey = true;
            }
            else
            {
                keyWriter     = EccKeyFormatHelper.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);
            }
        }
Example #17
0
        private static SafeSecKeyRefHandle ImportLegacyPrivateKey(ref ECParameters parameters)
        {
            AsnWriter keyWriter = EccKeyFormatHelper.WriteECPrivateKey(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);
            }
        }
Example #18
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);
            }
        }