summary refs log tree commit diff
path: root/crypto/src/crypto/engines/RSABlindedEngine.cs
blob: cdf69dddaa4393f4c093f2ca6143bbb6a6e7eac3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;

namespace Org.BouncyCastle.Crypto.Engines
{
	/**
	 * this does your basic RSA algorithm with blinding
	 */
	public class RsaBlindedEngine
		: IAsymmetricBlockCipher
	{
		private readonly RsaCoreEngine core = new RsaCoreEngine();
		private RsaKeyParameters key;
		private SecureRandom random;

		public string AlgorithmName
		{
			get { return "RSA"; }
		}

		/**
		 * 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	param)
		{
			core.Init(forEncryption, param);

			if (param is ParametersWithRandom)
			{
				ParametersWithRandom rParam = (ParametersWithRandom)param;

				key = (RsaKeyParameters)rParam.Parameters;
				random = rParam.Random;
			}
			else
			{
				key = (RsaKeyParameters)param;
				random = new SecureRandom();
			}
		}

		/**
		 * 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()
		{
			return core.GetInputBlockSize();
		}

		/**
		 * 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()
		{
			return core.GetOutputBlockSize();
		}

		/**
		 * Process a single block using the basic RSA algorithm.
		 *
		 * @param inBuf the input array.
		 * @param inOff the offset into the input buffer where the data starts.
		 * @param inLen the length of the data to be processed.
		 * @return the result of the RSA process.
		 * @exception DataLengthException the input block is too large.
		 */
		public byte[] ProcessBlock(
			byte[]	inBuf,
			int		inOff,
			int		inLen)
		{
			if (key == null)
				throw new InvalidOperationException("RSA engine not initialised");

			BigInteger input = core.ConvertInput(inBuf, inOff, inLen);

			BigInteger result;
			if (key is RsaPrivateCrtKeyParameters)
			{
				RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
				BigInteger e = k.PublicExponent;
				if (e != null)   // can't do blinding without a public exponent
				{
					BigInteger m = k.Modulus;
					BigInteger r = BigIntegers.CreateRandomInRange(
						BigInteger.One, m.Subtract(BigInteger.One), random);

					BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m);
					BigInteger blindedResult = core.ProcessBlock(blindedInput);

					BigInteger rInv = r.ModInverse(m);
					result = blindedResult.Multiply(rInv).Mod(m);
				}
				else
				{
					result = core.ProcessBlock(input);
				}
			}
			else
			{
				result = core.ProcessBlock(input);
			}

			return core.ConvertOutput(result);
		}
	}
}