【问题标题】:How to Convert "AES" key from byth[] to UTF-8 String如何将“AES”密钥从 byth[] 转换为 UTF-8 字符串
【发布时间】:2020-04-22 13:43:34
【问题描述】:

我需要将 secretKey.getEncoded() 从 byte[] 转换为 String 以便将密钥保存到 db 并通过消息将密钥发送给另一方。

现在我设法在 Base64 (24 字节) 中做到这一点,但对方只能以 UTF-8 格式读取它(16 字节)

我尝试这样做:String str = new String(bytes, Charsets.UTF_8); ,但我得到了错误的乱码格式,带有像这样的引号:k��$��v/~M�6�L�

这样做的正确方法是什么?

 public static String generateAESKey() throws Exception {

    KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
    kgen.init(128); 
    SecretKey secretKey = kgen.generateKey();

    return new String(Base64.encode(secretKey.getEncoded(), Base64.NO_WRAP));

}

【问题讨论】:

  • 你可以试试String str = new String(secretKey.toString(), Charsets.UTF_8);
  • 你是如何初始化变量bytes的?
  • @Arik6 AES 密钥是随机或伪随机(例如来自 KDF)字节串。在您的情况下,16 个字节对应于 128 位密钥。鉴于它是随机的或接近随机的,为什么您期望尝试将这些随机字节解释为 UTF-8 字符串不会只导致随机垃圾?我建议您和/或另一方在您更好地理解一些基本概念之前推迟使用密码学——错误地使用密码术可能会对用户的信任和隐私造成危险。
  • @Arik6 UTF-8 的一些值是不可打印的,比如前几个是控制字节。所以不,不可能将具有从 0-255 的所有可能值的字节数组转换为可读字符串。这就是使用 base64 的原因。
  • 好吧,我不明白。您在问题的文本中声称您不知道如何将二进制字节数组转换为字符串,并举例说明为什么这不起作用。然后你展示了正确方式的代码,然后你问“什么是正确的方式”。

标签: java android encryption public-key-encryption


【解决方案1】:

以字节数组的形式生成一个密钥,您可以使用它来加密和解密过程。

private SecretKey secretKey; // member variables (in class)

public byte[] generateAESKey() {
    try {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        if (secretKey == null) {
            secretKey = kgen.generateKey();
        }
        byte[] keyBytes = secretKey.getEncoded(); 
        //Log.i("keyBytes", toHexString(keyBytes));
        return keyBytes;
    }
    catch (Exception ex){
        ex.printStackTrace();
    }
    return null;
}

生成AESKey的结果:

0x04 0x90 0x74 0x21 0x73 0xB9 0x3D 0x1F 0x7B 0x19 0xC4 0x95 0x85 0x20 0xDF 0x27

以字符串的形式生成密钥,您可以保存或发送到另一个应用程序。

public String getStrAESkey()  {
    try {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        if (secretKey == null) {
            secretKey = kgen.generateKey();
        }
        String keyStr = toHexString(secretKey.getEncoded());
        Log.i("keyStr", keyStr);
        return keyStr;
    }
    catch (Exception ex){
        ex.printStackTrace();
    }
    return null;
}

getStrAESkey() 的结果:

0490742173B93D1F7B19C4958520DF27

//

public String toHexString(byte[] bytes) {
    return Utils.printHexBinary(bytes);
}

public byte[] toByteArray(String hexString) {
    return Utils.parseHexBinary(hexString);
}

Utils.java

public class Utils {
    private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

    private static int hexToBin(char ch) {
        if ('0' <= ch && ch <= '9') return ch - '0';
        if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
        if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
        return -1;
    }

    public static byte[] parseHexBinary(String s) {
        final int len = s.length();

        if (len % 2 != 0)
            throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);

        byte[] out = new byte[len / 2];

        for (int i = 0; i < len; i += 2) {
            int h = hexToBin(s.charAt(i));
            int l = hexToBin(s.charAt(i + 1));
            if (h == -1 || l == -1)
                throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);

            out[i / 2] = (byte) (h * 16 + l);
        }

        return out;
    }

    public static String printHexBinary(byte[] data) {
        StringBuilder r = new StringBuilder(data.length * 2);
        for (byte b : data) {
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
        }
        return r.toString();
    }
}

【讨论】:

  • 感谢您的回答,但正如我写的那样,当我这样做时,我得到了一个不正确的乱码字符串格式,例如:k��$��v/~M�6�L�
  • 这完全不正确,可能会导致信息丢失、安全性降低和无法解密。此外,这几乎是对OP已经说过他使用并认为是错误的方法的复制和粘贴。
  • 我根据这里的参考来回答,docs.oracle.com/javase/tutorial/i18n/text/string.html
猜你喜欢
  • 1970-01-01
  • 2014-04-20
  • 2012-12-31
  • 2015-03-18
  • 2013-03-02
  • 1970-01-01
  • 2016-07-13
  • 2011-11-25
  • 2013-08-20
相关资源
最近更新 更多