I have been tasked with decrypting a file in Java that has been encrypted using the following criteria:
AES encryption algorithm with 128-bit key, ECB mode and PKCS7 padding. The encrypted file format is: - first byte is hex 0x31 – specifying encryption method used (1 for AES) - followed by the encrypted bytes of the input file
I must also download the file, so here is my attempt so far:
The download code, I skip the first byte here as it is not required and is not encrypted:
final String PATH = "/sdcard/" + IMEI + ".xml"; //put the downloaded file here
try {
URL url = new URL(context.getString(R.string.xml_feed) + IMEI + ".xml");
enc_File = new File(PATH);
long startTime = System.currentTimeMillis();
/* Open a connection to that URL. */
URLConnection ucon = url.openConnection();
/*
* Define InputStreams to read from the URLConnection.
*/
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
/*
* Read bytes to the Buffer until there is nothing more to read(-1). */
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
bis.skip(1);
while ((current = bis.read()) != -1) {
baf.append((byte) current);
}
/* Convert the Bytes read to a String. */
FileOutputStream fos = new FileOutputStream(enc_File);
fos.write(baf.toByteArray());
fos.close();
} catch (IOException e) {
}
}
This gives me the encrypted file downloaded, So I then try to decrypt this file using the following code:
String bytes = toHex("the 16 bit key");
Key skeySpec = new SecretKeySpec(toByte(bytes), "AES");
Cipher c = Cipher.getInstance("AES/ECB/PKCS7Padding");
byte[] buf = new byte[1024];
// Bytes read from in will be decrypted
InputStream inCipher = new FileInputStream(enc_File);
OutputStream outCipher = new FileOutputStream(cipherFile);
c.init(Cipher.DECRYPT_MODE, skeySpec);
inCipher = new CipherInputStream(inCipher, c); // Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = inCipher.read(buf)) >= 0) {
outCipher.write(buf, 0, numRead);
}
outCipher.close();
the above should give me the decryted data in a new file.
And here are the util methods used in that code to create the Key in Byte format for the SecretKeySpec
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
However this currently gives me the following exception:
10-12 11:19:26.337: WARN/System.err(5376): java.io.IOException: last block incomplete in decryption
The encrypted file downloads fine, the decrytption runs but I get the above exception and checking the file that should be decrypted reveals that the first line of the file decrypted properly and then small parts of the next couple of lines but then returns junk for the rest.
I'm stuck at this now not knowing where to look for the problem, can anybody help? Or point me in the direction of what may be causing the exception?
Additional info:
10-12 15:30:37.291: WARN/System.err(6898): at com.mypackage.net.SettingsProvisioner.getRoutingDoc(SettingsProvisioner.java:217)
The above line is from the exception in the log cat (stacktrace)
And it shows that the exception is occuring at this line of code:
while ((numRead = inCipher.read(buf)) >= 0) {