0

I am trying to write a code for encryption and decryption input text with RC4 in Java. Does anyone know how to fix it?

My code:

import java.util.Arrays;

public class RC4 {

    private static final int SBOX_LEN = 256;
    private static final int MIN_KEY_LEN = 5;

    private byte[] key = new byte[SBOX_LEN - 1];

    private int[] sbox = new int[SBOX_LEN];

    public RC4() {
        initialize();
    }

    public RC4(String key) {

        this();
        setKey(key);
    }

    public static void main(String[] args) {

        RC4 rc4 = new RC4();

        byte[] cipherText = rc4.encryptMessage(args[0], args[1]);
        System.out.println(Arrays.toString(cipherText));

        String plainText = rc4.decryptMessage(cipherText, args[1]);
        System.out.println(plainText);
    }

    private void initialize() {

        Arrays.fill(key, (byte) 0);
        Arrays.fill(sbox, 0);
    }

    public byte[] encryptMessage(String message, String key) {

        initialize();
        setKey(key);

        byte[] crypt = crypt(message.getBytes());
        initialize();

        return crypt;
    }

    public String decryptMessage(byte[] message, String key) {

        initialize();
        setKey(key);

        byte[] msg = crypt(message);
        initialize();

        return new String(msg);
    }

    public byte[] crypt(final byte[] msg) {

        sbox = initializeSBox(key);

        byte[] code = new byte[msg.length];
        int i = 0;
        int j = 0;

        for (int n = 0; n < msg.length; n++) {

            i = (i + 1) % SBOX_LEN;
            j = (j + sbox[i]) % SBOX_LEN;
            swap(i, j, sbox);

            int rand = sbox[(sbox[i] + sbox[j]) % SBOX_LEN];
            code[n] = (byte) (rand ^ msg[n]);
        }

        return code;
    }

    private int[] initializeSBox(byte[] key) {

        int[] sbox = new int[SBOX_LEN];
        int j = 0;

        for (int i = 0; i < SBOX_LEN; i++) {
            sbox[i] = i;
        }

        for (int i = 0; i < SBOX_LEN; i++) {
            j = ((j + sbox[i] + (key[i % key.length])) & 0xFF) % SBOX_LEN;
            swap(i, j, sbox);
        }

        return sbox;
    }

    private void swap(int i, int j, int[] sbox) {

        int temp = sbox[i];

        sbox[i] = sbox[j];
        sbox[j] = temp;
    }

    public void setKey(String key) {

        if (!((key.length() >= MIN_KEY_LEN) && (key.length() < SBOX_LEN))) {

            throw new RuntimeException(String.format("Key length must be between %d and %d", MIN_KEY_LEN, SBOX_LEN - 1));
        }

        this.key = key.getBytes();
    }
}
Mike
  • 14,010
  • 29
  • 101
  • 161
David
  • 11
  • 2
  • 1
    suppose you refer this [post](http://stackoverflow.com/questions/12289717/rc4-encryption-java). and this is a implementation of [RC4](http://www.programcreek.com/java-api-examples/index.php?source_dir=redPandaj-master/src/org/redPandaLib/crypt/RC4.java) – Rajith Pemabandu Apr 15 '17 at 00:59
  • 2
    Why not use [Bouncy Castle](https://bouncycastle.org/docs/docs1.5on/org/bouncycastle/crypto/engines/RC4Engine.html)? – Elliott Frisch Apr 15 '17 at 01:16
  • 1
    Why RC4, it is not close to being secure. – zaph Apr 15 '17 at 04:06
  • 2
    Possible duplicate of [RC4 encryption java](https://stackoverflow.com/questions/12289717/rc4-encryption-java) – Ramachandra A Pai Sep 23 '18 at 06:48

1 Answers1

1

RC4 is a broken algorithm and recommendation is to not use the same anymore if the data is to be kept highly secure.

If you still need a working implementation, you don't need to recreate the algorithm in your code. Java API javax.crypto can do it for you. Just generate a key and call the init method with mode set to encryption/decryption.

static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException{

    byte[] testDataBytes = "testString".getBytes();

    KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
    SecretKey key = rc4KeyGenerator.generateKey();

    // Create Cipher instance and initialize it to encrytion mode
    Cipher cipher = Cipher.getInstance("RC4");  // Transformation of the algorithm
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherBytes = cipher.doFinal(testDataBytes);

    // Reinitialize the Cipher to decryption mode
    cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
    byte[] testDataBytesDecrypted = cipher.doFinal(cipherBytes);

    System.out.println("Decrypted Data : "+new String(testDataBytesDecrypted));
    return new String(testDataBytesDecrypted);
}

Output: enter image description here

If you need to send the encrypted data as part of a url then use Base64Encoding and then send.

e.g.

    static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException{

    byte[] plainBytes = "testString".getBytes();

    KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
    SecretKey key = rc4KeyGenerator.generateKey();

    // Create Cipher instance and initialize it to encrytion mode
    Cipher cipher = Cipher.getInstance("RC4");  // Transformation of the algorithm
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherBytes = cipher.doFinal(plainBytes);

    String encoded = encodeBase64(cipherBytes);

    String decoded = decodeBase64(encoded);

    // Reinitialize the Cipher to decryption mode
    cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
    byte[] plainBytesDecrypted = cipher.doFinal(Hex.decode(decoded));

    System.out.println("Decrypted Data : "+new String(plainBytesDecrypted));
    return new String(plainBytesDecrypted);
}

static String decodeBase64(String encodedData){
    byte[] b = Base64.getDecoder().decode(encodedData);
    String decodedData = DatatypeConverter.printHexBinary(b);
    return decodedData;
}

static String encodeBase64(byte[] data){
    byte[] b = Base64.getEncoder().encode(data);
    String encodedData = new String(b);
    /*String encodedData = DatatypeConverter.printHexBinary(b);*/
    return encodedData;
}

** Tip: ** Use Hex.decode as shown above to get bytes from the base64 decoded string or else you will get encoding issues. As much as possible do the conversions using Hex and convert to bytes array using bouncycastle methods.

Imports needed:

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;

import org.apache.commons.codec.DecoderException;
import org.bouncycastle.util.encoders.Hex;

Also if you are generating a key from your own string you can use MD5Hashing for the same.