summary refs log tree commit diff
path: root/Crypto/src/crypto/signers/RsaDigestSigner.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/signers/RsaDigestSigner.cs')
-rw-r--r--Crypto/src/crypto/signers/RsaDigestSigner.cs228
1 files changed, 228 insertions, 0 deletions
diff --git a/Crypto/src/crypto/signers/RsaDigestSigner.cs b/Crypto/src/crypto/signers/RsaDigestSigner.cs
new file mode 100644
index 000000000..f57bfc83d
--- /dev/null
+++ b/Crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -0,0 +1,228 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class RsaDigestSigner
+		: ISigner
+    {
+        private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
+        private readonly AlgorithmIdentifier algId;
+		private readonly IDigest digest;
+		private bool forSigning;
+
+		private static readonly IDictionary oidMap = Platform.CreateHashtable();
+
+		/// <summary>
+        /// Load oid table.
+        /// </summary>
+        static RsaDigestSigner()
+        {
+            oidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+            oidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+            oidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+
+            oidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1;
+            oidMap["SHA-224"] = NistObjectIdentifiers.IdSha224;
+            oidMap["SHA-256"] = NistObjectIdentifiers.IdSha256;
+            oidMap["SHA-384"] = NistObjectIdentifiers.IdSha384;
+            oidMap["SHA-512"] = NistObjectIdentifiers.IdSha512;
+
+            oidMap["MD2"] = PkcsObjectIdentifiers.MD2;
+            oidMap["MD4"] = PkcsObjectIdentifiers.MD4;
+            oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
+        }
+
+		public RsaDigestSigner(
+			IDigest digest)
+        {
+            this.digest = digest;
+
+			string algName = digest.AlgorithmName;
+			if (algName.Equals("NULL"))
+			{
+				this.algId = null;
+			}
+			else
+			{
+				this.algId = new AlgorithmIdentifier(
+					(DerObjectIdentifier)oidMap[digest.AlgorithmName], DerNull.Instance);
+			}
+        }
+
+		public string AlgorithmName
+        {
+            get { return digest.AlgorithmName + "withRSA"; }
+        }
+
+		/**
+         * Initialise the signer for signing or verification.
+         *
+         * @param forSigning true if for signing, false otherwise
+         * @param param necessary parameters.
+         */
+        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();
+
+            rsaEngine.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("RsaDigestSigner not initialised for signature generation.");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+			byte[] data = DerEncode(hash);
+            return rsaEngine.ProcessBlock(data, 0, data.Length);
+        }
+
+		/**
+         * return true if the internal state represents the signature described
+         * in the passed in array.
+         */
+        public bool VerifySignature(
+			byte[] signature)
+        {
+			if (forSigning)
+				throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			byte[] sig;
+			byte[] expected;
+
+			try
+			{
+				sig = rsaEngine.ProcessBlock(signature, 0, signature.Length);
+				expected = DerEncode(hash);
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+
+			if (sig.Length == expected.Length)
+			{
+				for (int i = 0; i < sig.Length; i++)
+				{
+					if (sig[i] != expected[i])
+					{
+						return false;
+					}
+				}
+			}
+			else if (sig.Length == expected.Length - 2)  // NULL left out
+			{
+				int sigOffset = sig.Length - hash.Length - 2;
+				int expectedOffset = expected.Length - hash.Length - 2;
+
+				expected[1] -= 2;      // adjust lengths
+				expected[3] -= 2;
+
+				for (int i = 0; i < hash.Length; i++)
+				{
+					if (sig[sigOffset + i] != expected[expectedOffset + i])  // check hash
+					{
+						return false;
+					}
+				}
+
+				for (int i = 0; i < sigOffset; i++)
+				{
+					if (sig[i] != expected[i])  // check header less NULL
+					{
+						return false;
+					}
+				}
+			}
+			else
+			{
+				return false;
+			}
+
+			return true;
+        }
+
+        public void Reset()
+        {
+            digest.Reset();
+        }
+
+		private byte[] DerEncode(byte[] hash)
+		{
+			if (algId == null)
+			{
+				// For raw RSA, the DigestInfo must be prepared externally
+				return hash;
+			}
+
+			DigestInfo dInfo = new DigestInfo(algId, hash);
+
+			return dInfo.GetDerEncoded();
+		}
+    }
+}