为了账号安全,请及时绑定邮箱和手机立即绑定

Java 中的 AES 加密以匹配 C# 输出

Java 中的 AES 加密以匹配 C# 输出

C#
www说 2022-10-15 14:06:46
我正在尝试使用 JAVA 进行 AES 加密,我进行了多次尝试,尝试了很多代码并进行了许多更改,最终达到了我的加密文本与使用 C# 代码生成的加密文本匹配但部分匹配的地方。最后一个 32 位块是不同的。我无权访问 C# 代码,因为它是第 3 方服务。谁能指导我错过了什么?提到的条件是使用:在 CBC 模式下使用 256 位 AES 加密并使用 PKCS5 填充使用您的主键和初始化向量来加密整个查询字符串。(不要在查询字符串中包含消息摘要。)主键是 64 位十六进制字符串,初始化向量是 32 位十六进制字符串。我使用的样本值是:Aes_IV = 50B666ADBAEDC14C3401E82CD6696D4Aes_Key = D4612601EDAF9B0852FC0641DC2F273E0F2B9D6E85EBF3833764BF80E09DD89F(我的密钥材料)Plain_Text = ss=brock&pw=123456&ts=20190304234431(输入)Encrypted_Text = 7643C7B400B9A6A2AD0FCFC40AC1B11E51A038A32C84E5560D92C0C49B3B7E0 A072AF44AADB62FA66F047EACA5C6A018(输出)我的输出= 7643C7B400B9A6A2AD0FCFC40AC1B11E51A038A32C84E5560D92C0C49B3B7E0 A38E71E5C846BAA6C31F996AB05AFD089public static String encrypt( String keyMaterial, String unencryptedString, String ivString ) {    String encryptedString = "";    Cipher cipher;    try {        byte[] secretKey = hexStrToByteArray( keyMaterial );        SecretKey key = new SecretKeySpec( secretKey, "AES" );        cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );        IvParameterSpec iv;        iv = new IvParameterSpec( hexStrToByteArray( ivString ) );        cipher.init( Cipher.ENCRYPT_MODE, key, iv );        byte[] plainText = unencryptedString.getBytes( "UTF-8") ;        byte[] encryptedText = cipher.doFinal( plainText );        encryptedString = URLEncoder.encode(byteArrayToHexString( encryptedText ),"UTF-8");    }    catch( InvalidKeyException | InvalidAlgorithmParameterException | UnsupportedEncodingException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException e ) {        System.out.println( "Exception=" +e.toString() );    }    return encryptedString;}任何建议,我应该怎么做才能匹配输出?
查看完整描述

1 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

如果只有 ECB / CBC 填充的最后一个块不同,那么您可以很确定使用了不同的块密码填充。要验证使用了哪个填充,您可以尝试(正如 Topaco 在问题下方的评论中所做的那样),或者您可以在没有填充的情况下解密密文。对于 Java,那将是"AES/CBC/NoPadding".

因此,如果您在给定密钥(和 IV)的情况下这样做,那么您将获得以下十六进制输出:

73733D62726F636B2670773D3132333435362674733D3230313930333034323334343331000000000000000000000000

显然这是零填充。

零填充有一个很大的缺点:如果您的密文以值为零的字节结尾,那么这个字节可能会被视为填充并从结果中删除。通常这对于由 ASCII 或 UTF-8 字符串组成的纯文本来说不是问题,但对于二进制输出可能会比较棘手。当然,我们在这里假设字符串不使用预期会出现在加密明文中的空终止符。

还有另一个较小的缺点:如果您的明文恰好是块大小,那么零填充就足够不标准了,因此有两种情况:

  1. 填充总是被应用并且需要被删除,这意味着如果明文大小正好是块大小的数倍,那么仍然会添加一个完整的填充块(所以对于 AES,你会有 1..16 零值字节作为填充);

  2. 仅在严格要求时才应用填充,这意味着如果明文大小正好是块大小的数倍,则不应用填充(因此对于 AES,您将有 0..15 个零值字节作为填充)。

因此,目前,对于加密,您可能必须测试预期/接受哪一个。例如,可用于 C# 和 Java 的 Bouncy Castle 总是(未)填充,而可怕的 PHP / mcrypt 库只在需要的地方填充。

当然,您始终可以执行自己的填充,然后"NoPadding"用于 Java。请记住,您永远不会取消填充超过 16 个字节。

一般警告:未经身份验证的加密不适合传输模式安全性。


查看完整回答
反对 回复 2022-10-15
  • 1 回答
  • 0 关注
  • 182 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号