summary refs log tree commit diff
path: root/crypto/src/bcpg
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-11-05 15:40:09 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-11-05 15:40:09 +0700
commit7f43ba84bd30b99d0e957920aa660a45f998c522 (patch)
tree7c6f4738d69ab3def1416c397752a3b63b66738f /crypto/src/bcpg
parentUpdate package icon (diff)
downloadBouncyCastle.NET-ed25519-7f43ba84bd30b99d0e957920aa660a45f998c522.tar.xz
Port OpenPGP support for XDH, EdDSA from bc-java
- see https://github.com/bcgit/bc-csharp/issues/345
Diffstat (limited to 'crypto/src/bcpg')
-rw-r--r--crypto/src/bcpg/ECDHPublicBCPGKey.cs16
-rw-r--r--crypto/src/bcpg/ECSecretBCPGKey.cs11
-rw-r--r--crypto/src/bcpg/EdDsaPublicBcpgKey.cs25
-rw-r--r--crypto/src/bcpg/EdSecretBcpgKey.cs43
-rw-r--r--crypto/src/bcpg/PublicKeyPacket.cs47
-rw-r--r--crypto/src/bcpg/SignaturePacket.cs100
6 files changed, 161 insertions, 81 deletions
diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
index 5b6d9460e..e43100d3a 100644
--- a/crypto/src/bcpg/ECDHPublicBCPGKey.cs
+++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
 
 namespace Org.BouncyCastle.Bcpg
@@ -51,6 +52,21 @@ namespace Org.BouncyCastle.Bcpg
             VerifySymmetricKeyAlgorithm();
         }
 
+        public ECDHPublicBcpgKey(
+            DerObjectIdentifier oid,
+            BigInteger point,
+            HashAlgorithmTag hashAlgorithm,
+            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
+            : base(oid, point)
+        {
+            reserved = 1;
+            hashFunctionId = hashAlgorithm;
+            symAlgorithmId = symmetricKeyAlgorithm;
+
+            VerifyHashAlgorithm();
+            VerifySymmetricKeyAlgorithm();
+        }
+
         public virtual byte Reserved
         {
             get { return reserved; }
diff --git a/crypto/src/bcpg/ECSecretBCPGKey.cs b/crypto/src/bcpg/ECSecretBCPGKey.cs
index 22e0a3473..eef632263 100644
--- a/crypto/src/bcpg/ECSecretBCPGKey.cs
+++ b/crypto/src/bcpg/ECSecretBCPGKey.cs
@@ -1,6 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Math;
 
 namespace Org.BouncyCastle.Bcpg
@@ -9,18 +8,18 @@ namespace Org.BouncyCastle.Bcpg
     public class ECSecretBcpgKey
         : BcpgObject, IBcpgKey
     {
-        internal MPInteger x;
+        internal readonly MPInteger m_x;
 
         public ECSecretBcpgKey(
             BcpgInputStream bcpgIn)
         {
-            this.x = new MPInteger(bcpgIn);
+            m_x = new MPInteger(bcpgIn);
         }
 
         public ECSecretBcpgKey(
             BigInteger x)
         {
-            this.x = new MPInteger(x);
+            m_x = new MPInteger(x);
         }
 
 		/// <summary>The format, as a string, always "PGP".</summary>
@@ -45,12 +44,12 @@ namespace Org.BouncyCastle.Bcpg
         public override void Encode(
             BcpgOutputStream bcpgOut)
         {
-            bcpgOut.WriteObject(x);
+            bcpgOut.WriteObject(m_x);
         }
 
         public virtual BigInteger X
         {
-            get { return x.Value; }
+            get { return m_x.Value; }
         }
     }
 }
diff --git a/crypto/src/bcpg/EdDsaPublicBcpgKey.cs b/crypto/src/bcpg/EdDsaPublicBcpgKey.cs
new file mode 100644
index 000000000..f3250b746
--- /dev/null
+++ b/crypto/src/bcpg/EdDsaPublicBcpgKey.cs
@@ -0,0 +1,25 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    public sealed class EdDsaPublicBcpgKey
+        : ECPublicBcpgKey
+    {
+        internal EdDsaPublicBcpgKey(BcpgInputStream bcpgIn)
+            : base(bcpgIn)
+        {
+        }
+
+        public EdDsaPublicBcpgKey(DerObjectIdentifier oid, ECPoint point)
+            : base(oid, point)
+        {
+        }
+
+        public EdDsaPublicBcpgKey(DerObjectIdentifier oid, BigInteger encodedPoint)
+            : base(oid, encodedPoint)
+        {
+        }
+    }
+}
diff --git a/crypto/src/bcpg/EdSecretBcpgKey.cs b/crypto/src/bcpg/EdSecretBcpgKey.cs
new file mode 100644
index 000000000..5b53f558d
--- /dev/null
+++ b/crypto/src/bcpg/EdSecretBcpgKey.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    public sealed class EdSecretBcpgKey
+        : BcpgObject, IBcpgKey
+    {
+        internal readonly MPInteger m_x;
+
+        public EdSecretBcpgKey(BcpgInputStream bcpgIn)
+        {
+            m_x = new MPInteger(bcpgIn);
+        }
+
+        public EdSecretBcpgKey(BigInteger x)
+        {
+            m_x = new MPInteger(x);
+        }
+
+        public string Format => "PGP";
+
+        public override byte[] GetEncoded()
+        {
+            try
+            {
+                return base.GetEncoded();
+            }
+            catch (Exception)
+            {
+                return null;
+            }
+        }
+
+        public override void Encode(BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WriteObject(m_x);
+        }
+
+        public BigInteger X => m_x.Value;
+    }
+}
diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs
index bbed941dc..40c696a37 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -28,30 +28,33 @@ namespace Org.BouncyCastle.Bcpg
                 validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
             }
 
-            algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+            algorithm = (PublicKeyAlgorithmTag)bcpgIn.ReadByte();
 
-            switch ((PublicKeyAlgorithmTag) algorithm)
+            switch (algorithm)
             {
-                case PublicKeyAlgorithmTag.RsaEncrypt:
-                case PublicKeyAlgorithmTag.RsaGeneral:
-                case PublicKeyAlgorithmTag.RsaSign:
-                    key = new RsaPublicBcpgKey(bcpgIn);
-                    break;
-                case PublicKeyAlgorithmTag.Dsa:
-                    key = new DsaPublicBcpgKey(bcpgIn);
-                    break;
-                case PublicKeyAlgorithmTag.ElGamalEncrypt:
-                case PublicKeyAlgorithmTag.ElGamalGeneral:
-                    key = new ElGamalPublicBcpgKey(bcpgIn);
-                    break;
-                case PublicKeyAlgorithmTag.ECDH:
-                    key = new ECDHPublicBcpgKey(bcpgIn);
-                    break;
-                case PublicKeyAlgorithmTag.ECDsa:
-                    key = new ECDsaPublicBcpgKey(bcpgIn);
-                    break;
-                default:
-                    throw new IOException("unknown PGP public key algorithm encountered");
+            case PublicKeyAlgorithmTag.RsaEncrypt:
+            case PublicKeyAlgorithmTag.RsaGeneral:
+            case PublicKeyAlgorithmTag.RsaSign:
+                key = new RsaPublicBcpgKey(bcpgIn);
+                break;
+            case PublicKeyAlgorithmTag.Dsa:
+                key = new DsaPublicBcpgKey(bcpgIn);
+                break;
+            case PublicKeyAlgorithmTag.ElGamalEncrypt:
+            case PublicKeyAlgorithmTag.ElGamalGeneral:
+                key = new ElGamalPublicBcpgKey(bcpgIn);
+                break;
+            case PublicKeyAlgorithmTag.ECDH:
+                key = new ECDHPublicBcpgKey(bcpgIn);
+                break;
+            case PublicKeyAlgorithmTag.ECDsa:
+                key = new ECDsaPublicBcpgKey(bcpgIn);
+                break;
+            case PublicKeyAlgorithmTag.EdDsa:
+                key = new EdDsaPublicBcpgKey(bcpgIn);
+                break;
+            default:
+                throw new IOException("unknown PGP public key algorithm encountered");
             }
         }
 
diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
index dd9cc78e3..a0e8588b3 100644
--- a/crypto/src/bcpg/SignaturePacket.cs
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Bcpg
 {
 	/// <remarks>Generic signature packet.</remarks>
     public class SignaturePacket
-        : ContainedPacket //, PublicKeyAlgorithmTag
+        : ContainedPacket
     {
 		private int						version;
         private int						signatureType;
@@ -128,41 +128,38 @@ namespace Org.BouncyCastle.Bcpg
                 case PublicKeyAlgorithmTag.RsaGeneral:
                 case PublicKeyAlgorithmTag.RsaSign:
                     MPInteger v = new MPInteger(bcpgIn);
-					signature = new MPInteger[]{ v };
+					signature = new MPInteger[1]{ v };
                     break;
 				case PublicKeyAlgorithmTag.Dsa:
                     MPInteger r = new MPInteger(bcpgIn);
                     MPInteger s = new MPInteger(bcpgIn);
-					signature = new MPInteger[]{ r, s };
+					signature = new MPInteger[2]{ r, s };
                     break;
                 case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes.
                 case PublicKeyAlgorithmTag.ElGamalGeneral:
                     MPInteger p = new MPInteger(bcpgIn);
                     MPInteger g = new MPInteger(bcpgIn);
                     MPInteger y = new MPInteger(bcpgIn);
-					signature = new MPInteger[]{ p, g, y };
+					signature = new MPInteger[3]{ p, g, y };
                     break;
                 case PublicKeyAlgorithmTag.ECDsa:
+                case PublicKeyAlgorithmTag.EdDsa:
                     MPInteger ecR = new MPInteger(bcpgIn);
                     MPInteger ecS = new MPInteger(bcpgIn);
-                    signature = new MPInteger[]{ ecR, ecS };
+                    signature = new MPInteger[2]{ ecR, ecS };
                     break;
                 default:
-					if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11)
-					{
-						signature = null;
-						MemoryStream bOut = new MemoryStream();
-						int ch;
-						while ((ch = bcpgIn.ReadByte()) >= 0)
-						{
-							bOut.WriteByte((byte) ch);
-						}
-						signatureEncoding = bOut.ToArray();
-					}
-					else
+					if (keyAlgorithm < PublicKeyAlgorithmTag.Experimental_1 || keyAlgorithm > PublicKeyAlgorithmTag.Experimental_11)
+                        throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
+
+                    signature = null;
+					MemoryStream bOut = new MemoryStream();
+					int ch;
+					while ((ch = bcpgIn.ReadByte()) >= 0)
 					{
-						throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
+						bOut.WriteByte((byte) ch);
 					}
+					signatureEncoding = bOut.ToArray();
 					break;
             }
         }
@@ -268,56 +265,53 @@ namespace Org.BouncyCastle.Bcpg
         */
         public byte[] GetSignatureTrailer()
         {
-            byte[] trailer = null;
-
 			if (version == 3)
             {
-                trailer = new byte[5];
-
-				long time = creationTime / 1000L;
+                long time = creationTime / 1000L;
 
+                byte[] trailer = new byte[5];
 				trailer[0] = (byte)signatureType;
                 trailer[1] = (byte)(time >> 24);
                 trailer[2] = (byte)(time >> 16);
-                trailer[3] = (byte)(time >> 8);
-                trailer[4] = (byte)(time);
+                trailer[3] = (byte)(time >>  8);
+                trailer[4] = (byte)(time      );
+                return trailer;
             }
-            else
-            {
-                MemoryStream sOut = new MemoryStream();
 
-				sOut.WriteByte((byte)this.Version);
-                sOut.WriteByte((byte)this.SignatureType);
-                sOut.WriteByte((byte)this.KeyAlgorithm);
-                sOut.WriteByte((byte)this.HashAlgorithm);
+            MemoryStream sOut = new MemoryStream();
 
-				MemoryStream hOut = new MemoryStream();
-                SignatureSubpacket[] hashed = this.GetHashedSubPackets();
+			sOut.WriteByte((byte)Version);
+            sOut.WriteByte((byte)SignatureType);
+            sOut.WriteByte((byte)KeyAlgorithm);
+            sOut.WriteByte((byte)HashAlgorithm);
 
-				for (int i = 0; i != hashed.Length; i++)
-                {
-                    hashed[i].Encode(hOut);
-                }
-
-				byte[] data = hOut.ToArray();
+            // Mark position an reserve two bytes for length
+            long lengthPosition = sOut.Position;
+            sOut.WriteByte(0x00);
+            sOut.WriteByte(0x00);
 
-				sOut.WriteByte((byte)(data.Length >> 8));
-                sOut.WriteByte((byte)data.Length);
-                sOut.Write(data, 0, data.Length);
+            SignatureSubpacket[] hashed = GetHashedSubPackets();
+			for (int i = 0; i != hashed.Length; i++)
+            {
+                hashed[i].Encode(sOut);
+            }
 
-				byte[] hData = sOut.ToArray();
+            ushort dataLength = Convert.ToUInt16(sOut.Position - lengthPosition - 2);
+            uint hDataLength = Convert.ToUInt32(sOut.Position);
 
-				sOut.WriteByte((byte)this.Version);
-                sOut.WriteByte((byte)0xff);
-                sOut.WriteByte((byte)(hData.Length>> 24));
-                sOut.WriteByte((byte)(hData.Length >> 16));
-                sOut.WriteByte((byte)(hData.Length >> 8));
-                sOut.WriteByte((byte)(hData.Length));
+			sOut.WriteByte((byte)Version);
+            sOut.WriteByte(0xff);
+            sOut.WriteByte((byte)(hDataLength >> 24));
+            sOut.WriteByte((byte)(hDataLength >> 16));
+            sOut.WriteByte((byte)(hDataLength >>  8));
+            sOut.WriteByte((byte)(hDataLength      ));
 
-				trailer = sOut.ToArray();
-            }
+            // Reset position and fill in length
+            sOut.Position = lengthPosition;
+            sOut.WriteByte((byte)(dataLength >> 8));
+            sOut.WriteByte((byte)(dataLength     ));
 
-			return trailer;
+            return sOut.ToArray();
         }
 
 		public PublicKeyAlgorithmTag KeyAlgorithm