【问题标题】:Encryption using AES-128 in Java在 Java 中使用 AES-128 进行加密
【发布时间】:2012-01-04 05:38:48
【问题描述】:

我在使用 AES-128/ecb/PKCS5Padding+base64 加密数据时遇到问题。我正在使用以下代码来加密我的数据:

String input = "{\"action\":\"getQuestion\"}";
String key = "4288f0b8060ca1b682bf795f2617cfdc";
byte[] data = input.getBytes();
byte[] encrypted = null;
byte[] keyBytes = new BigInteger(key, 16).toByteArray();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
encrypted = cipher.doFinal(data);
System.out.println(Base64.encodeBytes(encrypted));

加密后我收到6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk=,但我无法在服务器上使用 PHP 函数解密。

当我使用 PHP 函数加密这些数据时:

function encrypt($encrypt, $key=null) 
{
   $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
   $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $encrypt, MCRYPT_MODE_ECB, $iv));
   return $encrypted;
}

我收到6Wc3LPWvfJ7T86iG0igmdQaeZ8xs9qY419mAVWfNH+M=,我可以使用以下 PHP 函数成功解密:

function decrypt($decrypt, $key=null) 
{
   $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
   $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($decrypt), MCRYPT_MODE_ECB, $iv);
   return $decrypted;
}

base64加解密没有问题;我只在使用 AES-128 加密时遇到此问题。

【问题讨论】:

  • 您可能没有在两边使用相同的密钥。发布所有填充 $key 的 PHP 代码,包括当前发布代码中的常量声明。
  • 一些事情:1)删除IV,我不知道它会对PHP函数做什么,但如果它做了什么,它会搞砸加密/解密2)永远不要使用String.getBytes() 没有指定要使用的编码 3) BigInteger.toByteArray() 可能返回 1 到 17 个字节,具体取决于密钥值 4) ECB 绝对是错误的加密类型。在尝试其他任何事情之前修复这些问题。我认为您可以在与 PHP 通信并使用代码
  • @Paulo:最后一个“使用 ECB 模式”可能是一个错字,我想你会想在这里建议 CBC 模式(或任何其他提供完整性保护/身份验证的安全方案)。
  • @owlstead:啊,谢谢你的来信。这里有可怕的错字。
  • 这对您当前的问题没有帮助,但是:永远不要使用 ECB 模式,直到您了解它不安全的原因。使用 CBC 模式(与消息一起传输的随机 IV),结合一些身份验证(例如 HMAC)。

标签: java php encryption aes


【解决方案1】:

问题不在于我最初认为的 IV 或填充。这与您如何处理 PHP 代码中的密钥有关。如果您使用实际字符串4288f0b8060ca1b682bf795f2617cfdc 作为传递给mcrypt_encryptmcrypt_decrypt 的键,那么您使用的键与Java 代码中的键不同。您需要将该十六进制字符串转换为字节。您可以通过以下方式执行此操作:

$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, pack("H*", $key), base64_decode($decrypt), MCRYPT_MODE_ECB, $iv);

注意添加pack("H*", $key) 以转换值。我在 PHP bin2hex 函数的 cmets 中发现了 here。这将解决当前的问题。在处理不同长度的数据时,您可能会遇到填充问题,因为 PHP 不进行 PKCS5 填充。请参阅this 关于实现该缺失功能的评论。另外,由于 ECB 不适合数据加密并且存在弱点,我建议您研究 CBC 而不是 ECB。

【讨论】:

  • 我在没有初始化向量的情况下尝试了php,但是它们分别得到完全相同,并且无法解密java上生成的数据。
  • 是的,ECB 不使用初始化向量。这就是使它不如其他模式安全的原因。一切就绪后,您可能需要考虑使用静脉输液进行 CBC。
  • @silentnuke:无法保证默认的 Java IV 与默认的 PHP IV 相同。您需要在两侧明确指定 IV。至少,将加密 IV 复制到解密函数。此外,避免欧洲央行模式,它是不安全的。请改用 CBC 或 CTR 模式。
  • 我尝试使用此服务crypto.hurlant.com/demo 加密数据。 aes128/ecb/PKCS5Padding。得到的数据已经成功转用php函数破译
  • 感谢有关 cbc 的提示,但首先我想处理这个问题。在flash项目中没有这样的问题,我们使用库code.google.com/p/as3crypto进行加密
【解决方案2】:

您可以使用 openssl 在命令行中验证 Java 方法的输出。如果未指定,Java 会将您的 IV 默认为 0。

The file "enc.txt" contains "6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk=" [corrected]

运行

openssl aes-128-ecb -in enc.txt -a -K 4288f0b8060ca1b682bf795f2617cfdc -iv 0 -d

结果是:

{"action":"getQuestion"}

尝试使用 $iv 值为 0 的 mcrypt_decrypt。

【讨论】:

  • 如果 java functiob 返回 6Wc3LPWvfJ7T86iG0igmdQaeZ8xs9qY419mAVWfNH+M= 问题不会出现,但返回 6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk=
  • 哎呀。当我在这里写笔记时打错了——不是我测试的时候。文件“enc.txt”实际上是“6Gu...”字符串。
猜你喜欢
  • 2019-04-18
  • 2020-12-03
  • 1970-01-01
  • 2012-11-14
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
相关资源
最近更新 更多