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 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; if (k.PublicExponent != null) // can't do blinding without a public exponent { BigInteger m = k.Modulus; BigInteger r = calculateR(m); BigInteger blindedInput = r.ModPow(k.PublicExponent, m).Multiply(input).Mod(m); BigInteger blindedResult = core.ProcessBlock(blindedInput); result = blindedResult.Multiply(r.ModInverse(m)).Mod(m); } else { result = core.ProcessBlock(input); } } else { result = core.ProcessBlock(input); } return core.ConvertOutput(result); } /* * calculate a random mess-with-their-heads value. */ private BigInteger calculateR( BigInteger m) { int max = m.BitLength - 1; // must be less than m.BitLength int min = max / 2; int length = ((random.NextInt() & 0xff) * ((max - min) / 0xff)) + min; BigInteger factor = new BigInteger(length, random); while (factor.SignValue == 0) { factor = new BigInteger(length, random); } return factor; } } }