diff options
Diffstat (limited to 'crypto/src/openpgp/PgpSecretKey.cs')
-rw-r--r-- | crypto/src/openpgp/PgpSecretKey.cs | 105 |
1 files changed, 95 insertions, 10 deletions
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs index 51a45703a..0103cc187 100644 --- a/crypto/src/openpgp/PgpSecretKey.cs +++ b/crypto/src/openpgp/PgpSecretKey.cs @@ -2,10 +2,17 @@ using System; using System.Collections.Generic; using System.IO; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cryptlib; +using Org.BouncyCastle.Asn1.EdEC; +using Org.BouncyCastle.Asn1.Gnu; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC.Rfc8032; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -13,6 +20,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { /// <remarks>General class to handle a PGP secret key object.</remarks> public class PgpSecretKey + : PgpObject { private readonly SecretKeyPacket secret; private readonly PgpPublicKey pub; @@ -52,10 +60,39 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp secKey = new DsaSecretBcpgKey(dsK.X); break; case PublicKeyAlgorithmTag.ECDH: + { + if (privKey.Key is ECPrivateKeyParameters ecdhK) + { + secKey = new ECSecretBcpgKey(ecdhK.D); + } + else + { + // 'reverse' because the native format for X25519 private keys is little-endian + X25519PrivateKeyParameters xK = (X25519PrivateKeyParameters)privKey.Key; + secKey = new ECSecretBcpgKey(new BigInteger(1, Arrays.ReverseInPlace(xK.GetEncoded()))); + } + break; + } case PublicKeyAlgorithmTag.ECDsa: ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey.Key; secKey = new ECSecretBcpgKey(ecK.D); break; + case PublicKeyAlgorithmTag.EdDsa: + { + if (privKey.Key is Ed25519PrivateKeyParameters ed25519K) + { + secKey = new EdSecretBcpgKey(new BigInteger(1, ed25519K.GetEncoded())); + } + else if (privKey.Key is Ed448PrivateKeyParameters ed448K) + { + secKey = new EdSecretBcpgKey(new BigInteger(1, ed448K.GetEncoded())); + } + else + { + throw new PgpException("unknown EdDSA key class"); + } + break; + } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key; @@ -625,6 +662,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp return null; PublicKeyPacket pubPk = secret.PublicKeyPacket; + try { byte[] data = ExtractKeyData(rawPassPhrase, clearPassPhrase); @@ -655,11 +693,65 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams); break; case PublicKeyAlgorithmTag.ECDH: - privateKey = GetECKey("ECDH", bcpgIn); + { + ECDHPublicBcpgKey ecdhPub = (ECDHPublicBcpgKey)pubPk.Key; + ECSecretBcpgKey ecdhPriv = new ECSecretBcpgKey(bcpgIn); + var curveOid = ecdhPub.CurveOid; + + if (EdECObjectIdentifiers.id_X25519.Equals(curveOid) || + CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) + { + // 'reverse' because the native format for X25519 private keys is little-endian + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(Arrays.ReverseInPlace(BigIntegers.AsUnsignedByteArray(ecdhPriv.X))))); + } + else if (EdECObjectIdentifiers.id_X448.Equals(curveOid)) + { + // 'reverse' because the native format for X448 private keys is little-endian + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(Arrays.ReverseInPlace(BigIntegers.AsUnsignedByteArray(ecdhPriv.X))))); + } + else + { + privateKey = new ECPrivateKeyParameters("ECDH", ecdhPriv.X, ecdhPub.CurveOid); + } break; + } case PublicKeyAlgorithmTag.ECDsa: - privateKey = GetECKey("ECDSA", bcpgIn); + { + ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)pubPk.Key; + ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn); + + privateKey = new ECPrivateKeyParameters("ECDSA", ecdsaPriv.X, ecdsaPub.CurveOid); break; + } + case PublicKeyAlgorithmTag.EdDsa: + { + EdDsaPublicBcpgKey eddsaPub = (EdDsaPublicBcpgKey)pubPk.Key; + EdSecretBcpgKey ecdsaPriv = new EdSecretBcpgKey(bcpgIn); + + var curveOid = eddsaPub.CurveOid; + if (EdECObjectIdentifiers.id_Ed25519.Equals(curveOid) || + GnuObjectIdentifiers.Ed25519.Equals(curveOid)) + { + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(BigIntegers.AsUnsignedByteArray(Ed25519.SecretKeySize, ecdsaPriv.X)))); + } + else if (EdECObjectIdentifiers.id_Ed448.Equals(curveOid)) + { + privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo( + new AlgorithmIdentifier(curveOid), + new DerOctetString(BigIntegers.AsUnsignedByteArray(Ed448.SecretKeySize, ecdsaPriv.X)))); + } + else + { + throw new InvalidOperationException(); + } + break; + } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key; @@ -683,13 +775,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } - private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn) - { - ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)secret.PublicKeyPacket.Key; - ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn); - return new ECPrivateKeyParameters(algorithm, ecdsaPriv.X, ecdsaPub.CurveOid); - } - private static byte[] Checksum( bool useSha1, byte[] bytes, @@ -699,7 +784,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { try { - IDigest dig = DigestUtilities.GetDigest("SHA1"); + IDigest dig = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); dig.BlockUpdate(bytes, 0, length); return DigestUtilities.DoFinal(dig); } |