I run a java program to verify digital signature
package com.cryptography;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class VerifyDkimSignature {
public static void main(String[] args) {
FileInputStream fis;
try {
//Read encoded public key bytes
fis = new FileInputStream
("/home/src/com/cryptography/DkimPublicKey");
byte[] encKey = new byte[fis.available()];
fis.read(encKey);
fis.close();
//Generate public key
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
//Read signature bytes from file
BufferedInputStream bis = new BufferedInputStream
(new FileInputStream
("/home/src/com/cryptography/Signature"));
byte[] signatureBytes = new byte[bis.available()];
bis.read(signatureBytes);
//Initialise signature instance
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pubKey);
//Supply signature object with the data for verification
bis = new BufferedInputStream
(new FileInputStream
("/home/src/com/cryptography/SampleFile.txt"));
byte[] origFile = new byte[1024];
int len = 0;
while(bis.available() != 0) {
len = bis.read(origFile);
sig.update(origFile, 0, len);
}
boolean isVerifies = sig.verify(signatureBytes);
System.out.println("Signature verifies::"+isVerifies);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
When I execute it, I get the following exception
java.security.SignatureException: Signature encoding error
at sun.security.rsa.RSASignature.engineVerify(Unknown Source)
at java.security.Signature$Delegate.engineVerify(Unknown Source)
at java.security.Signature.verify(Unknown Source)
at com.cryptography.VerifyDkimSignature.main(VerifyDkimSignature.java:54)
Caused by: java.io.IOException: ObjectIdentifier mismatch: 1.3.14.3.2.26
at sun.security.rsa.RSASignature.decodeSignature(Unknown Source)
... 4 more
Can someone please explain the reason for the error?
It turns out that "1.3.14.3.2.26" (from the IOException) is the OID for a SHA-1 algorithm. So the mistake which I have done here is using different algorithms for verification and signing i.e I have used SHA1withRSA for signing and SHA256With RSA for verification. This got resolved once I changed the algorithm at the verification end to SHA1WithRSA
Related
I got another problem with input/output streams. Here i'm sending data from a server to a client. Before sending the data, the server send a little string just to say to the client what he'll send, and so the client know which function he should use to receive.
I'm receiving the first string well, but then i don't get the good integer and after that the second string i receive is "null".
Moreover, if i do a System.out.println before using the DataOutputStream with dos.writeInt, then everything works well.
I dont get it. here's the code:
Server:
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.SecureRandom;
public class Server {
private static OutputStream out;
static byte[] generateRandomBytes(int len) {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[len];
random.nextBytes(bytes);
return bytes;
}
public static void sendType(String type) {
PrintWriter textWriter = new PrintWriter(out);
textWriter.println(type);
textWriter.flush();
}
public static void sendKeyNumber(int keyNumber) {
sendType("keyNumber");
try {
DataOutputStream dos = new DataOutputStream(out);
//System.out.println("Sending key number: " + keyNumber);
dos.writeInt(keyNumber);
//dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void sendKey(byte[] key) {
sendType("key");
try {
DataOutputStream dos = new DataOutputStream(out);
//System.out.println("key length to send: " +key.length);
dos.writeInt(key.length); // write length of the byte array
//dos.flush();
dos.write(key);
//dos.flush();
System.out.println("key send: " +key);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Socket clientSocket ;
System.out.println("ouverture du server");
try {
ServerSocket serverSocket = new ServerSocket(2004);
clientSocket = serverSocket.accept();
out = clientSocket.getOutputStream();
sendKeyNumber(0);
byte[] keyBytes = generateRandomBytes(32);
sendKey(keyBytes);
clientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Client:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.crypto.spec.SecretKeySpec;
public class Main {
static InputStream in;
public static int receiveKeyNumber() {
DataInputStream dis = new DataInputStream(in);
int keyNumber = 0;
try {
keyNumber = dis.readInt();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return keyNumber;
}
public static SecretKeySpec receiveKey() {
DataInputStream dIn = new DataInputStream(in);
int length;
byte[] keyBytes = null;
try {
length = dIn.readInt(); // read length of incoming message
System.out.println("key length: " + length);
if(length!=32) {
System.err.println("Incorrect size for key: "+ length);
}
else {
keyBytes = new byte[length];
dIn.readFully(keyBytes, 0, keyBytes.length);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec aesKey = new SecretKeySpec(keyBytes, "AES");
return aesKey;
}
public static void main(String[] args) {
Socket clientSocket;
try {
clientSocket = new Socket(InetAddress.getLocalHost(),2004);
in = clientSocket.getInputStream();
while(!clientSocket.isClosed()) {
BufferedReader textReader = new BufferedReader(new InputStreamReader(in));
String type = textReader.readLine();
System.out.println(type);
if(type.equals("keyNumber")) {
int KN = receiveKeyNumber();
System.out.println(KN);
}
if(type.equals("key")) {
SecretKeySpec key = receiveKey();
System.out.println(key);
}
}
clientSocket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
End here's what i get (in Client console) when i don't do the System.out.println:
keyNumber
1801812234
null
I always get the same weird number; i've try to convert it to ASCII, but it's not readable.
Any suggestion?
In this case where binary data is sent, go entirely for DataOutputStream.
(Alternatively you could go for text.)
private static DataOutputStream out;
out = new DataOutputStream(clientSocket.getOutputStream());
public static void sendType(String type) {
out.writeUTF(type);
out.flush();
}
Flushing is important with binary conversations.
The problem with wrapping classes DataOutputStream, Printer, BufferedReader and such is that they start their own "cursor" and would close the wrapped I/O on their own closing. Having several DataOutputStreams is somewhat worrying; at least not as intended.
By the way my normal pattern is to do in main: new Server().exec(); or such.
That would remove all those statics.
I have written a program to encrypt text in Java. It works fine for the most part.
Short strings encrypt and decrypt just fine.
However, if I input more than a few words, the encrypted text output to the console contains carriage-returns. Any ideas on what might be going on?
If I paste the output into notepad, and remove the returns, and then decrypt it with my program, it returns the originally input text as expected.
I have included most of the code, because I haven't any idea where the error is occurring.
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder;
public class Application
{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
String textToEncrypt = "Hello World";
String textToDecrypt;
String textToDecryptAscii;
String result;
int operation;
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES");
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NoSuchPaddingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String key = "Baw12345Baw12345"; // 128 bit key
BASE64Encoder asciiEncoder = new BASE64Encoder();
BASE64Decoder asciiDecoder = new BASE64Decoder();
System.out.printf("Enter:\n1 for encryption\n2 for decryption\n\nChoice: ");
operation = input.nextInt();
input.nextLine();
if (operation == 1)
{
try
{
System.out.printf("\n---------\n\nText to encrypt: ");
textToEncrypt = input.nextLine();
//Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
//Cipher cipher = Cipher.getInstance("AES");
//encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(textToEncrypt.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b: encrypted)
{
sb.append((char)b);
}
// the encrypted String
String enc = sb.toString();
//System.out.println("encrypted:" + enc);
String asciiEncodedEncryptedResult = asciiEncoder.encodeBuffer(enc.getBytes());
System.out.println("Encrypted text: " + asciiEncodedEncryptedResult);
//System.out.printf("\n------------------------------\nDecrypted text: " + asciiEncodedEncryptedResult + "\n------------------------------\n\n\n");
}
catch(Exception e)
{
e.printStackTrace();
}
}
else if (operation == 2)
{
System.out.printf("\n---------\n\nText to decrypt: ");
textToDecryptAscii = input.nextLine();
byte[] decodedBytes = null;
try
{
decodedBytes = asciiDecoder.decodeBuffer(textToDecryptAscii);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//System.out.println("decodedBytes " + new String(decodedBytes));
textToDecrypt = new String(decodedBytes);
//Convert the string to byte array
//for decryption
byte[] bb = new byte[textToDecrypt.length()];
for (int i=0; i<textToDecrypt.length(); i++)
{
bb[i] = (byte) textToDecrypt.charAt(i);
}
//decrypt the text
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
try
{
cipher.init(Cipher.DECRYPT_MODE, aesKey);
}
catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String decrypted = null;
try
{
decrypted = new String(cipher.doFinal(bb));
}
catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.printf("\n------------------------------\nDecrypted text: " + decrypted + "\n------------------------------\n\n\n");
}
}
}
Your asciiEncoder (which is actually base64), will automatically add new line characters as part of how base64 works. You can remove this functionality in some implementations by something similar to this:
asciiEncoder.linelength = 0;
Additionally, you could just remove the newlines from the resulting string by replacing them with nothing.
How to Store the AES Key in Database using JavaKeyStore, please check the complete code and its straight forward. Currently i am storing the Key in .JCEKS extension in a given location, need to store the Key in database and read it back for encryption. Please help me out.
Note: This code is working any one who wants to encrypt and decrypt and store the date in the database use my code. Key generated gets save in file format and is retrieved back for reuse, encrypt or decrypt.
package user.dao;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.KeyStore.PasswordProtection;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import de.blowfish.core.Blowfish;
import user.util.UserConstants;
import user.bean.UserLoginBean;
import user.util.DButil;
public class UserDao {
public int insertUserDetails(Object bean)
{
user.bean.UserLoginBean beanobj=(UserLoginBean)bean;
Connection conn=null;
PreparedStatement ps=null;
PreparedStatement ps1=null;
ResultSet rs = null;
int result=0;
try{
conn=DButil.getConnection();
StringBuffer sbinsert=new StringBuffer();
sbinsert.append("insert into ");
sbinsert.append(UserConstants.USER_DETAILS_TABLE_NAME);
sbinsert.append(" values(?,?,?,?,?,?)");
//KeyStore Table
conn=DButil.getConnection();
StringBuffer sbinsert1 =new StringBuffer();
sbinsert1.append("insert into ");
sbinsert1.append(UserConstants.USER_DETAILS_TABLE_NAME1);
sbinsert1.append(" values(?,?)");
//
Security.addProvider(new blowfishProvider());
Cipher cipher = Cipher.getInstance("AES128_CBC", "blowfish");
KeyGenerator keyGen = KeyGenerator.getInstance("AES", "blowfish");
SecretKey secKey = keyGen.generateKey();
// Storing the secret Key
final String keyStoreFile = "C:\\mykey.jceks";
//String keyStoreFile = new String(sbinsert1);
//final String keyStoreDB = beanobj.getKeylock();
KeyStore keyStore = createKeyStore(keyStoreFile, "java0123");
System.out.println("Stored Key: " + (secKey));
System.out.println("secured key: " + (keyStore));
// store the secret key
KeyStore.SecretKeyEntry keyStoreEntry = new KeyStore.SecretKeyEntry(secKey);
PasswordProtection keyPassword = new PasswordProtection("www-secret".toCharArray());
keyStore.setEntry("mySecretKey", keyStoreEntry, keyPassword);
keyStore.store(new FileOutputStream(keyStoreFile), "java0123".toCharArray());
//keyStore.store(new FileOutputStream(keyStoreDB), "java0123".toCharArray());
//Encryption of string
String clearText = beanobj.getPassword() ;
byte[] clearTextBytes = clearText.getBytes("UTF8");
cipher.init(Cipher.ENCRYPT_MODE, secKey);
byte[] cipherBytes = cipher.doFinal(clearTextBytes);
String cipherText = new String(cipherBytes, "UTF8");
//Decryption of String
cipher.init(Cipher.DECRYPT_MODE, secKey );
byte[] decryptedBytes = cipher.doFinal(cipherBytes);
String decryptedText = new String(decryptedBytes, "UTF8");
System.out.println("Before encryption: " + clearText);
System.out.println("After encryption: " + cipherText);
System.out.println("After decryption: " + decryptedText);
//
ps=conn.prepareStatement(sbinsert.toString());
ps.setString(1,beanobj.getFirstname());
ps.setString(2, beanobj.getLastname());
ps.setString(3, beanobj.getUsername());
ps.setString(4, cipherText);
ps.setString(5, beanobj.getEmail());
ps.setString(6, beanobj.getMobileno());
ps1=conn.prepareStatement(sbinsert1.toString());
beanobj.setKeylock("mykey"); // Dummy key for checking if logic works
ps1.setString(1,beanobj.getUsername());
ps1.setString(2,beanobj.getKeylock());
result=ps.executeUpdate();
result=ps1.executeUpdate();
}
catch(SQLException e)
{
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
DButil.closeAllDBResources(conn, ps, null);
}
return result;
}
public boolean isRegisteredUser(String un,String pw)
{
boolean result=false;
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try
{
conn=DButil.getConnection();
StringBuffer sbselect=new StringBuffer();
sbselect.append("select * from ");
sbselect.append(UserConstants.USER_DETAILS_TABLE_NAME);
sbselect.append(" where BINARY Username=? and Password=?");
ps=conn.prepareStatement(sbselect.toString());
// Retreving the key
Security.addProvider(new FlexiCoreProvider());
Cipher cipher1 = Cipher.getInstance("AES128_CBC", "FlexiCore");
KeyStore keyStore = KeyStore.getInstance("JCEKS");
System.out.println(keyStore);
FileInputStream fis = new FileInputStream("C:\\mykey.jceks";);
keyStore.load(fis, "java0123".toCharArray());
Key secKey = keyStore.getKey("mySecret","www-secret".toCharArray());
//Encrypting the User Passowrd and comparing with the DB enPassword one way process
String clearText = pw ;
byte[] clearTextBytes = clearText.getBytes("UTF8");
cipher1.init(Cipher.ENCRYPT_MODE, secKey);
byte[] cipherBytes = cipher1.doFinal(clearTextBytes);
String cipherText1 = new String(cipherBytes, "UTF8");
ps.setString(1, un);
ps.setString(2, cipherText1);
//System.out.println(ps.toString());
rs=ps.executeQuery();
if(rs.next())
{
result=true;
}
}
catch(SQLException e)
{
System.out.println(e);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
DButil.closeAllDBResources(conn, ps, rs);
}
return result;
}
public int executeUpdate(String query)
{
int result=0;
Connection conn=null;
PreparedStatement ps=null;
try
{
conn=DButil.getConnection();
ps=conn.prepareStatement(query);
result=ps.executeUpdate();
}
catch(SQLException e)
{
e.printStackTrace();
}
finally{
DButil.closeAllDBResources(conn, ps, null);
}
return result;
}
private static java.security.KeyStore createKeyStore(String keyStoreFile,
String pw) throws Exception {
// TODO Auto-generated method stub
File file = new File("mykey.jceks");
/**
* Note that if you are storing a SecretKey or using any part of the SunJCE provider
* (Java Cryptography Extension),
* you will need to set your KeyStore type to JCEKS.
*/
final KeyStore keyStore = KeyStore.getInstance("JCEKS");
if (file.exists()) {
// .keystore file already exists => load it
keyStore.load(new FileInputStream(file), www.toCharArray());
} else {
// .keystore file not created yet => create it
keyStore.load(null, null);
keyStore.store(new FileOutputStream("mykey1.jceks"), www.toCharArray());
}
return keyStore;
}
}
Change keyStore.store(new FileOutputStream(keyStoreFile), "java0123".toCharArray()); and replace the FileOutputStream with a ByteArrayOutputStream. Use ByteArrayOutputStream.toByteArray() to retrieve the resulting blob. Then either store the (variable sized) blob in the byte array directly into your DB.
You may use CipherOutputStream connected to the ByteArrayOutputStream to additionally encrypt the KeyStore instance. If you do this then don't forget to close the CipherOutputStream or your data may become corrupted.
If you require characters for some reason or other, first base64 encode the blob and store the result.
I am trying to encrypt a file which consists of some sample data like
company=abc-company
I have written the following code to encrypt the file using AES-128 bit key using password and salt. I am able to encrypt the file successfully to a file and write the decrypted data from the file to another file successfully. But, I want to store the decrypted data in a string. So, after roaming here on SO, I used ByteArrayOutputStream. But with that I am not able to get the complete plaintext in to the string. I am getting partial data (only first 16 characters i.e. excluding 'any') from the file. How to get the complete text from the file into the string?
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestAES {
private static final Logger logger = LoggerFactory.getLogger(TestAES.class);
private char[] password = "1111111111111111".toCharArray();
private byte[] salt = "SampleSalt".getBytes();
private byte[] initializationVector;
public static void main(String[] args) {
TestAES aes = new TestAES();
aes.encrypt(new File("D:\\plainText.licence"), new File("D:\\sample.licence"));
aes.decrypt(new File("D:\\sample.licence"));
}
public void encrypt(File plainTextFile, File encryptedLicenceFile) {
if (plainTextFile.exists() == false) {
try {
throw new FileNotFoundException("The plainTextFile was not found");
} catch (FileNotFoundException e) {
logger.error("The plainTextFile was not found", e);
e.printStackTrace();
}
}
if (encryptedLicenceFile.exists() == false) {
try {
encryptedLicenceFile.createNewFile();
} catch (IOException e) {
logger.error("IOException while creating encryptedLicenceFile", e);
e.printStackTrace();
}
}
logger.info("plainTextFile.exists() = " + plainTextFile.exists());
// To read the file to be encrypted
FileInputStream fileInputStream = null;
// To write the encrypted file
FileOutputStream fileOutputStream = null;
// To read the file information and to encrypt
CipherInputStream cipherInputStream = null;
try {
fileInputStream = new FileInputStream(plainTextFile);
fileOutputStream = new FileOutputStream(encryptedLicenceFile);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password, salt, 65536, 128);
logger.info("Generating KeySpec with password, salt.");
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
logger.debug("Obtaining AES cipher in encryption mode with secret key.");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters parameters = cipher.getParameters();
this.initializationVector = parameters.getParameterSpec(IvParameterSpec.class).getIV();
logger.info("Initialization Vector length = " + initializationVector.length);
cipherInputStream = new CipherInputStream(fileInputStream, cipher);
int read = 0;
while ((read = cipherInputStream.read()) != -1) {
fileOutputStream.write((char) read);
fileOutputStream.flush();
}
logger.info("Successfully written the sample.licence file.");
} catch (NoSuchAlgorithmException e) {
logger.error("NoSuchAlgorithmException: Check alogrithm.", e);
e.printStackTrace();
} catch (NoSuchPaddingException e) {
logger.error("NoSuchPaddingException: Check padding.", e);
e.printStackTrace();
} catch (InvalidKeySpecException e) {
logger.error("InvalidKeySpecException: Check keySpec.", e);
e.printStackTrace();
} catch (InvalidKeyException e) {
logger.error("InvalidKeyException: Check keySize.", e);
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
logger.error("InvalidParameterSpecException: Check parameters.", e);
e.printStackTrace();
} catch (FileNotFoundException e) {
logger.error("FileNotFoundException: Check fileToBeEncrypted.", e);
e.printStackTrace();
} catch (IOException e) {
logger.error("IOException occured.", e);
e.printStackTrace();
} finally {
try {
if (cipherInputStream != null) {
cipherInputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
logger.error("Exception while closing stream.", e);
e.printStackTrace();
}
}
}
public void decrypt(File sampleLicence) {
if (sampleLicence.exists() == false) {
try {
throw new FileNotFoundException("The sampleLicence was not found");
} catch (FileNotFoundException e) {
logger.error("The sampleLicence was not found", e);
e.printStackTrace();
}
}
// To read the sample.licence
FileInputStream fileInputStream = null;
// To write decrypted licence file
FileOutputStream fileOutputStream = null;
// To read encrypted licence file and decrypt it
CipherOutputStream cipherOutputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
fileInputStream = new FileInputStream(sampleLicence);
byteArrayOutputStream = new ByteArrayOutputStream();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password, salt, 65536, 128);
logger.info("Generating KeySpec with password, salt during decryption.");
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
logger.debug("Obtaining AES cipher in decryption mode with secret key.");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initializationVector));
cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, cipher);
byte[] data = new byte[4096];
int read;
while ((read = fileInputStream.read(data)) != -1) {
cipherOutputStream.write(data, 0, read);
}
cipherOutputStream.flush();
byte[] plainText = byteArrayOutputStream.toByteArray();
System.out.println(new String(plainText, "UTF-8"));
} catch (NoSuchAlgorithmException e) {
logger.error("NoSuchAlgorithmException: Check alogrithm.", e);
e.printStackTrace();
} catch (NoSuchPaddingException e) {
logger.error("NoSuchPaddingException: Check padding.", e);
e.printStackTrace();
} catch (InvalidKeySpecException e) {
logger.error("InvalidKeySpecException: Check keySpec.", e);
e.printStackTrace();
} catch (InvalidKeyException e) {
logger.error("InvalidKeyException: Check keySize.", e);
e.printStackTrace();
} catch (FileNotFoundException e) {
logger.error("FileNotFoundException: Check fileToBeEncrypted.", e);
e.printStackTrace();
} catch (IOException e) {
logger.error("IOException occured.", e);
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
logger.error("InvalidAlgorithmParameterException", e);
e.printStackTrace();
} finally {
try {
if (cipherOutputStream != null) {
cipherOutputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
if (byteArrayOutputStream != null) {
byteArrayOutputStream.close();
}
} catch (IOException e) {
logger.error("Exception while closing stream.", e);
e.printStackTrace();
}
}
}
}
I did not try that, but it looks like you need to close the cipherOutputStream:
cipherOutputStream.close();
instead of the flush you have currently.
The reason is that flush can be called several times so the decryption will not be finished until close is called.
I have this strange issue with java IO, in combination with AES encryption.
I am writing some encrypted text to a binary file, appending \n at the end of text. Say,
my beautiful string...
look! Another of my beautiful strings...
When I read the data back, I get the following text in return with a lot of extra tabs:
my beautiful string...
look! Another of my beautiful strings...
Here is my self-contained code:
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class SecurityUtil
{
public static final String ENCRYPTION_ALGORITHM = "AES";
public static final String CHARACTER_SET = "UTF-8";
private static final int BLOCKS = 128;
private static final String KEY = "SomeSortOfEncryptionKey";
public static void main (String[] args) throws IOException
{
String str = "my beautiful string...\n";
byte[] encrypt = SecurityUtil.encrypt (str);
File f = new File ("C:\\myfile.dat");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f, true));
bos.write(encrypt);
bos.flush();
bos.close();
str = "look! Another of my beautiful strings...";
encrypt = SecurityUtil.encrypt (str);
bos = new BufferedOutputStream(new FileOutputStream(f, true));
bos.write(encrypt);
bos.flush();
bos.close();
byte[] buffer = new byte[(int) f.length ()];
FileInputStream fis = new FileInputStream (f);
fis.read (buffer);
fis.close ();
String decrypt = SecurityUtil.decrypt (buffer);
System.out.println(decrypt);
}
public static byte[] encrypt (String text)
{
try
{
byte[] rawKey = getRawKey (KEY.getBytes (CHARACTER_SET));
SecretKeySpec skeySpec = new SecretKeySpec (rawKey, ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance (ENCRYPTION_ALGORITHM);
cipher.init (Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal (text.getBytes (CHARACTER_SET));
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace ();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace ();
}
catch (BadPaddingException e)
{
e.printStackTrace ();
}
catch (InvalidKeyException e)
{
e.printStackTrace ();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace ();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace ();
}
return null;
}
public static String decrypt (byte[] data)
{
try
{
byte[] rawKey = getRawKey (KEY.getBytes (CHARACTER_SET));
SecretKeySpec skeySpec = new SecretKeySpec (rawKey, ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance (ENCRYPTION_ALGORITHM);
cipher.init (Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal (data);
return new String (decrypted);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace ();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace ();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace ();
}
catch (InvalidKeyException e)
{
e.printStackTrace ();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace ();
}
catch (BadPaddingException e)
{
e.printStackTrace ();
}
return null;
}
private static byte[] getRawKey (byte[] seed)
{
try
{
KeyGenerator kgen = KeyGenerator.getInstance (ENCRYPTION_ALGORITHM);
SecureRandom sr = SecureRandom.getInstance ("SHA1PRNG");
sr.setSeed (seed);
kgen.init (BLOCKS, sr);
SecretKey skey = kgen.generateKey ();
byte[] raw = skey.getEncoded ();
return raw;
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace ();
}
return null;
}
}
Here is the console output (with extra spaces):
my beautiful string...
look! Another of my beautiful strings...
What am I doing wrong?
Ok! I got it. You cannot just append the encrypted text to a file. One way of solving this is extracting existing text from the file, append the new text, encrypt and write in the file again.
This doesn't seem to be a good solution, but in my case, where there is little text in a file, this can work.