fazlurr
3/14/2015 - 7:33 AM

RC4+ Encryptor - http://stackoverflow.com/a/12290876

import android.util.Log;

import java.util.Arrays;

/**
 * RC4+ Encryption - from Stack Overflow
 * Stack Overflow : http://stackoverflow.com/a/12290876
 * Original Code : https://code.google.com/p/a9cipher/source/browse/src/com/a9development/a9cipher/RC4.java?r=1b5bdf2a70b3ef8cc9464f8a31332a2ec9f54e7a
 */

public class RC4Plus {
    private static final String TAG = "RC4Plus";
    private final byte[] S = new byte[256];
    private final byte[] T = new byte[256];
    private final int keyLength;

    public RC4Plus(final byte[] key) {
        if (key.length < 1 || key.length > 256) {
            throw new IllegalArgumentException("key must be between 1 and 256 bytes");
        } else {
            keyLength = key.length;
            /**
             * Key-scheduling algorithm (KSA)
             * The pseudo code :
             * for i from 0 to 255
             *   S[i] := i
             * endfor
             * j := 0
             * for i from 0 to 255
             *   j := (j + S[i] + key[i mod keylength]) mod 256
             *   swap values of S[i] and S[j]
             * endfor
             */
            for (int i = 0; i < 256; i++) {
                S[i] = (byte) i;
                T[i] = key[i % keyLength]; // key[i mod keylength]
            }
            int j = 0;
            byte tmp;
            for (int i = 0; i < 256; i++) {
                j = (j + S[i] + T[i]) & 0xFF; // & 0xff is same as mod 256
                // Swap values
                tmp = S[j];
                S[j] = S[i];
                S[i] = tmp;
            }
        }
    }

    /**
     * Pseudo-random generation algorithm (PRGA)
     * The pseudo code :
     * i := 0
     * j := 0
     * while GeneratingOutput:
     *   i := (i + 1) mod 256
     *   j := (j + S[i]) mod 256
     *   swap values of S[i] and S[j]
     *   K := S[(S[i] + S[j]) mod 256]
     *   output K
     * endwhile
     * @param plainTextBytes bytes from plain text
     * @return cipherText
     */
    public byte[] encrypt(final byte[] plainTextBytes) {
        // For storing keystream, not required
        byte[] keystreamByteArray = new  byte[plainTextBytes.length];

        final byte[] cipherText = new byte[plainTextBytes.length];
        int i = 0, j = 0, k, t;
        byte tmp;
        for (int counter = 0; counter < plainTextBytes.length; counter++) {
            i = (i + 1) & 0xFF;
            j = (j + S[i]) & 0xFF;

            // Swap values
            tmp = S[j];
            S[j] = S[i];
            S[i] = tmp;

            t = (S[i] + S[j]) & 0xFF;
            k = S[t];

            // The S(S(i) + S(j)) is used as a byte of the key stream, K
            cipherText[counter] = (byte) (plainTextBytes[counter] ^ k); // '^' is XOR

            // Not required for encryption, only for showing keystream hexadecimal
            keystreamByteArray[counter] = ((byte) k);
        }

        String hexadecimalKeystream = A9Utility.bytesToHex(keystreamByteArray);
        Log.i(TAG, "Keystream in bytes : " + Arrays.toString(keystreamByteArray));
        Log.i(TAG, "Keystream in hexadecimal : " + hexadecimalKeystream);

        String hexadecimalCiphertext = A9Utility.bytesToHex(cipherText);
        Log.i(TAG, "Ciphertext in bytes : " + Arrays.toString(cipherText));
        Log.i(TAG, "Ciphertext in hexadecimal : " + hexadecimalCiphertext);

        return cipherText;
    }

    public byte[] decrypt(final byte[] cipherText) {
        return encrypt(cipherText);
    }
}