【问题标题】:Encrypt and decrypt with hex string使用十六进制字符串加密和解密
【发布时间】:2015-01-01 22:20:37
【问题描述】:

我搜索了很多,但我没有找到一个好的解决方案来解决这个问题。我有一个应用程序必须使用 AES 256 解密一个长的十六进制字符串。

为了测试它,我创建了一个测试方法,它将长文本加密为十六进制,然后将其转换回来并解密。

如果我运行此方法,我总是会收到以下错误:Given final block not proper padding。我在解密方法中收到此错误。

测试方法如下:

@Test
public void testEncAndDecRequestWithHexString() throws UnsupportedEncodingException {
    CryptoHelper cryptoHelper = new CryptoHelper("AES256");
    String paramStr = "ABCB28BCEE5947B8AECE3386871EC0DF&{D5CA99D2-506B-4864-8971-E87821D6B105}&7523429";

    //encrypt the param string
    byte[] paramByteEnc = cryptoHelper.encryptBytesToBytes(paramStr.getBytes("ASCII"), PARAM_KEY, PARAM_IV);

    //convert it to hex
    String encryptedHexStr = cryptoHelper.byteArrayToHexStr(paramByteEnc);

    //convert it back to a byte array
    byte[] encryptedHexBytes = cryptoHelper.hexStrToByteArray(encryptedHexStr);

    // decrypt it
    byte[] paramByteDecrypted = cryptoHelper.decryptBytesToBytes(encryptedHexBytes, encryptedHexBytes.length, PARAM_KEY, PARAM_IV);

    String decryptedStr = new String(paramByteDecrypted);

    assertEquals("ABCB28BCEE5947B8AECE3386871EC0DF&{D5CA99D2-506B-4864-8971-E87821D6B105}&7523429", decryptedStr);
}

CryptHelper 类有以下方法:

@Override
public byte[] encryptBytesToBytes(byte[] plainData, byte[] key, byte[] iv) {
    try {
        initCipher(Cipher.ENCRYPT_MODE, key, iv);
        return aesCipher.doFinal(plainData);

    } catch (IllegalBlockSizeException | BadPaddingException e) {
        log.severe(e.getMessage());
    }

    return null;
}    

@Override
public byte[] decryptBytesToBytes(byte[] encryptedBytes, int length,
        byte[] key, byte[] iv) {
    try {
        initCipher(Cipher.DECRYPT_MODE, key, iv);
        return aesCipher.doFinal(encryptedBytes, 0, length);
    } catch (IllegalBlockSizeException | BadPaddingException e) {
        e.printStackTrace();
    }
    return null;
}

private void initCipher(int mode, byte[] keyBytes, byte[] ivBytes) {
    try {

        // create shared secret and init cipher mode
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        aesCipher.init(mode == Cipher.ENCRYPT_MODE ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes));
    } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
        e.printStackTrace();
    }
}

public String byteArrayToHexStr(byte[] encrypted) {
    StringBuilder hex = new StringBuilder();
    for (byte b : encrypted) {
        hex.append(String.format("%02X", b));
    }
    return new String(hex.toString());
}

public byte[] hexStrToByteArray(String hex) {
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < hex.length() - 1; i += 2) {
        String output = hex.substring(i, (i + 2));
        int decimal = Integer.parseInt(output, 16);
        sb.append((char) decimal);
    }

    String temp = sb.toString();
    return temp.getBytes();
}

我在解密过程中使用了相同的密钥和初始化向量,所以问题不在于错误的密钥或初始化向量。我也确信这里的每个功能都正确地完成了他们的工作。如果你不使用函数 hexStrToByteArray() 和 byteArrayToHexStr() 并且只使用加密的字节进行解密,它没有问题。我认为存在编码/解码问题,但我不知道如何在 java 中处理它。如果我使用 getBytes("UTF-8") 和 new String(byte[], "UTF-8") 我会得到 IllegalBlockSizeException。

我希望你能帮助我找出我是否走在正确的道路上以及我做错了什么。

【问题讨论】:

  • hexString.append(Integer.toHexString(0xFF &amp; digestBytes[i])); 这就是我将字节转换为十六进制的方式。
  • 不知道是不是它的 THE 问题,但是您的byteArrayToHexStr/hexStrToByteArray 没有正确处理负值。
  • @DavidSoroko: byteArrayToHexStr 看起来是正确的,其他方法看起来是错误的。
  • 写一个unitest测试,转换负值例如,下面CryptHelper.hexStrToByteArray(CryptHelper.byteArrayToHexStr(new byte[] {-97}))返回[63]
  • 谢谢你们的帮助。确实是函数 hexStrToByteArray() 不能正确处理负值。我用@DavidSoroko 所说的单元测试对其进行了测试。

标签: java encryption hex aes


【解决方案1】:

这清楚地表明,如果库函数已经定义,则不应编写它们。改用来自 Bouncy Castle、Guava 或 Apache 编解码器的十六进制编解码器(直到 Oracle 最终发现并在 java.util 包中提供一个)。

如果你自己实现,请不要将字符误认为字节:

public byte[] hexStrToByteArray(String hex) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(hex.length() / 2);

    for (int i = 0; i < hex.length(); i += 2) {
        String output = hex.substring(i, i + 2);
        int decimal = Integer.parseInt(output, 16);
        baos.write(decimal);
    }
    return baos.toByteArray();
}

【讨论】:

  • 你在开玩笑吗?刚刚用 ByteArrayOutputStream 替换了 StringBuilder ,然后一切正常吗?好的,谢谢! :D
猜你喜欢
  • 1970-01-01
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 2011-11-13
  • 2015-10-28
  • 1970-01-01
  • 2017-05-07
  • 1970-01-01
相关资源
最近更新 更多