public override void ImportParameters(RSAParameters parameters) { if (parameters.Exponent == null || parameters.Modulus == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_InvalidRsaParameters)); } bool publicOnly = parameters.P == null || parameters.Q == null; // // We need to build a key blob structured as follows: // BCRYPT_RSAKEY_BLOB header // byte[cbPublicExp] publicExponent - Exponent // byte[cbModulus] modulus - Modulus // -- Private only -- // byte[cbPrime1] prime1 - P // byte[cbPrime2] prime2 - Q // int blobSize = Marshal.SizeOf(typeof(BCryptNative.BCRYPT_RSAKEY_BLOB)) + parameters.Exponent.Length + parameters.Modulus.Length; if (!publicOnly) { blobSize += parameters.P.Length + parameters.Q.Length; } byte[] rsaBlob = new byte[blobSize]; unsafe { fixed(byte *pRsaBlob = rsaBlob) { // Build the header BCryptNative.BCRYPT_RSAKEY_BLOB *pBcryptBlob = (BCryptNative.BCRYPT_RSAKEY_BLOB *)pRsaBlob; pBcryptBlob->Magic = publicOnly ? BCryptNative.KeyBlobMagicNumber.RsaPublic : BCryptNative.KeyBlobMagicNumber.RsaPrivate; pBcryptBlob->BitLength = parameters.Modulus.Length * 8; pBcryptBlob->cbPublicExp = parameters.Exponent.Length; pBcryptBlob->cbModulus = parameters.Modulus.Length; if (!publicOnly) { pBcryptBlob->cbPrime1 = parameters.P.Length; pBcryptBlob->cbPrime2 = parameters.Q.Length; } int offset = Marshal.SizeOf(typeof(BCryptNative.BCRYPT_RSAKEY_BLOB)); // Copy the exponent Buffer.BlockCopy(parameters.Exponent, 0, rsaBlob, offset, parameters.Exponent.Length); offset += parameters.Exponent.Length; // Copy the modulus Buffer.BlockCopy(parameters.Modulus, 0, rsaBlob, offset, parameters.Modulus.Length); offset += parameters.Modulus.Length; if (!publicOnly) { // Copy P Buffer.BlockCopy(parameters.P, 0, rsaBlob, offset, parameters.P.Length); offset += parameters.P.Length; // Copy Q Buffer.BlockCopy(parameters.Q, 0, rsaBlob, offset, parameters.Q.Length); offset += parameters.Q.Length; } } } Key = CngKey.Import(rsaBlob, publicOnly ? s_rsaPublicBlob : s_rsaPrivateBlob); }
/// <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"); } CngKeyBlobFormat blobFormat = includePrivate ? s_rsaPrivateBlob : s_rsaPublicBlob; CngKey newKey = CngKey.Import(rsaBlob, blobFormat); newKey.ExportPolicy |= CngExportPolicies.AllowPlaintextExport; Key = newKey; } }