在加密密钥中查找丢失的字节:Java

时间:2016-09-19 16:27:56

标签: java encryption

因此,我的任务的第2部分是找到加密密钥的缺失字节。作为背景我不太熟悉这个,所以我不知道从哪里开始。我环顾四周,似乎找不到起点。我的信息是加密密钥是AES / ECB密钥:{'__''7e''15''16''28''ae''d2''a6''ab''f7''15' '88''09''cf''4f''3c'};

我尝试的是循环遍历ACII值(0-255),然后获取值的字节并将它们附加到密钥的字节数组。之后我会尝试正常解密文件并输出新文件以期查看图片。但是我没有看到任何东西。你能指点我出错的地方吗?

byte[] convertHexString = DatatypeConverter.parseHexBinary(key);
String newKey = new String(convertHexString);
byte[] keyByte = newKey.getBytes();
String[] asciiArray = new String[256];
FileInputStream file = new FileInputStream(path);
Cipher aesCipher = Cipher.getInstance(transformation);
for(int i = 0;i<256; i++){
    arrayInts[i] = Character.toString((char)i);
    byte[] b = asciiArray [i].getBytes();
    byte[] result = new byte[b.length + keyByte.length]; 
    System.arraycopy(b, 0, result, 0, b.length); 
    System.arraycopy(keyByte, 0, result, b.length, keyByte.length); 
    FileOutputStream out = new FileOutputStream("AESencrypt_view" + String.valueOf(i)+".jpg");
    SecretKeySpec key1 = new SecretKeySpec(result,"AES");
    aesCipher.init(Cipher.DECRYPT_MODE, key1);
    CipherOutputStream  outSt = new CipherOutputStream(out,aesCipher);
    byte[] buf = new byte[1024];
    int read;
    while((read=file.read(buf))!=-1){
        outSt.write(buf, 0, read);

    }
    //file.close();
    out.flush();
    outSt.flush();
}

2 个答案:

答案 0 :(得分:2)

您的代码存在许多问题。

不要将二进制数据存储在字符串

byte[] convertHexString = DatatypeConverter.parseHexBinary(key);
String newKey = new String(convertHexString);
byte[] keyByte = newKey.getBytes();

应该简化为

byte[] keyByte = DatatypeConverter.parseHexBinary(key);

注意NullPointerExceptions

String[] asciiArray = new String[256];
...
asciiArray[i].getBytes();

实际上是NullPointerException,因为asciiArray[i]从未初始化。创建非基本类型的数组时,始终使用所有null值初始化数组。

FileInputStream生成文件内容

你有代码

FileInputStream file = new FileInputStream(path);

在循环之外,但是您正在读取循环内部的file,直到它被完全读取。问题是这只适用于第一次迭代。在下一次迭代(i == 1)中,没有要读取的数据,因此无需解密。

您应该在for循环之前将文件读入byte[],或者在for循环内初始化流,以便每次都能读取文件。

听取错误

CipherInputStreamCipherOutputStream隐藏了一些例外情况。特别是,ECB模式是非流分组密码模式,因此它必须具有某种填充。通常,此填充来自PKCS#5(= PKCS#7)。您应该直接使用Cipher及其update方法。当您完成写入数据时,您可以调用doFinal方法,如果密钥错误,您将获得一个异常,您可以捕获255 / 256th(大约1)的概率。

使密钥迭代更容易

byte[] keyByte = DatatypeConverter.parseHexBinary("007e151628aed2a6abf7158809cf4f3c");

for(int i = 0; i < 256; i++){
    keyByte[0] = (byte)i;
    ...
}

那就是它。您不需要更多来更改密钥的第一个字节。

一些示例代码:

byte[] keyByte = DatatypeConverter.parseHexBinary("007e151628aed2a6abf7158809cf4f3c");
Cipher aesCipher = Cipher.getInstance(transformation);
byte[] buf = new byte[1024];

for(int i = 0; i < 256; i++){
    keyByte[0] = (byte)i;

    FileInputStream inFileStream = new FileInputStream(path);
    File outFile = new File("AESencrypt_view" + String.valueOf(i)+".jpg");
    FileOutputStream outFileStream = new FileOutputStream(outFile);

    SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
    aesCipher.init(Cipher.DECRYPT_MODE, keySpec);

    int read;
    while((read = inFileStream.read(buf)) != -1){
        outFileStream.write(aesCipher.update(buf, 0, read));
    }
    inFileStream.close();

    try {
        outFileStream.write(aesCipher.doFinal());
        outFileStream.close();
    }
    catch(BadPaddingException e) {
        // obviously a wrong key or broken ciphertext
        outFileStream.close();
        outFile.delete();
    }
}

如果文件很小,你不必在每次迭代中反复读取它,你可以在for循环之前读取它一次。

答案 1 :(得分:1)

这不是您希望迭代可能的256个byte值的方式!例如,考虑i = 137时发生的情况:您说Character.toString((char)137) - 此输出是Unicode字符U+0089。在此调用s.getBytes()会为您提供字节数组[-62, -118]。我们已经知道我们遇到了麻烦,因为这不应该是两个字节! (这是字符U+0089,仅供参考的UTF-8解释。)

相反,为什么不迭代可能的字节值呢? for-loop没有理由迭代int个值;您可以直接迭代字节值。 (注意:Java中的字节是有符号的,没有充分的理由,所以for循环看起来有点奇怪,但这是正确的方法):

for (byte b = -128; b<128; b++) {
    byte[] result = new byte[keyByte.length +1]; 
    result[0] = b;
    System.arraycopy(keyByte, 0, result, 1, keyByte.length); 
    // yadda yadda yadda
}