Caesar Cipher decoded wrongly in Java

222 Views Asked by At

I have implemented the Caesar Cipher algorithm in Java 8.

The Problem

Heute ist Freitag.

results into this encoded text using 22 as a key:

^{

{6

6{

w}D

Decoding this again gets me this output:

Heu

e is

Frei

ag.

The Code and description

It should be noted that my algorithm doesn't care about characters like '\n', meaning some characters might be translated to escape sequences or spaces etc. This is also totally what I want to happen, thought it doesn't work.

    public String encode(String txt, int key) {
    if(key <= 0)
        return txt;

    String result = "";
    for (int i = 0; i < txt.length(); i++) {
        int x = (txt.charAt(i) + key) % 128;
        result += (char) x;
    }
    System.out.println(result);
    return result;
    }
    public String decipherM(String txt, int key) {
    if(key <= 0)
        return txt;

    String result = "";
    for (int i = 0; i < txt.length(); i++) {
        int x = (txt.charAt(i) - key) % 128;
        if(x < 0)
            x += 128;

        result += (char) x;
    }
    System.out.println(result);
    return result;
}

The question

I would really like to know why it doesn't work with escape sequences or other non alphabetic characters.

1

There are 1 best solutions below

0
On BEST ANSWER

Control characters have a defined meaning and text processing tools may retain the meaning or even remove those control characters not having a valid meaning, rather than retaining the exact byte representation.

Note that when you go beyond ASCII, this may even happen with ordinary characters, e.g. since you used a German sample text, you have to be aware that the two Unicode codepoint sequences \u00E4 and \u0061\u0308 are semantically equivalent, both referring to the character ä and you can not rely on text processing tool to retain both forms.

After all, there is a reason why encodings like Base 64 have been invented for lossless transfer of byte sequences through text processing tools.

For an encoding as simple as yours, it might be the best to simply forbid control characters in the source string and rotate only through the ASCII non-control character range:

public String encodeRotation(String txt, int distance) {
    int first = ' ', last = 128, range = last - first;
    while(distance<0) distance+=range;
    if(distance == 0) return txt;
    char[] buffer = txt.toCharArray();
    for (int i = 0; i < txt.length(); i++) {
        char c = buffer[i];
        if(c<first || c>=last)
            throw new IllegalArgumentException("unsupported character "+c);
        buffer[i] = (char) ((c - first + distance) % range + first);
    }
    return String.valueOf(buffer);
}

public String decodeRotation(String txt, int key) {
    return encodeRotation(txt, -key);
}
System.out.println(encodeRotation("Heute ist Freitag.", 22));
^{+*{6)*6\({*w}D
System.out.println(decodeRotation("^{+*{6)*6\\({*w}D", 22));
Heute ist Freitag.