【问题标题】:Why am I not getting the output in the string format?为什么我没有得到字符串格式的输出?
【发布时间】:2013-08-17 16:28:31
【问题描述】:

在下面的 sn-p 中,我尝试以简单的字符串格式打印encrypted array

        KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
        SecretKey secretKey = keyGenerator.generateKey();
        Cipher cipher = Cipher.getInstance("Blowfish"); 
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        String input = "password";
        byte encrypted[] = cipher.doFinal(input.getBytes());
        String s = new String(encrypted);
        System.out.println(s);

但我得到的是 `┐╫Y²▓ô┴Vh¬∙:╪⌡¶ 。为什么 ?如何以正确的字符串格式打印它?

【问题讨论】:

  • 好吧,你加密了一个字符串。这就是您打印它时得到的 - 加密不一定将可读字符串转换为另一个可读字符串......这就是您想要的:其他人无法看到它是什么。你需要先解密。
  • @ppeterka 这不是加密字符串。
  • 不要尝试将二进制数据放入字符串中。这取决于平台,只会导致问题。如果您需要它作为字符串(例如可移植地保存到文本文件),请使用 base64。
  • 顺便说一句,input.getBytes() 将使用平台默认编码。不是一个好主意。你应该总是在像这样转换时指定一个编码 - 它通常应该是 UTF-8。
  • @saplingPro:要问自己一个重要问题:为什么您期望您的代码会生成字节数组的十六进制表示?

标签: java cryptography bytearray


【解决方案1】:

对字节进行 Base64 编码 (How do I convert a byte array to Base64 in Java?)

或十六进制:How to convert a byte array to a hex string in Java?

System.out.println(Hex.encodeHexString(bytes));

【讨论】:

    【解决方案2】:

    您可以使用来自common-codecBase64 编码。

        KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
        SecretKey secretKey = keyGenerator.generateKey();
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        String input = "password";
        byte encrypted[] = cipher.doFinal(input.getBytes());
        System.out.println(new String(Base64.encodeBase64(encrypted)));
    

    输出:

    8KA8ahr6INnY4qqtzjAJ8Q==
    

    【讨论】:

    【解决方案3】:

    大多数加密算法(包括河豚)处理二进制数据,这意味着它将接收二进制数据并分离出由算法(使用提供的规范)转换的二进制数据。

    二进制数据,如您所知,!= 表示字符串数据,但二进制数据可以表示为字符串数据(使用十六进制、base64 等)。

    如果我们查看您的示例代码,我们可以看到这一行:

    byte encrypted[] = cipher.doFinal(input.getBytes());
    

    这是它一步一步做的:

    1. 它首先使用平台的默认字符集将字符串数据转换为等效的二进制数据(不推荐,但无关紧要)。

    2. 它将二进制数据(以字节数组的形式)传递给方法doFinal()。

    3. doFinal() 方法正在通过此行之前的语句(Blowfish,加密)中指定的规范处理此字节数组。

    4. doFinal() 语句返回一个字节数组,该数组表示已处理(在您的情况下为加密)数据。

    数据最初来自字符串的事实不再相关,因为加密操作的性质不考虑数据的来源或类型。加密字节数组现在包含可能不是有效字符集编码字符串的数据。尝试使用字符集来解码字符串很可能会导致垃圾输出,因为二进制数据不再是有效的字符串。

    但是,二进制数据可以直接通过输出实际字节的VALUE来表示,而不是charset等效映射是什么(例如,一个字节可能有97的值,用十六进制表示是: 0x61 但通过 ASCII 解码得到字符 'a')。

    考虑使用此代码以十六进制输出您的加密数据:

    KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
    SecretKey secretKey = keyGenerator.generateKey();
    Cipher cipher = Cipher.getInstance("Blowfish"); 
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    String input = "password";
    byte encrypted[] = cipher.doFinal(input.getBytes());
    
    StringBuilder str = new StringBuilder();
    
    for(byte b:encrypted){
         str.append(String.format("%02x", b));
    }
    
    String encData = str.toString();
    System.out.println(encData);
    

    P.S:不要在没有任何参数的情况下使用 getBytes()!提供您自己的字符集,例如 UTF-8。执行以下操作:

    byte encrypted[] = cipher.doFinal(input.getBytes(Charset.forName("UTF-8")));
    

    【讨论】:

      【解决方案4】:

      你可以试试:

      new String(bytes, StandardCharsets.UTF_8)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-13
        • 1970-01-01
        • 2015-12-29
        • 2013-11-02
        • 1970-01-01
        • 1970-01-01
        • 2023-02-21
        相关资源
        最近更新 更多