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