3

I have put a lot of effort into making a cipher more robust so that the output is case sensitive.

Meaning, if a capital letter is in the message string, the output will have an encoded capital letter in the string at that location.. For example InpUT MesSagE turns into HrhTS WwlReyD. The key used is test.

public String encrypt(String text, final String key) {
    int a_num = (int) 'a';
    int A_num = (int) 'A';
    String output = "";
    for (int i = 0, j = 0; i < text.length(); i++) {
        int cur = (int) text.charAt(i);
        // check for spaces
        if (text.charAt(i) == ' ') {
            output += " ";
        // check for lowercase
        } else if (cur >= 'a' && cur < 'z' + 26) {
            output += Character.toString((char) ((cur + key.charAt(j) - 2 * 'a') % 26 + 'a'));
            j = ++j % key.length();
        // check for uppercase between 'N' and 'Z'
        } else if (cur >= 'N' && cur < 'Z') {
            output += Character.toString((char) ((cur + key.charAt(j) - 2 * 'A') % 26 + 'N' + 7));
            j = ++j % key.length();
        // check for uppercase between 'A' and 'M'
        } else {
            output += Character.toString((char) ((cur + key.charAt(j) - 2 * 'A') % 26 + 'A' - 6));
            j = ++j % key.length();
        }
    }
    return output;
}

Currently, all lowercase letters seem to come out right, and some of the uppercase do. My problem is sometimes the uppercase is wrong, for instance symbols will be part of the output because of my incorrect math/logic.

The variables that I'm pretty sure are the issue are in these sections of the code:

((cur + key.charAt(j) - 2 * 'A') % 26 + 'A' - 6));
parker_codes
  • 3,267
  • 1
  • 19
  • 27
  • 1
    Can you [edit] your question to include what `key` was used to turn `hOW Fun` into `qZU Grv` or the `key` you're using with example input and output? – Jonny Henly Aug 01 '16 at 23:09
  • The desired output for that message and key would be `BrhNM QwlLeyX`. – parker_codes Aug 02 '16 at 04:49
  • 1
    With U and t (fourth letter in test) 85+116=201 201-130=81 81 mod 26=3 add N (78) and 7 and you have 88, which is X not T? Also, as written 'Z' is going to fall through into the final else, which at least deserves a comment if it is what you want. – Jeremy Kahan Aug 02 '16 at 05:30
  • 1
    'N'+7 is already 'U." Any remainder of 6 or more will take you beyond the end of the alphabet into the funky characters you observed. But that could happen (let us say the test key has anywhere from a to z, you could probably hit every possible remainder 0 to 25. That will also explain why in your last clause a remainder smaller than 6 will take into character before the beginning of the alphabet. – Jeremy Kahan Aug 02 '16 at 05:42
  • 1
    Don't get why A..M and N..Z would be different cases. – Henry Aug 02 '16 at 06:44
  • The reason the capital letters are split up is because when I had the first half working, the latter half was displaying symbols (at that point, it was all in one else if statement). I couldn't figure out why, so I split it up to try to resolve it. – parker_codes Aug 02 '16 at 22:50

1 Answers1

0
public String encrypt(String text, final String key) {
    // we assume the key is all lower case
    // and only inputs are letters and space (could enhance to leave all else alone)
    int a_num = (int) 'a'; //unused?
    int A_num = (int) 'A';//unused?
    String output = "";

    for (int i = 0, j = 0; i < text.length(); i++) {
        int cur = (int) text.charAt(i);

        // check for spaces
        if (text.charAt(i) == ' ') {
            output += " ";
        }
        // check for lowercase
        else if (cur >= 'a' && cur <= 'z') {
            output += Character.toString((char) ((cur + key.charAt(j) - 2 * 'a') % 26 + 'a'));
            j = ++j % key.length();
        }
        // should work for uppercase between 'A' and 'Z'
        else {
            output += Character.toString((char) ((cur -'A' + key.charAt(j) - 'a') % 26 + 'A'));
            j = ++j % key.length();
        }
    }
    return output;
}
NatNgs
  • 874
  • 14
  • 25
Jeremy Kahan
  • 3,796
  • 1
  • 10
  • 23
  • I will try this as soon as I can. I'm assuming to "enhance" it to leave other characters alone it would require another else statement which captures all the symbols, etc, just like the spaces checker? How is that done? – parker_codes Aug 02 '16 at 22:53
  • I actually can't seem to get the decrypt method right. It is almost the same, I know, but the two main lines are what I can't narrow down. – parker_codes Aug 03 '16 at 05:23
  • to handle other characters I would remove the first if, make the current else if an if, make the current else into else if (cur>='A' && cur <='Z'), and then make a new else that says output+= the current character cast as a string. – Jeremy Kahan Aug 03 '16 at 23:20
  • for unshifting, try to make it work with all lower case stuff first. I think that would look like cur - key.charAt(j) and 'a''s cancel out, I believe. In the capital case you would still want (cur-'A'), but now + 'a'-key.charAt(j). – Jeremy Kahan Aug 03 '16 at 23:32
  • What do you mean by the a's cancelling out? Following your suggestion, it would look like this: `output += Character.toString((char) ((cur - key.charAt(j) - 2 * 'a') % 26 + 'a'));` and `output += Character.toString((char) ((cur - 'A' - key.charAt(j) + 'a') % 26 + 'A'));` – parker_codes Aug 04 '16 at 21:03
  • I mean assuming both are lower case, your character was shifted up key.charAt(j)-'a'. To undo that, you need to subtract that which gives -key.charAt(j)+'a'. But cur is cur-'a' into the alphabet. cur-'a'-key.charAt(j)+'a' is = cur-key.charAt(j), so I believe you can just drop the - 2* 'a' in your first assignment statement in the comment. I think I agree with your second expression. – Jeremy Kahan Aug 05 '16 at 19:49