2009-11-24 86 views
1

我想將這個php數字簽名函數改寫成Delphi代碼。將此數字簽名轉換爲Delphi

function SaySig() { 

    $privKeyFilePath = "c:\temp\myrsakey.pem"; 

    $data = "sign this string"; 
    $fp = fopen($privKeyFilePath, "r"); 
    $priv_key = fread($fp, 8192); 
    fclose($fp); 
    $privatekeyid = openssl_get_privatekey($priv_key); 
    openssl_sign($data, $signature, $privatekeyid, OPENSSL_ALGO_SHA1); 
    openssl_free_key($privatekeyid); 
    $sig = base64_encode($signature); 
    echo "<br>"; 
    echo "Signature:".$sig."<br><br>"; 
    } 

我不關心哪個分量被使用(鎖箱,DelphiOpenSSL,奇爾卡特隱窩的ActiveX等)。我嘗試過所有這些都沒有成功;這讓我覺得我正在做一些根本性錯誤的事情。

我的鑰匙生成這樣:

OpenSSL的REQ -x509 -nodes -days 365 -newkey RSA:1024 -sha1 -subj「/ C = US/ST = CA/L =山景/ CN = www.mycompany.com」 -keyout myrsakey.pem退房手續C:\ TEMP \ myrsacert.pem

關鍵的內容(不要擔心 - 我會生成一個新的):

----- BEGIN RSA PRIVATE KEY ----- MIICXgIBAAKBgQ CqsR7s4X74LfTiLv1PP6Yn0SBpGBtbzkBSQ95E2b9Haa3Qtf0a KjDJpZLMwXC/IrSP7K2Gxbl2cZotT19GVgw6PcYPTBBWX2gJoVrnQZP8uPdlGAgS plODP55R9f4F0KzIpE6d + dpTGfJ1wysFqYN8fxtlu8K7YO/Mh8tNzN5VOQIDAQAB AoGBAIvCvRyeQlU5Y + JzMSvbZNQDUrNabsRL67SwJ2VemVUCvbQ/3v62fv4M2VdY KFYIN6oE08yfRw0pVWE2NT + lIxqSQx7 + qv84Y7duqT7155wpCFj + A/6pYyNTFNFi 5wiTnN13eyHNgKxZm7QcMH67T/noTgz0LoT5p54ynmfNcjyBAkEA3DCEQ6Dm2xYH NHK3 + 7sNEVklN20zNqyYvrCunNLAiLioF1jDApdfcT8YtVd29L7tH1ZdJYG5DXJ8 Bs7eKLGekQJBAMZzy0Q7LZHdWQxSRi7wy0eq6SqZMqi0pb9VPuXjWG1y + rtRr1vV vyMaGz4rcE7mkbq/NKN + AQXc30GOj3GE8CkCQQCMDVwDfBN6pL8/fLjsJ + S + 9RnD 8HRTwWKCX/UgkLif/fwEpZOcUVYGvSBlL9XdBJfkh9VFZwaidABJgEk0Tw3RAkBd 6pjMnpDvUeh9e0Y5mr0pGookHcIqsuspxEby9od3rI1a LsslU9 + T1hwEbPxGarmW vj0MAUgspR2G4deiqn4ZAkEAnWxV7NhtVPLs5Y2ZYeHz7ipdcSL4/keLW4PwKerF 7LJj4s7/6ZqnHA6Z0yhCcziflYQArWt1ViLMIYZ8grr5Kg == ----- END RSA私鑰-----

和輸出看起來這樣:

jcIIsr145dTwDrT8g4jb2HZ5FP5UL6/9mK7hF6hC2lCZGlM0W4QqFqytghWaU0w3Z6JkMVUlxxWtQ2R + vWQVB0F3htAtbVZkiA67x0zor + zmpClBIazmfVJlng4sG1R7CCUZ0gGhdm4JMc08VsWU25utudcG6inpl whQiZgefW0 =

看起來好像我在請求某人「做我的工作」。但我一直在衝擊這一段時間,但沒有成功。 謝謝。

有人要求我發佈我的一些代碼。以下是我嘗試過的一些東西。

function TMainWeb.sign(mstring: String): string; 
var 
    mPrivateKey: TLbRSAKey; 
    LbRSASSA1: TLbRSASSA; 
begin 
    LbRSASSA1:= TLbRSASSA.create(nil); 
    LbRSASSA1.PrivateKey.LoadFromFile('C:\temp\myrsakey.der'); 
    LbRSASSA1.HashMethod := TRSAHashMethod(hmSHA1); 
    LbRSASSA1.SignString(mString); 
    result := LbRSASSA1.Signature.IntStr; 
end; 

function TMainWeb.sign1(mstring: String): string; 
var 
    LbDSA1: TLbDSA; 
    mPrivateKey: TLbRSAKey; 
begin 
    mPrivateKey := TLbRSAKey.Create(aks1024); 
    mPrivateKey.LoadFromFile('C:\temp\myrsakey.der'); 
    LbDSA1 := TLbDSA.create(application); 
    lbDSA1.PrivateKey.Assign(mPrivateKey); 
    LbDSA1.SignString(mString); 
end; 

function TMainWeb.Sign2(mString: String): string; 
var 
    signer: TMessageSigner; 
begin 
    signer := TMessageSigner.Create; 
    signer.LoadPrivateKey('C:\temp\myrsakey.pem'); 
    signer.PlainMessage := mString; 
    signer.MIMESign; 
    result := signer.SignedMessage; 
end; 
+0

哪裏是你的Delphi代碼? – 2009-11-24 20:12:57

+0

我試了很多東西,不知道要包括什麼。我已經添加了一些我的代碼片段;沒有一個工作。 – 2009-11-24 20:21:54

+0

我其實不是Delphi程序員,我只是假設沒有人會回答,除非你發佈了一個嘗試:) – 2009-11-24 21:15:30

回答

3

試試這個。
我並不認爲它是完美的代碼(!),但它會編譯:-)  並給出與您引用的結果相同的結果。使用上面提到的來自M Ferrante的OpenSSL API。很多它通常只會在啓動時執行 - 例如加載私鑰,InitSSL等。我使用Jedi JCL來處理base64的東西 - 這更直接。
此外,其中一些看起來有點奇怪(使用TBytes PChar會做等等),因爲我最初使用我修改後的Delphi 2010 API頭文件寫它,但後來意識到你使用D2007和TEncoding不可用,並且一些MOD是需要。
(SignStringToBase64是主要的電話,就在上市的底部)

uses libeay32, jclmime; 

const 
    LIBEAY_DLL_NAME = 'libeay32.dll'; 

// These aren't defined in the original libeay32.pas file 
procedure EVP_MD_CTX_init(ctx: PEVP_MD_CTX); cdecl; external LIBEAY_DLL_NAME; 
function EVP_MD_CTX_cleanup(ctx: PEVP_MD_CTX): integer; cdecl; external LIBEAY_DLL_NAME; 

procedure InitSSL; 
begin 
    OpenSSL_add_all_algorithms; 
    OpenSSL_add_all_ciphers; 
    OpenSSL_add_all_digests; 
    ERR_load_crypto_strings; 
    // Seed the pseudo-random number generator 
    // This should be something a little more "random"! 
    RAND_load_file('c:\windows\paint.exe', 512); 
end; 

procedure FinalizeSSL; 
begin 
    EVP_cleanup; 
end; 

function GetSSLErrorMessage: string; 
const 
    BUFF_SIZE = 128; // OpenSSL docs state should be >= 120 bytes 
var 
    err: TBytes; 
begin 
    SetLength(err, BUFF_SIZE); 
    ERR_error_string(ERR_get_error, @err[0]); 
    result := string(err); 
end; 

function RSALoadPrivateKey(const AFileName, APassPhrase: string): PRSA; 
var 
    bp: pBIO; 
    fn, pp: PAnsiChar; 
    pk: PRSA; 
begin 
    fn := PAnsiChar(AnsiString(AFileName)); 
    pp := PAnsiChar(AnsiString(APassPhrase)); 
    bp := BIO_new(BIO_s_file()); 
    BIO_read_filename(bp, fn); 
    pk := nil; 
    result := PEM_read_bio_RSAPrivateKey(bp, pk, nil, pp); 
    if result = nil then 
    raise Exception.Create('Private key failure.' + GetSSLErrorMessage); 
end; 

function LoadPrivateKey(const AFileName, APass: string): PEVP_PKEY; 
var 
    rkey: PRSA; 
begin 
    rkey := RSALoadPrivateKey(AFileName, APass); 
    result := EVP_PKEY_new; 
    EVP_PKEY_assign(result, EVP_PKEY_RSA, rkey); 
end; 

procedure CleanUpKey(AKey: PEVP_PKEY); 
begin 
    if (AKey <> nil) then 
    begin 
    EVP_PKEY_free(AKey); 
    // The OpenSSL docs state that the related rsa key will also 
    // be freed when the parent key is freed 
    end; 
end; 

function EVPSign(ASource: TBytes; const APrivateKey: PEVP_PKEY): TBytes; 
var 
    keysize: integer; 
    ks: cardinal; 
    ctx: EVP_MD_CTX; 
begin 
    keysize := EVP_PKEY_size(APrivateKey); 
    SetLength(result, keysize); 

    EVP_MD_CTX_init(@ctx); 
    try 
    EVP_SignInit(@ctx, EVP_sha1); 
    EVP_SignUpdate(@ctx, @ASource[0], Length(ASource)); 
    EVP_SignFinal(@ctx, @result[0], ks, APrivateKey); 
    SetLength(result, ks); 
    finally 
    EVP_MD_CTX_cleanup(@ctx); 
    end; 
end; 

function Base64EncodeBytes(Input: TBytes): string; 
var 
    b64: TBytes; 
begin 
    SetLength(b64, jclMime.MimeEncodedSizeNoCRLF(Length(Input))); 
    jclMime.MimeEncodeNoCRLF(Input[0], Length(Input), b64[0]); 
    result := string(b64); 
end; 

function SignStringToBase64(const AText: string): string; 
var 
    key: PEVP_PKEY; 
    src, enc: TBytes; 
begin 
    InitSSL; 
    try 
    key := LoadPrivateKey('c:\temp\priv-key.pem', ''); 
    try 
     SetLength(src, Length(AText)); 
     CopyMemory(@src[0], @AText, Length(AText));   
     enc := EVPSign(src, key); 
     result := Base64EncodeBytes(enc); 
    finally 
     CleanUpKey(key); 
    end; 
    finally 
    FinalizeSSL; 
    end; 
end; 
+0

非常感謝。試圖實現它,但有問題讓Jedi安裝/編譯(從http://sourceforge.net/projects/jvcl/files/得到它)。 jclmime.pas需要jcl.inc,它需要jcld11.inc,它無法找到。將繼續挖掘。 – 2009-11-27 15:04:47

+0

只需在JCL安裝的根目錄下運行install.bat - 它非常複雜。 jcld11.inc通過一系列版本特定的東西自動創建。 (或者使用你自己最喜歡的Base64庫) – shunty 2009-11-27 16:42:32

+0

實際上放下了一下,然後再回來。從http://sourceforge.net/projects/jcl/files/獲得源代碼並編譯。 – 2009-11-27 17:33:09