summary refs log tree commit diff
path: root/crypto/src/openpgp/PgpV3SignatureGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/openpgp/PgpV3SignatureGenerator.cs')
-rw-r--r--crypto/src/openpgp/PgpV3SignatureGenerator.cs199
1 files changed, 199 insertions, 0 deletions
diff --git a/crypto/src/openpgp/PgpV3SignatureGenerator.cs b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
new file mode 100644
index 000000000..fc8b42df2
--- /dev/null
+++ b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
@@ -0,0 +1,199 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Generator for old style PGP V3 Signatures.</remarks>
+	// TODO Should be able to implement ISigner?
+	public class PgpV3SignatureGenerator
+    {
+        private PublicKeyAlgorithmTag keyAlgorithm;
+        private HashAlgorithmTag hashAlgorithm;
+        private PgpPrivateKey privKey;
+        private ISigner sig;
+        private IDigest    dig;
+        private int signatureType;
+        private byte lastb;
+
+		/// <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        public PgpV3SignatureGenerator(
+            PublicKeyAlgorithmTag	keyAlgorithm,
+            HashAlgorithmTag		hashAlgorithm)
+        {
+            this.keyAlgorithm = keyAlgorithm;
+            this.hashAlgorithm = hashAlgorithm;
+
+            dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
+            sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+        }
+
+		/// <summary>Initialise the generator for signing.</summary>
+		public void InitSign(
+			int				sigType,
+			PgpPrivateKey	key)
+		{
+			InitSign(sigType, key, null);
+		}
+
+		/// <summary>Initialise the generator for signing.</summary>
+        public void InitSign(
+            int				sigType,
+            PgpPrivateKey	key,
+			SecureRandom	random)
+        {
+            this.privKey = key;
+            this.signatureType = sigType;
+
+			try
+            {
+				ICipherParameters cp = key.Key;
+				if (random != null)
+				{
+					cp = new ParametersWithRandom(key.Key, random);
+				}
+
+				sig.Init(true, cp);
+            }
+            catch (InvalidKeyException e)
+            {
+                throw new PgpException("invalid key.", e);
+            }
+
+			dig.Reset();
+            lastb = 0;
+        }
+
+		public void Update(
+            byte b)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+				doCanonicalUpdateByte(b);
+            }
+            else
+            {
+				doUpdateByte(b);
+            }
+        }
+
+		private void doCanonicalUpdateByte(
+			byte b)
+		{
+			if (b == '\r')
+			{
+				doUpdateCRLF();
+			}
+			else if (b == '\n')
+			{
+				if (lastb != '\r')
+				{
+					doUpdateCRLF();
+				}
+			}
+			else
+			{
+				doUpdateByte(b);
+			}
+
+			lastb = b;
+		}
+
+		private void doUpdateCRLF()
+		{
+			doUpdateByte((byte)'\r');
+			doUpdateByte((byte)'\n');
+		}
+
+		private void doUpdateByte(
+			byte b)
+		{
+			sig.Update(b);
+			dig.Update(b);
+		}
+
+		public void Update(
+            byte[] b)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                for (int i = 0; i != b.Length; i++)
+                {
+                    doCanonicalUpdateByte(b[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(b, 0, b.Length);
+                dig.BlockUpdate(b, 0, b.Length);
+            }
+        }
+
+		public void Update(
+            byte[]	b,
+            int		off,
+            int		len)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                int finish = off + len;
+
+				for (int i = off; i != finish; i++)
+                {
+                    doCanonicalUpdateByte(b[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(b, off, len);
+                dig.BlockUpdate(b, off, len);
+            }
+        }
+
+		/// <summary>Return the one pass header associated with the current signature.</summary>
+        public PgpOnePassSignature GenerateOnePassVersion(
+            bool isNested)
+        {
+            return new PgpOnePassSignature(
+				new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
+        }
+
+		/// <summary>Return a V3 signature object containing the current signature state.</summary>
+        public PgpSignature Generate()
+        {
+            long creationTime = DateTimeUtilities.CurrentUnixMs() / 1000L;
+
+			byte[] hData = new byte[]
+			{
+				(byte) signatureType,
+				(byte)(creationTime >> 24),
+				(byte)(creationTime >> 16),
+				(byte)(creationTime >> 8),
+				(byte) creationTime
+			};
+
+			sig.BlockUpdate(hData, 0, hData.Length);
+            dig.BlockUpdate(hData, 0, hData.Length);
+
+			byte[] sigBytes = sig.GenerateSignature();
+			byte[] digest = DigestUtilities.DoFinal(dig);
+			byte[] fingerPrint = new byte[]{ digest[0], digest[1] };
+
+			// an RSA signature
+			bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
+                || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
+
+			MPInteger[] sigValues = isRsa
+				?	PgpUtilities.RsaSigToMpi(sigBytes)
+				:	PgpUtilities.DsaSigToMpi(sigBytes);
+
+			return new PgpSignature(
+				new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm,
+					hashAlgorithm, creationTime * 1000L, fingerPrint, sigValues));
+        }
+    }
+}