2011-08-13 4 views
2

rijndael 암호를 사용하여 PHP에서 Delphi로 전송 된 문자열을 해독하는 데 문제가 있습니다. PHP 측에서 mcrypt를 사용하고 있고 Delphi 측에서 DCP_rijndael을 사용하고 있습니다.Delphi에서 PHP로 돌아 가기 Rijndael을 사용하여 암호화 - 암호 해독

현재 아래 코드가 있습니다.

PHP :

function encRJ($key, $iv, $data) 
{ 
    $r = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv); 
    $r = base64_encode($r); 
    return $r; 
} 

그리고 델파이

: 내가 암호를 구현 인터넷에서 여러 단위를 사용했는데, 대부분의 사람들이 DCP 구성 요소에 대해 말을 발견했다

function decRJ(Data: string; Key: string; IV: string): string; 
var ciph: TDCP_rijndael; 
begin 
    Data := Base64DecodeStr(Data); 

    ciph:= TDCP_rijndael.Create(Self); 
    ciph.Init(Key[1], 256, @IV[1]); 
    ciph.DecryptCBC(Data[1], Data[1], Length(Data)); 
    ciph.Free; 

    Result := Data; 
end; 

. 그렇다고해도 올바르게 해독 할 수 없었습니다. 필자는 매개 변수, AnsiStrings, WideString 등의 Byte 배열을 사용해 보았지만 불행히도 행운은 없습니다.

시간이 지나면 내 마음이 좋지 않아서 정말 실망스러운 부분이 있다면 실례합니다.

+5

나는 암호화를 모두 구현 제안 모두 PHP와 델파이의 기능을 해독 할 것이다 :

편집

Base64DecodeBytes 내가 DCP Base64로 장치에 추가 코드의 약간이었다. 그런 다음 둘 다 동일한 중간 값을 생성하고 서로의 중간 값을 해독 할 수 있는지 확인할 수 있습니다.체계적으로 문제가 있는지 또는 특정 기능에 오류가 있는지 여부를 결정해야합니다. – Gus

+2

nist.gov 웹 사이트와 많은 다른 곳에서 이러한 구현이 어떻게 작동하는지 확인할 수있는 수많은 테스트 벡터가 있습니다. 델파이 함수의 '데이터'처리는 나에게 잘못되었습니다. base64 디코딩의 결과는 UTF8로 인코딩 된 문자열이 아닌 임의의 바이트 여야합니다. –

+0

@ GregS, 나는 암호화되지 않은 일반 텍스트를 base64로 해독하려고 시도했지만 정상적으로 처리됩니다. 나는 그 문제가 거기에 있다고 생각하지 않는다. 비록 그렇다하더라도, 나는 다른 최종 결과를 얻은 2 개의 다른 Base64 구현을 시도했다. – Josh

답변

0

PHP와 델파이 방법 모두 패딩을 지정하지 않습니다. 기본 패딩이 다른 경우 문제가 발생합니다. 둘 모두에 대해 PKCS7 (또는 PKCS5)을 명시 적으로 지정하십시오.

Base64를 디코딩 한 결과에 대한 GregS의 의견이 정확합니다. decRJ() 메소드에 암호화 된 암호 텍스트를 제공하고 있습니다. 랜덤으로 나타나는 바이트입니다. UTF-8로 변환하려고 시도하면 해독 할 수 없을만큼 충분히 맹독됩니다. 들어오는 암호 텍스트는 Base64에서 바이트 배열로 직접 변환되어야합니다. Cyphertext는 문자열이 아니므로 텍스트로 전송하려면 Base64로 변환해야합니다. 이후 텍스트는 다시 이 될 것이고, 다시 일반 텍스트로 복호화됩니다.

+0

나는 바이트 배열과 함께 다양한 데이터 유형으로 Base64 str을 변환하는 여러 방법을 시도했지만 여전히 운이 없다. 이제 나는 PHP 데모 [here] (http://www.cityinthesky.co.uk/opensource/DCPcrypt)를 확인했다. 나는 그저 작동하지 않는다는 것을 발견했다. 기묘한. 나는 무엇을 해야할지 모르겠다. – Josh

+1

Delphi에서'encrypt()'메소드를 작성하고 Delphi'decRJ()'메소드로 작동 시키십시오. – rossum

7

나는 이걸 너무 오래 쓰긴했지만 ...

문제는 블록 크기입니다. TDCP_rijndael은 MCRYPT_RIJNDAEL_128 (_256 아님)과 동일합니다. 그러나 ciph.Init (...) 호출의 '256'값은 여전히 ​​정확합니다. 그것보다 꽤 괜찮아 보인다. 즉, 키/iv에 ansistrings을 사용하고 있거나 유니 코드가 아닌 델파이를 사용하고 있다고 가정합니다.
유니 코드 Delphi 버전에서는 TBytes와 key [0]/iv [0]을 사용하려고합니다.

여백은 여전히 ​​문제 일 수 있습니다. 그렇다면 PHP 매뉴얼 페이지와 시행 착오를 토대로 필자가 맹목적으로 작성한 내용이 여기에있다.

는 PHP :

function Encrypt($src, $key, $iv) 
{ 
    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc'); 
    //echo "Block size: " . $block . "\r\n"; 
    $pad = $block - (strlen($src) % $block); 
    $src .= str_repeat(chr($pad), $pad); 

    $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $src, MCRYPT_MODE_CBC, $iv); 
    $r = base64_encode($enc); 
    return $r; 
} 

function Decrypt($src, $key, $iv) 
{ 
    $enc = base64_decode($src); 
    $dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $enc, MCRYPT_MODE_CBC, $iv); 

    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc'); 
    $pad = ord($dec[($len = strlen($dec)) - 1]); 
    return substr($dec, 0, strlen($dec) - $pad); 
} 

델파이 :

function DecryptData(Data: string; AKey: AnsiString; AIv: AnsiString): string; 
var 
    key, iv, src, dest: TBytes; 
    cipher: TDCP_rijndael; 
    slen, pad: integer; 
begin 
    //key := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AKey)); 
    //iv := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AIv)); 
    key := TEncoding.ASCII.GetBytes(AKey); 
    iv := TEncoding.ASCII.GetBytes(AIv); 

    src := Base64DecodeBytes(TEncoding.UTF8.GetBytes(Data)); 

    cipher := TDCP_rijndael.Create(nil); 
    try 
    cipher.CipherMode := cmCBC; 
    slen := Length(src); 
    SetLength(dest, slen); 
    cipher.Init(key[0], 256, @iv[0]); // DCP uses key size in BITS not BYTES 
    cipher.Decrypt(src[0], dest[0], slen); 
    // Remove the padding. Get the numerical value of the last byte and remove 
    // that number of bytes 
    pad := dest[slen - 1]; 
    SetLength(dest, slen - pad); 

    // Base64 encode it 
    result := TEncoding.Default.GetString(dest); 
    finally 
    cipher.Free; 
    end; 
end; 

function EncryptData(Data: string; AKey: AnsiString; AIv: AnsiString): string; 
var 
    cipher: TDCP_rijndael; 
    key, iv, src, dest, b64: TBytes; 
    index, slen, bsize, pad: integer; 
begin 
    //key := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AKey)); 
    //iv := Base64DecodeBytes(TEncoding.UTF8.GetBytes(AIv)); 
    key := TEncoding.ASCII.GetBytes(AKey); 
    iv := TEncoding.ASCII.GetBytes(AIv); 

    src := TEncoding.UTF8.GetBytes(Data); 

    cipher := TDCP_rijndael.Create(nil); 
    try 
    cipher.CipherMode := cmCBC; 
    // Add padding. 
    // Resize the Value array to make it a multiple of the block length. 
    // If it's already an exact multiple then add a full block of padding. 
    slen := Length(src); 
    bsize := (cipher.BlockSize div 8); 
    pad := bsize - (slen mod bsize); 
    Inc(slen, pad); 
    SetLength(src, slen); 
    for index := pad downto 1 do 
    begin 
     src[slen - index] := pad; 
    end; 

    SetLength(dest, slen); 
    cipher.Init(key[0], 256, @iv[0]); // DCP uses key size in BITS not BYTES 
    cipher.Encrypt(src[0], dest[0], slen); 

    b64 := Base64EncodeBytes(dest); 
    result := TEncoding.Default.GetString(b64); 
    finally 
    cipher.Free; 
    end; 
end; 

PHP의 델파이 기능은 이제 나에게 같은 대답을 제공합니다.

function Base64DecodeBytes(Input: TBytes): TBytes; 
var 
    ilen, rlen: integer; 
begin 
    ilen := Length(Input); 
    SetLength(result, (ilen div 4) * 3); 
    rlen := Base64Decode(@Input[0], @result[0], ilen); 
    // Adjust the length of the output buffer according to the number of valid 
    // b64 characters 
    SetLength(result, rlen); 
end; 
+0

Delphi에서 Base64DecodeBytes 함수에 대한 참조를 찾을 수없는 것 같습니다. Delphi의 기본 단위 중 하나에서 선언 되었습니까? 아니면 사용자가 직접 작성한 함수입니까? – Josh

+0

와우. 나 자신의 유니 코드를 인식하고 Base64XXXBytes 물건을 추가하기 위해 DCP 물건을 오래 전에 수정했습니다. 대답을 수정하여 (선택하지 않은) 기능을 추가합니다. – shunty

+0

Base64DecodeBytes (입력 : TBytes) : TBytes; 버그! 그것은 짧은 텍스트 (때로는 범위 검사 오류 암호 또는 디코딩 오류 반환)와 함께 작동합니다 괜찮아요 Soap.EncdDecd 기능을 사용하십시오. – Evilripper

관련 문제