summary refs log tree commit diff
path: root/crypto/src/openpgp/PgpSignatureGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/openpgp/PgpSignatureGenerator.cs')
-rw-r--r--crypto/src/openpgp/PgpSignatureGenerator.cs193
1 files changed, 110 insertions, 83 deletions
diff --git a/crypto/src/openpgp/PgpSignatureGenerator.cs b/crypto/src/openpgp/PgpSignatureGenerator.cs
index c5309689f..12edf9f89 100644
--- a/crypto/src/openpgp/PgpSignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -5,19 +5,20 @@ using Org.BouncyCastle.Bcpg.Sig;
 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;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
 	/// <remarks>Generator for PGP signatures.</remarks>
-	// TODO Should be able to implement ISigner?
     public class PgpSignatureGenerator
     {
 		private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
 
-		private PublicKeyAlgorithmTag	keyAlgorithm;
-        private HashAlgorithmTag		hashAlgorithm;
+		private readonly PublicKeyAlgorithmTag keyAlgorithm;
+        private readonly HashAlgorithmTag hashAlgorithm;
+
         private PgpPrivateKey			privKey;
         private ISigner					sig;
         private IDigest					dig;
@@ -35,33 +36,39 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             this.keyAlgorithm = keyAlgorithm;
             this.hashAlgorithm = hashAlgorithm;
 
-			dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
-            sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+			dig = PgpUtilities.CreateDigest(hashAlgorithm);
         }
 
 		/// <summary>Initialise the generator for signing.</summary>
         public void InitSign(
             int				sigType,
-            PgpPrivateKey	key)
+            PgpPrivateKey	privKey)
         {
-			InitSign(sigType, key, null);
+			InitSign(sigType, privKey, null);
         }
 
 		/// <summary>Initialise the generator for signing.</summary>
 		public void InitSign(
 			int				sigType,
-			PgpPrivateKey	key,
+			PgpPrivateKey privKey,
 			SecureRandom	random)
 		{
-			this.privKey = key;
+			this.privKey = privKey;
 			this.signatureType = sigType;
 
-			try
+			AsymmetricKeyParameter key = privKey.Key;
+
+			if (sig == null)
 			{
-				ICipherParameters cp = key.Key;
+                this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
+            }
+
+            try
+			{
+				ICipherParameters cp = key;
 				if (random != null)
 				{
-					cp = new ParametersWithRandom(key.Key, random);
+					cp = new ParametersWithRandom(cp, random);
 				}
 
 				sig.Init(true, cp);
@@ -75,72 +82,68 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			lastb = 0;
 		}
 
-		public void Update(
-            byte b)
+		public void Update(byte b)
         {
             if (signatureType == PgpSignature.CanonicalTextDocument)
             {
-				doCanonicalUpdateByte(b);
+				DoCanonicalUpdateByte(b);
             }
             else
             {
-				doUpdateByte(b);
+				DoUpdateByte(b);
             }
         }
 
-		private void doCanonicalUpdateByte(
-			byte b)
+		private void DoCanonicalUpdateByte(byte b)
 		{
 			if (b == '\r')
 			{
-				doUpdateCRLF();
+				DoUpdateCRLF();
 			}
 			else if (b == '\n')
 			{
 				if (lastb != '\r')
 				{
-					doUpdateCRLF();
+					DoUpdateCRLF();
 				}
 			}
 			else
 			{
-				doUpdateByte(b);
+				DoUpdateByte(b);
 			}
 
 			lastb = b;
 		}
 
-		private void doUpdateCRLF()
+		private void DoUpdateCRLF()
 		{
-			doUpdateByte((byte)'\r');
-			doUpdateByte((byte)'\n');
+			DoUpdateByte((byte)'\r');
+			DoUpdateByte((byte)'\n');
 		}
 
-		private void doUpdateByte(
-			byte b)
+		private void DoUpdateByte(byte b)
 		{
 			sig.Update(b);
 			dig.Update(b);
 		}
 
-		public void Update(
-            params byte[] b)
+		public void Update(params byte[] b)
         {
 			Update(b, 0, b.Length);
         }
 
-		public void Update(
-            byte[]	b,
-            int		off,
-            int		len)
+		public void Update(byte[] b, int off, int len)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Update(b.AsSpan(off, len));
+#else
             if (signatureType == PgpSignature.CanonicalTextDocument)
             {
                 int finish = off + len;
 
 				for (int i = off; i != finish; i++)
                 {
-                    doCanonicalUpdateByte(b[i]);
+                    DoCanonicalUpdateByte(b[i]);
                 }
             }
             else
@@ -148,9 +151,28 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 sig.BlockUpdate(b, off, len);
                 dig.BlockUpdate(b, off, len);
             }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void Update(ReadOnlySpan<byte> input)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                for (int i = 0; i < input.Length; ++i)
+                {
+                    DoCanonicalUpdateByte(input[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(input);
+                dig.BlockUpdate(input);
+            }
         }
+#endif
 
-		public void SetHashedSubpackets(
+        public void SetHashedSubpackets(
             PgpSignatureSubpacketVector hashedPackets)
         {
 			hashed = hashedPackets == null
@@ -180,15 +202,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
 			SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed;
 
-			if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
+			if (!IsPacketPresent(hashed, SignatureSubpacketTag.CreationTime))
 			{
-				hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
+				hPkts = InsertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
 			}
 
-			if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
-				&& !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
+			if (!IsPacketPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
+				&& !IsPacketPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
 			{
-				unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
+				unhPkts = InsertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
 			}
 
 			int version = 4;
@@ -239,17 +261,41 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 			byte[] sigBytes = sig.GenerateSignature();
 			byte[] digest = DigestUtilities.DoFinal(dig);
-			byte[] fingerPrint = new byte[] { digest[0], digest[1] };
+			byte[] fingerPrint = new byte[2]{ digest[0], digest[1] };
 
-			// an RSA signature
-			bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
-				|| keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
-
-			MPInteger[] sigValues = isRsa
-				?	PgpUtilities.RsaSigToMpi(sigBytes)
-				:	PgpUtilities.DsaSigToMpi(sigBytes);
+			MPInteger[] sigValues;
+            if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa)
+            {
+                int sigLen = sigBytes.Length;
+                if (sigLen == Ed25519.SignatureSize)
+				{
+					sigValues = new MPInteger[2]{
+						new MPInteger(new BigInteger(1, sigBytes,  0, 32)),
+						new MPInteger(new BigInteger(1, sigBytes, 32, 32))
+					};
+				}
+                else if (sigLen == Ed448.SignatureSize)
+                {
+                    sigValues = new MPInteger[2]{
+                        new MPInteger(new BigInteger(1, Arrays.Prepend(sigBytes, 0x40))),
+                        new MPInteger(BigInteger.Zero)
+                    };
+                }
+                else
+				{
+					throw new InvalidOperationException();
+				}
+            }
+			else if (keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral)
+			{
+                sigValues = PgpUtilities.RsaSigToMpi(sigBytes);
+            }
+			else
+			{
+                sigValues = PgpUtilities.DsaSigToMpi(sigBytes);
+            }
 
-			return new PgpSignature(
+            return new PgpSignature(
 				new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm,
 					hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues));
         }
@@ -258,9 +304,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// <param name="id">The ID we are certifying against the public key.</param>
 		/// <param name="pubKey">The key we are certifying against the ID.</param>
 		/// <returns>The certification.</returns>
-        public PgpSignature GenerateCertification(
-            string			id,
-            PgpPublicKey	pubKey)
+        public PgpSignature GenerateCertification(string id, PgpPublicKey pubKey)
         {
 			UpdateWithPublicKey(pubKey);
 
@@ -276,9 +320,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// <param name="userAttributes">The ID we are certifying against the public key.</param>
 		/// <param name="pubKey">The key we are certifying against the ID.</param>
 		/// <returns>The certification.</returns>
-		public PgpSignature GenerateCertification(
-			PgpUserAttributeSubpacketVector	userAttributes,
-			PgpPublicKey					pubKey)
+		public PgpSignature GenerateCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey pubKey)
 		{
 			UpdateWithPublicKey(pubKey);
 
@@ -287,7 +329,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			//
 			try
 			{
-				MemoryStream bOut = new MemoryStream();
+				var bOut = new MemoryStream();
 				foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
 				{
 					packet.Encode(bOut);
@@ -299,16 +341,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 				throw new PgpException("cannot encode subpacket array", e);
 			}
 
-			return this.Generate();
+			return Generate();
 		}
 
 		/// <summary>Generate a certification for the passed in key against the passed in master key.</summary>
 		/// <param name="masterKey">The key we are certifying against.</param>
 		/// <param name="pubKey">The key we are certifying.</param>
 		/// <returns>The certification.</returns>
-        public PgpSignature GenerateCertification(
-            PgpPublicKey	masterKey,
-            PgpPublicKey	pubKey)
+        public PgpSignature GenerateCertification(PgpPublicKey masterKey, PgpPublicKey pubKey)
         {
 			UpdateWithPublicKey(masterKey);
 			UpdateWithPublicKey(pubKey);
@@ -319,16 +359,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// <summary>Generate a certification, such as a revocation, for the passed in key.</summary>
 		/// <param name="pubKey">The key we are certifying.</param>
 		/// <returns>The certification.</returns>
-        public PgpSignature GenerateCertification(
-            PgpPublicKey pubKey)
+        public PgpSignature GenerateCertification(PgpPublicKey pubKey)
         {
 			UpdateWithPublicKey(pubKey);
 
 			return Generate();
         }
 
-		private byte[] GetEncodedPublicKey(
-			PgpPublicKey pubKey) 
+		private static byte[] GetEncodedPublicKey(PgpPublicKey pubKey) 
 		{
 			try
 			{
@@ -340,42 +378,31 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			}
 		}
 
-		private bool packetPresent(
-			SignatureSubpacket[]	packets,
-			SignatureSubpacketTag	type)
+		private static bool IsPacketPresent(SignatureSubpacket[] packets, SignatureSubpacketTag type)
 		{
 			for (int i = 0; i != packets.Length; i++)
 			{
 				if (packets[i].SubpacketType == type)
-				{
 					return true;
-				}
 			}
 
 			return false;
 		}
 
-		private SignatureSubpacket[] insertSubpacket(
-			SignatureSubpacket[]	packets,
-			SignatureSubpacket		subpacket)
+		private static SignatureSubpacket[] InsertSubpacket(SignatureSubpacket[] packets, SignatureSubpacket subpacket)
 		{
-			SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1];
-			tmp[0] = subpacket;
-			packets.CopyTo(tmp, 1);
-			return tmp;
+			return Arrays.Prepend(packets, subpacket);
 		}
 
-		private void UpdateWithIdData(
-			int		header,
-			byte[]	idBytes)
+		private void UpdateWithIdData(int header, byte[] idBytes)
 		{
-			this.Update(
+			Update(
 				(byte) header,
 				(byte)(idBytes.Length >> 24),
 				(byte)(idBytes.Length >> 16),
 				(byte)(idBytes.Length >> 8),
 				(byte)(idBytes.Length));
-			this.Update(idBytes);
+			Update(idBytes);
 		}
 
 		private void UpdateWithPublicKey(
@@ -383,11 +410,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		{
 			byte[] keyBytes = GetEncodedPublicKey(key);
 
-			this.Update(
-				(byte) 0x99,
+			Update(
+				0x99,
 				(byte)(keyBytes.Length >> 8),
 				(byte)(keyBytes.Length));
-			this.Update(keyBytes);
+			Update(keyBytes);
 		}
 	}
 }