diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-11-05 15:40:09 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-11-05 15:40:09 +0700 |
commit | 7f43ba84bd30b99d0e957920aa660a45f998c522 (patch) | |
tree | 7c6f4738d69ab3def1416c397752a3b63b66738f /crypto/src/bcpg | |
parent | Update package icon (diff) | |
download | BouncyCastle.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.cs | 16 | ||||
-rw-r--r-- | crypto/src/bcpg/ECSecretBCPGKey.cs | 11 | ||||
-rw-r--r-- | crypto/src/bcpg/EdDsaPublicBcpgKey.cs | 25 | ||||
-rw-r--r-- | crypto/src/bcpg/EdSecretBcpgKey.cs | 43 | ||||
-rw-r--r-- | crypto/src/bcpg/PublicKeyPacket.cs | 47 | ||||
-rw-r--r-- | crypto/src/bcpg/SignaturePacket.cs | 100 |
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 |