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.StreamCipher;
      6 import org.bouncycastle.crypto.params.KeyParameter;
      7 
      8 public class RC4Engine implements StreamCipher
      9 {
     10     private final static int STATE_LENGTH = 256;
     11 
     12     /*
     13      * variables to hold the state of the RC4 engine
     14      * during encryption and decryption
     15      */
     16 
     17     private byte[]      engineState = null;
     18     private int         x = 0;
     19     private int         y = 0;
     20     private byte[]      workingKey = null;
     21 
     22     /**
     23      * initialise a RC4 cipher.
     24      *
     25      * @param forEncryption whether or not we are for encryption.
     26      * @param params the parameters required to set up the cipher.
     27      * @exception IllegalArgumentException if the params argument is
     28      * inappropriate.
     29      */
     30     public void init(
     31         boolean             forEncryption,
     32         CipherParameters     params
     33    )
     34     {
     35         if (params instanceof KeyParameter)
     36         {
     37             /*
     38              * RC4 encryption and decryption is completely
     39              * symmetrical, so the 'forEncryption' is
     40              * irrelevant.
     41              */
     42             workingKey = ((KeyParameter)params).getKey();
     43             setKey(workingKey);
     44 
     45             return;
     46         }
     47 
     48         throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName());
     49     }
     50 
     51     public String getAlgorithmName()
     52     {
     53         return "RC4";
     54     }
     55 
     56     public byte returnByte(byte in)
     57     {
     58         x = (x + 1) & 0xff;
     59         y = (engineState[x] + y) & 0xff;
     60 
     61         // swap
     62         byte tmp = engineState[x];
     63         engineState[x] = engineState[y];
     64         engineState[y] = tmp;
     65 
     66         // xor
     67         return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
     68     }
     69 
     70     public void processBytes(
     71         byte[]     in,
     72         int     inOff,
     73         int     len,
     74         byte[]     out,
     75         int     outOff)
     76     {
     77         if ((inOff + len) > in.length)
     78         {
     79             throw new DataLengthException("input buffer too short");
     80         }
     81 
     82         if ((outOff + len) > out.length)
     83         {
     84             throw new DataLengthException("output buffer too short");
     85         }
     86 
     87         for (int i = 0; i < len ; i++)
     88         {
     89             x = (x + 1) & 0xff;
     90             y = (engineState[x] + y) & 0xff;
     91 
     92             // swap
     93             byte tmp = engineState[x];
     94             engineState[x] = engineState[y];
     95             engineState[y] = tmp;
     96 
     97             // xor
     98             out[i+outOff] = (byte)(in[i + inOff]
     99                     ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
    100         }
    101     }
    102 
    103     public void reset()
    104     {
    105         setKey(workingKey);
    106     }
    107 
    108     // Private implementation
    109 
    110     private void setKey(byte[] keyBytes)
    111     {
    112         workingKey = keyBytes;
    113 
    114         // System.out.println("the key length is ; "+ workingKey.length);
    115 
    116         x = 0;
    117         y = 0;
    118 
    119         if (engineState == null)
    120         {
    121             engineState = new byte[STATE_LENGTH];
    122         }
    123 
    124         // reset the state of the engine
    125         for (int i=0; i < STATE_LENGTH; i++)
    126         {
    127             engineState[i] = (byte)i;
    128         }
    129 
    130         int i1 = 0;
    131         int i2 = 0;
    132 
    133         for (int i=0; i < STATE_LENGTH; i++)
    134         {
    135             i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
    136             // do the byte-swap inline
    137             byte tmp = engineState[i];
    138             engineState[i] = engineState[i2];
    139             engineState[i2] = tmp;
    140             i1 = (i1+1) % keyBytes.length;
    141         }
    142     }
    143 }
    144