Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions crypto/src/pkcs/PrivateKeyInfoFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

namespace Org.BouncyCastle.Pkcs
{
/// <summary>
/// A factory to produce <see cref="PrivateKeyInfo"/> (PKCS#8) objects from Bouncy Castle private key parameters.
/// </summary>
public static class PrivateKeyInfoFactory
{
private static readonly HashSet<DerObjectIdentifier> cryptoProOids = new HashSet<DerObjectIdentifier>
Expand All @@ -29,17 +32,28 @@ public static class PrivateKeyInfoFactory
CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB,
};

/// <summary>
/// Create a <see cref="PrivateKeyInfo"/> representation of a private key.
/// </summary>
/// <example>
/// Example of exporting a private key to PKCS#8 bytes:
/// <code>
/// byte[] pkcs8Bytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey).GetEncoded();
/// </code>
/// </example>
/// <param name="privateKey">The private key parameters.</param>
/// <returns>The <see cref="PrivateKeyInfo"/> object.</returns>
public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter privateKey) =>
CreatePrivateKeyInfo(privateKey, null);

/**
* Create a PrivateKeyInfo representation of a private key with attributes.
*
* @param privateKey the key to be encoded into the info object.
* @param attributes the set of attributes to be included.
* @return the appropriate PrivateKeyInfo
* @throws java.io.IOException on an error encoding the key
*/
/// <summary>
/// Create a <see cref="PrivateKeyInfo"/> representation of a private key with attributes.
/// </summary>
/// <param name="privateKey">The key to be encoded into the info object.</param>
/// <param name="attributes">The set of attributes to be included.</param>
/// <returns>The appropriate <see cref="PrivateKeyInfo"/>.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="privateKey"/> is null.</exception>
/// <exception cref="ArgumentException">If a public key is passed instead of a private key.</exception>
public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter privateKey, Asn1Set attributes)
{
if (privateKey == null)
Expand Down Expand Up @@ -267,9 +281,23 @@ public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter private
throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(privateKey));
}

/// <summary>
/// Create a <see cref="PrivateKeyInfo"/> from an encrypted representation using a passphrase.
/// </summary>
/// <param name="passPhrase">The password for decryption.</param>
/// <param name="encInfo">The encrypted private key information.</param>
/// <returns>A <see cref="PrivateKeyInfo"/> object.</returns>
public static PrivateKeyInfo CreatePrivateKeyInfo(char[] passPhrase, EncryptedPrivateKeyInfo encInfo) =>
CreatePrivateKeyInfo(passPhrase, false, encInfo);

/// <summary>
/// Create a <see cref="PrivateKeyInfo"/> from an encrypted representation using a passphrase.
/// </summary>
/// <param name="passPhrase">The password for decryption.</param>
/// <param name="wrongPkcs12Zero">If true, uses a specific zero-padding for PKCS#12 PBE (for compatibility).</param>
/// <param name="encInfo">The encrypted private key information.</param>
/// <returns>A <see cref="PrivateKeyInfo"/> object.</returns>
/// <exception cref="ArgumentException">If the encryption algorithm is unknown.</exception>
public static PrivateKeyInfo CreatePrivateKeyInfo(char[] passPhrase, bool wrongPkcs12Zero,
EncryptedPrivateKeyInfo encInfo)
{
Expand Down
171 changes: 166 additions & 5 deletions crypto/src/security/DotNetUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,76 @@ public static SystemX509.X509Certificate ToX509Certificate(X509CertificateStruct
public static SystemX509.X509Certificate ToX509Certificate(X509Certificate x509Cert) =>
ToX509Certificate(x509Cert.CertificateStructure);

/// <summary>
/// Create a Bouncy Castle <see cref="X509Certificate"/> from a .NET <see cref="SystemX509.X509Certificate"/>.
/// </summary>
/// <param name="x509Cert">The .NET certificate.</param>
/// <returns>A Bouncy Castle <see cref="X509Certificate"/>.</returns>
public static X509Certificate FromX509Certificate(SystemX509.X509Certificate x509Cert) =>
new X509Certificate(x509Cert.GetRawCertData());

/// <summary>
/// Create a Bouncy Castle <see cref="X509Certificate"/> from a .NET <see cref="SystemX509.X509Certificate2"/>.
/// </summary>
/// <param name="x509Cert">The .NET certificate.</param>
/// <returns>A Bouncy Castle <see cref="X509Certificate"/>.</returns>
public static X509Certificate FromX509Certificate(SystemX509.X509Certificate2 x509Cert) =>
new X509Certificate(x509Cert.RawData);

/// <summary>
/// Extract the <see cref="SubjectPublicKeyInfo"/> (an X.509 ASN.1 type used for public keys) from a .NET
/// <see cref="SystemX509.X509Certificate2"/>.
/// </summary>
/// <param name="certificate">The .NET certificate.</param>
/// <returns>A <see cref="SubjectPublicKeyInfo"/> object.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="certificate"/> is null.</exception>
public static SubjectPublicKeyInfo GetSubjectPublicKeyInfo(SystemX509.X509Certificate2 certificate)
{
if (certificate == null)
throw new ArgumentNullException(nameof(certificate));

#if NET6_0_OR_GREATER
return SubjectPublicKeyInfo.GetInstance(certificate.PublicKey.ExportSubjectPublicKeyInfo());
#else
var bcCert = FromX509Certificate(certificate);
return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcCert.GetPublicKey());
Comment thread
KonradSop marked this conversation as resolved.
#endif
}

/// <summary>
/// Extract the DER-encoded <see cref="SubjectPublicKeyInfo"/> bytes from a .NET
/// <see cref="SystemX509.X509Certificate2"/>.
/// </summary>
/// <param name="certificate">The .NET certificate.</param>
/// <returns>A byte array containing the DER-encoded public key info.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="certificate"/> is null.</exception>
public static byte[] GetSubjectPublicKeyInfoDer(SystemX509.X509Certificate2 certificate)
{
if (certificate == null)
throw new ArgumentNullException(nameof(certificate));

#if NET6_0_OR_GREATER
return certificate.PublicKey.ExportSubjectPublicKeyInfo();
#else
return GetSubjectPublicKeyInfo(certificate).GetEncoded(Asn1Encodable.Der);
Comment thread
KonradSop marked this conversation as resolved.
#endif
}

/// <summary>
/// Extract a DSA key pair from a .NET <see cref="DSA"/> object.
/// </summary>
/// <param name="dsa">The .NET DSA object.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC DSA keys.</returns>
public static AsymmetricCipherKeyPair GetDsaKeyPair(DSA dsa)
{
return GetDsaKeyPair(dsa.ExportParameters(true));
}

/// <summary>
/// Extract a DSA key pair from <see cref="DSAParameters"/>.
/// </summary>
/// <param name="dp">The .NET DSA parameters.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC DSA keys.</returns>
public static AsymmetricCipherKeyPair GetDsaKeyPair(DSAParameters dp)
{
DsaPublicKeyParameters pubKey = GetDsaPublicKey(dp);
Expand All @@ -76,11 +135,21 @@ public static AsymmetricCipherKeyPair GetDsaKeyPair(DSAParameters dp)
return new AsymmetricCipherKeyPair(pubKey, privKey);
}

/// <summary>
/// Extract DSA public key parameters from a .NET <see cref="DSA"/> object.
/// </summary>
/// <param name="dsa">The .NET DSA object.</param>
/// <returns>A <see cref="DsaPublicKeyParameters"/> object.</returns>
public static DsaPublicKeyParameters GetDsaPublicKey(DSA dsa)
{
return GetDsaPublicKey(dsa.ExportParameters(false));
}

/// <summary>
/// Extract DSA public key parameters from <see cref="DSAParameters"/>.
/// </summary>
/// <param name="dp">The .NET DSA parameters.</param>
/// <returns>A <see cref="DsaPublicKeyParameters"/> object.</returns>
public static DsaPublicKeyParameters GetDsaPublicKey(DSAParameters dp)
{
DsaValidationParameters validationParameters = (dp.Seed != null)
Expand All @@ -99,16 +168,32 @@ public static DsaPublicKeyParameters GetDsaPublicKey(DSAParameters dp)
}

#if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER
/// <summary>
/// Extract an EC key pair from a .NET <see cref="ECDsa"/> object.
/// </summary>
/// <param name="ecDsa">The .NET ECDsa object.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC EC keys.</returns>
public static AsymmetricCipherKeyPair GetECDsaKeyPair(ECDsa ecDsa)
{
return GetECKeyPair("ECDSA", ecDsa.ExportParameters(true));
}

/// <summary>
/// Extract EC public key parameters from a .NET <see cref="ECDsa"/> object.
/// </summary>
/// <param name="ecDsa">The .NET ECDsa object.</param>
/// <returns>An <see cref="ECPublicKeyParameters"/> object.</returns>
public static ECPublicKeyParameters GetECDsaPublicKey(ECDsa ecDsa)
{
return GetECPublicKey("ECDSA", ecDsa.ExportParameters(false));
}

/// <summary>
/// Extract an EC key pair from <see cref="ECParameters"/>.
/// </summary>
/// <param name="algorithm">The algorithm name (e.g., "ECDSA").</param>
/// <param name="ec">The .NET EC parameters.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC EC keys.</returns>
public static AsymmetricCipherKeyPair GetECKeyPair(string algorithm, ECParameters ec)
{
ECPublicKeyParameters pubKey = GetECPublicKey(algorithm, ec);
Expand All @@ -121,6 +206,12 @@ public static AsymmetricCipherKeyPair GetECKeyPair(string algorithm, ECParameter
return new AsymmetricCipherKeyPair(pubKey, privKey);
}

/// <summary>
/// Extract EC public key parameters from <see cref="ECParameters"/>.
/// </summary>
/// <param name="algorithm">The algorithm name (e.g., "ECDSA").</param>
/// <param name="ec">The .NET EC parameters.</param>
/// <returns>An <see cref="ECPublicKeyParameters"/> object.</returns>
public static ECPublicKeyParameters GetECPublicKey(string algorithm, ECParameters ec)
{
X9ECParameters x9 = GetX9ECParameters(ec.Curve);
Expand Down Expand Up @@ -154,11 +245,21 @@ private static X9ECParameters GetX9ECParameters(ECCurve curve)
}
#endif

/// <summary>
/// Extract an RSA key pair from a .NET <see cref="RSA"/> object.
/// </summary>
/// <param name="rsa">The .NET RSA object.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC RSA keys.</returns>
public static AsymmetricCipherKeyPair GetRsaKeyPair(RSA rsa)
{
return GetRsaKeyPair(rsa.ExportParameters(true));
}

/// <summary>
/// Extract an RSA key pair from <see cref="RSAParameters"/>.
/// </summary>
/// <param name="rp">The .NET RSA parameters.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC RSA keys.</returns>
public static AsymmetricCipherKeyPair GetRsaKeyPair(RSAParameters rp)
{
RsaKeyParameters pubKey = GetRsaPublicKey(rp);
Expand All @@ -176,20 +277,35 @@ public static AsymmetricCipherKeyPair GetRsaKeyPair(RSAParameters rp)
return new AsymmetricCipherKeyPair(pubKey, privKey);
}

/// <summary>
/// Extract RSA public key parameters from a .NET <see cref="RSA"/> object.
/// </summary>
/// <param name="rsa">The .NET RSA object.</param>
/// <returns>An <see cref="RsaKeyParameters"/> object.</returns>
public static RsaKeyParameters GetRsaPublicKey(RSA rsa)
{
return GetRsaPublicKey(rsa.ExportParameters(false));
}

public static RsaKeyParameters GetRsaPublicKey(
RSAParameters rp)
/// <summary>
/// Extract RSA public key parameters from <see cref="RSAParameters"/>.
/// </summary>
/// <param name="rp">The .NET RSA parameters.</param>
/// <returns>An <see cref="RsaKeyParameters"/> object.</returns>
public static RsaKeyParameters GetRsaPublicKey(RSAParameters rp)
{
return new RsaKeyParameters(
false,
new BigInteger(1, rp.Modulus),
new BigInteger(1, rp.Exponent));
}

/// <summary>
/// Extract an asymmetric key pair from a .NET <see cref="AsymmetricAlgorithm"/> object.
/// </summary>
/// <param name="privateKey">The .NET private key object.</param>
/// <returns>An <see cref="AsymmetricCipherKeyPair"/> containing the BC keys.</returns>
/// <exception cref="ArgumentException">If the algorithm is not supported.</exception>
public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey)
{
if (privateKey is DSA dsa)
Expand All @@ -205,28 +321,41 @@ public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey)

throw new ArgumentException("Unsupported algorithm specified", nameof(privateKey));
}

#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
/// <summary>
/// Create a .NET <see cref="RSA"/> instance from Bouncy Castle RSA public key parameters.
/// </summary>
/// <param name="rsaKey">The BC RSA public key.</param>
/// <returns>A .NET <see cref="RSA"/> instance.</returns>
public static RSA ToRSA(RsaKeyParameters rsaKey)
{
// TODO This appears to not work for private keys (when no CRT info)
return CreateRSAProvider(ToRSAParameters(rsaKey));
}

#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
/// <summary>
/// Create a .NET <see cref="RSA"/> instance from Bouncy Castle RSA public key parameters.
/// </summary>
/// <param name="rsaKey">The BC RSA public key.</param>
/// <param name="csp">The .NET CspParameters.</param>
/// <returns>A .NET <see cref="RSA"/> instance.</returns>
public static RSA ToRSA(RsaKeyParameters rsaKey, CspParameters csp)
{
// TODO This appears to not work for private keys (when no CRT info)
return CreateRSAProvider(ToRSAParameters(rsaKey), csp);
}

#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
/// <summary>
/// Create a .NET <see cref="RSA"/> instance from Bouncy Castle RSA private CRT parameters.
/// </summary>
/// <param name="privKey">The BC RSA private CRT keys.</param>
/// <returns>A .NET <see cref="RSA"/> instance.</returns>
public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
{
return CreateRSAProvider(ToRSAParameters(privKey));
Expand All @@ -235,6 +364,12 @@ public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
/// <summary>
/// Create a .NET <see cref="RSA"/> instance from Bouncy Castle RSA private CRT parameters and CSP info.
/// </summary>
/// <param name="privKey">The BC RSA private CRT keys.</param>
/// <param name="csp">The .NET CspParameters.</param>
/// <returns>A .NET <see cref="RSA"/> instance.</returns>
public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey, CspParameters csp)
{
return CreateRSAProvider(ToRSAParameters(privKey), csp);
Expand All @@ -243,6 +378,11 @@ public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey, CspParameters csp)
#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
/// <summary>
/// Create a .NET <see cref="RSA"/> instance from Bouncy Castle RSA private CRT structure.
/// </summary>
/// <param name="privKey">The BC RSA private CRT keys.</param>
/// <returns>A .NET <see cref="RSA"/> instance.</returns>
public static RSA ToRSA(RsaPrivateKeyStructure privKey)
{
return CreateRSAProvider(ToRSAParameters(privKey));
Expand All @@ -251,11 +391,22 @@ public static RSA ToRSA(RsaPrivateKeyStructure privKey)
#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
/// <summary>
/// Create a .NET <see cref="RSA"/> instance from Bouncy Castle RSA private CRT structure and CSP info.
/// </summary>
/// <param name="privKey">The BC RSA private CRT keys.</param>
/// <param name="csp">The .NET CspParameters.</param>
/// <returns>A .NET <see cref="RSA"/> instance.</returns>
public static RSA ToRSA(RsaPrivateKeyStructure privKey, CspParameters csp)
{
return CreateRSAProvider(ToRSAParameters(privKey), csp);
}

/// <summary>
/// Convert Bouncy Castle RSA public key parameters to .NET <see cref="RSAParameters"/>.
/// </summary>
/// <param name="rsaKey">The BC RSA key.</param>
/// <returns>A .NET <see cref="RSAParameters"/> object.</returns>
public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
{
RSAParameters rp = new RSAParameters();
Expand All @@ -267,6 +418,11 @@ public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
return rp;
}

/// <summary>
/// Convert Bouncy Castle RSA private CRT parameters to .NET <see cref="RSAParameters"/>.
/// </summary>
/// <param name="privKey">The BC RSA key.</param>
/// <returns>A .NET <see cref="RSAParameters"/> object.</returns>
public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
{
RSAParameters rp = new RSAParameters();
Expand All @@ -281,6 +437,11 @@ public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
return rp;
}

/// <summary>
/// Convert Bouncy Castle RSA private CRT structure to .NET <see cref="RSAParameters"/>.
/// </summary>
/// <param name="privKey">The BC RSA key.</param>
/// <returns>A .NET <see cref="RSAParameters"/> object.</returns>
public static RSAParameters ToRSAParameters(RsaPrivateKeyStructure privKey)
{
RSAParameters rp = new RSAParameters();
Expand Down
Loading