AES算法在我的数据字符串中间返回垃圾字符

时间:2018-11-07 06:33:59

标签: java encryption aes

我获取一个数据字符串=“ AkhilRanjanBiharabcdefghijklmnopMovedtoChennai18”,先对其进行加密,然后再对其进行解密。我返回解密的字符串是“AkhilRanjanBiharÙ†+™¸„ À–ýæó @Movedtoñhennai18”,这对于前16个字符和最后16个字符几乎没问题,但是中间的16个字符绝对是垃圾。可能出什么问题了?

我的加密代码:-

public String encrypt(String value) {
    log.info("This method is not going to be used");
    String key = "theabcd@heymaths";
    initVector = "{{{{{{{{{{{{{{{{";
    String encryptedStr="";
    byte[] encrBytes =null;
    try {
        IvParameterSpec iv = new IvParameterSpec(initVector.getBytes());
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        encrBytes = cipher.doFinal(value.getBytes());
        encryptedStr = new String(encrBytes);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    String strToBeEncoded = encryptedStr +"::"+initVector;
    encrBytes = strToBeEncoded.getBytes();
    //String encoded = Base64.encodeBase64String(encrBytes);
    String encoded = Base64.getEncoder().encodeToString(encrBytes);
    String urlEncoded = null;
    try {
        urlEncoded = java.net.URLEncoder.encode(encoded, CHARSET);
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return urlEncoded;
}

解密代码:-

public String decrypt(String encrypted) {
    String decryptedStr = null;
    byte[] base64Bytes = null;
    String urlDecoded = null;
    String key = HmCommonProperty.getProperty("abcd_crypt_key");
    if(key == null || key.isEmpty()) {
        key = securityKey;
    }
    String encryptionMech = HmCommonProperty.getProperty("abcd_crypt_algo");
    if(encryptionMech == null || encryptionMech.isEmpty()) {
        encryptionMech = CRYPT_MECHANISM;
    }
    try {
        //Url and Base64 decoding
        urlDecoded = java.net.URLDecoder.decode(encrypted, CHARSET);
        //base64Bytes = Base64.decodeBase64(urlDecoded);
        base64Bytes = Base64.getDecoder().decode(urlDecoded);
        //Generating IV
        String str = new String(base64Bytes);
        String[] bodyIVArr = str.split("::");
        initVector = bodyIVArr[1];
        String bodyStr = bodyIVArr[0];

        //AES Decryption
        Cipher cipher = Cipher.getInstance(encryptionMech);
        IvParameterSpec iv = new IvParameterSpec(initVector.getBytes());

        System.out.println("initVector Length ->  "
                +iv.getIV().length);
        System.out.println("input length ->  "
                +bodyStr.getBytes().length);

        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        byte[] decryptedBytes = cipher.doFinal(bodyStr.getBytes());
        decryptedStr =  new String(decryptedBytes);
    } catch (Exception ex) {
        ex.printStackTrace();
        log.error("Error occurred while decryption abcd data",ex);
    }

    return decryptedStr;
}

2 个答案:

答案 0 :(得分:1)

您的加密数据是字节序列。如果需要将其编码为字符串,则应使用base64或旨在对任意字节数组进行编码的类似编码。假装您的任意字节数组是有效的字符串编码,即使使用ISO_8859_1,也会造成麻烦。

替换

encryptedStr = new String(encrBytes)

使用

encryptedStr = Base64.getEncoder().encodeToString(encrBytes)

并替换

bodyStr.getBytes()

Base64.getDecoder().decode(bodyStr)

另请参阅:How to correctly and consistely get bytes from a string for AES encryption?

答案 1 :(得分:0)

您的错误在这里:

encryptedStr = new String(encrBytes);
strToBeEncoded.getBytes();

这些方法使用平台默认字符集,并且当您从byte[]转换为String并返回到byte[]时,通常该过程有损案件。唯一不会造成损失的方法是,如果平台默认字符集为"ISO_8859_1"

我将11个此类呼叫全部更改为:

encryptedStr = new String(encrBytes, StandardCharsets.ISO_8859_1);
strToBeEncoded.getBytes(StandardCharsets.ISO_8859_1);

(我没有更改CHARSET)。我现在得到的输出是:

  

initVector长度-> 16
  输入长度-> 48
  AkhilRanjanBiharabcdefghijklmnopMovedtoChennai18

奖金警告1:加密使用硬编码的"AES/CBC/NoPadding",但是解密是动态的(当然也应该使用"AES/CBC/NoPadding")。

奖金警告2:机会很小,但是"::"很有可能出现在encrBytes内部,从而使str.split("::");陷入困境。一种解决方案是搜索"::" last 最后出现的地方,然后仅对此进行拆分。