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