我该如何将这个Java DES程序转换为PHP?

时间:2016-06-20 08:50:06

标签: java php encryption des

我有一个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吗?

2 个答案:

答案 0 :(得分:2)

始终使用完全限定的密码字符串。 Cipher.getInstance("DES");可能会导致不同的密码,具体取决于默认的安全提供程序。它最有可能产生"DES/ECB/PKCS5Padding",但并非必须如此。如果它发生变化,您将失去不同JVM之间的兼容性。

您需要在PHP中实现与Java的兼容性是使用ECB模式而不是CBC模式并应用PKCS#5填充(与PKCS#7填充相同)。 This answer显示了该填充的实现。您只需使用正确的块大小,即DES为8。

绝不使用ECB mode 。它具有确定性,因此在语义上不安全。您应该至少使用CBCCTR等随机模式。最好对您的密文进行身份验证,以便像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);
}