0

I have to make a small demonstration about encrypting text using the RC4 Algorithm. To do so, I chose to use Java in NetBeans.

My code uses byte arrays for the permutation and the XOR operation. But the input and the output are to be in String.

  1. Almost all of my outputs, for encryption looks like this: "¯[á" . Is it normal? Using this however, i can still find the plain text, which in this case is "though".
  2. let's say I am trying to encrypt the word "stack". The result I would sometimes get would be of form: "¯[??ô" and then while trying to decrypt, I will get: "s??ck" or "stÄck". This especially happens if my key and the origin plain text is in french (which sucks since it's the language I a making the presentation in).

I tried changing the encoding character, from UTF-8, to ISO-8859-1 to ASCII. I have had the best results with ASCII. It gives me less question marks, but is sometimes changes the characters.

  1. This is an example of strange character returns
  2. Same code. Just changed the print sentences in french, and used french words for encryption, but there is a question mark

My RC4 class code for encrypting and decrypting text

public class RC4 
{
    private int[] S =new int[256];
    private int[] T =new int[256];
    private int keylen;
    
    public RC4(byte[] key)
    {
        if (key.length < 1 || key.length > 256) {
            throw new IllegalArgumentException("La clé doit avoir entre 1 et 256 bytes");
        }
        else
        {
            keylen = key.length;
            for (int i = 0; i < 256; i++) //initialisation de S et T 
            {
                S[i] = i;
                T[i] = (int)key[i % keylen];
            }
            int j = 0;
            for (int i = 0; i < 256; i++) //Premiere permutation de S qui utilise la clé
            {
                j = (j + S[i] + T[i]) % 256;
                int temp = S[i];
                S[i] = S[j];
                S[j] = temp;
            }
        }
    }
    
    public byte[] chiffrer(byte[] plaintext) 
    {
        int i = 0;
        int j = 0;
        byte[] ciphertext = new byte[plaintext.length];// texte et cryptogramme ont la même longueur 
        for (int k = 0; k < plaintext.length; k++) //seconde permutation, n'utilisant que des procédés mathématiques sans l'intervention de la clé
        {
            i = (i + 1) % 256;
            j = (j + S[i]) % 256;
            int temp = S[i];
            S[i] = S[j];
            S[j] = temp;
            int t = (S[i] + S[j]) % 256;
            int keystream = S[t];
            byte keyByte = (byte)keystream;
            ciphertext[k] = (byte)(plaintext[k] ^ keyByte ); //Pour l'opération XOR  
        }
        
        return ciphertext;
    }
    
    public byte[] dechiffrer(byte[] ciphertext) 
    {
        return chiffrer(ciphertext); // Le chiffrement et le déchiffrement se font exactement de la même manière
    }
}

My main class

public class testRC4 
{

    public static void main(String args[])
    {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Saisir la clé secrète:");
        String keyText = scanner.nextLine();
        byte[] key = keyText.getBytes();
        RC4 rc = new RC4(key);
        System.out.println("Entrer a pour chiffrer et b pour déchiffrer:");
        String choice = scanner.nextLine();
        if (choice.equals("a"))
        {
            System.out.println("Saisir le mot à chiffrer:");
            String plainText = scanner.nextLine();
            byte[] plain = plainText.getBytes();   
            byte[] cipher = rc.chiffrer(plain);
            String cipherText = new String(cipher);
            System.out.println("Le cryptogramme :  " +cipherText);  
        }
        else if(choice.equals("b"))
        {
            System.out.println("Saisir le mot à déchiffrer :");
            String cipherText = scanner.nextLine();
            byte[] cipher = cipherText.getBytes();
            byte[] plain = rc.chiffrer(cipher);
            String plainText = new String(plain);
            System.out.println("Le texte en clair :  " +plainText);     
        }
        else
        {
            System.out.println("Le choix fait n'est pas reconnu. Veuillez recommencer!");
        }
        
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Marie
  • 1
  • 1
  • Reading your question again, I'm not sure my above comment is actually relevant. You may simply be running into an issue with non-printable characters. Try encrypting and decrypting the text in the same code without going through output/input (does it still break?). The encrypted text is going to have some hairy characters in it and they are possibly getting broken if you print/input them back. – teapot418 Mar 19 '23 at 21:44
  • If that is the problem, maybe it would be best to run the encrypted text through [base64](https://www.baeldung.com/java-base64-encode-and-decode) or output it as hex. – teapot418 Mar 19 '23 at 21:50
  • Basically, yes, after you XOR a printable character with some random value you can expect rubbish. There are test vectors on the Wiki page for RC4. You should test against those, and print your output as decimal or hexidecimal numbers. – markspace Mar 19 '23 at 22:22
  • @teapot418 When you say output using hex, does it means I should convert the ruslt from byte to hex rather than byte to String? – Marie Mar 19 '23 at 23:26
  • @markspace So basically, I should convert my returned byte array from byte to hex? – Marie Mar 19 '23 at 23:28
  • You would go from bytes to a string that has two characters (0-9a-f) per byte. Display the ciphertext like that. And when reading ciphertext, convert back from hex string to bytes. – teapot418 Mar 19 '23 at 23:29
  • https://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java <- I'm sure this is already implemented somewhere, just pick one you like – teapot418 Mar 19 '23 at 23:32
  • @teapot418 That helped me. I kept everything as it is but after retrieving the byte array that returned, I converted it to an hexadecimal value that was then set as a string and display. And for decryption, I converted my string into hexadecimal value, before converting it again to a byte array and doing everything else as it is. Thank you very much!! – Marie Mar 20 '23 at 00:12

1 Answers1

0

Diagnosed in comments. The main problem is that the ciphertext contains hairy unprintable characters that break when copy&pasted.

Recommeded solution: display ciphertext in hexadecimal instead.

teapot418
  • 1,239
  • 1
  • 3
  • 9