summary refs log tree commit diff
path: root/crypto/src/openpgp/PgpSecretKey.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/openpgp/PgpSecretKey.cs')
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs105
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);
                 }