java write to file results in chinese letters - java

I'm decrypting a regular text file and encountering an issue I cant solve,
My code works like this,
I receive a txt file with letters,numbers and the signs + and / (which is Radix64)
I then read 12 chars from the file, convert them into a string, and then using base64.decoder to decode the text into an 8 byte array.
Using system.out.print on both the byte array and on the string I build shows me that the reading was correct and I got what I needed from the file.
Now I shift the bytes a few times to the right or left and want to write the byte array to a new file which is the decrypted message.
I'm using FileOutputStream to write to a new file, now comes the problem, I open the file and its all Chinese letters.
I have no clue how is that even possible since the only thing I do is write bytes to a file.
I tried to find information regarding this subject without any success, only related topic was python/ruby related and was stating that its a UTF-8/UTF-16 problem but no answers to how to fix it.
Any help would be appreciated, and if posting parts of my code will help please let me know what exactly is needed.
private static void Decryption() {
InputStream byteReader = null;
FileOutputStream fop = null;
int byteByByte = 0;
char[] radixToByte = new char[12];
byte[] block = new byte[8];
byte[] decryptedBlock = new byte[8];
long key = 0;
//the file which will contain the plain text will be p.txt in the same directory c.txt is
try {
fop = new FileOutputStream(new File(fileName.substring(0, fileName.length()-5)+"p.txt"));
} catch (FileNotFoundException e) {
System.out.println("File was not found");
e.printStackTrace();
}
//open key file and read the key.
try {
byteReader = new FileInputStream(keyFileName);
} catch (FileNotFoundException e) {
System.out.println("File was not found");
System.exit(0);
}
//reading 56 bits in radix format and building the key accordingly
char[] keyByteArray = new char[12];
for(int k = 0; k < 12; k++){
try {
byteByByte = byteReader.read();
} catch (IOException e) {
e.printStackTrace();
}
keyByteArray[k] = (char) byteByByte;
}
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedByteArray = decoder.decode(new String(keyByteArray));
for(int k = 0; k < 7; k++){
key <<= 8;
key |= (decodedByteArray[k] & 0x00000000000000FF);
}
//open cipher text to decrypt.
try {
byteReader = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
System.out.println("File was not found");
System.exit(0);
}
//while haven't reached end of cipher text message keep reading byte by byte and decrypting
//them block by block (each block 64 bits).
while(isFileReadingFinished == false){
for(int i = 0; i < 12; i++){
try {
byteByByte = byteReader.read();
} catch (IOException e) {
e.printStackTrace();
}
if(byteByByte == -1){
isFileReadingFinished = true;
break;
}
radixToByte[i] = (char)byteByByte;
}
//this is the block after radix but still decrypted so we will save it for CBC
block = decoder.decode(new String(radixToByte));
//encrypt via feistel
decryptedBlock = feistel(block, key);
//after decryption we still need to xor with previous encrypted data or IV.
for(int i = 0; i < 8; i++){
decryptedBlock[i] = (byte) (decryptedBlock[i] ^ initializationVector[i]);
}
//next decrypted text will need to be xored with the current encrypted text after decryption.
for(int i = 0; i < 8; i++){
initializationVector[i] = block[i];
}
try {
fop.write(decryptedBlock);
fop.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
try {
fop.close();
} catch (IOException e) {
e.printStackTrace();
}
}

Related

How to convert binary text into useable file

So I use the following methods
(File is converted to Byte Array through 'convertFileToByteArray()', then written to .txt file by 'convertByteArrayToBitTextFile()'
to convert any kind of file into a Binary Text file (and by that I mean only 1's and 0's in human readable form.)
public static byte[] convertFileToByteArray(String path) throws IOException
{
File file = new File(path);
byte[] fileData;
fileData = new byte[(int)file.length()];
FileInputStream in = new FileInputStream(file);
in.read(fileData);
in.close();
return fileData;
}
public static boolean convertByteArrayToBitTextFile(String path, byte[] bytes)
{
String content = convertByteArrayToBitString(bytes);
try
{
PrintWriter out = new PrintWriter(path);
out.println(content);
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static String convertByteArrayToBitString(byte[] bytes)
{
String content = "";
for (int i = 0; i < bytes.length; i++)
{
content += String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0');
}
return content;
}
Edit: Additional Code:
public static byte[] convertFileToByteArray(String path) throws IOException
{
File file = new File(path);
byte[] fileData;
fileData = new byte[(int)file.length()];
FileInputStream in = new FileInputStream(file);
in.read(fileData);
in.close();
return fileData;
}
public static boolean convertByteArrayToBitTextFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for (int i = 0; i < bytes.length; i++)
{
out.print(String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0'));
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertByteArrayToByteTextFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for(int i = 0; i < bytes.length; i++)
{
out.print(bytes[i]);
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertByteArrayToRegularFile(String path, byte[] bytes)
{
try
{
PrintWriter out = new PrintWriter(path);
for(int i = 0; i < bytes.length; i++)
{
out.write(bytes[i]);
}
out.close();
return true;
}
catch (FileNotFoundException e)
{
return false;
}
}
public static boolean convertBitFileToByteTextFile(String path)
{
try
{
byte[] b = convertFileToByteArray(path);
convertByteArrayToByteTextFile(path, b);
return true;
}
catch (IOException e)
{
return false;
}
}
I do this to try methods of compression on a very fundamental level, so please let's not discuss why use human-readable form.
Now this works quite well so far, however I got two problems.
1)
It takes foreeeever (>20 Minutes for 230KB into binary text). Is this just a by-product of the relatively complicated conversion or are there other methods to do this faster?
2) and main problem:
I have no idea how to convert the files back to what they used to be. Renaming from .txt to .exe does not work (not too surprising as the resulting file is two times larger than the original)
Is this still possible or did I lose Information about what the file is supposed to represent by converting it to a human-readable text file?
If so, do you know any alternative that prevents this?
Any help is appreciated.
The thing that'll cost you most time is the construction of an ever increasing String. A better approach would be to write the data as soon as you have it.
The other problem is very easy. You know that every sequence of eight characters ('0' or '1') was made from a byte. Hence, you know the values of each character in an 8-character block:
01001010
^----- 0*1
^------ 1*2
^------- 0*4
^-------- 1*8
^--------- 0*16
^---------- 0*32
^----------- 1*64
^------------ 0*128
-----
64+8+2 = 74
You only need to add the values where an '1' is present.
You can do it in Java like this, without even knowing the individual bit values:
String sbyte = "01001010";
int bytevalue = 0;
for (i=0; i<8; i++) {
bytevalue *= 2; // shifts the bit pattern to the left 1 position
if (sbyte.charAt(i) == '1') bytevalue += 1;
}
Use StringBuilder to avoid generating enormous numbers of unused String instances.
Better yet, write directly to the PrintWriter instead of building it in-memory at all.
Loop through every 8-character subsequence and call Byte.parseByte(text, 2) to parse it back to a byte.

cipher block chaining / cipher text stealing java

To gain a better understanding of CBC and CTS im trying to impliment my own class that can encrypt and decrypt without using java's built in CTS Mode. Im using an AES wrapper class as the underlying algorithm but CTS as the mode of operation. So far i have been working on the encryption method but not sure where to go from there. I'm not really sure how to implement the swap of the blocks at end of the CTS mode.
Here is the code i have so far for my encryption method (and dont worry about the AES class it works 100%):
static byte[] encrypt(byte[] ptBytes, javax.crypto.SecretKey key, byte[] IV){
byte [] ct;
byte [] pt;
byte [] ptBlock, ctBlock;
//pad the array to proper length
pt = Arrays.copyOf(ptBytes, (int) (Math.ceil( ( ptBytes.length )/16)*16) );
//ctBlock = one block of cipher text
ctBlock = new byte [16];
//make ct the length of the padded pt
ct = new byte [pt.length];
//do the encryption
//i is for the current block of plain / cipher text we are on
for( int i = 1; i < (int) ((Math.ceil( ( ptBytes.length )/16)+1)); i++){
if( i == 1 ){
//make ptBlock the first block of the entire plain text
ptBlock = Arrays.copyOfRange(pt, 0, (i*16)-1);
//since i = 1 do the XOR to get new plain text with IV
for (int j = 0; j < ptBlock.length - 1; j++){
ptBlock[j] = (byte)(ptBlock[j] ^ IV[j]);
}
//now time to do the encryption between the current block of plain text and the key
try {
ctBlock = AES.encrypt(ptBlock, key);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//now put the cipher text block we just got into the final cipher text array
for( int k = 0; k < ctBlock.length; k++){
ct[k] = ctBlock[k];
}
}
else{
//make ptBlock the current number block of entire plain text
ptBlock = Arrays.copyOfRange(pt, (i-1)*16, (i*16)-1);
//now XOR the plain text block with the prior cipher text block
for(int j = 0; j < ptBlock.length - 1; j++){
ptBlock[i] = (byte) (ptBlock[j] ^ ctBlock[j]);
}
//now time to do the encryption between the current block of plain text and the key
try {
ctBlock = AES.encrypt(ptBlock, key);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//now put the cipher text block we just got into the final cipher text array
for( int k = (i-1)*16; k < (i*16)-1; k++){
ct[k] = ctBlock[k-16];
}
}
}
return ct;
}
Just if anyone could give some insight into how to finish this method up that would be great because i still am learning the ins and outs of CBC/CTS
Thanks!

Image Steganography Java

I am trying to decode the data encoded in the image. The encoding works fine and the data size of image also changes but for some reason the decoded data is an empty string. Either the encoded data get lost or this code has some mistake.
int temp,tempText=0,x=0,p=0;
try
{
image= ImageIO.read(new File("C:\\Users\\Desktop\\Encoded.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
for(int i=0;i<image.getWidth();i++)
{
for(int j=0;j<image.getHeight();j++)
{
pixels[i][j]=image.getRGB(i, j);
}
}
for(int i=0;i<Width;i++)
{
for(int j=0;j<Height;j++)
{
temp=pixels[i][j];
int change=0;
for(int k=0;k<4;k++) // 4 iterations for 4bytes of every pixel
{
if(k==0)
{
change=1;
}
else
if(k==1)
{
change=256;
}
else
if(k==2)
{
change=65536;
}
else
if(k==3)
{
change = 16777216;
}
tempText=tempText | (pixels[i][j] & change);
p++;
if(p==8) // because character is of 8bits
{
myString.concat(String.valueOf(tempText));// Writing decoded data in string
p=0;
tempText=0;
}
}
}
// Writing in file
try
{
file = new File("C:\\Users\\Desktop\\Retreive.txt");
fw = new FileWriter(file);
bw= new BufferedWriter(fw);
bw.write(myString);
bw.close();
}
catch (Exception e)
{
e.printStackTrace();
}
Kindly notify me if any mistake I am making or any thing this code is lacking.
String.concat doesn't change the string you call it on, but instead returns a new string. So if you use myString = myString.concat(...) instead, you might get better results. If tempText contains a character code, you could cast it to a char (since String.valueOf returns the string representation of the int):
// Writing decoded data in string
// myString = myString.concat(String.valueOf(tempText));
myString += (char) tempText;
instead of:
myString.concat(String.valueOf(tempText));// Writing decoded data in string

Huffman Coding - Dealing with unicode

I've implemented a Huffman coding in java, that works on byte data from an input file. However, it only works when compressing ascii. I'd like to extend it so that it can deal with characters that are larger than 1 byte long, but I'm not sure how to do this exactly.
private static final int CHARS = 256;
private int [] getByteFrequency(File f) throws FileNotFoundException {
try {
FileInputStream fis = new FileInputStream(f);
byte [] bb = new byte[(int) f.length()];
int [] aa = new int[CHARS];
if(fis.read(bb) == bb.length) {
System.out.print("Uncompressed data: ");
for(int i = 0; i < bb.length; i++) {
System.out.print((char) bb[i]);
aa[bb[i]]++;
}
System.out.println();
}
return aa;
} catch (FileNotFoundException e) { throw new FileNotFoundException();
} catch (IOException e) { e.printStackTrace(); }
return null;
}
For example, this is what I'm using to get the frequency of the characters in the file, and obviously it only works on a single byte. If I give it a unicode file, I get an ArrayIndexOutOfBoundsException at aa[bb[i]]++;, and i is normally a negative number. I know this is because aa[bb[i]]++; is only looking at one byte, and the unicode character will be more than one, but I'm not sure on how I can change it.
Can anybody give me some pointers?
Try the following:
private static final int CHARS = 256;
private int [] getByteFrequency(File f) throws FileNotFoundException {
try {
FileInputStream fis = new FileInputStream(f);
byte [] bb = new byte[(int) f.length()];
int [] aa = new int[CHARS];
if(fis.read(bb) == bb.length) {
System.out.print("Uncompressed data: ");
for(int i = 0; i < bb.length; i++) {
System.out.print((char) bb[i]);
aa[((int)bb[i])&0xff]++;
}
System.out.println();
}
return aa;
} catch (FileNotFoundException e) { throw new FileNotFoundException();
} catch (IOException e) { e.printStackTrace(); }
return null;
}
If i'm correct (I haven't tested it), your problem is that byte is a SIGNED value in java. The cast to integer + masking it to 0xff should handle it correctly.

Failed to Decrypt after compressing string into a text file (AES)

First time posting this so don't go too hard on me (although I've been read this forum quite for some time)
The problem that I encounter using AES in Java is like this.
First, I need to encrypt a string and write it into a text file then compress it, no problem with this. I'm using AES encryption and I define my own key e.g "123"
Second, I need to decompress the file (or extract it?) and decrypt it using the same key that I used on 1st step.
What happen in here is : First step is good but the 2nd one failed on decrypting the file even though the string result is the same, total character, word, etc
Here is the code to write the file
private static void inputKeFile(String input) throws IOException
{
FileWriter fstream = new FileWriter("C:/Users/Sactio/Desktop/tyo/txtToZip.txt",false);
BufferedWriter out = new BufferedWriter(fstream);
out.write(input);
//Close the output stream
out.close();
}
to zip the file
private static void doZip() {
try {
String filename ="C:/Users/Sactio/Desktop/tyo/txtToZip.txt";
String zipfilename="C:/Users/Sactio/Desktop/OutputZipWrite";
File file = new File(filename);
FileInputStream fis = new FileInputStream(file);
long length = file.length();
byte[] buf = new byte[(int)length];
fis.read(buf,0,buf.length);
CRC32 crc = new CRC32();
ZipOutputStream s = new ZipOutputStream(new FileOutputStream(zipfilename));
s.setLevel(9);
ZipEntry entry = new ZipEntry(filename);
entry.setSize((long)buf.length);
crc.reset();
crc.update(buf);
entry.setCrc( crc.getValue());
s.putNextEntry(entry);
s.write(buf, 0, buf.length);
s.finish();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
and this is the encryption
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class JcaTest {
private Cipher ecipher;
private Cipher dcipher;
JcaTest(SecretKey key) {
try {
ecipher = Cipher.getInstance("AES");
dcipher = Cipher.getInstance("AES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
} catch (Exception e) {
System.out.println("Failed in initialization");
}
}
public String encrypt(String str) {
try {
byte[] utf8 = str.getBytes("UTF-8");
byte[] enc = ecipher.doFinal(utf8);
return new sun.misc.BASE64Encoder().encode(enc);
} catch (Exception e) {
System.out.println("Failed in Encryption");
}
return null;
}
public String decrypt(String str) {
try {
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF-8");
} catch (Exception e) {
System.out.println("Failed in Decryption");
}
return null;
}
and last, the extractor for zip
private static void bacaZip(String zipfilename) throws IOException
{
ZipInputStream zinstream = new ZipInputStream(
new FileInputStream(zipfilename));
File file = new File(zipfilename);
FileInputStream fis = new FileInputStream(file);
long length = file.length();
byte[] buf = new byte[(int)length];
ZipEntry zentry = zinstream.getNextEntry();
System.out.println("Name of current Zip Entry : " + zentry + "\n");
while (zentry != null) {
String entryName = zentry.getName();
System.out.println("Name of Zip Entry : " + entryName);
FileOutputStream outstream = new FileOutputStream("C:/Users/Sactio/Desktop/OutputZipWrite.txt");
int n;
while ((n = zinstream.read(buf, 0, buf.length)) > -1) {
outstream.write(buf, 0, n);
}
System.out.println("Successfully Extracted File Name : "
+ entryName);
outstream.close();
zinstream.closeEntry();
zentry = zinstream.getNextEntry();
}
}
private static void extractZip(String jsonString) throws FileNotFoundException
{
try {
bacaZip(jsonString);
} catch (IOException e1) {
// TODO Auto-generated catch block
System.err.println("Exception: "+e1);
}
StringBuffer contents = new StringBuffer();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("C:/Users/Sactio/Desktop/OutputZipWrite.txt"));
String text = null;
// repeat until all lines is read
while ((text = reader.readLine()) != null) {
contents.append(text)
.append(System.getProperty(
"line.separator"));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// show file contents here
System.out.println("HASIL: "+contents.toString());
}
If I skip compression and file steps, AES works good, but if I send the string into a file and compress it, AES encryption fail for some reason. Does anyone have any idea for this problem?
The file you decrypt must be byte-for-byte the same as the output from the encryption process. You say "even though the string result is the same, total character, word, etc" To me that indicates you are treating the encrypted file as text, 'character'. It isn't text, it is bytes. Treating it as text is a recipe for disaster because of the many different ways characters can be expressed as bytes. You need to check byte-for-byte identity and always treat the cyphertext as bytes, not characters.
As #Thilo pointed out, compressing encrypted data is useless. Use the sequence compress -> encrypt -> decrypt -> expand.

Categories