我有一个DES算法使用java,现在我需要转换这个java程序用于php,我不知道java cipher.init
方法的第三个参数SecureRandom
,所以我用我的php Des程序加密一个字符串,但我得到了与java Des。不同的结果。
这是我的Java DES:
public static String encode(String srcStr) {
if (srcStr == null)
return null;
String dst = null;
byte[] result = encrypt2(srcStr.getBytes(), "h43au76U");
if (result == null)
return null;
System.out.println(result);
dst = byte2HexStr(result, result.length);
return dst;
}
private static final char[] mChars = "0123456789ABCDEF".toCharArray();
public static String byte2HexStr(byte[] b, int iLen) {
if (b == null)
return null;
StringBuilder sb = new StringBuilder();
for (int n = 0; n < iLen; n++) {
sb.append(mChars[(b[n] & 0xff) >> 4]);
sb.append(mChars[b[n] & 0xf]);
}
return sb.toString().trim().toUpperCase(Locale.US);
}
private static byte[] encrypt2(byte[] datasource, String password) {
byte[] is;
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
javax.crypto.SecretKey securekey
= keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(1, securekey, random);
is = cipher.doFinal(datasource);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
return is;
}
这是我的php des:
function encrypt($input,$key,$iv=0){
$size = mcrypt_get_block_size(MCRYPT_DES,MCRYPT_MODE_CBC); //3DES加密将MCRYPT_DES改为MCRYPT_3DES
$input =pkcs5_pad($input, $size); //如果采用PaddingPKCS7,请更换成PaddingPKCS7方法。
$td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_CBC, '');
@mcrypt_generic_init($td, $key,$iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
// return $data;
return strtoupper(bin2hex($data));
}
我得到了不同的结果,为什么?我不知道SecureRandom是iv
吗?
答案 0 :(得分:2)
始终使用完全限定的密码字符串。 Cipher.getInstance("DES");
可能会导致不同的密码,具体取决于默认的安全提供程序。它最有可能产生"DES/ECB/PKCS5Padding"
,但并非必须如此。如果它发生变化,您将失去不同JVM之间的兼容性。
您需要在PHP中实现与Java的兼容性是使用ECB模式而不是CBC模式并应用PKCS#5填充(与PKCS#7填充相同)。 This answer显示了该填充的实现。您只需使用正确的块大小,即DES为8。
绝不使用ECB mode 。它具有确定性,因此在语义上不安全。您应该至少使用CBC或CTR等随机模式。最好对您的密文进行身份验证,以便像padding oracle attack这样的攻击是不可能的。这可以使用经过身份验证的模式(如GCM或EAX)或encrypt-then-MAC方案来完成。
IV必须是不可预测的(读:随机)。不要使用静态IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定何时发送相同的消息前缀。 IV不是秘密,因此您可以将其与密文一起发送。通常,它只是在密文之前预先填写并在解密之前切掉。
答案 1 :(得分:0)
public static function encryptDes($data, $key)
{
$paddedData = static::pad($data);
$opts = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA;
return strtoupper(bin2hex(openssl_encrypt($paddedData, 'DES-ECB', $key, $opts)));
}
public static function decryptDes($data, $key)
{
$data = hex2bin($data);
$opts = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA;
return static::unpad(openssl_decrypt($data, 'DES-ECB', $key, $opts));
}
private static function pad($text)
{
$blockSize = 8;
$length = strlen($text);
$pad = $blockSize - ($length % $blockSize);
return str_pad($text, $length + $pad, chr($pad));
}
private static function unpad($text)
{
$length = ord($text[strlen($text) - 1]);
return substr($text, 0, -$length);
}