用PHP代替JAVA进行PKCS5加密


Replacing JAVA with PHP for PKCS5 encryption

我的任务是用运行PHP的东西替换遗留的java系统。

我有点拘泥于用PHP代码替换java密码。

cipherAlgorythm = "PBEWithMD5AndDES";                           
cipherTransformation = "PBEWithMD5AndDES/CBC/PKCS5Padding";     
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt, iterations);
SecretKeyFactory kf = SecretKeyFactory.getInstance(cipherAlgorythm);
SecretKey key = kf.generateSecret(new javax.crypto.spec.PBEKeySpec(password.toCharArray()));
Cipher encryptCipher = Cipher.getInstance(cipherTransformation);   
encryptCipher.init(Cipher.ENCRYPT_MODE, key, ps);
byte[] output = encryptCipher.doFinal("This is a test string".getBytes("UTF-8"));

似乎是Java 的核心

在PHP中,我正在做

$hashed_key = pbkdf2('md5', $this->key, $this->salt, $this->reps , <GUESS 1>, TRUE);
$output = mcrypt_encrypt(MCRYPT_DES, $hashed_key, "This is a test string", MCRYPT_MODE_CBC, <GUESS 2>);

pbkdf2来自这里。

所以<GUESS 1>是密钥大小,<GUESS 2>是IV。有人对这样的价值观有建议吗?据我所知,加密本身应该是可移植的,但我不确定一些Java方法中发生了什么。

看起来java在某个地方创建了一个IV,但我不知道如何创建,也不知道在哪里创建。

相关

解密(使用PHP)Java加密(PBEWithMD5AndDES)

您可能需要查看http://us3.php.net/manual/en/ref.mcrypt.php#69782,但基本上他实现了一个DIY填充解决方案:

function pkcs5_pad ($text, $blocksize) 
{ 
    $pad = $blocksize - (strlen($text) % $blocksize); 
    return $text . str_repeat(chr($pad), $pad); 
} 

这可能是你最好的选择,但如果你看看这条评论,他关于如何验证每一步都是正确的建议可能对你有用。

https://stackoverflow.com/a/10201034/67566

理想情况下,你应该远离DES,既然这种填充在PHP中会成为一个问题,为什么不看看你是否可以将加密算法更改为不那么麻烦、更安全的算法呢?

要帮助您显示此页面,请执行以下操作:http://www.ietf.org/rfc/rfc4772.txt,其中简洁地表示DES易受暴力攻击,因此已被弃用,并被AES取代。

现有的两个答案都有帮助,但我将在这里发布完整的解决方案。

我在任何地方都没有看到它的文档,但在查看了这个加密方案的实现后,我发现密钥是加密哈希的前8个字节,IV是最后8个字节。

 public function get_key_and_iv($key, $salt, $reps) {
    $hash = $key . $salt;
    for ($i = 0; $i< $reps; $i++) {
      $hash = md5($hash, TRUE);
    }
    return str_split($hash,8);
  }

似乎奏效了。它取代了我问题中的pbkdf2,否定了对<GUESS 1>的需求,并给出了<GUESS 2> 的值

然后我遇到了詹姆斯·布莱克提到的填充问题,并设法解决了这个问题。所以最后的代码是

list($hashed_key, $iv) = get_key_and_iv($key, $salt, $reps);
// 8 is DES block size.
$pad = 8 - (strlen($plaintext) % 8);
$padded_string = $plaintext . str_repeat(chr($pad), $pad);
return mcrypt_encrypt(MCRYPT_DES, $hashed_key, $padded_string, MCRYPT_MODE_CBC, $iv);

您也可以使用hash_pbkdf2 PHP(5.5)函数,而不是使用pbkdf2 PHP库。

根据PHP文档,GUESS 1是创建的派生密钥的长度

长度

输出字符串的长度。如果raw_output为TRUE,则对应于派生密钥的字节长度,如果raw_output为FALSE这相当于派生密钥字节长度的两倍(如密钥的每个字节都作为两个十六进制返回)。

如果传递了0,则使用所提供算法的全部输出。

也许这篇文章(以字节为单位的最佳哈希大小是多少?)的结果对你来说很有趣。

GUESS 2或IV是用于创建唯一salt以生成散列的随机初始化向量。

您可以使用mycript_create_IV函数创建IV。

查看PHP.net 中的完整样本

<?php
$password = "password";
$iterations = 1000;
// Generate a random IV using mcrypt_create_iv(),
// openssl_random_pseudo_bytes() or another suitable source of randomness
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$hash = hash_pbkdf2("sha256", $password, $salt, $iterations, 20);
echo $hash;
?>