summary refs log tree commit diff
path: root/crypto/src/crypto/signers/GOST3410DigestSigner.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto/signers/GOST3410DigestSigner.cs')
-rw-r--r--crypto/src/crypto/signers/GOST3410DigestSigner.cs145
1 files changed, 145 insertions, 0 deletions
diff --git a/crypto/src/crypto/signers/GOST3410DigestSigner.cs b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
new file mode 100644
index 000000000..58aefa368
--- /dev/null
+++ b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+	public class Gost3410DigestSigner
+		: ISigner
+	{
+		private readonly IDigest digest;
+		private readonly IDsa dsaSigner;
+		private bool forSigning;
+
+		public Gost3410DigestSigner(
+			IDsa	signer,
+			IDigest	digest)
+		{
+			this.dsaSigner = signer;
+			this.digest = digest;
+		}
+
+		public string AlgorithmName
+		{
+			get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+		}
+
+		public void Init(
+			bool				forSigning,
+			ICipherParameters	parameters)
+		{
+			this.forSigning = forSigning;
+
+			AsymmetricKeyParameter k;
+			if (parameters is ParametersWithRandom)
+			{
+				k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+			}
+			else
+			{
+				k = (AsymmetricKeyParameter)parameters;
+			}
+
+			if (forSigning && !k.IsPrivate)
+			{
+				throw new InvalidKeyException("Signing Requires Private Key.");
+			}
+
+			if (!forSigning && k.IsPrivate)
+			{
+				throw new InvalidKeyException("Verification Requires Public Key.");
+			}
+
+			Reset();
+
+			dsaSigner.Init(forSigning, parameters);
+		}
+
+		/**
+		 * update the internal digest with the byte b
+		 */
+		public void Update(
+			byte input)
+		{
+			digest.Update(input);
+		}
+
+		/**
+		 * update the internal digest with the byte array in
+		 */
+		public void BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			digest.BlockUpdate(input, inOff, length);
+		}
+
+		/**
+		 * Generate a signature for the message we've been loaded with using
+		 * the key we were initialised with.
+		 */
+		public byte[] GenerateSignature()
+		{
+			if (!forSigning)
+				throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			try
+			{
+				BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+				byte[] sigBytes = new byte[64];
+
+				// TODO Add methods to allow writing BigInteger to existing byte array?
+				byte[] r = sig[0].ToByteArrayUnsigned();
+				byte[] s = sig[1].ToByteArrayUnsigned();
+				s.CopyTo(sigBytes, 32 - s.Length);
+				r.CopyTo(sigBytes, 64 - r.Length);
+				return sigBytes;
+			}
+			catch (Exception e)
+			{
+				throw new SignatureException(e.Message, e);
+			}
+		}
+
+		/// <returns>true if the internal state represents the signature described in the passed in array.</returns>
+		public bool VerifySignature(
+			byte[] signature)
+		{
+			if (forSigning)
+				throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			BigInteger R, S;
+			try
+			{
+				R = new BigInteger(1, signature, 32, 32);
+				S = new BigInteger(1, signature, 0, 32);
+			}
+			catch (Exception e)
+			{
+				throw new SignatureException("error decoding signature bytes.", e);
+			}
+
+			return dsaSigner.VerifySignature(hash, R, S);
+		}
+
+		/// <summary>Reset the internal state</summary>
+		public void Reset()
+		{
+			digest.Reset();
+		}
+	}
+}