Java AES/CFB8/NoPadding加密和Charset

Mic*_*ael 3 java encryption aes character-encoding

我正在尝试Strings使用Java和PHP 加密和解密,所以我使用AES/CFB8/NoPadding它可以在双方都工作.

现在Cryptor,只要我将Charset设置为拉丁语,我的作品就会完全放弃拉丁字符.但是当我将它设置为UTF-8(这是我在我的数据库中使用的)时,加密没有正确完成.

这是输出:

/*
* Latin (ISO-8859-1) output:
* Original: MiiiMüäöMee?
* Encoded: rQ¶[ÉÐRíD
* Decoded: MiiiMüäöMee?
* 
* UTF-8 output:
* Original: MiiiMüäöMee?
* Encoded: rQ?[?
* Decoded: Mii0SS1])_?E?I?S?;?W??W?*
*/
Run Code Online (Sandbox Code Playgroud)

由于"ʞ"不是拉丁字符,我理解它无法正确加密.但为什么UTF-8不起作用?

public class Cryptor {

    private Cipher cipher;
    private String secretKey = "1234567890qwertz";
    private String iv = "1234567890qwertz";

    private SecretKey keySpec;
    private IvParameterSpec ivSpec;
    private Charset CHARSET = Charset.forName("ISO-8859-1"); // ISO-8859-1 vs. UTF-8

    public Cryptor() throws CryptingException {

        keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES");
        ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
        try {
            cipher = Cipher.getInstance("AES/CFB8/NoPadding");
        } catch (NoSuchAlgorithmException e) {
            throw new SecurityException(e);
        } catch (NoSuchPaddingException e) {
            throw new SecurityException(e);
        }
    }

    public String decrypt(String input) throws CryptingException {

        try {
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            return new String(cipher.doFinal(input.getBytes(CHARSET)), CHARSET).trim();
        } catch (IllegalBlockSizeException e) {
            throw new SecurityException(e);
        } catch (BadPaddingException e) {
            throw new SecurityException(e);
        } catch (InvalidKeyException e) {
            throw new SecurityException(e);
        } catch (InvalidAlgorithmParameterException e) {
            throw new SecurityException(e);
        }
    }

    public String encrypt(String input) throws CryptingException {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            return new String(cipher.doFinal(input.getBytes(CHARSET)), CHARSET).trim();
        } catch (InvalidKeyException e) {
            throw new SecurityException(e);
        } catch (InvalidAlgorithmParameterException e) {
            throw new SecurityException(e);
        } catch (IllegalBlockSizeException e) {
            throw new SecurityException(e);
        } catch (BadPaddingException e) {
            throw new SecurityException(e);
        }
    }

    public static void main(String Args[]) {

        try {
            Cryptor c = new Cryptor();
            String original = "MiiiMüäöMee?";
            System.out.println("Original: " + original);
            String encrypted = c.encrypt("MiiiMüäöMee?");
            System.out.println("Encoded: " + encrypted);
            System.out.println("Decoded: " + c.decrypt(encrypted));

        } catch (CryptingException e) {
            e.printStackTrace();
        }
    }

    class CryptingException extends RuntimeException {

        private static final long serialVersionUID = 7123322995084333687L;

        public CryptingException() {
            super();
        }

        public CryptingException(String message) {
            super(message);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Bor*_*der 12

我认为将加密的字节转换为a String是一个坏主意.字节对任何编码都无效,它们是随机的.

您需要将结果编码byte[]为base64以获得一致的结果.见sun.misc.BASE64Encoder/ sun.misc.BASE64Decoder.

这里是一个base64解码的一个例子Stringbyte[],相反的过程非常相似.

您可以声明解码器/编码器和类的顶部:

private final BASE64Decoder base64Decoder = new BASE64Decoder();
private final BASE64Encoder base64Encoder = new BASE64Encoder();
Run Code Online (Sandbox Code Playgroud)

然后在你的decypt方法中你需要打电话

return new String(cipher.doFinal(base64Decoder.decodeBuffer(input)), CHARSET);
Run Code Online (Sandbox Code Playgroud)

在你的encrypt方法

return base64Encoder.encode(cipher.doFinal(input.getBytes(CHARSET)));
Run Code Online (Sandbox Code Playgroud)

使用UTF-8输出:

Original: MiiiMüäöMee?
Encoded: clEUtlv2ALXsKYw4ivOfwQ==
Decoded: MiiiMüäöMee?
Run Code Online (Sandbox Code Playgroud)

一方面注意,使用包不是严格意义上的好习惯,sun.*因为它们不是java规范的一部分,因此可能会因版本而变化/消失.

是关于迁移到Apache Commons Codec实现的一篇小文章.
这也是Guava API中的类似类.