解密Java中的CommonCrypto加密的Base 64编码的字符串(AES / CBC / PKCS7Padding)

时间:2018-06-30 19:42:49

标签: java encryption aes commoncrypto cbc-mode

我正在尝试使用标准String API用Java中的已知密钥解密Cipher

加密的String来自Web Service,它使用标准的CommonCrypto库,其中的responds和一些statistics作为加密字符串,并定期进行加密。

规范为AES/CBC/PKCS7PaddingKeySize = 32 BytesBlockSize = 16 Bytes,以及Encoding UTF-8 (raw)Base64。我打算编写一个Java客户端,该客户端可以请求这些statisticsdecrypt并将它们存储起来以便以后进行分析。

问题1.如果密钥很短,CommonCrypto是否会自动用额外的字符填充密钥?例如小于16 Bytes or 32 Bytes

问题2.应该采取什么编码措施来确保两端的encryption/decryption相同?

示例字符串和键

String message = "mQp9sp8ri1E0V1Xfso1d5g==Mrf3wtaqUjASlZmUO+BI8MrWsrZSC0MxxMocswfYnqSn/VKB9luv6E8887eCxpLNNAOMB0YXv6OS7rFDFdlvC53pCHo3cVZiLJFqgWN/eNiC9p4RMxyFCcOzWrwKzT5P8sy55DwE25DNJkvMthSaxK5zcP1OdLgBiZFOSxYRsX4rBk7VP7p5xr2uTGjRL+jmGgB9u3TmeCNCr8NxGLNt6g==";
String userKey = "123456789";

private static String decrypt (String message, String userKey) throws UnsupportedEncodingException,
            NoSuchPaddingException,
            NoSuchAlgorithmException,
            InvalidKeyException,
            ShortBufferException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchProviderException {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        if (message.length() >= 48) {

        ivFromEncryptedString = message.substring(0, Math.min(message.length(), 24));
        messageFromEncryptedString = message.substring(24, message.length());

        System.out.println(ivFromEncryptedString);
        System.out.println(messageFromEncryptedString);

        byte[] data = decodeBase64(messageFromEncryptedString);
        byte[] ivData = decodeBase64(ivFromEncryptedString);

        paddedKey = padShortKeys(userKey);

        byte[] keyBytes = paddedKey.getBytes(CHARSET);

        MessageDigest sha = MessageDigest.getInstance("SHA-256"); //key
        keyBytes = sha.digest(keyBytes);

        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);

            byte [] encrypted = new byte[cipher.getOutputSize(data.length)];
            int ctLength = cipher.update(data, 0, data.length, encrypted, 0);
            ctLength += cipher.doFinal(encrypted, ctLength);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            return encrypted;
        }
    }
    return null;
    }
private static String encodeBase64(byte [] in){
    return Base64.getEncoder().encodeToString(in);
}

private static byte[] decodeBase64(String str) throws UnsupportedEncodingException {
    return DatatypeConverter.parseBase64Binary(str);
}

在当前代码状态下,我也得到了占位符而不是期望的结果。

先谢谢大家。 :)

1 个答案:

答案 0 :(得分:1)

CommonCrypto不清楚,您正在使用哪种实现?苹果,Apache,Java类密码或其他,请提供指向它的链接。

  1. 永远不要假设加密会填充密钥或IV,应该始终以确切的长度提供它们,没有关于填充的标准。如果他们需要填充(他们不应该)自己动手。

  2. 通常,如果需要将加密数据表示为使用Base64编码的字符串。

如James所述,一次性加密只需使用doFinal(ByteBuffer input, ByteBuffer output) 单步操作即可加密或解密数据。

注意:9位数的密钥仅具有约33位的安全性,这还远远不够。简单地使用哈希函数不足以从密码派生加密密钥,而应使用PBKDF2Argon2