2013-02-21 93 views
1

我正在使用德尔福2009年和我见过的大部分答案是2010+ 我想同步加密(delphi)解密(php)和失败。如何同步delphi和php之间的加密使用dcpcrypt

产生在delphi加密的字符串:在PHP

program Project4; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    DCPcrypt2, 
    DCPsha1, 
    DCPblockciphers, 
    DCPdes, 
    EncdDecd; 

var des: tdcp_des; 
    enc,dec: ansistring; 

begin 
    try 
    des:=tdcp_des.Create(nil); 
    des.InitStr('test', tdcp_sha1); 
    enc:=encodestring(des.EncryptString('this is a test')); 
    des.Free; 

    des:=tdcp_des.Create(nil); 
    des.InitStr('test', tdcp_sha1); 
    dec:=des.DecryptString(decodestring(enc)); 
    des.Free; 

    writeln(enc); 
    writeln(dec); 
    except 
    on E:Exception do 
     Writeln(E.Classname, ': ', E.Message); 
    end; 
end. 

解密:

<?php 
function decrypt($str, $key) 
{ 
    $size = mcrypt_get_iv_size(MCRYPT_DES, MCRYPT_MODE_CBC); 
    $iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM); 
    $data = base64_decode($str); 
    $block = mcrypt_get_block_size('des', 'ecb'); 
    $k = substr(sha1($key), 0, $block); 
    $str = mcrypt_decrypt(MCRYPT_DES, $k, $data, MCRYPT_MODE_CBC, $iv); 
    $pad = ord($str[($len = strlen($str)) - 1]); 
    return substr($str, 0, strlen($str) - $pad); 
} 

$enc = 'TW5mbVFhODUyR2FoOTA2WWJIOD0='; 
$dec = decrypt($enc, 'test'); 
echo "$dec\n"; 
?> 
+3

我认为没有理由会有德尔福2009年和德尔福2010年你是如何“失败”之间的这段代码显著差异? – 2013-02-21 05:58:50

+0

解密的输出为空 – Daniel 2013-02-21 07:41:08

+0

@Daniel in “test”是一个unicode字符串,try ComputerSaysNo 2013-02-21 12:13:11

回答

8

几个问题,我想:-)

  • des.InitStr()内部创建从8个空字节它然后加密的IV。你需要在你的PHP中使用相同的IV。

  • sha1($ key)产生一个十六进制字符串而不是密码的实际字节。你需要像mhash那样的东西。

  • 我无法用给定的Delphi函数重新设置你的$ enc字符串。

  • Unicode问题 - 密码和源文本在Delphi中将被视为unicode。

  • 你似乎是在Delphi例程中两次编译源码的base 64。 des.EncryptString和des.DecryptString产生并使用base 64编码的字符串,因此不需要再次执行。

  • 填充

根据我以前的答案here - 这是我的建议:

function EncryptStringDES: string; 
var 
    des: TDCP_des; 
    src, enc, b64: TBytes; 
    index, slen, bsize, padsize: integer; 
begin 
    des:=tdcp_des.Create(nil); 
    try 
    des.InitStr(AnsiString('test'), tdcp_sha1); 

    src := TEncoding.UTF8.GetBytes('this is a test'); 
    slen := Length(src); 
    // Add padding 
    bsize := des.BlockSize div 8; 
    padsize := bsize - (slen mod bsize); 
    Inc(slen, padsize); 
    SetLength(src, slen); 
    for index := padsize downto 1 do 
    begin 
     src[slen - index] := padsize; 
    end; 

    SetLength(enc, slen); 
    des.EncryptCBC(src[0], enc[0], slen); 
    result := EncdDecd.EncodeBase64(@enc[0], Length(enc)); 
    finally 
    des.Free; 
    end; 
end; 

function DecryptStringDES(ASource: string): string; 
var 
    des: TDCP_des; 
    key, src, dec, b64: TBytes; 
    pad, slen: integer; 
begin 
    des := TDCP_des.Create(nil); 
    try 
    des.InitStr(AnsiString('test'), tdcp_sha1); 

    src := EncdDecd.DecodeBase64(AnsiString(ASource)); 
    slen := Length(src); 
    SetLength(dec, slen); 
    des.DecryptCBC(src[0], dec[0], slen); 

    // Remove padding 
    pad := dec[slen - 1]; 
    SetLength(dec, slen - pad); 

    result := TEncoding.UTF8.GetString(dec); 
    finally 
    des.Free; 
    end; 
end; 

和PHP:

<?php 
function decrypt_SO($str, $key) 
{ 
    //$ivsize = mcrypt_get_iv_size(MCRYPT_DES, MCRYPT_MODE_CBC); 
    //$blocksize = mcrypt_get_block_size(MCRYPT_DES, MCRYPT_MODE_CBC); 
    $keysize = mcrypt_get_key_size(MCRYPT_DES, MCRYPT_MODE_CBC); 

    // Need to use the SAME IV as the Delphi function. By default 
    // this is (0,0,0,0,0,0,0,0) encrypted using ECB mode and gives the 
    // following bytes: 
    $ivbytes = array(72, 163, 99, 62, 219, 111, 163, 114); 
    $iv = implode(array_map("chr", $ivbytes)); 

    $enc = base64_decode($str); 
    $k = mhash(MHASH_SHA1, $key); 
    $dec = mcrypt_decrypt(MCRYPT_DES, substr($k, 0, $keysize), $enc, MCRYPT_MODE_CBC, $iv); 

    $pad = ord($dec[strlen($dec) - 1]); 
    return substr($dec, 0, strlen($dec) - $pad); 
} 

$enc = 'WRaG/8xlxqqcTAJ5UAk4DA=='; 
$dec = decrypt_SO($enc, 'test'); 
echo "$dec\n"; 
?> 
+0

+1表示非常慷慨的答案。 – 2013-02-21 13:57:55

+0

谢谢你,完美的工作! – Daniel 2013-02-21 19:51:47

+0

谢谢您的回答,但如果密码长度超过4个符号,则解码字符串的某些第一个字符会出现错误的编码。我使用openssl openssl_decrypt($ enc,$ alg,$ k,OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,$ iv); – 2017-05-04 17:15:00

0

我用这种成功整合的,但我不能提供比这更多的信息,它是属于我的雇主。

你初始化mycrypt了吗?

$iv = "nononono"; 
$key = "nononono"; 
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); 
mcrypt_generic_init($td, $key, $iv); 
$decoded = base64_decode($mySecretString); 
$decryptedcbc = mdecrypt_generic($td, $decoded); 
mcrypt_generic_deinit($td); 

不要忘记你的字符串正确编码在Delphi中,我使用Base64EncodeStr(缓冲区);

我希望它有帮助。

-1

谁是四字节

$ivbytes = array(72, 163, 99, 62, 219, 111, 163, 114); 

的关键:test123456

$ivbytes = array(??, ??, ??, ??, ??, ??, ??, ??);