Well, this is not a new program and I haven't done any changes with problem parts.
My system admin has just patched the IBM WebSphere Application Server from 8.5.0.1 to 8.5.5.4.
I have encrypted numbers of files in the past. But after the upgrade has completed, I can't decrypt these files any more.
I am sure I am using the same method and key as they are all hard-coded in my program. And I haven't changed any related codes.
Here is the error.
javax.crypto.BadPaddingException: Given final block not properly padded
at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Unknown Source)
at com.xxx.framework.core.common.util.CipherUtil.crypt(CipherUtil.java:175)
at com.xxx.framework.core.common.util.CipherUtil.decrypt(CipherUtil.java:102)
at com.xxx.framework.core.common.util.ZipCipherUtil.decryptUnzip(ZipCipherUtil.java:84)
at xxx(xxx.java:2894)
at xxx(xxx.java:748)
at xxx(xxx.java:727)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at yyy(ActionProxy.java:54)
I have deleted some parts as there are some sensitive business information
And this is the code
CipherUtil.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class CipherUtil {
private static String type = "AES";
private static final String HEXES = "0123456789ABCDEF";
public void encrypt(String srcFile, String destFile, String privateKey) throws GeneralSecurityException, IOException {
Key key = getKey(privateKey);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(mkdirFiles(destFile));
crypt(fis, fos, cipher);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
}
}
public void decrypt(String srcFile, String destFile, String privateKey) throws GeneralSecurityException, IOException {
Key key = getKey(privateKey);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(mkdirFiles(destFile));
crypt(fis, fos, cipher);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
}
}
private static Key getKey(String secret) throws GeneralSecurityException {
KeyGenerator kgen = KeyGenerator.getInstance(type);
kgen.init(128, new SecureRandom(secret.getBytes()));
SecretKey secretKey = kgen.generateKey();
return secretKey;
}
private static void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException, GeneralSecurityException {
int blockSize = cipher.getBlockSize() * 1000;
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;
boolean more = true;
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else {
more = false;
}
}
if (inLength > 0)
outBytes = cipher.doFinal(inBytes, 0, inLength);
else
outBytes = cipher.doFinal();
out.write(outBytes);
}
public String encryptString(String srcString, String keyString) throws GeneralSecurityException {
Key key = getKey(keyString);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] coded = cipher.doFinal(srcString.getBytes());
return byteArrayToHexString(coded);
}
public String decryptString(String srcString, String keyString) throws GeneralSecurityException {
Key key = getKey(keyString);
Cipher cipher = Cipher.getInstance(type + "/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = cipher.doFinal(hexStringToByteArray(srcString));
return new String(decoded);
}
private String byteArrayToHexString(byte[] raw)
{
if (raw == null)
{
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw)
{
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
public static byte[] hexStringToByteArray(String s) {
if (s == null || (s.length() % 2) == 1)
{
throw new IllegalArgumentException();
}
final char[] chars = s.toCharArray();
final int len = chars.length;
final byte [] data = new byte [len / 2];
for (int i=0; i<len; i+=2)
{
data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
}
return data;
}
}
Although I have mentioned "files", this method only treat the files as binary string to encrypt.
As I have DEV and UAT environment to test (DEV=8.5.5.4, UAT=8.5.0.1), I have tried to put the old encrypted files on DEV to the UAT. And they can decrypted under UAT.
Also I have tried to encrypt a new file under DEV and decrypt it, it is ok.
Is there anything I need to call my system admin to do?
I am only a programmer and I am not very skillful in server setup.
P.S. If there is anything to check, I am able to go into the WebSphere admin panel with admin right.
P.S.2. These codes are not written by me. Don't ask me what is the reason of these coding. By the way I have checked the codes and I can't find any issue with these codes, except some security worries but I am not sure.
Not sure if it is your problem or not, but this block:
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else {
more = false;
}
}
is at least in principle incorrect. The in.read() could theoretically read less than the block length before reaching the end of file. The EOF condition is that in.read() returns -1. Maybe the update to the operating system has caused the FileInputStream to occasionally interrupt the read? In this case you will for the first time fall into the the inLength > 0 block of your code and try to decrypt a partial block which will definitely give the wrong result.
You can also temporarily disable PKCS5Padding by using NoPadding and see what the output of the encryption is.
Related
package test;
/**
* Created by
* newbme on 12/25/2018.
*/
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class MyJava {
/**
* IT IS THIS CLASS THAT WILL ENCRYPT OR DECRYPT
* ANY FILE
*/
private static final String SECRET_KEY_1 = "ssdkF$HUy2A#D%kd";
private static final String SECRET_KEY_2 = "weJiSEvR5yAC5ftB";
private IvParameterSpec ivParameterSpec;
private SecretKeySpec secretKeySpec;
private Cipher cipher;
private File from,to;
private static boolean trouble =false;
/**
* CBC MODE
*/
public MyJava(File from,File to) throws UnsupportedEncodingException, NoSuchPaddingException, NoSuchAlgorithmException {
ivParameterSpec = new IvParameterSpec(SECRET_KEY_1.getBytes("UTF-8"));
secretKeySpec = new SecretKeySpec(SECRET_KEY_2.getBytes("UTF-8"), "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
//INITIALIZE THE PLACE TO READ AND SAVE FILE
this.from =from;
this.to =to;
//if the desination doesnt exists create it
if(! this.to .exists()){
try {
this.to.getParentFile().mkdirs();
this.to.createNewFile();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
/**
*
* USE THIS METHOD TO ENCRYPT ANYTHING
*/
public boolean encrypt()throws Exception{
FileInputStream fis =null;
FileOutputStream fos=null;
boolean success =false;
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
//read the file into memory
fis = new FileInputStream(from);
fos = new FileOutputStream(to);
byte [] inBytes = new byte[50*1024];
int count;
while( ( count = fis.read(inBytes)) > 0){
byte encrypted[] = cipher.doFinal(inBytes);
fos.write(encrypted,0,count);
fos.flush();
}
success =true;
}catch(InvalidKeyException ivke){
ivke.printStackTrace();
trouble = true;
}finally{
if(fis!=null)fis.close();
if(fos!=null)fos.close();
}
//return Base64.encodeBase64String(encrypted);
return success;
}
/**
*
* USE THIS METHOD TO DECRYPT ANYTHING
*/
public boolean decrypt() throws Exception{
FileInputStream fis =null;
FileOutputStream fos=null;
boolean success =false;
try {
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
//read the file into memory
fis = new FileInputStream(from);
fos = new FileOutputStream(to);
byte [] inBytes = new byte[50*1024];
int count;
while( ( count = fis.read(inBytes)) > 0){
byte decrypted[] = cipher.doFinal(inBytes);//this line fails
fos.write(decrypted,0,count);
fos.flush();
}
success =true;
}catch(InvalidKeyException ivke){
trouble = true;
ivke.printStackTrace();
}finally{
if(fis!=null)fis.close();
if(fos!=null)fos.close();
}
//return Base64.encodeBase64String(encrypted);
return success;
}
private static boolean isInvalidKeyException(){
return trouble;
}
public static void main(String [] R){
File f = new File(PATH);
//encrypt
new MyJava(f,new File("c:/logs1/"+f.getName())).encrypt();
//Toast.makeText(context,"to decrypt",Toast.LENGTH_LONG).show();
//decrypt
new MyJava(f,new File("c:/logs2/"+f.getName())).decrypt();
}
}
Error:
D/OpenSSLLib: OpensslErr:Module:30(101:); file:external/boringssl/src/crypto/cipher/cipher.c ;Line:460;Function:EVP_DecryptFinal_ex
W/System.err: javax.crypto.BadPaddingException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT
W/System.err: at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
W/System.err: at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:568)
W/System.err: at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:350)
W/System.err: at javax.crypto.Cipher.doFinal(Cipher.java:2056)
W/System.err: at com.presentapps.aiapp.utility.AISCipher.decrypt(AISCipher.java:122)
W/System.err: at com.presentapps.aiapp.popups.ActionPop$1.onClick(ActionPop.java:65)
Hello, I tried to encrypt a file which could be a text file or a music file etc. The program kinda encrypts it without any exception, however when I try to decrypt, it throws an exception.
I've been trying to use CBC mode to get it working for days now, could someone help point out my errors?
And uhm, I am actually running it on Android device so I changed the root part with "c:" while posting on SO the error posted was same gotten from debugger console on A.S.
I'm a newb to java, just improving on my learning, so any help is appreciated. Thanks.
Please note that real code should use a non-secret random IV for each encryption rather than a fixed, secret IV. Passwords should use a password-hashing function to make into keys. PBKDF2 is available on Android and Java for this purpose.
There are a number of problems with your code:
You're calling Cipher.doFinal() every time through the loop. Combined with a fixed IV, the result is effectively equivalent to ECB mode and is thus insecure. Use Cipher.update() for all intermediate blocks until the final block, then call Cipher.doFinal().
You're supplying invalid data to encrypt and decrypt every time you read less than a full buffer into inBytes.
count is the number of bytes that were read in, not necessarily the size of encrypted. You should output exactly the contents of encrypted, not some piece of it.
You main method encrypts a file at PATH and writes the result to c:/logs1/PATH. It then attempts to decrypt the file at PATH, but that file is the plaintext file, not the cipher text file.
Here are the corrected encrypt and decrypt methods:
public boolean encrypt() throws Exception {
FileInputStream fis = null;
FileOutputStream fos = null;
boolean success = false;
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
//read the file into memory
fis = new FileInputStream(from);
fos = new FileOutputStream(to);
byte[] inBytes = new byte[50 * 1024];
int count;
while ((count = fis.read(inBytes)) > 0) {
byte encrypted[] = cipher.update(inBytes, 0, count);
fos.write(encrypted);
}
byte encrypted[] = cipher.doFinal();
fos.write(encrypted);
fos.flush(); // redundant, since closing the stream will flush it.
success = true;
} catch (InvalidKeyException ivke) {
ivke.printStackTrace();
trouble = true;
} finally {
if (fis != null) fis.close();
if (fos != null) fos.close();
}
//return Base64.encodeBase64String(encrypted);
return success;
}
public boolean decrypt() throws Exception {
FileInputStream fis = null;
FileOutputStream fos = null;
boolean success = false;
try {
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
//read the file into memory
fis = new FileInputStream(from);
fos = new FileOutputStream(to);
byte[] inBytes = new byte[50 * 1024];
int count;
while ((count = fis.read(inBytes)) > 0) {
byte decrypted[] = cipher.update(inBytes, 0, count);
fos.write(decrypted);
}
byte decrypted[] = cipher.doFinal();
fos.write(decrypted);
fos.flush();
success = true;
} catch (InvalidKeyException ivke) {
trouble = true;
ivke.printStackTrace();
} finally {
if (fis != null) fis.close();
if (fos != null) fos.close();
}
//return Base64.encodeBase64String(encrypted);
return success;
}
Every time I run the code it says that the deciphered text file can't be found. It works without the code I can't modify (because my teacher wrote that we can't) but with it, it refuses to work. My teacher won't help me and no one else in my class knows how to code with the cipher class. I have used the PrintWriter class, and pretty much everything else. So I don't know what to do. Someone please help me figure out how to make it work.
package Crypto;
import java.util.Scanner;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.FileWriter;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class Crypto {
public static void main(String[] args) throws IOException {
try {
String key = "B1LLYB0B";
FileInputStream One = new FileInputStream("CryptoPlaintext.txt");
FileOutputStream Two = new FileOutputStream("CryptoCiphertext.txt");
encrypt(key, One, Two);
Two.flush();
Two.close();
FileInputStream One2 = new FileInputStream("CryptoCiphertext.txt");
FileOutputStream Two2 = new FileOutputStream("CryptoDeciphered.txt");
Two2.write(key.getBytes());
Two2.close();
decrypt(key, One2, Two2);
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os);
}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey desKey = skf.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, desKey);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
// =============================== DO NOT MODIFY ANY CODE BELOW HERE ===============================
// Compare the files
System.out.println(compareFiles() ? "The files are identical!" : "The files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException
{
Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the plaintext file
Scanner dc = new Scanner(new File("CryptoDeciphered.txt")); // Open the deciphered file
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while(pt.hasNextLine() && dc.hasNextLine())
if(!pt.nextLine().equals(dc.nextLine())) return false;
// If we have any records left over, then the files are not identical.
if(pt.hasNextLine() || dc.hasNextLine()) return false;
// The files are identical.
return true;
}
}
Why the error occurs:
You invoke the method compareFiles in your copy method, which is called to copy the encrypted content of the plaintext file to the cipher text file. When this call occurs the file containing the decrypted cipher text doesn't exist but is required by the compareFiles method resulting in your exception.
How to improve your code:
you don't need the statement Two2.write(key.getBytes())
use the try-with-resource statement to automatically flush and close your streams
the standard library provides methods to copy data from a path to a stream and vice versa. Have a look at Files.copy(...) or Guava's ByteStreams.copy(...)
change your methods' throws clause, throws Throwable is just bad design to get rid of proper exception handling, if you are struggling with InvalidKeyException, NoSuchAlgorithmException, etc, catch these when you create your cipher and rethrow e.g. IllegalArgumentException or a custom exception
Here is an example how to implement it:
public class Crypto
{
public static void main(String[] args)
{
byte[] key = "B1LLYB0B".getBytes(StandardCharsets.UTF_8);
Path plaintext = Paths.get("CryptoPlaintext.txt");
Path ciphertext = plaintext.resolveSibling("CryptoCiphertext.txt");
Path decrypted = ciphertext.resolveSibling("CryptoDeciphered.txt");
try
{
// Encrypt plaintext.
try (OutputStream os = encrypt(key, Files.newOutputStream(ciphertext)))
{
Files.copy(plaintext, os);
}
// Decrypt ciphertext.
try (InputStream is = decrypt(key, Files.newInputStream(ciphertext)))
{
Files.copy(is, decrypted);
}
// TODO Compare plaintext and decrypted ciphertext.
}
catch (IOException e)
{
e.printStackTrace(); // TODO Handle exception properly.
}
}
private static OutputStream encrypt(byte[] key, OutputStream os)
{
return new CipherOutputStream(os, getCipherInstance(key, Cipher.ENCRYPT_MODE));
}
private static InputStream decrypt(byte[] key, InputStream is)
{
return new CipherInputStream(is, getCipherInstance(key, Cipher.DECRYPT_MODE));
}
private static Cipher getCipherInstance(byte[] key, int mode)
{
// TODO Implement and return the desired cipher.
}
}
By the way: Your teacher doesn't close his scanners in compareFiles() resulting in a resource leak.
I have a web app which is deployed on tomcat in both Linux and windows environment . Blowfish algo has been implemented for login password encryption/security check. It works fine in windows but throws illegal key size exception in linux. key file is packed with war
I have gone through multiple post but nothing really helped me.
generating key file
/** Generate a secret TripleDES encryption/decryption key */
KeyGenerator keygen = KeyGenerator.getInstance(SecurityConstant.BLOW_FISH_ALGO);
// Use it to generate a key
SecretKey key = keygen.generateKey();
// Convert the secret key to an array of bytes like this
byte[] rawKey = key.getEncoded();
// Write the raw key to the file
String keyPath = getBlowFishKeyPath();
FileOutputStream out = new FileOutputStream(keyPath);
Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
Files.write( Paths.get(keyPath),rawkey,StandardOpenOption.CREATE);
writer.close();
key comparision
String hexCipher = null;
try {
byte[] byteClearText = pwd.getBytes("UTF-8");
byte[] ivBytes = SecurityUtil.hexToBytes("0000000000000000");
// read secretkey from key file
byte[] secretKeyByte = secretKey.getBytes();
Cipher cipher = null;
SecretKeySpec key = new SecretKeySpec(secretKeyByte, SecurityConstant.BLOW_FISH_ALGO);
// Create and initialize the encryption engine
cipher = Cipher.getInstance(SecurityConstant.BLOW_FISH_CBC_ZEROBYTE_ALGO, SecurityConstant.BC);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // throws exception
byte[] cipherText = new byte[cipher.getOutputSize(byteClearText.length)];
int ctLength = cipher.update(byteClearText, 0, byteClearText.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
hexCipher = SecurityUtil.bytesToHex(cipherText);// hexdecimal password stored in DB
} catch (Exception e) {
ExceptionLogger.logException(logger, e);
}
made it simpler to test
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class SecTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
/** Generate a secret TripleDES encryption/decryption key */
Security.addProvider(new BouncyCastleProvider());
KeyGenerator keygen = KeyGenerator.getInstance("Blowfish");
// Use it to generate a key
SecretKey key = keygen.generateKey();
// Convert the secret key to an array of bytes like this
byte[] rawKey = key.getEncoded();
// Write the raw key to the file
String keyPath = "/data2/key/BlowFish.key";
FileOutputStream out = null;
try {
out = new FileOutputStream(keyPath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
Files.write( Paths.get(keyPath),rawKey,StandardOpenOption.CREATE);
writer.close();
out.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
generateHexCode("a");
}
private static void generateHexCode(String pwd) {
String hexCipher = null;
try {
byte[] byteClearText = pwd.getBytes("UTF-8");
byte[] ivBytes = hexToBytes("0000000000000000");
// read secretkey from key file
byte[] secretKeyByte = readSecretKey().getBytes();
Cipher cipher = null;
SecretKeySpec key = new SecretKeySpec(secretKeyByte, "Blowfish");
// Create and initialize the encryption engine
cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // throws exception
byte[] cipherText = new byte[cipher.getOutputSize(byteClearText.length)];
int ctLength = cipher.update(byteClearText, 0, byteClearText.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
hexCipher = bytesToHex(cipherText);// hexdecimal password stored in DB
System.out.println("hex cipher is "+hexCipher);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String readSecretKey() {
byte[] rawkey = null;
String file ="";
// Read the raw bytes from the keyfile
String keyFile = "/data2/key/BlowFish.key";
String is = null;
try {
is = FileUtils.readFileToString(new File(keyFile),"UTF-8");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return is;
}
public static byte[] hexToBytes(String str) {
byte[] bytes = null;
if (str != null && str.length() >= 2) {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
}
bytes = buffer;
}
return bytes;
}
public static String bytesToHex(byte[] data) {
if (data == null) {
return null;
} else {
int len = data.length;
StringBuilder str = new StringBuilder();
for (int i = 0; i < len; i++) {
if ((data[i] & 0xFF) < 16) {
str = str.append("0").append(java.lang.Integer.toHexString(data[i] & 0xFF));
} else {
str.append(java.lang.Integer.toHexString(data[i] & 0xFF));
}
}
return str.toString().toUpperCase();
}
}
}
Made a simple program to test it out . This also runs fine on windows but fails on linux. any clue ?
I was trying to decrypt Whatsapp database file (msgstore.db.crypt) with java.
I found some python code and tried to do same thing with java. Probably its not that hard thing to do but I had some problems with handling decryption key.
But finally did it. So I wanted to share the code for people who need it.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class Crypto {
public FileInputStream mIn;
public FileOutputStream mOut;
public Crypto(String fileIn, String fileOut) {
try {
mIn = new FileInputStream(new File(fileIn));
mOut = new FileOutputStream(new File(fileOut));
decryptAES(mIn, mOut);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void decryptAES(InputStream in, FileOutputStream out) throws Exception {
final String string = "346a23652a46392b4d73257c67317e352e3372482177652c";
byte[] hexAsBytes = DatatypeConverter.parseHexBinary(string);
SecretKeySpec keySpec = new SecretKeySpec(hexAsBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
in = new CipherInputStream(in, cipher);
byte[] buffer = new byte[24];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1)
{
out.write(buffer, 0, bytesRead);
}
}
public static void main(String[] args){
Crypto c = new Crypto("C:\\msgstore.db.crypt", "D:\\WhatsappDb");
System.out.println("Decrypting Done");
}
}
An updated answer for .crypt12 files:
These are compressed, and then encrypted using AES in GCM mode
Here is some python code showing how:
"""
Example how to decrypt whatsapp msgstore backups with extension .crypt12.
Author: Willem Hengeveld <itsme#xs4all.nl>
"""
from Crypto.Cipher import AES
import zlib
import sys
datafile = keyfile = None
if len(sys.argv)==1:
print("Usage: decrypt12.py <keyfile> <msgstore.db.crypt12>")
print(" the key file is commonly found in /data/data/com.whatsapp/files/key")
print(" the crypt file is commonly found in the directory: /data/media/0/WhatsApp/Databases/")
exit(1)
for arg in sys.argv[1:]:
if arg.find('crypt12')>0:
datafile = arg
elif arg.find('key')>0:
keyfile = arg
else:
print("unknown arg", arg)
with open(keyfile, "rb") as fh:
keydata = fh.read()
key = keydata[126:]
with open(datafile, "rb") as fh:
filedata = fh.read()
iv = filedata[51:67]
aes = AES.new(key, mode=AES.MODE_GCM, nonce=iv)
with open("msg-decrypted.db", "wb") as fh:
fh.write(zlib.decompress(aes.decrypt(filedata[67:-20])))
here is an pure java routine for .db.crypt12 without bouncycastle, but only JDK.
public class Crypt12 {
public static void main(final String[] args) {
final String c12File = "1/msgstore.db.crypt12"; // input file
final String decryptedDbFile = "1/msgstore.db"; // sqlite3 db output file
final String keyFile = "1/key";
try {
final byte[] key; try(FileInputStream s = new FileInputStream(keyFile)) { key = s.readAllBytes(); }
final byte[] buf; try(FileInputStream s = new FileInputStream(c12File)) { buf = s.readAllBytes(); }
if(!Arrays.equals(key, 27, 78, buf, 0, 51)) { System.out.println("Wrong Key-File"); return; }
final int available = buf.length - 67 - 20; // 67 Byte Header + 20 byte footer
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
final GCMParameterSpec iv = new GCMParameterSpec(128, buf, 51, 16);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, 126, 32, "AES"), iv);
final int zipLen = cipher.doFinal(buf, 67, available, buf, 0);
final Inflater unzip = new Inflater(false);
try(FileOutputStream s = new FileOutputStream(decryptedDbFile)) {
unzip.setInput(buf, 0, zipLen);
final byte[] b = new byte[1024];
while(!unzip.needsInput()) {
final int l = unzip.inflate(b, 0, b.length);
if(l > 0) s.write(b, 0, l);
}
}
} catch (final Exception e) {
e.printStackTrace(System.out);
}
}
}
I have an application which displays image downloaded from server. the image is encrypted and kept in the server using AES. I need to decrypt the image at the client side. The code used for encryption is as follows
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
public class Crypto {
Cipher ecipher;
Cipher dcipher;
/**
* Input a string that will be md5 hashed to create the key.
* #return void, cipher initialized
*/
public Crypto(){
try{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
this.setupCrypto(kgen.generateKey());
} catch (Exception e) {
e.printStackTrace();
}
}
public Crypto(String key){
SecretKeySpec skey = new SecretKeySpec(getMD5(key), "AES");
this.setupCrypto(skey);
}
private void setupCrypto(SecretKey key){
try
{ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
ecipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
dcipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
}
catch (Exception e)
{
e.printStackTrace();
}
}
// Buffer used to transport the bytes from one stream to another
byte[] buf = new byte[1024];
public void encrypt(InputStream in, OutputStream out){
try {
// Bytes written to out will be encrypted
out = new CipherOutputStream(out, ecipher);
// Read in the cleartext bytes and write to out to encrypt
int numRead = 0;
while ((numRead = in.read(buf)) >= 0){
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e){
e.printStackTrace();
}
}
public void decrypt(InputStream in, OutputStream out){
try {
// Bytes read from in will be decrypted
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
private static byte[] getMD5(String input){
try{
byte[] bytesOfMessage = input.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytesOfMessage);
} catch (Exception e){
return null;
}
}
public static void main(String args[]){
try {
Crypto encrypter = new Crypto("yursxjdlbkuikeqe"); ///key for decryption logic
encrypter.encrypt(new FileInputStream("D:\\Path\\Lighthouse.jpg"),new FileOutputStream("D:\\Encryption\\iOS code base\\Lighthouse.jpg.pkcs5"));
encrypter.decrypt(new FileInputStream("D:\\Path\\Lighthouse.jpg.pkcs5"),new FileOutputStream("D:\\Encryption\\iOS code base\\Lighthouse.jpg"));
System.out.println("DONE");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
I am not able to decrypt this using Blackberry AESDecryptor Engine. I am new to this crypto graphy. Is it possible to decrypt using AESDecryptor engine. I am attaching the code which I am using. Please help me in solving this
public MyScreen(){
// Set the displayed title of the screen
setTitle("MyTitle");
byte[] keyData = new String("yursxjdlbkuikeqe").getBytes();
byte[] cipherText = openFile("file:///SDCard/Lighthouse.jpg.pkcs5");
try {
imageData = decrypt(keyData, cipherText);
} catch (CryptoException e) {
System.out.println("::::::::::::::::::::::::::::::::::Crypto Exception:::::::"+e.getMessage());
} catch (IOException e) {
System.out.println("::::::::::::::::::::::::::::::::::IO Exception:::::::"+e.getMessage());
}
if(imageData!=null){
writeByteData(imageData);
// EncodedImage image = EncodedImage.createEncodedImage(imageData, 0, imageData.length);
// add(new BitmapField(image.getBitmap()));
System.out.println("------------------Image saved successfully-----------");
}else{
System.out.println("-------------------Image Data is null");
}
}
public static byte[] decrypt(byte[] keyData, byte[] ciphertext) throws CryptoException, IOException {
// First, create the AESKey again.
/*String str=new String(keyData);
System.out.println(str);*/
AESKey key = new AESKey(keyData,0,128);
System.out.println("Key is ::"+key.getAlgorithm()+"Length:"+key.getBitLength());
//
// // Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine(key);
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine(engine);
/
// // Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream(ciphertext);
BlockDecryptor decryptor = new BlockDecryptor(engine, input);
byte[] plaintextAndHash = new byte[1024];
ByteArrayOutputStream output = new ByteArrayOutputStream();
int bytesRead=0;
do{
bytesRead =decryptor.read(plaintextAndHash);
if(bytesRead!=-1){
output.write(plaintextAndHash,0,bytesRead);
}
}
while(bytesRead!=-1);
return output.toByteArray();
}
You don't really say what your problem is, but at least the following line looks incorrect:
BlockDecryptor decryptor = new BlockDecryptor(engine, input);
It should be
BlockDecryptor decryptor = new BlockDecryptor(uengine, input);
I just changed engine to uengine
RIM's APIs make this pretty easy but it is a little tough to find the documentation. Check out the Javadocs for the package net.rim.device.api.crypto at:
http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/crypto/package-summary.html
You should look through all of it but the answer is in number 7: Encryptor and decryptor factories.
http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/crypto/doc-files/factories.html
The DecryptorFactory can create an input stream that you can just read as any InputStream.