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