不解密我加密的内容


问题内容

我有一个奇怪的问题

我的解决方案基于将硬编码文件解密为字节[]

因此,我写了一个小的Cypher类来帮助进行加密/解密…它曾经用来模拟在某个地方进行硬编码的密钥,以及另一个在其他地方存储的预加密密钥。但这与atm无关。

加密过程如下:

  • 检索硬编码的字节数组
  • 用它来解密key2
  • 使用key2解密数据
  • 使用key1进一步解密数据
  • 已解密数据

我将加密的数据存储为十六进制字符串,使用这两个函数来获取数据

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;
}

那完美无瑕。实际上,它是如此出色,以至于我在实际项目中实现了它。该项目由于我没有彻底测试而无法运行。

事实证明,除了一个文件外,几乎所有文件都可以解密/解密,一个文件不想解密。

但是,我已经查明了问题-
此行引发了IllegalNumberFormat异常;在某些时候,我也熟悉此http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307。如果有人描述了一种将长度为2的字符串转换为引发IllegalNumberFormatException的四个字节的情况的绕过情况的方法,则我将并且可以恢复为该方法。

因此,我认为由于无法解码文件(并且显然无法在此处共享该文件供您试用),我需要以某种方式对其进行转换以使其传输安全。输入编码为base64字符串的Base64Coder类…

这似乎引入了一个新问题-填充变得烦人了。

问题很简单-
我在做什么错?我需要遵循此数据,并且它必须能够正确且均等地进行加密/解密。我想要一个关于最轻量级解决方案的建议,该方法可能需要最少的复制/粘贴操作……伪代码在这里不会解决问题。

这就是我现在正在做的…

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;
}

请注意,出于测试目的,密钥当前已完全暴露(硬编码)。

这是我的测试用例

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…。请有人对此有所了解,我只是想让它工作…

我现在正在考虑将IV的“ key2”替换为以后在“ AES / CBC /
PKCS5Padding”中使用。基本上,除了加密的第二步之外,什么都不会改变。从理论上和方法上讲,我将保持不变-除非描述了更好的解决方案。

最后,我想指出的是,这是一个程序员的问题,而不是IT安全性学生的问题,因此,正确的代码比对涉及不太可能发生的情况的理论答复的重视程度更高。

编辑:好吧,我不能给您提供导致IllegalNumberFormatException的数字,因为我从今天早上丢失了代码。我似乎无法复制该问题,因此我想尝试弄清楚该部分没有用。

这是样本测试的输出:

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有点搞砸了…


问题答案:

在今天早上检查了代码并进行了一些调整之后,我开始使用它。

public static byte[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
    SecretKeySpec key1 = getSecretKeySpec(true);
    System.err.println("encrypt():\t" + 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():\t" + 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():\t" + 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():\t" + key2.toString());
    cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, key2);
    byte[] decrypted2 = cipher.doFinal(decrypted);

    return decrypted2;
}