1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.crypto.engines; 2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.CipherParameters; 4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.DataLengthException; 5c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.ParametersWithRandom; 6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.params.RSAKeyParameters; 7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; 8b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 9c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.math.BigInteger; 10c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/** 12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * this does your basic RSA algorithm. 13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 14c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromclass RSACoreEngine 15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{ 16c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom private RSAKeyParameters key; 17c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom private boolean forEncryption; 18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * initialise the RSA engine. 21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param forEncryption true if we are encrypting, false otherwise. 23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @param param the necessary RSA key parameters. 24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public void init( 26c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom boolean forEncryption, 27c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom CipherParameters param) 28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 29c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom if (param instanceof ParametersWithRandom) 30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 31c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom ParametersWithRandom rParam = (ParametersWithRandom)param; 32c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 33c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom key = (RSAKeyParameters)rParam.getParameters(); 34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 37c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom key = (RSAKeyParameters)param; 38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 39c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 40c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom this.forEncryption = forEncryption; 41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Return the maximum size for an input block to this engine. 45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * For RSA this is always one byte less than the key size on 46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * encryption, and the same length as the key size on decryption. 47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return maximum size for an input block. 49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int getInputBlockSize() 51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int bitSize = key.getModulus().bitLength(); 53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (forEncryption) 55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (bitSize + 7) / 8 - 1; 57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (bitSize + 7) / 8; 61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam /** 65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Return the maximum size for an output block to this engine. 66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * For RSA this is always one byte less than the key size on 67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * decryption, and the same length as the key size on encryption. 68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * 69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * @return maximum size for an output block. 70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */ 71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam public int getOutputBlockSize() 72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int bitSize = key.getModulus().bitLength(); 74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (forEncryption) 76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (bitSize + 7) / 8; 78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return (bitSize + 7) / 8 - 1; 82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 85c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom public BigInteger convertInput( 86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] in, 87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int inOff, 88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam int inLen) 89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (inLen > (getInputBlockSize() + 1)) 91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 92c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom throw new DataLengthException("input too large for RSA cipher."); 93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 94c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom else if (inLen == (getInputBlockSize() + 1) && !forEncryption) 95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 96c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom throw new DataLengthException("input too large for RSA cipher."); 97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] block; 100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (inOff != 0 || inLen != in.length) 102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam block = new byte[inLen]; 104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(in, inOff, block, 0, inLen); 106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam block = in; 110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 112c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger res = new BigInteger(1, block); 113c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom if (res.compareTo(key.getModulus()) >= 0) 114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 115c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom throw new DataLengthException("input too large for RSA cipher."); 116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 118c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom return res; 119c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom } 120c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 121c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom public byte[] convertOutput( 122c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger result) 123c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom { 124c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom byte[] output = result.toByteArray(); 125c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 126b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (forEncryption) 127b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 128b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down. 129b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 130b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] tmp = new byte[output.length - 1]; 131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(output, 1, tmp, 0, tmp.length); 133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return tmp; 135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen 138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] tmp = new byte[getOutputBlockSize()]; 140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length); 142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return tmp; 144b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 145b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam else 147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam if (output[0] == 0) // have ended up with an extra zero byte, copy down. 149b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam { 150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam byte[] tmp = new byte[output.length - 1]; 151b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam System.arraycopy(output, 1, tmp, 0, tmp.length); 153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam 154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return tmp; 155b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 156b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 157c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam return output; 159b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam } 160c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 161c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom public BigInteger processBlock(BigInteger input) 162c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom { 163c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom if (key instanceof RSAPrivateCrtKeyParameters) 164c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom { 165c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // 166c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // we have the extra factors, use the Chinese Remainder Theorem - the author 167c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for 168c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // advice regarding the expression of this. 169c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // 170c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key; 171c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 172c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger p = crtKey.getP(); 173c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger q = crtKey.getQ(); 174c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger dP = crtKey.getDP(); 175c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger dQ = crtKey.getDQ(); 176c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger qInv = crtKey.getQInv(); 177c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 178c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom BigInteger mP, mQ, h, m; 179c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 180c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // mP = ((input mod p) ^ dP)) mod p 181c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom mP = (input.remainder(p)).modPow(dP, p); 182c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 183c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // mQ = ((input mod q) ^ dQ)) mod q 184c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom mQ = (input.remainder(q)).modPow(dQ, q); 185c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 186c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // h = qInv * (mP - mQ) mod p 187c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom h = mP.subtract(mQ); 188c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom h = h.multiply(qInv); 189c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom h = h.mod(p); // mod (in Java) returns the positive residual 190c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 191c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom // m = h * q + mQ 192c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom m = h.multiply(q); 193c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom m = m.add(mQ); 194c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom 195c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom return m; 196c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom } 197c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom else 198c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom { 199c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom return input.modPow( 200c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom key.getExponent(), key.getModulus()); 201c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom } 202c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom } 203b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam} 204