summary refs log tree commit diff
path: root/Crypto/src/crypto/engines/RSACoreEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/engines/RSACoreEngine.cs')
-rw-r--r--Crypto/src/crypto/engines/RSACoreEngine.cs156
1 files changed, 156 insertions, 0 deletions
diff --git a/Crypto/src/crypto/engines/RSACoreEngine.cs b/Crypto/src/crypto/engines/RSACoreEngine.cs
new file mode 100644
index 000000000..4e64d25d6
--- /dev/null
+++ b/Crypto/src/crypto/engines/RSACoreEngine.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* this does your basic RSA algorithm.
+	*/
+	class RsaCoreEngine
+	{
+		private RsaKeyParameters	key;
+		private bool				forEncryption;
+		private int					bitSize;
+
+		/**
+		* initialise the RSA engine.
+		*
+		* @param forEncryption true if we are encrypting, false otherwise.
+		* @param param the necessary RSA key parameters.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			if (!(parameters is RsaKeyParameters))
+				throw new InvalidKeyException("Not an RSA key");
+
+			this.key = (RsaKeyParameters) parameters;
+			this.forEncryption = forEncryption;
+			this.bitSize = key.Modulus.BitLength;
+		}
+
+		/**
+		* Return the maximum size for an input block to this engine.
+		* For RSA this is always one byte less than the key size on
+		* encryption, and the same length as the key size on decryption.
+		*
+		* @return maximum size for an input block.
+		*/
+		public int GetInputBlockSize()
+		{
+			if (forEncryption)
+			{
+				return (bitSize - 1) / 8;
+			}
+
+			return (bitSize + 7) / 8;
+		}
+
+		/**
+		* Return the maximum size for an output block to this engine.
+		* For RSA this is always one byte less than the key size on
+		* decryption, and the same length as the key size on encryption.
+		*
+		* @return maximum size for an output block.
+		*/
+		public int GetOutputBlockSize()
+		{
+			if (forEncryption)
+			{
+				return (bitSize + 7) / 8;
+			}
+
+			return (bitSize - 1) / 8;
+		}
+
+		public BigInteger ConvertInput(
+			byte[]	inBuf,
+			int		inOff,
+			int		inLen)
+		{
+			int maxLength = (bitSize + 7) / 8;
+
+			if (inLen > maxLength)
+				throw new DataLengthException("input too large for RSA cipher.");
+
+			BigInteger input = new BigInteger(1, inBuf, inOff, inLen);
+
+			if (input.CompareTo(key.Modulus) >= 0)
+				throw new DataLengthException("input too large for RSA cipher.");
+
+			return input;
+		}
+
+		public byte[] ConvertOutput(
+			BigInteger result)
+		{
+			byte[] output = result.ToByteArrayUnsigned();
+
+			if (forEncryption)
+			{
+				int outSize = GetOutputBlockSize();
+
+				// TODO To avoid this, create version of BigInteger.ToByteArray that
+				// writes to an existing array
+				if (output.Length < outSize) // have ended up with less bytes than normal, lengthen
+				{
+					byte[] tmp = new byte[outSize];
+					output.CopyTo(tmp, tmp.Length - output.Length);
+					output = tmp;
+				}
+			}
+
+			return output;
+		}
+
+		public BigInteger ProcessBlock(
+			BigInteger input)
+		{
+			if (key is RsaPrivateCrtKeyParameters)
+			{
+				//
+				// we have the extra factors, use the Chinese Remainder Theorem - the author
+				// wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+				// advice regarding the expression of this.
+				//
+				RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
+
+				BigInteger p = crtKey.P;;
+				BigInteger q = crtKey.Q;
+				BigInteger dP = crtKey.DP;
+				BigInteger dQ = crtKey.DQ;
+				BigInteger qInv = crtKey.QInv;
+
+				BigInteger mP, mQ, h, m;
+
+				// mP = ((input Mod p) ^ dP)) Mod p
+				mP = (input.Remainder(p)).ModPow(dP, p);
+
+				// mQ = ((input Mod q) ^ dQ)) Mod q
+				mQ = (input.Remainder(q)).ModPow(dQ, q);
+
+				// h = qInv * (mP - mQ) Mod p
+				h = mP.Subtract(mQ);
+				h = h.Multiply(qInv);
+				h = h.Mod(p);               // Mod (in Java) returns the positive residual
+
+				// m = h * q + mQ
+				m = h.Multiply(q);
+				m = m.Add(mQ);
+
+				return m;
+			}
+
+			return input.ModPow(key.Exponent, key.Modulus);
+		}
+	}
+}