/// <summary>
        ///     Exports the key used by the RSA object into an RSAParameters object.
        /// </summary>
        public override RSAParameters ExportParameters(bool includePrivateParameters)
        {
            byte[]        rsaBlob   = Key.Export(includePrivateParameters ? s_rsaFullPrivateBlob : s_rsaPublicBlob);
            RSAParameters rsaParams = new RSAParameters();

            //
            // We now have a buffer laid out as follows:
            //     BCRYPT_RSAKEY_BLOB   header
            //     byte[cbPublicExp]    publicExponent      - Exponent
            //     byte[cbModulus]      modulus             - Modulus
            //     -- Private only --
            //     byte[cbPrime1]       prime1              - P
            //     byte[cbPrime2]       prime2              - Q
            //     byte[cbPrime1]       exponent1           - DP
            //     byte[cbPrime2]       exponent2           - DQ
            //     byte[cbPrime1]       coefficient         - InverseQ
            //     byte[cbModulus]      privateExponent     - D
            //
            byte[] tempMagic = new byte[4];
            tempMagic[0] = rsaBlob[0]; tempMagic[1] = rsaBlob[1]; tempMagic[2] = rsaBlob[2]; tempMagic[3] = rsaBlob[3];
            KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(tempMagic, 0);

            // Check the magic value in the key blob header. If the blob does not have the required magic,
            // then throw a CryptographicException.
            CheckMagicValueOfKey(magic, includePrivateParameters);

            unsafe
            {
                // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header.
                if (rsaBlob.Length < sizeof(BCRYPT_RSAKEY_BLOB))
                    throw ErrorCode.E_FAIL.ToCryptographicException();

                fixed(byte *pRsaBlob = rsaBlob)
                {
                    BCRYPT_RSAKEY_BLOB *pBcryptBlob = (BCRYPT_RSAKEY_BLOB *)pRsaBlob;

                    int offset = sizeof(BCRYPT_RSAKEY_BLOB);

                    // Read out the exponent
                    rsaParams.Exponent = Consume(rsaBlob, ref offset, pBcryptBlob->cbPublicExp);
                    rsaParams.Modulus  = Consume(rsaBlob, ref offset, pBcryptBlob->cbModulus);

                    if (includePrivateParameters)
                    {
                        rsaParams.P        = Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime1);
                        rsaParams.Q        = Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime2);
                        rsaParams.DP       = Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime1);
                        rsaParams.DQ       = Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime2);
                        rsaParams.InverseQ = Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime1);
                        rsaParams.D        = Consume(rsaBlob, ref offset, pBcryptBlob->cbModulus);
                    }
                }
            }

            return(rsaParams);
        }
Beispiel #2
0
        private static void ExportParameters(ref RSAParameters rsaParams, byte[] rsaBlob, bool includePrivateParameters)
        {
            //
            // We now have a buffer laid out as follows:
            //     BCRYPT_RSAKEY_BLOB   header
            //     byte[cbPublicExp]    publicExponent      - Exponent
            //     byte[cbModulus]      modulus             - Modulus
            //     -- Private only --
            //     byte[cbPrime1]       prime1              - P
            //     byte[cbPrime2]       prime2              - Q
            //     byte[cbPrime1]       exponent1           - DP
            //     byte[cbPrime2]       exponent2           - DQ
            //     byte[cbPrime1]       coefficient         - InverseQ
            //     byte[cbModulus]      privateExponent     - D
            //
            KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(rsaBlob, 0);

            // Check the magic value in the key blob header. If the blob does not have the required magic,
            // then throw a CryptographicException.
            CheckMagicValueOfKey(magic, includePrivateParameters);

            unsafe
            {
                // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header.
                if (rsaBlob.Length < sizeof(BCRYPT_RSAKEY_BLOB))
                    throw ErrorCode.E_FAIL.ToCryptographicException();

                fixed(byte *pRsaBlob = &rsaBlob[0])
                {
                    BCRYPT_RSAKEY_BLOB *pBcryptBlob = (BCRYPT_RSAKEY_BLOB *)pRsaBlob;

                    int offset = sizeof(BCRYPT_RSAKEY_BLOB);

                    // Read out the exponent
                    rsaParams.Exponent = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbPublicExp);
                    rsaParams.Modulus  = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbModulus);

                    if (includePrivateParameters)
                    {
                        rsaParams.P        = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime1);
                        rsaParams.Q        = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime2);
                        rsaParams.DP       = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime1);
                        rsaParams.DQ       = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime2);
                        rsaParams.InverseQ = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbPrime1);
                        rsaParams.D        = Interop.BCrypt.Consume(rsaBlob, ref offset, pBcryptBlob->cbModulus);
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        ///     <para>
        ///         ImportParameters will replace the existing key that RSACng is working with by creating a
        ///         new CngKey for the parameters structure. If the parameters structure contains only an
        ///         exponent and modulus, then only a public key will be imported. If the parameters also
        ///         contain P and Q values, then a full key pair will be imported.
        ///     </para>
        /// </summary>
        /// <exception cref="ArgumentException">
        ///     if <paramref name="parameters" /> contains neither an exponent nor a modulus.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///     if <paramref name="parameters" /> is not a valid RSA key or if <paramref name="parameters"
        ///     /> is a full key pair and the default KSP is used.
        /// </exception>
        public override unsafe void ImportParameters(RSAParameters parameters)
        {
            if (parameters.Exponent == null || parameters.Modulus == null)
            {
                throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
            }

            bool includePrivate;

            if (parameters.D == null)
            {
                includePrivate = false;

                if (parameters.P != null ||
                    parameters.DP != null ||
                    parameters.Q != null ||
                    parameters.DQ != null ||
                    parameters.InverseQ != null)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                }
            }
            else
            {
                includePrivate = true;

                if (parameters.P == null ||
                    parameters.DP == null ||
                    parameters.Q == null ||
                    parameters.DQ == null ||
                    parameters.InverseQ == null)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                }

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

                // The same checks are done by RSACryptoServiceProvider on import (when building the key blob)
                // Historically RSACng let CNG handle this (reporting NTE_NOT_SUPPORTED), but on RS1 CNG let the
                // import succeed, then on private key use (e.g. signing) it would report NTE_INVALID_PARAMETER.
                //
                // Doing the check here prevents the state in RS1 where the Import succeeds, but corrupts the key,
                // and makes for a friendlier exception message.
                if (parameters.D.Length != parameters.Modulus.Length ||
                    parameters.P.Length != halfModulusLength ||
                    parameters.Q.Length != halfModulusLength ||
                    parameters.DP.Length != halfModulusLength ||
                    parameters.DQ.Length != halfModulusLength ||
                    parameters.InverseQ.Length != halfModulusLength)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                }
            }

            //
            // We need to build a key blob structured as follows:
            //
            //     BCRYPT_RSAKEY_BLOB   header
            //     byte[cbPublicExp]    publicExponent      - Exponent
            //     byte[cbModulus]      modulus             - Modulus
            //     -- Only if "includePrivate" is true --
            //     byte[cbPrime1]       prime1              - P
            //     byte[cbPrime2]       prime2              - Q
            //     ------------------
            //

            int blobSize = sizeof(BCRYPT_RSAKEY_BLOB) +
                           parameters.Exponent.Length +
                           parameters.Modulus.Length;

            if (includePrivate)
            {
                blobSize += parameters.P !.Length +
                            parameters.Q !.Length;
            }

            byte[] rsaBlob = new byte[blobSize];
            fixed(byte *pRsaBlob = &rsaBlob[0])
            {
                // Build the header
                BCRYPT_RSAKEY_BLOB *pBcryptBlob = (BCRYPT_RSAKEY_BLOB *)pRsaBlob;

                pBcryptBlob->Magic       = includePrivate ? KeyBlobMagicNumber.BCRYPT_RSAPRIVATE_MAGIC : KeyBlobMagicNumber.BCRYPT_RSAPUBLIC_MAGIC;
                pBcryptBlob->BitLength   = parameters.Modulus.Length * 8;
                pBcryptBlob->cbPublicExp = parameters.Exponent.Length;
                pBcryptBlob->cbModulus   = parameters.Modulus.Length;

                if (includePrivate)
                {
                    pBcryptBlob->cbPrime1 = parameters.P !.Length;
                    pBcryptBlob->cbPrime2 = parameters.Q !.Length;
                }

                int offset = sizeof(BCRYPT_RSAKEY_BLOB);

                Interop.BCrypt.Emit(rsaBlob, ref offset, parameters.Exponent);
                Interop.BCrypt.Emit(rsaBlob, ref offset, parameters.Modulus);

                if (includePrivate)
                {
                    Interop.BCrypt.Emit(rsaBlob, ref offset, parameters.P !);
                    Interop.BCrypt.Emit(rsaBlob, ref offset, parameters.Q !);
                }

                // We better have computed the right allocation size above!
                Debug.Assert(offset == blobSize, "offset == blobSize");
            }

            ImportKeyBlob(rsaBlob, includePrivate);
        }
        /// <summary>
        ///     <para>
        ///         ImportParameters will replace the existing key that RSACng is working with by creating a
        ///         new CngKey for the parameters structure. If the parameters structure contains only an
        ///         exponent and modulus, then only a public key will be imported. If the parameters also
        ///         contain P and Q values, then a full key pair will be imported.
        ///     </para>
        /// </summary>
        /// <exception cref="ArgumentException">
        ///     if <paramref name="parameters" /> contains neither an exponent nor a modulus.
        /// </exception>
        /// <exception cref="CryptographicException">
        ///     if <paramref name="parameters" /> is not a valid RSA key or if <paramref name="parameters"
        ///     /> is a full key pair and the default KSP is used.
        /// </exception>
        public override void ImportParameters(RSAParameters parameters)
        {
            unsafe
            {
                if (parameters.Exponent == null || parameters.Modulus == null)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                }

                bool includePrivate;
                if (parameters.D == null)
                {
                    includePrivate = false;
                    if (parameters.P != null || parameters.DP != null || parameters.Q != null || parameters.DQ != null || parameters.InverseQ != null)
                    {
                        throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                    }
                }
                else
                {
                    includePrivate = true;
                    if (parameters.P == null || parameters.DP == null || parameters.Q == null || parameters.DQ == null || parameters.InverseQ == null)
                    {
                        throw new CryptographicException(SR.Cryptography_InvalidRsaParameters);
                    }
                }

                //
                // We need to build a key blob structured as follows:
                //
                //     BCRYPT_RSAKEY_BLOB   header
                //     byte[cbPublicExp]    publicExponent      - Exponent
                //     byte[cbModulus]      modulus             - Modulus
                //     -- Only if "includePrivate" is true --
                //     byte[cbPrime1]       prime1              - P
                //     byte[cbPrime2]       prime2              - Q
                //     ------------------
                //

                int blobSize = sizeof(BCRYPT_RSAKEY_BLOB) +
                               parameters.Exponent.Length +
                               parameters.Modulus.Length;
                if (includePrivate)
                {
                    blobSize += parameters.P.Length +
                                parameters.Q.Length;
                }

                byte[] rsaBlob = new byte[blobSize];
                fixed(byte *pRsaBlob = rsaBlob)
                {
                    // Build the header
                    BCRYPT_RSAKEY_BLOB *pBcryptBlob = (BCRYPT_RSAKEY_BLOB *)pRsaBlob;

                    pBcryptBlob->Magic       = includePrivate ? KeyBlobMagicNumber.BCRYPT_RSAPRIVATE_MAGIC : KeyBlobMagicNumber.BCRYPT_RSAPUBLIC_MAGIC;
                    pBcryptBlob->BitLength   = parameters.Modulus.Length * 8;
                    pBcryptBlob->cbPublicExp = parameters.Exponent.Length;
                    pBcryptBlob->cbModulus   = parameters.Modulus.Length;

                    if (includePrivate)
                    {
                        pBcryptBlob->cbPrime1 = parameters.P.Length;
                        pBcryptBlob->cbPrime2 = parameters.Q.Length;
                    }

                    int offset = sizeof(BCRYPT_RSAKEY_BLOB);

                    Emit(rsaBlob, ref offset, parameters.Exponent);
                    Emit(rsaBlob, ref offset, parameters.Modulus);

                    if (includePrivate)
                    {
                        Emit(rsaBlob, ref offset, parameters.P);
                        Emit(rsaBlob, ref offset, parameters.Q);
                    }

                    // We better have computed the right allocation size above!
                    Debug.Assert(offset == blobSize, "offset == blobSize");
                }

                ImportKeyBlob(rsaBlob, includePrivate);
            }
        }