I made simple encryption and decryption methods by following this video: http://www.youtube.com/watch?v=8AID7DKhSoM&feature=g-hist
however when its implemented in my program any character higher than "s" is encrypted to a "?"
and then decrypted to a 3. It doesn't seem to happen in the tutorial however even though some of his characters get increased by large numbers. So why does this happen?
Btw here's the relevant part of my program:
public class crypt {
public String encrypt(String pass){
String cryppass_string="";
int l= pass.length();
char ch;
for (int i=0; i<l; i++){
ch= pass.charAt(i);
ch+= 12;
cryppass_string+= ch;
}
return cryppass_string;
}
public String decrypt (String cryppass_string){
String pass_string= "";
int l= cryppass_string.length();
char ch;
for (int i=0; i<l; i++){
ch= cryppass_string.charAt(i);
ch-= 12;
pass_string += ch;
}
return pass_string;
}
}
Here's an example :
a password ("astu") needs to be encrypted so its entered, this is done:
char[] newpass= newPassField.getPassword();
char[] repass= rePassField.getPassword();
if(Arrays.equals( newpass , repass ))
{
if(number==1)
{
Login_info.McIntosh_custom_pwd= fileob.string_to_char(cryptob.encrypt(fileob.char_to_string(newpass)));
fileob.evr_tofile();
}
In another class McIntoshcrypted is declared as:
McIntosh_custom_pwd= fileob.string_to_char(cryptob.decrypt(FileData[0]));
fileob is an object of class Files
cryptob is an object of class crypt
public class Files {
File f= new File("Eng Dept.txt");
public Formatter x;
public void openfile(){
try{
x= new Formatter ("Eng Dept.txt");
}
catch (Exception error){
System.out.println("error");
}
}
public void writing(String towrite){
try{
String filename= "Eng Dept.txt";
String newLine = System.getProperty("line.separator");
FileWriter fw = new FileWriter(filename,true);
fw.write(towrite);
fw.write(newLine);
fw.close();
}
catch (Exception eror){
System.out.println("error");
}
}
public String reading_string(int linenum){
String readline= "";
String filename= "Eng Dept.txt";
int lineno;
try{
FileReader fr= new FileReader(filename);
BufferedReader br= new BufferedReader(fr);
for (lineno=1; lineno<= 1000; lineno++){
if(lineno== linenum){
readline= br.readLine();
}
else
br.readLine();
}
br.close();
}
catch (Exception eror){
System.out.println("error");
}
return readline;
}
public String char_to_string(char[] toconv){
int l= toconv.length;
String converted= "";
for (int i=0; i<l; i++)
{
converted+= toconv[i];
}
return converted;
}
public char[] string_to_char(String toconv){
int l= toconv.length();
char[] converted = new char[l];
for (int i= 0; i<l; i++)
{
converted[i]=toconv.charAt(i);
}
return converted;
}
public void evr_tofile()
{
f.delete();
openfile();
writing(char_to_string(Login_info.McIntosh_custom_pwd));
}
In the txt file "as??" is seen, and the result of
System.out.print(Login_info.McIntosh_custom_pwd);
is "as33". Hope I explained this correctly...
edit: tried solution
public String encrypt(String pass){
String cryppass_string="";
int l= pass.length();
int x=0;
char ch;
for (int i=0; i<l; i++){
ch= pass.charAt(i);
x= ((ch - 32) + 12) % 126 + 32;
ch = (char)x;
cryppass_string+= ch;
}
return cryppass_string;
}
public String decrypt (String cryppass_string){
String pass_string= "";
int l= cryppass_string.length();
int x=0;
char ch;
for (int i=0; i<l; i++){
ch= cryppass_string.charAt(i);
x= ch-32;
ch= (char)x;
if (ch < 0)
x= ch+126;
ch= (char)x;
x= ch-12+32;
ch= (char)x;
pass_string += ch;
}
return pass_string;
}
I'm guessing that you output the values to a text file (web page?) using an operation that converts unprintable characters to ?, then the decryption problem happens when you read it back in. If you want to do something like that, you'll need to restrict your encryption to output only printable characters. One way to do that is to use modular arithmetic to ensure that your encrypted character is within the printable set (ASCII 32 to ASCII 126). The code you have will transform properly if you read/write binary, but not if you output it as ASCII text.
Encrypt
ch = (char)((ch - 32) + 12) % 126 + 32; // extended expression to show rebasing/modulus
Decrypt
ch = ch - 32;
if (ch < 0) ch = ch + 126;
ch = ch - 12 + 32;
Related
I want to develop a OTPInputStream in Java that extends the InputStream and takes another input stream of key data and provides a stream encrypting / decrypting input stream.I need to develop a test program to show the use of OTPInputStream that uses XOR and arbitrary data.
I tried with this code but I have problem that is
java.io.FileInputStream cannot be cast to java.lang.CharSequence
What should I do here?
public class Bitwise_Encryption {
static String file = "" ;
static String key = "VFGHTrbg";
private static int[] encrypt(FileInputStream file, String key) {
int[] output = new int[((CharSequence) file).length()];
for(int i = 0; i < ((CharSequence) file).length(); i++) {
int o = (Integer.valueOf(((CharSequence) file).charAt(i)) ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
private static String decrypt(int[] input, String key) {
String output = "";
for(int i = 0; i < input.length; i++) {
output += (char) ((input[i] - 48) ^ (int) key.charAt(i % (key.length() - 1)));
}
return output;
}
public static void main(String args[]) throws FileNotFoundException {
FileInputStream file = new FileInputStream("directory");
encrypt(file,key);
//decrypt();
int[] encrypted = encrypt(file,key);
System.out.println("Encrypted Data is :");
for(int i = 0; i < encrypted.length; i++)
System.out.printf("%d,", encrypted[i]);
System.out.println("");
System.out.println("---------------------------------------------------");
System.out.println("Decrypted Data is :");
System.out.println(decrypt(encrypted,key));
}
}
Think what you want is just file.read() and file.getChannel().size() to read one character at a time and get the size of the file
Try something like this:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
for(int i = 0; i < output.length; i++) {
char char1 = (char) file.read();
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
Will have to do some error handling because file.read() will return -1 if the end of the file has been reached and as pointed out reading one byte at a time is lot of IO operations and can slow down performance. You can keep the data in a buffer and read it another way like this:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
int read = 0;
int offset = 0;
byte[] buffer = new byte[1024];
while((read = file.read(buffer)) > 0) {
for(int i = 0; i < read; i++) {
char char1 = (char) buffer[i];
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i + offset] = o;
}
offset += read;
}
return output;
}
This will read in 1024 bytes at a time from the file and store it in your buffer, then you can loop through the buffer to do your logic. The offset value is to store where in our output the current spot is. Also you will have to make sure that i + offset doesn't exceed your array size.
UPDATE
After working with it; i decided to switch to Base64 Encoding/Decoding to remove non-printable characters:
private static String encrypt(InputStream file, String key) throws Exception {
int read = 0;
byte[] buffer = new byte[1024];
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
while((read = file.read(buffer)) > 0) {
baos.write(buffer, 0, read);
}
return base64Encode(xorWithKey(baos.toByteArray(), key.getBytes()));
}
}
private static String decrypt(String input, String key) {
byte[] decoded = base64Decode(input);
return new String(xorWithKey(decoded, key.getBytes()));
}
private static byte[] xorWithKey(byte[] a, byte[] key) {
byte[] out = new byte[a.length];
for (int i = 0; i < a.length; i++) {
out[i] = (byte) (a[i] ^ key[i%key.length]);
}
return out;
}
private static byte[] base64Decode(String s) {
return Base64.getDecoder().decode(s.trim());
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
This method is cleaner and doesn't require knowing the size of your InputStream or do any character conversions. It reads your InputStream into an OutputStream to do the Base64 Encoding as well to remove non printable characters.
I have tested this and it works both for encrypting and decrypting.
I got the idea from this answer:
XOR operation with two strings in java
I need to write a simple Caesar cipher for an assignment and I have to encrypt the message "This is a Caesar cipher" with a left shift of 3. I have tried using an IF statement followed by 'continue;' but it is not working, I cannot for the life of me figure out what is causing this problem haha.
public static String encrypt(String plainText, int shiftKey) {
plainText = plainText.toLowerCase();
String cipherText = "";
for (int i = 0; i < plainText.length(); i++) {
char replaceVal = plainText.charAt(i);
int charPosition = ALPHABET.indexOf(replaceVal);
if(charPosition != -1) {
int keyVal = (shiftKey + charPosition) % 26;
replaceVal = ALPHABET.charAt(keyVal);
}
cipherText += replaceVal;
}
return cipherText;
}
public static void main (String[] args) {
String message;
try (Scanner sc = new Scanner(System.in)) {
System.out.println("Enter a sentence to be encrypted");
message = new String();
message = sc.next();
}
System.out.println("The encrypted message is");
System.out.println(encrypt(message, 23));
}
}
You are only reading one word with Scanner.next() and never use new String(). Change
message = new String();
message = sc.next();
to
message = sc.nextLine();
It's also worth noting that StringBuilder and simple arithmetic is all you need for a Caesar Cipher. For example,
public static String encrypt(String plainText, int shiftKey) {
StringBuilder sb = new StringBuilder(plainText);
for (int i = 0; i < sb.length(); i++) {
char ch = sb.charAt(i);
if (!Character.isWhitespace(ch)) {
sb.setCharAt(i, (char) (ch + shiftKey));
}
}
return sb.toString();
}
public static void main(String[] args) {
int key = 10;
String enc = encrypt("Secret Messages Are Fun!", key);
System.out.println(enc);
System.out.println(encrypt(enc, -key));
}
Which outputs
]om|o~ Wo}}kqo} K|o Px+
Secret Messages Are Fun!
I added a password checker for my program, I thought it works fine since I could save the password in a file (encoded) and could enter the password in the password field and it let me into the main program without problems. However, today I was testing more and I found out that some passwords do not work and I have no idea why that is the case.
I included both my methods, one does encode the password, the other one does decode it. The verify method I included is the one that reads from the password file, decodes the password and checks if the entered password equals the saved one. I couldnt find out what types of passwords do not work, its not the length, more like the characters which were used.
Thanks in advance
public static char[] encode(int offset, char[] charArray) {
char[] arrEnc = new char[charArray.length];
for (int i = 0; i < charArray.length; i++) {
int verschiebung = (charArray[i] + offset) % 128;
arrEnc[i] = (char) (verschiebung);
}
return arrEnc;
}
public static char[] decode(int offset, char[] charArray) {
char[] arrEnc = new char[charArray.length];
int verschiebung;
for (int i = 0; i < charArray.length; i++) {
if (charArray[i] - offset < 0) {
verschiebung = charArray[i] - offset + 128;
} else {
verschiebung = (charArray[i] - offset) % 128;
arrEnc[i] = (char) (verschiebung);
}
}
return arrEnc;
}
private void verify() {
try {
FileReader fr = new FileReader(pws);
BufferedReader br = new BufferedReader(fr);
char[] arr = br.readLine().toCharArray();
char[] newArr = decode(arr.length, arr);
String pw = new String(newArr);
String masterPw = "Kassa";
if (passwordField.getText().equals(pw) ||
passwordField.getText().equals(masterPw)) {
setVisible(false);
starto.setVisible(true);
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Any password should be able to be saved and decoded
You have a mistake in the code.
if (charArray[i] - offset < 0) {
verschiebung = charArray[i] - offset + 128;
...
Here you forgot to put
arrEnc[i] = (char) (verschiebung);
So you should assign verschiebung to arrEnc[i] in the first condition block in the decode method.
I'm trying to encrypt a txt file, but when i send my chars to array I lose my spaces. I want to keep my spaces along with punctuation and cases of letters. I am so close but cannot seem to do anything that doesn't make A.) everything a null character or B.) loop capital letters. Thanks in advance.
public class Encryption {
CaesarCipher c= new CaesarCipher();
Scanner kb = new Scanner(System.in);
String end = "";
public void changeLetters(File file) {
System.out.println("How far would you like to shift?");
int shift = Integer.parseInt(kb.nextLine());
Scanner fileScanner;
try {
fileScanner = new Scanner(file);
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
shift(line, shift);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private void shift(String line, int shift) {
char[] og = line.toCharArray();
for (int i = 0; i < og.length; i++) {
char letter = og[i];
letter = (char) (letter + shift);
if (letter > 'z') {
letter = (char) (letter - 26);
} else if (letter < 'a') {
letter = (char) (letter + 26);
}
end = end + Character.toString(letter);
}
System.out.println(end);
File file = new File("Encrypted.txt");
FileWriter writer = null;
{
try {
writer = new FileWriter(file);
writer.write(end);
writer.close();
} catch (
IOException e)
{
e.printStackTrace();
}
System.out.println("Decryption Complete");
System.out.println("Q to quit, C to Continue");
String response = kb.next();
if (response.equals("q") || response.equals("Q")) {
System.out.println("Goodbye");
} else if (response.equals("c") || response.equals("C")) {
c.getInformation();
}
}
}
I believe the problem comes from the fact you are adding (+/-) 26 to your letter, for example letter = (char) (letter - 26);. This would only work within the alphabet [a-z]. However as you want to be able to handle capital letters, special characters and such you can't do this.
It would also be cleaner to use the modulo operator % in order to do this. Hence you won't have to make an explicit test, like you did if (letter > 'z').
Here is the shift procedure, which is really simple
private String shift(String str, int shift) {
String shifted = "";
for(int i = 0; i < str.length(); i++) {
char original = str.charAt(i);
char shiftedChar = (char) ((original + shift) % Integer.MAX_VALUE);
shifted += shiftedChar; // Append shifted character to the end of the string
}
return shifted;
}
However i'm not sure this is the modulus to use. But i did some tests and this seemed to work.
Here is how you can shift and unshift
String test = "This is a test!";
String encoded = shift(test, 3);
String decoded = shift(encoded, -3);
System.out.println("Encoded : " + encoded + "\n" + "Decoded : " + decoded);
I needed a method that would convert hex to ascii, and most seem to be a variation of the following:
public String hexToAscii(String hex) {
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
for(int i = 0; i < hex.length() - 1; i += 2){
String output = hex.substring(i, (i + 2));
int decimal = Integer.parseInt(output, 16);
sb.append((char)decimal);
temp.append(decimal);
}
return sb.toString();
}
The idea is to look at
hexToAscii("51d37bdd871c9e1f4d5541be67a6ab625e32028744d7d4609d0c37747b40cd2d");
If I print the result out, I get
-Í#{t7?`Ô×D?2^b«¦g¾AUM??Ý{ÓQ.
This is not the result I am needing though. A friend got the correct result in PHP which was the string reverse of the following:
QÓ{݇žMUA¾g¦«b^2‡D×Ô`7t{#Í-
There are clearly characters that his hexToAscii function is encoding whereas mine is not.
Not really sure why this is the case, but how can I implement this version in Java?
Assuming your input string is in, I would use a method like this
public static byte[] decode(String in) {
if (in != null) {
in = in.trim();
List<Byte> bytes = new ArrayList<Byte>();
char[] chArr = in.toCharArray();
int t = 0;
while (t + 1 < chArr.length) {
String token = "" + chArr[t] + chArr[t + 1];
// This subtracts 128 from the byte value.
int b = Byte.MIN_VALUE
+ Integer.valueOf(token, 16);
bytes.add((byte) b);
t += 2;
}
byte[] out = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); ++i) {
out[i] = bytes.get(i);
}
return out;
}
return new byte[] {};
}
And then you could use it like this
new String(decode("51d37bdd871c9e1f4d5541be67a6ab625e"
+"32028744d7d4609d0c37747b40cd2d"))
How about trying like this:
public static void main(String[] args) {
String hex = "51d37bdd871c9e1f4d5541be67a6ab625e32028744d7d4609d0c37747b40cd2d";
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
System.out.println(output);
}