Substitution Cipher encrypter code given but no decrypter - java

So given the encrypt code
// encrypt looks up the character at the appropriate place
// in the encryption String and substitutes it.
public void encrypt (StringBuilder text)
{
for (int i=0; i<text.length(); i++)
{
char ch = text.charAt(i);
if ('A' <= ch && ch <= 'Z')
{
int index = ALPHABET.indexOf(ch);
text.setCharAt(i, encryptionString.charAt(index));
}
}
}
How would I modify the above code to make it so it decrypts?
public class SubstitutionCipher
{
// The alphabet as a String. We use this for both
// encoding and decoding
public static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// The encryption string is how we represent the table
// of values. The first character in the String
// is substituted for 'A', the second for 'B', etc.
private String encryptionString;
/**
* Constructor for objects of class Substitution
*/
public SubstitutionCipher(String substitutionString)
{
if (substitutionString.length() != 26)
{
System.out.println ("Illegal substitution string "
+ substitutionString);
encryptionString = ALPHABET;
}
else
{
encryptionString = substitutionString;
}
}
// encrypt looks up the character at the appropriate place
// in the encryption String and substitutes it.
public void encrypt (StringBuilder text)
{
for (int i=0; i<text.length(); i++)
{
char ch = text.charAt(i);
if ('A' <= ch && ch <= 'Z')
{
int index = ALPHABET.indexOf(ch);
text.setCharAt(i, encryptionString.charAt(index));
}
}
}
// decrypt looks up the character at the appropriate place
// in the alphabet and substitutes it.
public void decrypt (StringBuilder text)
{
for (int i=0; i<text.length(); i++)
{
char ch = text.charAt(i);
if ('A' <= ch && ch <= 'Z')
{
int index = ALPHABET.indexOf(ch);
text.setCharAt(i, encryptionString.charAt(index));
}
}
}
}

In decryption you have to do just reverse of encryption, But in your code, you are doing the same thing, So change it to this :
public void decrypt (StringBuilder text)
{
for (int i=0; i<text.length(); i++)
{
char ch = text.charAt(i);
if ('A' <= ch && ch <= 'Z')
{
int index =encryptionString.indexOf(ch);
text.setCharAt(i, ALPHABET.charAt(index));
}
}
}

Related

Why my caesar cipher is only working in lowercase

I am new in JAVA Programming and I am trying to create a caesar cipher encrypt/decrypt program. Unfortunately, my program is only working in lower cases. I cannot see where did I go wrong I tried reviewing my code for several times but I cant seem to find out the problem. Here is my code so far:
import java.util.Scanner;
public class CaesarCipher {
public static String encrypt(String plainText, int shift) {
if (shift > 26) {
shift = shift % 26;
} else if (shift < 0) {
shift = (shift % 26) + 26;
}
String cipherText = "";
int length = plainText.length();
for (int i = 0; i < length; i++) {
char ch = plainText.charAt(i);
if (Character.isLetter(ch)) {
if (Character.isLowerCase(ch)) {
char c = (char) (ch + shift);
if (c > 'z') {
cipherText += (char) (ch - (26 - shift));
} else {
cipherText += c;
}
} else if (Character.isUpperCase(ch)) {
char c = (char) (ch + shift);
if (c > 'Z') {
cipherText += (char) (ch - (26 - shift));
} else {
cipherText += c;
}
}
} else {
cipherText += ch;
}
}
return cipherText;
}
// Decrypt
public static String decrypt(String plainText, int shift) {
if (shift > 26) {
shift = shift % 26;
} else if (shift < 0) {
shift = (shift % 26) + 26;
}
String cipherText = "";
int length = plainText.length();
for (int i = 0; i < length; i++) {
char ch = plainText.charAt(i);
if (Character.isLetter(ch)) {
if (Character.isLowerCase(ch)) {
char c = (char) (ch - shift);
if (c < 'a') {
cipherText += (char) (ch + (26 - shift));
} else {
cipherText += c;
}
} else if (Character.isUpperCase(ch)) {
char c = (char) (ch + shift);
if (c < 'A') {
cipherText += (char) (ch + (26 - shift));
} else {
cipherText += c;
}
}
} else {
cipherText += ch;
}
}
return cipherText;
}
public static void main(String[] args) {
Scanner input1 = new Scanner(System.in);
Scanner input2 = new Scanner(System.in);
System.out.print("Enter your phrase: ");
String inputPlainText = input1.nextLine();
System.out.print("Enter your shift: ");
int shiftForPlainText = input1.nextInt();
String convertPlainText = encrypt(inputPlainText, shiftForPlainText);
System.out.println(convertPlainText);
System.out.print("Enter ciphertext: ");
String inputCipherText = input2.nextLine();
System.out.print("Enter shift: ");
int shiftForCipherText = input2.nextInt();
String convertCipherText = decrypt(inputCipherText, shiftForCipherText);
System.out.println(convertCipherText);
}
}
In decrypt method, for lower case you write:
char c = (char)(ch-shift);
and for upper case you write:
char c = (char)(ch+shift);
I'm pretty sure that both lines should have the same operator between ch and shift. If you don't want to make such mistakes, try to refactor your code so there are no duplicate lines.

What is best approach to encrypting an encryption?

For my CPSC class, I need to make encryption code using caesar cipher. That is done. The next part is taking the encrypted message and cycling the secretKey to be added to the encrypted message. For example, if I encrypt "Hello!" using a shift of 13, it will turn into "Uryyb!". Then I must shift "U" by one, "r" by three, "y" by one, etc... which will encrpt into "Vuzbc!" I am in a beginner class so I do not know all the cool tips and tricks. Only possible solution I know is to take the outcome of the caesar cipher and somehow index the secret key to be added to the outcome.
Here is my code that I have so far:
public class Cipher {
private int secretKey;
private int superSecretKey;
public static void main(String [] args)
{
Cipher cipher = new Cipher(1);
}
public Cipher(int myKey) {
secretKey = myKey;
}
public String caesarEncrpyt (String s) {
String r = "";
for(int i = 0; i < s.length(); i++) {
char c = (char) (s.charAt(i));
if(Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
r += (char) ('A' + (c - 'A' + secretKey) % 26);
}
else {
r += (char) ('a' + (c - 'a' + secretKey) % 26);
}
}
else {
r += c;
}
}
return r;
}
public String caesarDecrypt (String s) {
String r = "";
for(int i = 0; i < s.length(); i++) {
char c = (char) (s.charAt(i));
if(Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
r += (char) ('A' + (c - 'A' - secretKey) % 26);
}
else {
r += (char) ('a' + (c - 'a' - secretKey) % 26);
}
}
else {
r += c;
}
}
return r;
}
public String augustusEncrypt (String s) {
String r = "";
for(int i = 0; i < s.length(); i++) {
char c = (char) (s.charAt(i));
if(Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
r += (char) ('A' + (c - 'A' + secretKey) % 26);
}
else {
r += (char) ('a' + (c - 'a' + secretKey) % 26);
}
}
else {
r += c;
}
}
return r;
}
augustusEncrypt is a copy and paste of caesarEncrypt. I've been moving some stuff around hoping for a solution. Thanks in advance!
Edit: I may not have explained this correctly, if you have a question, I'll be here.
Write a function, call it toDigits which will take an int (or a long) and return an array of ints corresponding to the digits of the input. to toDigits(13)=>{1,3} and toDigits(4834)=>{4,8,3,4}, etc
Then write a function encryptChar, taking a char and an int and encrypting the char by that int. (encryptChar('e', 1)=>'f', encryptChar('a',28)=>c, etc)
Then you can loop over the characters of the message and the digits in this array, passing the values to encryptChar and use the results to assemble your encrypted message. In a loose sort of pseudocode:
fn encryptMessage(message, key):
key_array = toDigits(key)
output = ""
for i in length (message):
output.append(encryptChar(message[i], key_array[i % length(key_array)]))
Best practices and conventions for encrypting aside, the solution is simple.
You have letters A-Z and a-z which already perform the correct loop when we step off of the alphabet, and you believe you have that working correctly. All you need to do is add 1 before you loop around.
It would be something like this (warning: untested):
('A' + ((c+1) - 'A' + secretKey) % 26)

Define a method named encode that accepts a String as input and returns a new String which is the original String encoded using the ROT13 cipher

For example: String "abc" should return "nop".
I did a System.out.println and it is printing the correct result, however, the JUnit Test case is giving me a red bar. The method move13 just takes the character and moves it 13 spaces left or right.
The method encode is where I am having trouble with.
package code;
public class Encoder {
public char move13(char letter) {
if (letter >= 'a' && letter <= 'm') {
return (char)(letter + 13);
}
if (letter >= 'A' && letter <= 'M') {
return (char)(letter + 13);
}
if (letter >= 'n' && letter <= 'z') {
return (char)(letter - 13);
}
if (letter >= 'N' && letter <= 'Z') {
return (char)(letter - 13);
}
return letter;
}
public String encode(String text) {
String valueOfchar = "";
for (int i = 0; i < text.length(); i++) {
char character = text.charAt(i);
character = move13(character);
valueOfchar = String.valueOf(character);
System.out.println(valueOfchar);
}
return valueOfchar;
}
}
Here you go, hope it helps
public static char move13(char letter) {
if (letter >= 'a' && letter <= 'm')
return (char) (letter + 13);
if (letter >= 'A' && letter <= 'M')
return (char) (letter + 13);
if (letter >= 'n' && letter <= 'z')
return (char) (letter - 13);
if (letter >= 'N' && letter <= 'Z')
return (char) (letter - 13);
return letter;
}
public static String encode(String text) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char character = text.charAt(i);
character = move13(character);
sb.append(character);
//System.out.println(valueOfchar);
}
return sb.toString();
}
The char are concatenated in a StringBuilder (sb.append(char)). After each letter processed in move13(), you return the concatenated chars (sb.toString()).
We don't see the unit test code, but at a guess, your method encode() will only ever return a single char, not the whole String.
public String encode(String text) {
String valueOfchar = "";
for (int i = 0; i < text.length(); i++) {
....
valueOfchar = String.valueOf(character); // A single char
....
}
return valueOfchar;
Try:
valueOfchar = valueOfchar.concat(String.valueOf(character));

Java - Convert lower to upper case without using toUppercase()

I'm trying to create a short program that would convert all letters that are uppercase to lowercase (from the command line input).
The following compiles but does not give me the result I am expecting. What would be the reason for this??
Eg) java toLowerCase BANaNa -> to give an output of banana
public class toLowerCase{
public static void main(String[] args){
toLowerCase(args[0]);
}
public static void toLowerCase(String a){
for (int i = 0; i< a.length(); i++){
char aChar = a.charAt(i);
if (65 <= aChar && aChar<=90){
aChar = (char)( (aChar + 32) );
}
System.out.print(a);
}
}
}
You are printing the String a, without modifying it. You can print char directly in the loop as follows:
public class toLowerCase
{
public static void main(String[] args)
{
toLowerCase(args[0]);
}
public static void toLowerCase(String a)
{
for (int i = 0; i< a.length(); i++)
{
char aChar = a.charAt(i);
if (65 <= aChar && aChar<=90)
{
aChar = (char)( (aChar + 32) );
}
System.out.print(aChar);
}
}
}
Looks like homework to me, Just a hint. You are printing string a whereas you are modifying the char type aChar, its not modifying the original string a. (Remember strings are immutable).
A cleaner way of writing this code is
public static void printLowerCase(String a){
for(char ch: a.toCharArray()) {
if(ch >= 'A' && ch <= 'Z')
ch += 'a' - 'A';
System.out.print(ch);
}
}
Note: this will not work for upper case characters in any other range. (There are 1,000s of them)
Looks like you're close. :)
For starters...
char aChar = a.charAt(i);
"a" is an array of Strings, so I believe you would want to iterate over each element
char aChar = a[i].charAt(0);
and it also seems like you want to return the value of the modified variable, not of "a" which was the originally passed in variable.
System.out.print(aChar);
not
System.out.print(a);
Hope that helps you.
public static void toLowerCase(String a){
String newStr = "";
for (int i = 0; i< a.length(); i++){
char aChar = a.charAt(i);
if (65 <= aChar && aChar<=90){
aChar = (char)( (aChar + 32) );
}
newStr = newStr + aChar;
}
System.out.println(newStr);
}
You should print newStr outside for loop. You were trying to print it inside the loop
/**
* Method will convert the Lowercase to uppercase
* if input is null, null will be returned
* #param input
* #return
*/
public static String toUpperCase(String input){
if(input == null){
return input;
}
StringBuilder builder = new StringBuilder();
for(int i=0;i<input.length();i++){
char stringChar = input.charAt(i);
if(92 <= stringChar && stringChar <=122){
stringChar = (char)( (stringChar - 32) );
builder.append(stringChar);
}
else if (65 <= stringChar && stringChar<=90)
{
builder.append(stringChar);
}
}
if(builder.length() ==0){
builder.append(input);
}
return builder.toString();
}
public class Changecase
{
static int i;
static void changecase(String s)
{
for(i=0;i<s.length();i++)
{
int ch=s.charAt(i);
if(ch>64&&ch<91)
{
ch=ch+32;
System.out.print( (char) ch);
}
else if(ch>96&&ch<123)
{
ch=ch-32;
System.out.print( (char) ch);
}
if(ch==32)
System.out.print(" ");
}
}
public static void main (String args[])
{
System.out.println("Original String is : ");
System.out.println("Alive is awesome ");
Changecase.changecase("Alive is awesome ");
}
}
public class MyClass
{
private String txt;
private char lower;
public MyClass(String txt)
{
this.txt = txt;
}
public void print()
{
for(int i=0;i<txt.length();i++)
{
if('A' <= txt.charAt(i) && txt.charAt(i) <= 'Z')
{
lower = (char)(txt.charAt(i) + 32);
System.out.print(lower);
}
else
{
lower = txt.charAt(i);
System.out.print(lower);
}
}
}
public static void main(String[] args)
{
MyClass mc = new MyClass("BaNaNa");
mc.print();
}
}
Sorry pretty late to the scene but this should solve it. An else condition because when it is not zero it totally discards the alphabet.
If somebody needs clear code without MagicNumbers and as less as possible conversions here is my solution:
final char[] charArray = new char[string.length()];
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
charArray[i] = Character.isLowerCase(c) ? Character.toUpperCase(c) : Character.toLowerCase(c);
}
String.valueOf(charArray);
import java.util.Scanner;
public class LowerToUpperC {
public static void main(String[] args) {
char ch;
int temp;
Scanner scan = new Scanner(System.in);
System.out.print("Enter a Character in Lowercase : ");
ch = scan.next().charAt(0);
temp = (int) ch;
temp = temp - 32;
ch = (char) temp;
System.out.print("Equivalent Character in Uppercase = " +ch);
}
}

Vigenère cipher in Java for all UTF-8 characters

I have this simple function for encrypting strings via Vigenère in Java. I omitted the decryption as this is just a "-" instead of the "+" in the line where the new value is calculated.
But this function works only for the normal alphabet A-Z. How can I change the function so that it supports lowercase letters as well as uppercase letters and all other UTF-8 chars?
public static String vigenere_encrypt(String plaintext, String key) {
String encryptedText = "";
for (int i = 0, j = 0; i < plaintext.length(); i++, j++) {
if (j == key.length()) { j = 0; } // use key again if end reached
encryptedText += (char) ((plaintext.charAt(i)+key.charAt(j)-130)%26 + 65);
}
return encryptedText;
}
Thank you very much for your help!
Well, you asked for it and I felt like puzzling, but print out the cipher text and you will know what you just asked for...
public static String vigenereUNICODE(String plaintext, String key, boolean encrypt) {
final int textSize = plaintext.length();
final int keySize = key.length();
final StringBuilder encryptedText = new StringBuilder(textSize);
for (int i = 0; i < textSize; i++) {
final int plainNR = plaintext.codePointAt(i);
final int keyNR = key.codePointAt(i % keySize);
final long cipherNR;
if (encrypt) {
cipherNR = ((long) plainNR + (long) keyNR) & 0xFFFFFFFFL;
} else {
cipherNR = ((long) plainNR - (long) keyNR) & 0xFFFFFFFFL;
}
encryptedText.appendCodePoint((int) cipherNR);
}
return encryptedText.toString();
}
EDIT: Please don't ever use in production code, as I haven't got a clue if the code points can indeed be encoded/decoded. Not all points have been defined, as far as I know, and the standard is a moving target.
If full unicode support is not possible and you have to define your list of valid characters, anyway, why not just use a function like this?
public static String vigenere_cipher(String plaintext, String key, boolean encrypt) {
String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.-"; // including some special chars
final int alphabetSize = alphabet.length();
final int textSize = plaintext.length();
final int keySize = key.length();
final StringBuilder encryptedText = new StringBuilder(textSize);
for (int i = 0; i < textSize; i++) {
final char plainChar = plaintext.charAt(i); // get the current character to be shifted
final char keyChar = key.charAt(i % keySize); // use key again if the end is reached
final int plainPos = alphabet.indexOf(plainChar); // plain character's position in alphabet string
if (plainPos == -1) { // if character not in alphabet just append unshifted one to the result text
encryptedText.append(plainChar);
}
else { // if character is in alphabet shift it and append the new character to the result text
final int keyPos = alphabet.indexOf(keyChar); // key character's position in alphabet string
if (encrypt) { // encrypt the input text
encryptedText.append(alphabet.charAt((plainPos+keyPos) % alphabetSize));
}
else { // decrypt the input text
int shiftedPos = plainPos-keyPos;
if (shiftedPos < 0) { // negative numbers cannot be handled with modulo
shiftedPos += alphabetSize;
}
encryptedText.append(alphabet.charAt(shiftedPos));
}
}
}
return encryptedText.toString();
}
This should be a very short and working version. And the alphabet can easily be stored in a string that can always be extended (which results in different ciphertexts).
Another answer, that does do the Vigenere cipher on upper & lower case characters, simply inserting the other characters. Use this technique to create multiple groups of characters to encode.
public static String vigenere(String plaintext, String key, boolean encrypt) {
final int textSize = plaintext.length();
final int keySize = key.length();
final int groupSize1 = 'Z' - 'A' + 1;
final int groupSize2 = 'z' - 'a' + 1;
final int totalGroupSize = groupSize1 + groupSize2;
final StringBuilder encryptedText = new StringBuilder(textSize);
for (int i = 0; i < textSize; i++) {
final char plainChar = plaintext.charAt(i);
// this should be a method, called for both the plain text as well as the key
final int plainGroupNumber;
if (plainChar >= 'A' && plainChar <= 'Z') {
plainGroupNumber = plainChar - 'A';
} else if (plainChar >= 'a' && plainChar <= 'z') {
plainGroupNumber = groupSize1 + plainChar - 'a';
} else {
// simply leave spaces and other characters
encryptedText.append(plainChar);
continue;
}
final char keyChar = key.charAt(i % keySize);
final int keyGroupNumber;
if (keyChar >= 'A' && keyChar <= 'Z') {
keyGroupNumber = keyChar - 'A';
} else if (keyChar >= 'a' && keyChar <= 'z') {
keyGroupNumber = groupSize1 + keyChar - 'a';
} else {
throw new IllegalStateException("Invalid character in key");
}
// this should be a separate method
final int cipherGroupNumber;
if (encrypt) {
cipherGroupNumber = (plainGroupNumber + keyGroupNumber) % totalGroupSize;
} else {
// some code to go around the awkward way of handling % in Java for negative numbers
final int someCipherGroupNumber = plainGroupNumber - keyGroupNumber;
if (someCipherGroupNumber < 0) {
cipherGroupNumber = (someCipherGroupNumber + totalGroupSize);
} else {
cipherGroupNumber = someCipherGroupNumber;
}
}
// this should be a separate method
final char cipherChar;
if (cipherGroupNumber < groupSize1) {
cipherChar = (char) ('A' + cipherGroupNumber);
} else {
cipherChar = (char) ('a' + cipherGroupNumber - groupSize1);
}
encryptedText.append(cipherChar);
}
return encryptedText.toString();
}
Again, this is unsafe code as the cipher used has been broken for ages. Don't use too many 'A' characters in your keys :) But the character encoding should be sound.

Categories