使用 base64 编码写入文件时的 AES 解密

AES Decryption when writing to a file using base64 encoding

我正在执行以下步骤:

  1. Bob 使用 AES 加密消息
  2. Bob 将加密编码为 base64 字符串
  3. Bob 将字符串写入文件
  4. Alice 读取文件
  5. Alice 将字符串转换为字节
  6. 爱丽丝解密消息

但是,我在最后一步失败了。

这里是加密:

public void sendHelloWorld() {
    String msg = "hello world!";
    try {
        SecretKeySpec AesKeySpec = new SecretKeySpec(aesKeyBytes, "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, AesKeySpec);
        aesEncryptedHello = c.doFinal(msg.getBytes());
    } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    String s = new String(aesEncryptedHello, StandardCharsets.UTF_8);
    System.out.println("Message = " + s);
    sendMessage(Base64.getEncoder().encodeToString(aesEncryptedHello));
}

解密如下:

public void decryptAESMessage(byte[] encryptedMessage) {
    try {
        String s = new String(encryptedMessage, StandardCharsets.UTF_8);
        System.out.println("Message = " + s);
        SecretKeySpec AesKeySpec = new SecretKeySpec(bobAesKey, "AES");
        Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
        c.init(Cipher.DECRYPT_MODE, AesKeySpec);
        byte[] aesMessage = c.doFinal(encryptedMessage);
        String message = new String(aesMessage, StandardCharsets.UTF_8);
        System.out.println("Message is " + message);
    } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    
}

这是写入文件:

public void sendMessage(String msg) {
    try {
        
        FileWriter myWriter = new FileWriter(<myredactedfilepath>);
        myWriter.write(msg);
        myWriter.close();
    } catch (IOException e) {
        System.out.println("An error occurred.");}
}

这里是第 5 阶段,只是为了表明没有遗漏解码:

alice.decryptAESMessage(Base64.getDecoder().decode(alice.readEncryptedMessage()));

我在两端打印密钥和加密消息,它们匹配。

在加密部分,您使用了 AES/CBC/PKCS5Padding,即 PKCS#5 的 CBC 操作模式 - 实际上,它是 PKCS#7 - 缺少 IV。 CBC 模式需要和 IV,这至少应该是随机的。可以用

生成
SecureRandom randomSecureRandom = new SecureRandom();
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);

在解密部分,你使用了AES/ECB/PKCS5Padding。通常两者必须匹配。使用 IV 创建 ECB(请不要)或 CBC。

IV 通常附加在密文的开头。在解密过程中解析并使用它。

另外,在解密里面进行base64解码。这将使您的模式更加健壮。

最后说明:如果没有具体原因,更喜欢AES-GCM,它不仅可以提供机密性,还可以提供完整性和身份验证。如果你需要坚持CBC你需要额外使用HMAC来实现完整性和认证。

以及完整的代码示例;参见