I am working on a caesar cipher program as my final project in java I. I have a method for the encryption that handles lower and uppercase characters. However I have hit a wall trying to adjust the algorithm to work the shift factor in the opposite direction to decrypt text already run through the program.
Another issue is that I cannot make the program work with spaces, either ignoring them or encrypting them as well. So far it only encrypts the first word and ignores the rest.
Here is my encryption method thus far, with the message passed from main() as a parameter.
//Caesar Cipher
public class EncryptionClass1 {
protected static String encryptedMessageString;
public static String setEncryptedMessage(String message) {
StringBuffer encryptedMessageBuffer = new StringBuffer();
char newCharacter;
int shiftFactor = 1;
int i;
//for length of secret message
for (i = 0; i<message.length(); i++) {
//uppercase encoder
if (Character.isUpperCase(message.charAt(i))) {
newCharacter = (char)(((int)message.charAt(i) -
shiftFactor - 65) % 26 + 65);
encryptedMessageBuffer.append(newCharacter);
}//if close
//lowercase encoder
else {
newCharacter = (char)(((int)message.charAt(i) -
shiftFactor - 97) % 26 + 97);
encryptedMessageBuffer.append(newCharacter);
}//else close
}//for close
//convert StringBuffer to string
encryptedMessageString = encryptedMessageBuffer.toString();
return encryptedMessageString;
}//setEncryptedMessage close
}//EncryptionClass1 close
For the decryption, I figure that I only need to adjust some of the operations for the encryption method, but I cant pinpoint what.
as for the spaces, an input and output example should be as follows:
Input: “my secret message”
Output: rp dbxbbf rbddtfb
To shift in the opposite direction, shift further in the current direction. Visualize the 26 letters of the alphabet on a 360° dial. If encryption is to rotate (shift) the dial 5 letters to the right, you'd normally think of decryption as rotating the dial 5 letters to the left. But you could also rotate the dial 21 (26 - 5) letters to the right. So, if encryption is shifting shiftFactor up, then decryption is shifting 26 - shiftFactor up. By only shifting up, the % 26 operation will correctly wrap the shift around.
Since the encrypted message is always exactly the same length as the original message, and you only replace one letter at a time, the code will be simpler if you just work on a char[] from the original message. If you do that, then simply skip characters in the array that are not ASCII letters.
Instead of using magic numbers 65 and 97 , use their char values to make the code more readable.
All of the above means that your code could be written like this:
private static final int SHIFT_FACTOR = 5;
public static String encryptMessage(String message) {
return applyShift(message, SHIFT_FACTOR);
}
public static String decryptMessage(String message) {
return applyShift(message, 26 - SHIFT_FACTOR);
}
private static String applyShift(String message, int shiftFactor) {
char[] chars = message.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c >= 'A' && c <= 'Z')
chars[i] = (char) ((c - 'A' + shiftFactor) % 26 + 'A');
else if (c >= 'a' && c <= 'z')
chars[i] = (char) ((c - 'a' + shiftFactor) % 26 + 'a');
}
return new String(chars);
}
Test
public static void main(String[] args) {
test("my secret message");
test("Hello World!");
}
private static void test(String message) {
String encrypted = encryptMessage(message);
System.out.println("Input : " + message);
System.out.println("Encrypted: " + encrypted);
System.out.println("Decrypted: " + decryptMessage(encrypted));
System.out.println();
}
Output
Input : my secret message
Encrypted: rd xjhwjy rjxxflj
Decrypted: my secret message
Input : Hello World!
Encrypted: Mjqqt Btwqi!
Decrypted: Hello World!
Related
However I had an assignment of programming in java related to a text i already have under (text).
the function is supposed to as below
getEncryptedText(int shift)
return a string representation of ciphertext given that the text to be manipulated is the plaintext using Caesar Cipher.
The number of rotation is depend on the shift value;
positive shift value represent the right rotation while negative shift value represent left
rotation. However, unlike explain in Wikipedia, this method used following string as
plain:
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Other characters than above will be treated as it is (i.e. will not been encrypted)
*Further reading: https://en.wikipedia.org/wiki/Caesar_cipher
So this is the class method I have made so far and wanted to know how can i keep the text chars which aren't included in the plaintext i have such as "!,#,#,$,%... and so on". So far i tried everything but couldn't make it but the rest seems fine!
public String getEncryptedText(int shift) {
String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
String cipherText = "";
for (int i = 0; i < text.length(); i++){
{
int charPosition = ALPHABET.indexOf(text.charAt(i));
if(text.charAt(i) == ' ') {
cipherText += " ";
}
else
{
int keyVal = (shift + charPosition) % 62;
char replaceVal = ALPHABET.charAt(keyVal);
cipherText += replaceVal;
}
}
}
return cipherText;
}
Consider modifying your if statement and using the StringBuilder class:
class Main {
public static void main(String[] args) {
CesarCypherHelper cesarCypherHelper = new CesarCypherHelper();
System.out.println(cesarCypherHelper.getEncryptedText("Hello World!", 2));
System.out.println(cesarCypherHelper.getEncryptedText("Hello World!", 64));
}
}
class CesarCypherHelper {
public String getEncryptedText(String text, int shift) {
String ALPHABET =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder encryptedText = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
int charPosition = ALPHABET.indexOf(ch);
if (charPosition == -1) {
encryptedText.append(ch);
} else {
int keyVal = (shift + charPosition) % ALPHABET.length();
encryptedText.append(ALPHABET.charAt(keyVal));
}
}
return encryptedText.toString();
}
}
Output:
Jgnnq Yqtnf!
Jgnnq Yqtnf!
I'm trying to let the encryption function ignore the white spaces and the symbols between words from the UserInput. Should I use isWhitespace or what? and how to implement that?
The output for this program is totally correct, it shifts each letter to the next 7 one. but it doesn't accept shifting 2 words separated by space or coma.
I'm new into Java stunning world & I'm really enjoying it! Hence this's my 3rd week since I began.
import java.util.Scanner;
public class Test_Cipher{
public static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
public static String encrypt(String plainText, int shiftKey) {
plainText = plainText.toLowerCase();
String cipherText = "";
for (int i = 0; i < plainText.length(); i++) {
int charPosition = ALPHABET.indexOf(plainText.charAt(i));
int keyVal = (shiftKey + charPosition) % 26;
char replaceVal = ALPHABET.charAt(keyVal);
cipherText += replaceVal;
}
return cipherText;
}
}
There is two ways of doing this: either create a positive match for the character or a negative one. In the positive match variant you first check if plainText.charAt(i) is a character that you want to keep, and in that case add it to the cipherText and continue with the loop.
In the other you can check if indexOf returns -1 indicating that the alphabet doesn't contain the character. In that case you do the same thing: add it and continue. This is the common method I've seen for the classic Ceasar "play" cipher:
// introduce a local variable, you don't want to perform charAt twice
char c = plainText.charAt(i);
int charPosition = ALPHABET.indexOf(c);
// if charPositions is -1 then it is not found
if (charPosition == -1) { // or define a constant NOT_FOUND = -1
cipherText += c;
// continue with the for loop
continue;
}
Hello evrybody who reads this!
I need to realize Vigenere cipher on Java.
I have a .txt document, which I'm going to read, encode and decode. Here it is:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
My problem is that I don't know how to shift chars correctly, According to this table latin letters have codes from 0061 to 007A. German ones that I need: 00C0 - 00FF, polish: 0100-017F, russian 0430-044F and I didn't gind chineese.
How can I specify unshiftChar and shiftChar to make it correst?
Now my input looks like this:
The original text from file is:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
String that will be encoded is:
asciiabcdexyzgermanäöüäöüßpolishąęźżńłrussianабвгдежэюяcjk你好
The encrypted string is:
äckkwdfaqmzjökcbucäbdslhwfssjvåjoxfbsltfvwgnvboegbrnboeghxöb
The decrypted phrase is:
asciiab¥dexyzgrmanäöäöuupo○ibmjcåäldhtciwmtdåawmtddpw
Here is a Java code:
public class VigenereCipher
{
public static void main(String[] args) throws IOException
{
String key = "Unicode";
File file = new File("G:\\unicode.txt");
FileInputStream fis = new FileInputStream(file);
byte[] fileBArray = new byte[fis.available()];
fis.read(fileBArray);
String text = new String(fileBArray, "UTF-8");
//String text = "Some simple text to check the decoding algorythm";
System.out.println("The original text from file is: \n" + text);
String enc = encrypt(text, key);
System.out.println(enc + "\n");
System.out.println("The decrypted phrase is: ");
System.out.println(decrypt(enc, key));
}
// Encrypts a string
public static String encrypt(String message, String key)
{
message = StringToLowerCaseWithAllSymbols(message);
System.out.println("String that will be encoded is: \n" + message);
char messageChar, keyChar;
String encryptedMessage = "";
for (int i = 0; i < message.length(); i++)
{
messageChar = shiftChar(message.charAt(i));
keyChar = shiftChar(key.charAt(i % key.length()));
messageChar = (char) ((keyChar + messageChar) % 29);
messageChar = unshiftChar(messageChar);
encryptedMessage += messageChar;
}
System.out.println("\nThe encrypted string is: ");
return encryptedMessage;
}
// Decrypts a string
public static String decrypt(String cipher,String key)
{
char cipherChar, keyChar;
cipher = StringToLowerCaseWithAllSymbols(cipher);
String decryptedMessage = "";
cipher = cipher.toLowerCase();
for (int i = 0; i < cipher.length(); i++)
{
cipherChar = shiftChar(cipher.charAt(i));
keyChar = shiftChar(key.charAt(i % key.length()));
cipherChar = (char) ((29 + cipherChar - keyChar) % 29);
cipherChar = unshiftChar(cipherChar);
decryptedMessage += cipherChar;
}
return decryptedMessage;
}
// Prunes all characters not in the alphabet {A-Öa-ö} from a string and changes it to all lower case.
public static String StringToLowerCaseWithAllSymbols(String s)
{
//s = s.replaceAll("[^A-Za-zåäöÅÄÖ]", "");
// 's' contains all the symbols from my text
s = s.replaceAll("[^A-Za-zäöüÄÖÜßąęźżńłабвгдежэюя你好]", "");
return s.toLowerCase();
}
// Assigns characters a,b,c...å,ä,ö the values 1,2,3...,26,28,29.
private static char shiftChar(char c)
{
if (96 < c && c < 123)
{
c -= 97;
}
else if (c == 229)
{
c = 26;
}
else if (c == 228)
{
c = 27;
}
else if (c == 246)
{
c = 28;
}
return c;
}
// Undoes the assignment in shiftChar and gives the characters back their UTF-8 values.
private static char unshiftChar(char c)
{
if (0 <= c && c <= 25)
{
c += 97;
}
else if (c == 26)
{
c = 229;
}
else if (c == 27)
{
c = 228;
}
else if (c == 28)
{
c = 246;
}
return c;
}
}
First of all, you don't want to shift: You want to rotate. Suppose we're working with the English alphabet. If 'A'+2 is 'C', what's 'Z'+2? When you're implementing a Vigenere cipher, you want 'Z'+2=='B'.
I would would not use Unicode in a Vigenere cipher program: I would use my own encoding in which the first letter of the alphabet is represented by zero, the second letter is represented by one, and so on. So, for my English example, code('A')==>0, code('B')==>, ... code('Z')==>26.
Then my rotation function looks like this:
int rotate(Alphabet alphabet, int code, int amount) {
return (code + amount) % alphabet.getLength();
}
So:
rotate(english, code('A'), 2) ==> (0 + 2)%26 == 2, (the code for 'C'), and
rotate(english, code('Z'), 2) ==> (25 + 2)%26 == 1, (the code for 'B').
I have made a vigenere encryption/decryption program which seems to work as I intended, however running my encryption/decryption on a very large text file (500,000 characters aprox) takes 2-4minutes. I have looked through my code and cannot see what operations might be slowing it down. Anyone have any ideas how I could speed this up?
Code:
public static String encrypt(String text, String key)
{
String cipherText = "";
text = text.toLowerCase();
for(int i = 0; i < text.length(); i++)
{
System.out.println("Count: "+ i); //I just put this in to check the
//loop wasn't doing anything unexpected
int keyIndex = key.charAt(i%key.length()) - 'a';
int textIndex = text.charAt(i) - 'a';
if(text.charAt(i) >= 'a' && text.charAt(i) <= 'z') { //check letter is in alphabet
int vigenere = ((textIndex + keyIndex) % 26) + 'a';
cipherText = cipherText + (char)vigenere;
} else
cipherText = cipherText + text.charAt(i);
}
}
return cipherText;
}
Prior to running the encrypt I have a method which reads the text file to a String using Scanner. This String plus a predefined key are used to create the encrypted text.
Thanks.
ANSWER
Thanks to RC - it was my string concatenation taking the time. If anyone else is interested this is my updated code which works quickly now:
public static String encrypt(String text, String key)
{
StringBuilder cipher = new StringBuilder();
for(int i = 0; i < text.length(); i++)
{
int keyIndex = key.charAt(i%key.length()) - 'a';
int textIndex = text.charAt(i) - 'a';
if(text.charAt(i) >= 'a' && text.charAt(i) <= 'z') {
int vigenere = ((textIndex + keyIndex) % 26) + 'a';
cipher.append((char)vigenere);
} else {
cipher.append(text.charAt(i));
}
}
return cipher.toString();
}
Append to a StringBuilder instead of creating new String instances.
You want to do a
buffer.append((char)vigenere);
instead of a cipherText = cipherText + (char)vigenere;
At present you are doing
for(int i = 0; i < text.length(); i++){
...
int keyIndex = key.charAt(i%key.length()) - 'a';
...
}
You can try to remove the calucation of the keyIndex from the for-loop and realize it in a preprocessing step. For example, you can store the keyIndex values/ characters in a separate array and access the array contents in your original loop. This should save you some calculation steps.
Hey I'm making a simple caesar cipher in Java using the formula [x-> (x+shift-1) mod 127 + 1] I want to have my encrypted text to have the ASCII characters except the control characters(i.e from 32-127). How can I avoid the control characters from 0-31 applying in the encrypted text. Thank you.
How about something like this:
public String applyCaesar(String text, int shift)
{
char[] chars = text.toCharArray();
for (int i=0; i < text.length(); i++)
{
char c = chars[i];
if (c >= 32 && c <= 127)
{
// Change base to make life easier, and use an
// int explicitly to avoid worrying... cast later
int x = c - 32;
x = (x + shift) % 96;
if (x < 0)
x += 96; //java modulo can lead to negative values!
chars[i] = (char) (x + 32);
}
}
return new String(chars);
}
Admittedly this treats 127 as a non-control character, which it isn't... you may wish to tweak it to keep the range as [32, 126].
Map your characters from [32..127] to [0..95], do a mod 95+1 and map the result back to [32..127].
Usually cipher text is base64 encoded, base16 (hex) also works well. Base64 is used most often for cipher text because it takes up less space than hex, hex is most commonly used for message digests. In the java.util.prefs.Base64 library you will find byteArrayToBase64() and base64ToByteArray().
On a side note you should NEVER write your own encryption algorithm for security reasons, you should be using a block cipher or stream cipher. I hope this is for fun!
there! Is there any way to consider the whole range of characters? For example, "á", "é", "ö", "ñ", and not consider " " (the [Space])? (For example, my String is "Hello World", and the standard result is "Khoor#Zruog"; I want to erase that "#", so the result would be "KhoorZruog")
I'm sure my answer is in this piece of code:
if (c >= 32 && c <= 127)
{
// Change base to make life easier, and use an
// int explicitly to avoid worrying... cast later
int x = c - 32;
x = (x + shift) % 96;
chars[i] = (char) (x + 32);
}
... But I've tried some things, and the didn't work :S So, I'll wait for your answers :D See you!
Why not try
for(int i = 0; i < length; i++)
{
char c = chars[i]
if(Character.isLetter(c))
{
int x = c - 32;
x = (x + shift) % 96;
chars[i] = (char) (x+32);
}
}
Copy paste this in NetBeans with name "caesar":
//package caesar;
import java.io.*;
public class caesar {
int offset=3;
public String encrypt(String s) throws IOException
{
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++)
{
char t=s.charAt(i);
if(t>='A' && t<='Z')
{
int t1=t-'A'+offset;
t1=t1%26;
sb.append((char)(t1+'A'));
}
else if(t>='a' && t<='z')
{
int t1=t-'a'+offset;
t1=t1%26;
sb.append((char)(t1+'a'));
}
}
return sb.toString();
}
public String decrypt(String s) throws IOException
{
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++)
{
char t=s.charAt(i);
if(t>='A' && t<='Z')
{
int t1=t-'A'-offset;
if(t1<0)t1=26+t1;
sb.append((char)(t1+'A'));
}
else if(t>='a' && t<='z')
{
int t1=t-'a'-offset;
if(t1<0)t1=26+t1;
sb.append((char)(t1+'a'));
}
}
return sb.toString();
}
public static void main(String[] args) {
try
{
System.out.println("Caesar encrypion technique");
BufferedReader b;
String oriTxt,encTxt,decTxt;
System.out.println("Enter string to encrypt:");
b=new BufferedReader(new InputStreamReader(System.in));
oriTxt=b.readLine();
caesar c=new caesar();
encTxt=c.encrypt(oriTxt);
System.out.println("Encrypted text :"+encTxt);
decTxt=c.decrypt(encTxt);
System.out.println("Derypted text :"+decTxt);
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
}
import java.util.Scanner;
//caeser
public class Major_Assingment {
public static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZhh";
public static String encrypt(String plainText,int shiftKey)
{
plainText = plainText.toUpperCase();
String cipherText= " ";
for(int i=0; i<plainText.length(); i++)
{
int charPosition = ALPHABET.indexOf(plainText.charAt(i));
int keyVal = (shiftKey + charPosition)% 26 ;
char replaceVal = ALPHABET.charAt(keyVal);
cipherText += replaceVal;
}
return cipherText;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the string for Encryption:");
String message = new String();
message = sc.next();
System.out.println(encrypt(message,3));
sc.close();
}
}