不解密我加密的内容
我有一个奇怪的问题...
I have a weird problem...
我的解决方案基于将硬编码文件解密为字节[]
所以,我编写了一个小的 Cypher 类来帮助加密/解密...它曾经模拟在某个地方硬编码的密钥和存储在其他地方的另一个预加密密钥.但这有点无关紧要.
So, I wrote a small Cypher class to help out with crypting/decrypting... It used to mock-up a key hardcoded at some place and another pre-crypted key stored somewhere else. But that's somewhat irrelevant atm.
加密过程是这样的:
- 检索硬编码的字节数组
- 用它来解密 key2
- 使用 key2 解密数据
- 使用 key1 进一步解密数据
- 已解密数据
我将加密数据存储为十六进制字符串,使用这两个函数进出那里
I was storing the crypted data as a hex-string, used these two functions to get in-out of there
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); //THIS LINE
b[i] = (byte) v;
}
return b;
}
完美无缺;事实上它工作得很好,以至于我在我的真实项目中实现了它.由于我没有彻底测试,该项目未能运行.
That worked flawlessly; in fact it worked so good that I implemented it in my real project. The project failed to run due to the fact that i didn't thoroughly test.
事实证明,它几乎可以加密/解密所有文件,除了一个不想解密的文件.
Turns out it crypts/decrypts pretty much all files OK except one - that one doesn't want to decrypt.
我已经查明了这个问题——这行抛出了一个 IllegalNumberFormat 异常;在某个时候,我熟悉了这个 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 也是如此.如果有人描述了一种绕过情况的方法,即长度为 2 的字符串转换为抛出 IllegalNumberFormatException 的四个字节,我会并且可以恢复使用此方法.
I have pinpointed the issue however - THIS line throws an IllegalNumberFormat exception; at some point i got acquainted with this http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 as well. I would and can revert to this method if someone describes a way to bypass a case when a string of length 2 is converted to four bytes which throw an IllegalNumberFormatException.
所以,我认为,由于我无法解码文件(显然无法在此处共享供大家试用),因此我需要以某种方式对其进行转换以使其安全传输.输入 Base64Coder 类,该类编码为 base64 字符串...
So, I figured that since I cannot decode a file (and obviously cannot share it here for you guys to try out) I needed to transform it somehow to make it transport-safe. Enter the Base64Coder class which encodes to base64 strings...
这似乎引入了一个新问题 - 填充被破坏了.
That seemed to have introduced a new issue - padding was getting effed up.
问题很简单——我做错了什么?我需要符合这些数据,并且它必须能够正确和平等地加密/解密.我想要一个关于尽可能少复制/粘贴的最轻量级解决方案的建议......伪代码在这里无法解决问题.
The question is simple - what am I doing wrong? I need to conform to this data and it has to be able to crypt/decrypt properly and equally. I'd like a proposal on the most light-weight solution possible with least copy/pasting... pseudocode won't do the trick here.
这就是我现在正在做的事情......
Here's what I'm doing now....
public static char[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
SecretKeySpec key1 = getSecretKeySpec(true);
System.err.println("encrypt(): " + 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(): " + 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;
}
请注意,出于测试目的,密钥目前已完全公开(硬编码).
Note that keys are currently fully-exposed (hardcoded) for testing purposes.
这是我的测试用例
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"); }
}
我现在得到一个 InvalidBlockSizeException ......请有人对此有所了解,我只是希望它能够工作......
And I'm getting an InvalidBlockSizeException now.... Please, someone shed some light on this, I just want this to work...
为稍后在AES/CBC/PKCS5Padding"中使用的 IV 替换key2"是我现在正在考虑的一个选项.除了加密的第二步之外,基本上什么都不会改变.从理论上和方法上,我会保持不变 - 当然除非描述了更好的解决方案.
Replacing 'key2' for an IV to be later used in a "AES/CBC/PKCS5Padding" is an option I'm considering right now. Essentially nothing will change except the second step of encrypting. Theoretically and metodically I'd keep things the same - unless of course a better solution is described.
最后我想指出,这是一个程序员问题,而不是 IT 安全学生问题,因此正确的代码比涵盖不太可能的边缘情况的理论响应更有价值.
At the end I'd like to point out that this is a programmer question, not a IT security-student question so proper code is valued more than a theoretical response that covers unlikely fringe cases.
好吧,我不能给你导致 IllegalNumberFormatException 的数字,因为我从今天早上丢失了代码.我似乎无法复制这个问题,所以我想试图弄清楚那部分是没有用的.
well, I can't give you the numbers that cause the IllegalNumberFormatException because I lost the code from this morning. I can't seem to replicate the issue so I guess trying to figure that part is of no use.
这是示例测试的输出:
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
这意味着 Base64 有点搞砸了……
which means that Base64 is kinda messing it up...
推荐答案
今天早上查看代码并稍作调整后,我得到了它的工作.
After reviewing the code this morning and tweaking a little bit I got it to work.
public static byte[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
SecretKeySpec key1 = getSecretKeySpec(true);
System.err.println("encrypt(): " + key1.toString());
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key1, cipher.getParameters());
byte[] encrypted = cipher.doFinal(value);
SecretKeySpec key2 = getSecretKeySpec(false);
System.err.println("encrypt(): " + key2.toString());
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key2, new IvParameterSpec(getIV()));
byte[] encrypted2 = cipher.doFinal(encrypted);
return encrypted2;//Base64Coder.encode(encrypted2);
}
public static byte[] decrypt2(byte[] message, boolean A) throws GeneralSecurityException, IOException
{
SecretKeySpec key1 = getSecretKeySpec(false);
System.err.println("decrypt(): " + key1.toString());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key1, new IvParameterSpec(getIV()));
byte[] decrypted = cipher.doFinal(message);
SecretKeySpec key2 = getSecretKeySpec(true);
System.err.println("decrypt(): " + key2.toString());
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key2);
byte[] decrypted2 = cipher.doFinal(decrypted);
return decrypted2;
}
相关文章