I have a strange problem ...
The Basics of My Decision on Decrypting a Hard File as Byte []
So, I wrote a small Cypher class to help with encryption / decryption ... He used for the layout a key hardcoded in some place, and another pre-encrypted key stored somewhere else. But this is somewhat inappropriate.
The encryption process went as follows:
- get an array of hard-coded bytes
- use it to decrypt key2
- use key2 to decrypt data
- use key1 to further decrypt the data.
- have decrypted data
I stored the encrypted data as a hexadecimal string, used these two functions to go back and forth
private static String byteArrayToHexString(byte[] b) { StringBuffer sb = new StringBuffer(b.length * 2); for (int i = 0; i < b.length; i++) { int v = b[i] & 0xff; if (v < 16) { sb.append('0'); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(); } private static byte[] hexStringToByteArray(String s) { byte[] b = new byte[s.length() / 2]; for (int i = 0; i < b.length; i++) { int index = i * 2; int v = Integer.parseInt(s.substring(index, index + 2), 16);
It worked flawlessly; in fact, it worked so well that I implemented it in my real project. The project could not be launched due to the fact that I did not pass a thorough test.
It turns out that he encrypts / decrypts almost all files, except for one - one that does not want to decrypt.
I pointed out the problem exactly - this line throws an IllegalNumberFormat exception; at some point I met this http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 . I could return to this method if someone describes a way around the case where a string of length 2 is converted to four bytes that throw an IllegalNumberFormat exception.
So, I thought that since I can’t decode the file (and obviously I can’t share it here, for you guys to try) I needed to somehow convert it to make it transport. Enter a Base64Coder class that encodes base64 strings ...
It seemed that she introduced a new problem - the filling was filled.
The question is simple - what am I doing wrong? I have to match this data, and it should be able to glue / decrypt correctly and equally. I would like the suggestion of the easiest solution to be possible with minimal copy / paste ... the pseudocode will not do the trick here.
Here is what I am doing now ....
public static char[] encrypt2(byte[] value) throws GeneralSecurityException, IOException { SecretKeySpec key1 = getSecretKeySpec(true); System.err.println("encrypt():\t" + key1.toString()); Cipher cipher = Cipher.getInstance(CRYPTOSYS); cipher.init(Cipher.ENCRYPT_MODE, key1, cipher.getParameters()); byte[] encrypted = cipher.doFinal(value); SecretKeySpec key2 = getSecretKeySpec(false); cipher = Cipher.getInstance(CRYPTOSYS); cipher.init(Cipher.ENCRYPT_MODE, key2, cipher.getParameters()); byte[] encrypted2 = cipher.doFinal(encrypted); return Base64Coder.encode(encrypted2); } public static byte[] decrypt2(char[] message) throws GeneralSecurityException, IOException { SecretKeySpec key1 = getSecretKeySpec(false); System.err.println("decrypt():\t" + key1.toString()); Cipher cipher = Cipher.getInstance(CRYPTOSYS); cipher.init(Cipher.DECRYPT_MODE, key1); byte[] decrypted = cipher.doFinal(Base64Coder.decode(message)); SecretKeySpec key2 = getSecretKeySpec(true); cipher = Cipher.getInstance(CRYPTOSYS); cipher.init(Cipher.DECRYPT_MODE, key2); byte[] decrypted2 = cipher.doFinal(decrypted); return decrypted2; }
Please note that the keys are currently fully open (hard-coded) for testing purposes.
Here is my test case
public static void main(String... args) throws Exception { // byte[] data = "hello".getBytes(); File PEM = new File(PATH_TO_FILES + SOURCE_PEM); File DER = new File(PATH_TO_FILES + SOURCE_DER); File cryptoPEM = new File(PATH_TO_FILES + "cryptopem"); File cryptoDER = new File(PATH_TO_FILES + "cryptoder"); byte[] cryptokey = encryptA(ASSET_KEY); System.out.println(new String(cryptokey)); //pem key System.out.println("PEM"); byte[] data = getBytesFromFile(PEM); char[] crypted = encrypt2(data); // FileOutputStream fos = new FileOutputStream(cryptoPEM); FileWriter fw = new FileWriter(cryptoPEM); fw.write(crypted); fw.flush(); //der key System.out.println("DER"); data = getBytesFromFile(DER); crypted = encrypt2(data); fw = new FileWriter(cryptoDER); fw.write(crypted); fw.flush(); //opentext System.out.println("checking PEM..."); crypted = Base64Coder.encode(getBytesFromFile(cryptoPEM)); byte[] decrypted = decrypt2(crypted, false); byte[] decryptedData = decrypted; if (!Arrays.equals(getBytesFromFile(PEM), decryptedData)) { throw new Exception("PEM Data was not decrypted successfully"); } System.out.println("checking DER..."); crypted = Base64Coder.encode(getBytesFromFile(cryptoDER)); decrypted = decrypt2(crypted, false); decryptedData = decrypted; if (!Arrays.equals(getBytesFromFile(DER), decryptedData)) { throw new Exception("DER Data was not decrypted successfully"); } }
And now I get an InvalidBlockSizeException .... Please someone shed some light on this, I just want it to work ...
Replacing "key2" for IV, which will later be used in "AES / CBC / PKCS5Padding", is an option that I am considering right now. Essentially, nothing will change except the second step of encryption. Theoretically and by the method, I would keep the same thing - unless, of course, the best solution is described.
In the end, I would like to point out that this is a programmer’s question and not a question of IT security, so the correct code is evaluated more than the theoretical answer, which covers unlikely cases.
EDIT: well, I can't give you the numbers that raise the IllegalNumberFormatException, because I lost the code in the morning. I can not reproduce the problem, so I think I'm trying to understand that this part is useless.
Here is the sample test result:
encrypt(): javax.crypto.spec.SecretKeySpec@15dd7 5@ _G j ! c;D i lR?z j\ PEM encrypt(): javax.crypto.spec.SecretKeySpec@15dd7 DER encrypt(): javax.crypto.spec.SecretKeySpec@15dd7 checking PEM... decrypt(): javax.crypto.spec.SecretKeySpec@15c78 Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
which means Base64 just messed it up ...