Here is my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class EncryptedLogger {
private static Date lastLogTime = null;
private static EncryptedLogger instance = null;
private static FileOutputStream fos = null;
private static CipherOutputStream cos = null;
private static PrintWriter writer = null;
private Cipher cipher;
byte[] Key ={(byte) 0x12,(byte) 0x34,0x55,(byte) 0x66,0x67,(byte)0x88,(byte)0x90,0x12,(byte) 0x23,0x45,0x67,(byte)0x89,0x12,0x33,(byte) 0x55,0x74};
public static EncryptedLogger getInstance(){
if (instance==null) {
instance = new EncryptedLogger();
}
return instance;
}
private EncryptedLogger(){
class SQLShutdownHook extends Thread{
#Override
public void run() {
EncryptedLogger.close();
super.run();
}
}
SecretKeySpec sks = new SecretKeySpec(Key,"AES");
try {
cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE,sks);
fos = new FileOutputStream(new File("log.txt"),true);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
cos = new CipherOutputStream(fos, cipher);
writer = new PrintWriter(cos);
SQLShutdownHook hook = new SQLShutdownHook();
Runtime.getRuntime().addShutdownHook(hook);
}
public synchronized void logSQL(String s){
if ((lastLogTime==null)||((new Date().getTime() -lastLogTime.getTime())>1000)){
lastLogTime = new Date();
writer.printf("-- %1$tm-%1$te-%1$tY %1$tH-%1$tM-%1$tS\n%2$s\n",new Date(),s);
}
else{
writer.println(s);
}
}
public synchronized void logComment(String s){
writer.printf("-- %1$tm-%1$te-%1$tY %1$tH-%1$tM-%1$tS: %2$s\n",new Date(),s);
}
public static void close(){
writer.flush();
writer.close();
}
public static void main(String[] args) throws InterruptedException {
EncryptedLogger.getInstance().logSQL("1");
EncryptedLogger.getInstance().logSQL("22");
EncryptedLogger.getInstance().logSQL("33333");
EncryptedLogger.getInstance().logSQL("4900");
EncryptedLogger.getInstance().logSQL("5");
EncryptedLogger.getInstance().logSQL("66666");
EncryptedLogger.getInstance().logSQL("Some test logging statement");
EncryptedLogger.getInstance().logSQL("AAAAAAAAAAAAAAAAAAAAAAAAAA");
EncryptedLogger.getInstance().logComment("here is test commentary");
}
}
As you see i'm trying to encrypt text entries piping them through PrintWriter->CipherOutputStream->FileOutputStream chain. But when I decrypt result file there are missing bytes. I tried to flush cos and fos in EncryptedLogger.close() method - same result. Obviously i'm missing something. What is wrong?
EDIT: here is decryption code i use. It's not mine, taken from tutorial or something...
And it works fine when using simmilar encryption. But when using my code...
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AESDecrypter
{
Cipher dcipher;
public AESDecrypter(SecretKey key)
{
try
{
dcipher = Cipher.getInstance("AES");
dcipher.init(Cipher.DECRYPT_MODE, key);
}
catch (Exception e)
{
e.printStackTrace();
}
}
byte[] buf = new byte[1024];
public void decrypt(InputStream in, OutputStream out)
{
System.out.println("decrypting");
try
{
in = new CipherInputStream(in, dcipher);
int numRead = 0;
while ((numRead = in.read(buf)) >= 0)
{
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e)
{
}
}
public static void main(String args[])
{
try
{
byte[] keystr ={(byte) 0x12,(byte) 0x34,0x55,(byte) 0x66,0x67,(byte)0x88,(byte)0x90,0x12,(byte) 0x23,0x45,0x67,(byte)0x89,0x12,0x33,(byte) 0x55,0x74};
SecretKeySpec sks = new SecretKeySpec(keystr,"AES");
AESDecrypter encrypter = new AESDecrypter(sks);
encrypter.decrypt(new FileInputStream("sqllogenc.log"),new FileOutputStream("sqllogdec.log"));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
EDIT2: when i write directly to fos i get this output:
-- 04-19-2012 16-17-56
1
22
33333
4900
5
66666 + delay starting 1100
Some test logging statement
AAAAAAAAAAAAAAAAAAAAAAAAAA
-- 04-19-2012 16-17-56: here is test commentary
and when writing using cos and decrypting:
-- 04-19-2012 16-22-13
1
22
33333
4900
5
66666 + delay starting 1100
Some test logging statement
AAAAAAAAAAAAAAAAAAAAAAAAAA
-- 04-19-2012 16-22-13: here
As you see part of the last line is missing including linebreak.
You should use the same cryptographic transformation (such as AES/ECB/NoPadding) at both sides. Also, note that NoPadding mode doesn't allow you to pass data of arbitrary size, therefore you need to specify some other kind of padding.
So, you need to construct Ciphers as Cipher.getInstance("AES/ECB/PKCS5Padding") at both sides.
Also, note the suggestion of rossum about use of CBC or CTR instead of ECB.
Well, AES has a fixed block size of 128 bits.
When you use AES/ECB/NoPadding, you take the responsability of making sure the size of your message is a multiple of the block size.
It probably isn't, so you get less text when you decrypt.
You should use AES/ECB/NoPadding for arbitrary length of text.
Related
Currently working on making a pipeline among two files in java and I would to transmit a float via stream bytes. However I don't know how I can receive it and convert it into a float. Here is what I have done so far:
(3 files)
Consumi.java:
package tryout5_stream_bytes;
import java.io.Serializable;
public class Consumi implements Serializable{
private float consumi = 0.0F;
public Consumi(float consumi){
this.consumi = consumi;
}
public float getConsumi(){
return consumi;
}
public byte[] getBytes(String encode){
return String.valueOf(consumi).getBytes();
}
}
SimulaConsumi.java
package tryout5_stream_bytes;
import java.io.PipedOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.atomic.AtomicBoolean;
public class SimulaConsumi implements Runnable {
private AtomicBoolean isRunning = new AtomicBoolean(false);
private PipedOutputStream pos = null;
public SimulaConsumi(PipedOutputStream pos){
this.pos = pos;
}
#Override
public void run(){
isRunning.set(true);
while(isRunning.get()){
Consumi c = new Consumi((float) (30 * Math.random()));
byte[] message = null;
message = c.getBytes("UTF-8");
try{
pos.write(message);
pos.flush();
} catch(IOException e){
e.printStackTrace();
}
try{
Thread.sleep(1000);
} catch(InterruptedException e){
e.printStackTrace();
}
}
}
public void terminaSimulaConsumi(){
isRunning.set(false);
}
}
Main.java
package tryout5_stream_bytes;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.io.*;
import java.lang.object;
import java.nio.ByteBuffer;
public class Main {
public static void main(String[] args){
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = null;
try{
pos = new PipedOutputStream(pis);
}catch(IOException e){
e.printStackTrace();
}
SimulaConsumi sc = new SimulaConsumi(pos);
Thread tsc = new Thread();
tsc.start();
while(true){
try{
Thread.sleep(900);
}catch(InterruptedException e){
e.printStackTrace();
}
byte[] buffer = new byte[256];
try{
pis.read(buffer);
}catch(IOException e){
e.printStackTrace();
}
float received = //Get a float from a stream bytes???
System.out.println("Value:"+received);
}
}
}
I believe that the sending of the float in the file "SimulaConsumi" is done well (however I might still be wrong). On the other hand I really have no idea how I can receive it!
I have two text files that are more than 600MB and I want to compare the content of them if they are the same (Ignoring any space at the end or the start of any line in it i.e. trim() each line).
I am thinking of reading each line of them as a string and then trim it and compare it.
Is there is a better idea and if not what is the fastest implementation to this idea?
Thanks in advance.
If you want to compare whether the files are consistent, please calculate the file md5 value to compare:
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class MainServer {
public static void main(String[] args) {
String filePath1 = "D:\\Download\\a.mp3";
String filePath2 = "D:\\Download\\b.mp3";
String file1_md5 = md5HashCode(filePath1);
String file2_md5 = md5HashCode(filePath2);
System.out.println(file1_md5);
System.out.println(file2_md5);
if(file1_md5.equals(file2_md5)){
System.out.println("Two files are the same ");
}
}
/**
* get file md5 value
*/
public static String md5HashCode(String filePath) {
try {
InputStream fis =new FileInputStream(filePath);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md.update(buffer, 0, length);
}
fis.close();
byte[] md5Bytes = md.digest();
BigInteger bigInt = new BigInteger(1, md5Bytes);
return bigInt.toString(16);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
If you need to read each line of the file for comparison:
List<String> file1_lines = null;
List<String> file2_lines = null;
try {
file1_lines = Files.readAllLines(Paths.get("D:/a.txt"), StandardCharsets.UTF_8);
file2_lines = Files.readAllLines(Paths.get("D:/b.txt"), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < file1_lines.size(); i++) {
String file1_line = file1_lines.get(i).trim();
String file2_line = file2_lines.get(i).trim();
if (file1_line.equals(file2_line)) {
//do some
}
}
Why must I use DigestInputStream and not FileInputStream to get a digest of an file?
I have written a program that reads ints from FileInputStream, converts them to bytes and passes them to update method of MessageDigest object. But I have a suspicion that it doesn't work properly, because it calculates a digest of a very large file instanlty. Why doesn't it work?
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class DigestDemo {
public static byte[] getSha1(String file) {
FileInputStream fis = null;
MessageDigest md = null;
try {
fis = new FileInputStream(file);
} catch(FileNotFoundException exc) {
System.out.println(exc);
}
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException exc) {
System.out.println(exc);
}
byte b = 0;
do {
try {
b = (byte) fis.read();
} catch (IOException e) {
System.out.println(e);
}
if (b != -1)
md.update(b);
} while(b != -1);
return md.digest();
}
public static void writeBytes(byte[] a) {
for (byte b : a) {
System.out.printf("%x", b);
}
}
public static void main(String[] args) {
String file = "C:\\Users\\Mike\\Desktop\\test.txt";
byte[] digest = getSha1(file);
writeBytes(digest);
}
}
You need to change the type of b to int,, and you need to call MessageDigest.doFinal() at the end of the file, but this is horrifically inefficient. Try reading and updating from a byte array.
There's too much try-catching in this code. Reduce it to one try and two catches, outside the loop.
I wrote a utility program to do encryption and decryption using AES algorithm. Regular program works fine but when I run test with same method I am getting Cipher initialization error on doFinal method.
I did some research and some suggest to put init and doFinal in a synchronized block. I did that and still getting same exception.
I also updated US_export_policy.jar and local_policy.jar in jre7/lib/security folder as suggested by some forum. Still getting same issue.
What could be wrong in the code?
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;
public class CipherUtil {
private static Logger log = Logger.getLogger(CipherUtil.class);
private static final String SECRET_KEY = "000102030405060708090A0B0C0D0E0F";
private Cipher cipher;
private SecretKeySpec secretKeySpec;
private static CipherUtil cipherUtil;
private CipherUtil() {
try {
cipher = Cipher.getInstance("AES");
} catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
log.error(ex);
}
byte[] key = null;
try {
key = Hex.decodeHex(SECRET_KEY.toCharArray());
} catch (DecoderException ex) {
log.error(ex);
}
secretKeySpec = new SecretKeySpec(key, "AES");
}
public static synchronized CipherUtil getCipherUtilObject() {
if (cipherUtil == null) {
cipherUtil = new CipherUtil();
}
return cipherUtil;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public String encrypt(String plainText) {
if (plainText == null)
return null;
String encryptedText = null;
byte[] encrypted = null;
synchronized (cipher) {
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
} catch (InvalidKeyException e) {
log.error(e.getMessage());
}
}
synchronized (cipher) {
try {
encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
encryptedText = new String(Base64.encodeBase64(encrypted));
} catch (IllegalBlockSizeException | BadPaddingException
| UnsupportedEncodingException e) {
log.error(e.getMessage());
}
}
return encryptedText;
}
public synchronized String decrypt(String encryptedText) {
if (encryptedText == null)
return null;
byte[] toDecrypt = null;
byte[] original = null;
String decryptedText = null;
synchronized (cipher) {
try {
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
} catch (InvalidKeyException e) {
log.error(e.getMessage());
}
}
toDecrypt = Base64.decodeBase64(encryptedText);
synchronized (cipher) {
try {
original = cipher.doFinal(toDecrypt);
} catch (IllegalBlockSizeException | BadPaddingException e) {
log.error(e.getMessage());
}
}
try {
decryptedText = new String(original, "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage());
}
return decryptedText;
}
}
and the test class:
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
public class CipherTest {
CipherUtil cipherUtil;
#Before
public void setUp() {
cipherUtil = CipherUtil.getCipherUtilObject();
}
#Test
public void testEncryptDecrypt() {
String plainText = "Secret Message";
String encryptedText = cipherUtil.encrypt(plainText);
assertThat(encryptedText, not(equalTo(plainText)));
String decryptedText = cipherUtil.decrypt(encryptedText);
assertThat(decryptedText, is(equalTo(plainText)));
assertThat(encryptedText, not(equalTo(decryptedText)));
}
}
and finally this is the exception:
java.lang.IllegalStateException: Cipher not initialized
at javax.crypto.Cipher.checkCipherState(Cipher.java:1672)
at javax.crypto.Cipher.doFinal(Cipher.java:2079)
at com.testapp.util.CipherUtil.encrypt(CipherUtil.java:67)
at com.testapp.util.CipherTest.testEncryptDecrypt(CipherTest.java:23)
The code ran fine on my machine. Note that your encrypt method is not synchronized, so running this in a threaded environment will make it fail. In general you should have one Cipher instance per thread. Cipher contains state between method calls, so just synchronizing access to the method calls themselves will fail from time to time.
I am coding a little tool to encrypt and decrypt files. The encrypted files will be added to a zip-archive. The following code is working so far. I can encrypt any files but textfiles. If I choose a textfile it is written incomplete. If there is the following text:
"one two three test check check test" it gets cut like "one two three test che".
There is no exception thrown just a few bytes are missing. Any other files (pdf, mp3, mp4, exe and so forth) are written completely.
package encryptme.crypto;
import encryptme.fileoperations.FileIn;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
public class Encrypt {
private String algorithm;
private int keylength;
private Key key;
private KeyPair keypair;
private File[] source;
private String destination;
public Encrypt(String a, int kl, Key k, File[] s, String dest) {
this.algorithm = a;
this.keylength = kl;
this.key = k;
this.source = s;
this.destination = dest;
this.output = o;
}
public void encOut() {
CipherOutputStream cout = null;
ZipOutputStream zout = null;
OutputStream out = null;
Cipher cipher;
try {
out = new FileOutputStream(this.destination);
System.out.println(this.destination);
zout = new ZipOutputStream(out);
cipher = Cipher.getInstance(this.algorithm);
cipher.init(Cipher.ENCRYPT_MODE, this.key);
for (int i = 0; i < this.source.length; i++) {
FileInputStream in = new FileInputStream(this.source[i].getAbsolutePath());
ZipEntry ze = new ZipEntry(this.source[i].getName());
zout.putNextEntry(ze);
cout = new CipherOutputStream(zout, cipher);
byte[] buffer = new byte[1024];
long bytesRead = 0;
for (bytesRead = 0; (bytesRead = in.read(buffer)) != -1;) {
cout.write(buffer, 0, (int) bytesRead);
}
zout.closeEntry();
in.close();
}
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (cout != null) {
cout.close();
}
if (zout != null) {
zout.close();
}
if (out != null) {
out.close();
}
} catch (IOException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
The files to be encrypted are chosen with a jFileChooser and added to an array which gets passed in to the class above as parameter. I thought about using a PrintWriter for those textfiles identifying them by their ending e.g. 'textfile.txt' or 'textfile.odt'. But what shall I do if the file does not have an ending just like 'textfile'?
I'm pretty new to Java and coding in general so I hope there is just a bad mistake which causes the problem.
You need to close the cout before you call zout.closeEntry in order to flush out any remaining data that the cipher has buffered. Unfortunately, cout.close() will call zout.close(), which we definitely don't want because that will stop you writing any further entries.
I would use the CloseShieldOutputStream from commons-io:
cout = new CipherOutputStream(new CloseShieldOutputStream(zout), cipher);
This class is designed to stop the close() call from propagating to the underlying wrapped stream (in this case zout).
I'm not 100% sure what your asking, but do you want to sanitize the array of files your receive to your Encrypt class? One way indeed is to look at the file extension:
public class ImageFileFilter implements FileFilter {
private String[] imageExtentions = {"png", "jpg", "gif" };
#Override
public boolean accept(File file) {
for(String ext : imageExtentions){
if(file.isFile()){
if(file.getName().toLowerCase().endsWith(ext))
return true;
}
}
return false;
}
}
The above example is a class which is supposed to handle image extensions, but its generic so it will work for any extention thats passed into the accept method. The key is to implment the FileFilter interface, then you can sanitize your files.
Edit:
ahh, you edited your question which makes it more clear about what you want, which is not what the answer I've given solves.