2016-04-21 12 views
5

विफल रहता है मैं OpenSSL libeay32.dll का उपयोग करके डेल्फी में SHA256 हस्ताक्षर और सत्यापन को लागू करने का प्रयास कर रहा हूं। यही कारण है कि अब तक इतना आसानडेल्फी में ओपनएसएसएल के साथ SHA256 हस्ताक्षर सत्यापित करना

openssl genrsa -out private.pem 2048 
openssl rsa -in private.pem -outform PEM -pubout -out public.pem 

: की वजह एक पहला कदम में मेरे द्वारा बनाए गए एक आरएसए 2048-बिट कुंजी जोड़ी निम्नलिखित OpenSSL का उपयोग कर आदेशों।

function TSignSHA256.ReadKeyFile(aFileName : String; aType : TKeyFileType) : pEVP_PKEY; 
var locFile : RawByteString; 
    locBIO : pBIO; 
begin 
    locFile := UTF8Encode(aFileName); 

    locBIO := BIO_new(BIO_s_file()); 

    try 
    BIO_read_filename(locBIO, PAnsiChar(locFile)); 

    result := NIL; 
    case aType of 
     kfPrivate : result := PEM_read_bio_PrivateKey(locBIO, result, nil, nil); 
     kfPublic : result := PEM_read_bio_PUBKEY(locBIO, result, nil, nil); 
    end; 
    finally 
    BIO_free(locBIO); 
    end; 
end; 

कि के रूप में अच्छी तरह से काम करने के लिए लग रहा था: अगले कदम के लिए मैंने किया था एक समारोह है कि पीईएम फाइलों से सार्वजनिक और निजी कुंजियों को पढ़ने में सक्षम था बनाने गया था। तो मैं कुछ संकेत प्रक्रिया को लागू किया:

procedure TSignSHA256.Sign; 
var locData : RawByteString; 
    locKey : pEVP_PKEY; 
    locCtx : pEVP_MD_CTX; 
    locSHA256 : pEVP_MD; 
    locSize : Cardinal; 
    locStream : TBytesStream; 
begin 
    locKey := ReadKeyFile('private.pem', kfPrivate); 
    locData := ReadMessage('message.txt'); 

    locCtx := EVP_MD_CTX_create; 
    try 
    locSHA256 := EVP_sha256(); 

    EVP_DigestSignInit(locCtx, NIL, locSHA256, NIL, locKey); 
    EVP_DigestSignUpdate(locCtx, PAnsiChar(locData), Length(locData)); 
    EVP_DigestSignFinal(locCtx, NIL, locSize); 

    locStream := TBytesStream.Create; 
    try 
     locStream.SetSize(locSize); 
     EVP_DigestSignFinal(locCtx, PAnsiChar(locStream.Memory), locSize); 
     WriteSignature('message.sig', locStream.Bytes, locSize); 
    finally 
     FreeAndNIL(locStream); 
    end; 
    finally 
    EVP_MD_CTX_destroy(locCtx); 
    end; 
end; 

आप देख सकते हैं प्रक्रिया, एक फ़ाइल message.txt बुलाया पढ़ रही है हस्ताक्षर की गणना और message.sig है कि sig भंडारण। अगर मैं चलाने निम्नलिखित OpenSSL परिणाम कमान सत्यापित ठीक है:

openssl dgst -sha256 -verify public.pem -signature message.sig message.txt 

तो यह की तरह मेरे हस्ताक्षर करने की प्रक्रिया भी सही काम कर रहा है लगता है। इसलिए मैंने अंत में एक सत्यापन प्रक्रिया लागू की:

function TSignSHA256.Verify : Boolean; 
var locData : RawByteString; 
    locSig : TArray<Byte>; 
    locKey : pEVP_PKEY; 
    locCtx : pEVP_MD_CTX; 
    locSHA256 : pEVP_MD; 
    locSize : Cardinal; 
    locStream : TBytesStream; 
begin 
    locKey := ReadKeyFile('public.pem', kfPublic); 
    locData := ReadMessage('message.txt'); 
    locSig := ReadSignature('message.sig'); 
    locSize := Length(locSig); 

    locCtx := EVP_MD_CTX_create; 
    try 
    locSHA256 := EVP_sha256(); 

    EVP_DigestVerifyInit(locCtx, NIL, EVP_sha256(), NIL, locKey); //Returns 1 
    EVP_DigestVerifyUpdate(locCtx, PAnsiChar(locData), Length(locData)); //Returns 1 

    locStream := TBytesStream.Create(locSig); 
    try 
     result := (EVP_DigestVerifyFinal(locCtx, PAnsiChar(locStream.Memory), locSize) = 1); //Returns false! WHY??? 
    finally 
     FreeAndNIL(locStream); 
    end; 
    finally 
    EVP_MD_CTX_destroy(locCtx); 
    end; 
end; 

जैसा कि आप देख सकते हैं कि मैंने इस प्रक्रिया को ठीक उसी तरह कार्यान्वित किया जैसा मैंने हस्ताक्षर प्रक्रिया को लागू किया था। दुर्भाग्य से इसका परिणाम झूठा है। त्रुटि OpenSSL द्वारा लौटाए गए कोड

error04091077:lib(4):func(145):reason:(119) 

कि lib आरएसए में किसी त्रुटि के लिए अनुवाद है, int_rsa_verify कार्य करते है, कारण गलत हस्ताक्षर लंबाई। मैंने Google की खोज की लेकिन मुझे उस त्रुटि के बारे में कोई उपयोगी जानकारी नहीं मिली। मैंने ओपनएसएसएल स्रोतों को समझने की भी कोशिश की, लेकिन मैं सी में गहराई से नहीं हूं और ऐसा लगता है कि इसमें उम्र लग सकती है जब तक कि मैं इसे समझने में सक्षम न हो।

मेरी व्यक्तिगत भावना यह है कि मैंने सार्वजनिक कुंजी को पढ़ने में कुछ गलत किया। लेकिन यह केवल एक भावना है और मुझे नहीं पता कि मैं इसे अलग तरीके से कैसे कर सकता हूं। मेरा दूसरा अनुमान यह होगा कि मैंने सत्यापन प्रक्रिया में संदर्भ को गलत बनाने में कुछ गलत किया है। लेकिन मुझे कोई संकेत नहीं है कि यह क्या हो सकता है।

हस्ताक्षर सत्यापन विफल क्यों है?

+0

आप याद आती है त्रुटि हैंडलिंग, 'अगर EVP_DigestVerifyInit' जाँच और' EVP_DigestVerifyUpdate' सफल होने के साथ शुरू (वापसी मूल्यों की जाँच) – Remko

+2

सी [ ईवीपी हस्ताक्षर और सत्यापन] (http://wiki.openssl.org/index.php/EVP_Signing_and_Verifying) ओपनएसएसएल विकी पर। यह आपको उदाहरण देता है जो बॉक्स से बाहर काम करता है। – jww

+0

@Remko: मैंने अभी पठनीयता के लिए त्रुटि को संभालने में त्रुटि छोड़ी है। EVP_DigestVerifyInit और EVP_DigistVerify दोनों रिटर्न 1 अपडेट करें जिसका अर्थ सफलता है। मैंने इसे और अधिक स्पष्ट करने के लिए अपना कोड संपादित किया है। –

उत्तर

1

एक हस्ताक्षर एक पाठ हस्ताक्षर नहीं है। इसमें बाइट सरणी होती है जिसके लिए बाइट्स का कोई मूल्य हो सकता है। आप एएनएसआई तारों से सीधे और उससे बाइट सरणी को परिवर्तित कर रहे हैं। यह असफल हो जाएगा यदि सरणी में एएनएसआई रेंज के बाहर मूल्य शामिल हैं (जो कुछ भी हो, मैं एएससीआईआई मानूंगा)।

आपको हस्ताक्षर का इलाज बाइनरी डेटा के रूप में करना होगा। यदि आप इसे एक स्ट्रिंग (टेक्स्ट युक्त) के रूप में पेश करने की आवश्यकता है तो आप बेस 64 कोडेक का उपयोग कर सकते हैं।

+0

'परिणाम: = (EVP_DigestVerifyFinal (locCtx, PAnsiChar (locStream.Memory), locSize) = 1) से फ़ंक्शन कॉल को बदलना; 'to' result: = (EVP_DigestVerifyFinal (locCtx, @ locStream.Memory, locSize) = 1); 'कोई फर्क नहीं पड़ता। –

+0

क्या आप सीधे हस्ताक्षर के द्विआधारी मूल्यों की तुलना कर सकते हैं? मुझे उस कोड को नहीं देखना है जो बीच में है। आप बाइनरी एन्कोडेड टेक्स्ट और सार्वजनिक और निजी कुंजी के मॉड्यूलस (जो समान होने की आवश्यकता है) के साथ वही काम कर सकते हैं। –

+0

ठीक है, मुझे नहीं पता कि वास्तव में क्या हो रहा है। EVP_DigestVerifyFinal libeay32.dll में एक सीधी कॉल है। लिंकिंग 'फ़ंक्शन EVP_DigestVerifyFinal (ctx: pEVP_MD_CTX; const d: PAnsiChar; var cnt: Cardinal) के साथ किया जाता है: पूर्णांक; cdecl; 'और' function EVP_DigestVerifyFinal; बाहरी 'libeay32.dll'; कार्यान्वयन भाग में '। कारणों से मैंने 'EVV_DigestVerifyFinal (ctx: pEVP_MD_CTX; कॉन्स डी: पॉइंटर; var cnt: कार्डिनल) फ़ंक्शन की कोशिश की: इंटीजर; cdecl; 'लेकिन इससे कोई फर्क नहीं पड़ता। –

3

ठीक है, मुझे समाधान मिला। वास्तव में मुझे दो त्रुटियों से निपटना पड़ा। पहली त्रुटि यह थी कि मैं गलत तरीके से EVP_DigestVerifyFinal में हस्ताक्षर पारित कर रहा था। मार्टन बोडवेस ने उनके जवाब में यही कहा था और मैं इसे अपने प्रश्न के उत्तर के रूप में स्वीकार करूंगा।

दूसरी समस्या डीएलएल में प्रवेश बिंदु की मेरी परिभाषा के भीतर थी।मैंने एक var param के रूप में EVP_DigistVerifyFinal का तीसरा पैरामीटर घोषित किया था। शायद एक प्रति & पिछली त्रुटि के रूप में EVP_DigistSignFinal का तीसरा पैरामीटर एक var param है।

हर किसी के लिए जो कभी भी ऐसा करना होगा, मैं यहां अपना समाधान पोस्ट करता हूं। यह EVP Signing and Verifying, DelphiOpenSSL और ओपनएसएसएल स्रोत (मुख्य रूप से dgst.c) पढ़ने से प्रेरित था। कोड को डेल्फी एक्सई 2 के साथ कार्यान्वित और परीक्षण किया गया था।

ध्यान रखें कि मेरा कोड कोई त्रुटि संभाल नहीं करता है और न ही मुझे स्मृति मुक्त करने के बारे में बहुत अधिक परवाह है। इसका मतलब है कि कोड उत्पादन तैयार नहीं है और आपको इसे देखभाल के साथ उपयोग करना चाहिए!

आयात इकाई:

unit uOpenSSLCrypt; 

interface 

type 
    pBIO = Pointer; 
    pBIO_METHOD = Pointer; 

    pEVP_MD_CTX = Pointer; 
    pEVP_MD = Pointer; 

    pEVP_PKEY_CTX = Pointer; 
    pEVP_PKEY = Pointer; 

    ENGINE = Pointer; 

    TPWCallbackFunction = function(buffer : PAnsiChar; length : Integer; verify : Integer; data : Pointer) : Integer; cdecl; 

    //Error functions 
    function ERR_get_error : Cardinal; cdecl; 
    function ERR_error_string(e : Cardinal; buf : PAnsiChar) : PAnsiChar; cdecl; 

    function ERR_GetErrorMessage : String; 

    //BIO functions 
    function BIO_new(_type : pBIO_METHOD) : pBIO; cdecl; 
    function BIO_new_file(const aFileName : PAnsiChar; const aMode : PAnsiChar) : pBIO; cdecl; 
    function BIO_free(a: pBIO): integer; cdecl; 
    function BIO_s_file : pBIO_METHOD; cdecl; 
    function BIO_f_md : pBIO_METHOD; cdecl; 
    function BIO_ctrl(bp : pBIO; cmd : Integer; larg : Longint; parg : Pointer) : Longint; cdecl; 
    function BIO_read(b : pBIO; buf : Pointer; len : Integer) : integer; cdecl; 
    function BIO_get_md_ctx(bp: pBIO; mdcp: Pointer): Longint; 
    function BIO_read_filename(bp : pBIO; filename : PAnsiChar) : Integer; 

    function PEM_read_bio_PrivateKey(bp : pBIO; x : pEVP_PKEY; cb : TPWCallbackFunction; u : pointer) : pEVP_PKEY; cdecl; 
    function PEM_read_bio_PUBKEY(bp : pBIO; x : pEVP_PKEY; cb : TPWCallbackFunction; u : Pointer) : pEVP_PKEY; cdecl; 

    //EVP functions 
    function EVP_MD_CTX_create() : pEVP_MD_CTX; cdecl; 
    procedure EVP_MD_CTX_destroy(ctx : pEVP_MD_CTX); cdecl; 
    function EVP_sha256() : pEVP_MD; cdecl; 

    function EVP_PKEY_size(key: pEVP_PKEY): integer; cdecl; 
    function EVP_DigestSignInit(aCtx : pEVP_MD_CTX; aPCtx : pEVP_PKEY_CTX; aType : pEVP_MD; aEngine : ENGINE; aKey : pEVP_PKEY ) : Integer; cdecl; 
    function EVP_DigestSignUpdate(ctx : pEVP_MD_CTX; const d : Pointer; cnt : Cardinal) : Integer; cdecl; 
    function EVP_DigestSignFinal(ctx : pEVP_MD_CTX; const d : PByte; var cnt : Cardinal) : Integer; cdecl; 

    function EVP_DigestVerifyInit(aCtx : pEVP_MD_CTX; aPCtx : pEVP_PKEY_CTX; aType : pEVP_MD; aEngine : ENGINE; aKey : pEVP_PKEY ) : Integer; cdecl; 
    function EVP_DigestVerifyUpdate(ctx : pEVP_MD_CTX; const d : Pointer; cnt : Cardinal) : Integer; cdecl; 
    function EVP_DigestVerifyFinal(ctx : pEVP_MD_CTX; const d : PByte; cnt : Cardinal) : Integer; cdecl; 

    function CRYPTO_malloc(aLength : LongInt; const f : PAnsiChar; aLine : Integer) : Pointer; cdecl; 
    procedure CRYPTO_free(str : Pointer); cdecl; 

const BIO_C_SET_FILENAME = 108; 
     BIO_C_GET_MD_CTX = 120; 

     BIO_CLOSE = $01; 
     BIO_FP_READ = $02; 

implementation 

uses System.SysUtils, Windows; 

const LIBEAY_DLL_NAME = 'libeay32.dll'; 

function ERR_get_error : Cardinal; external LIBEAY_DLL_NAME; 
function ERR_error_string;   external LIBEAY_DLL_NAME; 

function ERR_GetErrorMessage : String; 
var locErrMsg: array [0..160] of Char; 
begin 
    ERR_error_string(ERR_get_error, @locErrMsg); 
    result := String(StrPas(PAnsiChar(@locErrMsg))); 
end; 

function BIO_new;     external LIBEAY_DLL_NAME; 
function BIO_new_file;   external LIBEAY_DLL_NAME; 
function BIO_free;    external LIBEAY_DLL_NAME; 
function BIO_ctrl;    external LIBEAY_DLL_NAME; 
function BIO_s_file;    external LIBEAY_DLL_NAME; 
function BIO_f_md;    external LIBEAY_DLL_NAME; 
function BIO_read;    external LIBEAY_DLL_NAME; 

function BIO_get_md_ctx(bp : pBIO; mdcp : Pointer) : Longint; 
begin 
    result := BIO_ctrl(bp, BIO_C_GET_MD_CTX, 0, mdcp); 
end; 

function BIO_read_filename(bp : pBIO; filename : PAnsiChar) : Integer; 
begin 
    result := BIO_ctrl(bp, BIO_C_SET_FILENAME, BIO_CLOSE or BIO_FP_READ, filename); 
end; 

function PEM_read_bio_PrivateKey; external LIBEAY_DLL_NAME; 
function PEM_read_bio_PUBKEY;  external LIBEAY_DLL_NAME; 

function EVP_MD_CTX_create; external LIBEAY_DLL_NAME; 
procedure EVP_MD_CTX_destroy; external LIBEAY_DLL_NAME; 
function EVP_sha256;   external LIBEAY_DLL_NAME; 

function EVP_PKEY_size;   external LIBEAY_DLL_NAME; 
function EVP_DigestSignInit; external LIBEAY_DLL_NAME; 
function EVP_DigestSignUpdate; external LIBEAY_DLL_NAME name 'EVP_DigestUpdate'; 
function EVP_DigestSignFinal; external LIBEAY_DLL_NAME; 

function EVP_DigestVerifyInit; external LIBEAY_DLL_NAME; 
function EVP_DigestVerifyUpdate; external LIBEAY_DLL_NAME name 'EVP_DigestUpdate'; 
function EVP_DigestVerifyFinal; external LIBEAY_DLL_NAME; 

function CRYPTO_malloc; external LIBEAY_DLL_NAME; 
procedure CRYPTO_free; external LIBEAY_DLL_NAME; 

end. 

कार्यान्वयन:

unit uSignSHA256; 

interface 

uses uOpenSSLCrypt; 

type 
    TKeyFileType = (kfPrivate, kfPublic); 

    TSignSHA256 = class(TObject) 
    private 
    function ReadKeyFile(aFileName : String; aType : TKeyFileType) : pEVP_PKEY; 
    function ReadMessage(aName : String) : RawByteString; 
    function ReadSignature(aName : String; var aLength : Cardinal) : Pointer; 
    procedure FreeSignature(aSig : Pointer); 

    procedure WriteSignature(aName : String; aSignature : TArray<Byte>; aLength : Integer); 

    public 
    constructor Create; 
    destructor Destroy; override; 

    procedure Sign(aKeyFile : String; aMsgFile : String; aSigFile : String); 
    function Verify(aKeyFile : String; aMsgFile : String; aSigFile : String) : Boolean; 
    end; 

implementation 

uses System.Classes, System.SysUtils; 

{ TSignSHA256 } 

constructor TSignSHA256.Create; 
begin 

end; 

destructor TSignSHA256.Destroy; 
begin 

    inherited; 
end; 

procedure TSignSHA256.FreeSignature(aSig : Pointer); 
begin 
    CRYPTO_free(aSig); 
end; 

function TSignSHA256.ReadKeyFile(aFileName : String; aType : TKeyFileType) : pEVP_PKEY; 
var locFile : RawByteString; 
    locBIO : pBIO; 
begin 
    locFile := UTF8Encode(aFileName); 

    locBIO := BIO_new(BIO_s_file()); 

    try 
    BIO_read_filename(locBIO, PAnsiChar(locFile)); 

    result := NIL; 
    case aType of 
     kfPrivate : result := PEM_read_bio_PrivateKey(locBIO, nil, nil, nil); 
     kfPublic : result := PEM_read_bio_PUBKEY(locBIO, nil, nil, nil); 
    end; 
    finally 
    BIO_free(locBIO); 
    end; 
end; 

function TSignSHA256.ReadMessage(aName : String) : RawByteString; 
var locFileStream : TFileStream; 
    locSize  : Cardinal; 
    locBytes  : TArray<Byte>; 
    locText  : String; 
begin 
    locFileStream := TFileStream.Create(aName, fmOpenRead); 
    try 
    locSize := locFileStream.Size; 

    SetLength(locBytes, locSize); 
    locFileStream.Read(locBytes[0], locSize); 
    finally 
    FreeAndNIL(locFileStream); 
    end; 

    SetString(locText, PAnsiChar(locBytes), locSize); 
    result := UTF8Encode(locText); 
end; 

function TSignSHA256.ReadSignature(aName : String; var aLength : Cardinal) : Pointer; 
var locSigBio : pBIO; 
    locFile : RawByteString; 
    locMode : RawByteString; 
begin 
    locFile := UTF8Encode(aName); 
    locMode := UTF8Encode('rb'); 

    locSigBio := BIO_new_file(PAnsiChar(locFile), PAnsiChar(locMode)); 
    try 
    result := CRYPTO_malloc(aLength, NIL, 0); 
    aLength := BIO_read(locSigBio, result, aLength); 
    finally 
    BIO_free(locSigBio); 
    end; 
end; 

procedure TSignSHA256.Sign(aKeyFile : String; aMsgFile : String; aSigFile : String); 
var locData : RawByteString; 
    locKey : pEVP_PKEY; 
    locCtx : pEVP_MD_CTX; 
    locSHA256 : pEVP_MD; 
    locSize : Cardinal; 
    locStream : TBytesStream; 
begin 
    locKey := ReadKeyFile(aKeyFile, kfPrivate); 
    locData := ReadMessage(aMsgFile); 

    locCtx := EVP_MD_CTX_create; 
    try 
    locSHA256 := EVP_sha256(); 

    EVP_DigestSignInit(locCtx, NIL, locSHA256, NIL, locKey); 
    EVP_DigestSignUpdate(locCtx, PAnsiChar(locData), Length(locData)); 
    EVP_DigestSignFinal(locCtx, NIL, locSize); 

    locStream := TBytesStream.Create; 
    try 
     locStream.SetSize(locSize); 
     EVP_DigestSignFinal(locCtx, PByte(locStream.Memory), locSize); 
     WriteSignature(aSigFile, locStream.Bytes, locSize); 
    finally 
     FreeAndNIL(locStream); 
    end; 
    finally 
    EVP_MD_CTX_destroy(locCtx); 
    end; 
end; 

function TSignSHA256.Verify(aKeyFile : String; aMsgFile : String; aSigFile : String) : Boolean; 
var locData : RawByteString; 
    locSig : Pointer; 
    locKey : pEVP_PKEY; 
    locBio : pBIO; 
    locCtx : pEVP_MD_CTX; 
    locKeyCtx : pEVP_PKEY_CTX; 
    locSHA256 : pEVP_MD; 
    locSize : Cardinal; 
    locStream : TBytesStream; 
begin 
    locKey := ReadKeyFile(aKeyFile, kfPublic); 
    locData := ReadMessage(aMsgFile); 
    locSize := EVP_PKEY_size(locKey); 

    locBio := BIO_new(BIO_f_md); 
    try 
    BIO_get_md_ctx(locBio, @locCtx); 
    locSHA256 := EVP_sha256(); 

    EVP_DigestVerifyInit(locCtx, NIL, locSHA256, NIL, locKey); 
    EVP_DigestVerifyUpdate(locCtx, PAnsiChar(locData), Length(locData)); 

    try 
     locSig := ReadSignature(aSigFile, locSize); 
     result := (EVP_DigestVerifyFinal(locCtx, PByte(locSig), locSize) = 1); 
    finally 
     FreeSignature(locSig); 
    end; 
    finally 
    BIO_free(locBio); 
    end; 
end; 

procedure TSignSHA256.WriteSignature(aName : String; aSignature : TArray<Byte>; aLength : Integer); 
var locFileStream : TFileStream; 
begin 
    locFileStream := TFileStream.Create(aName, fmCreate); 
    try 
    locFileStream.Write(aSignature[0], aLength); 
    finally 
    FreeAndNIL(locFileStream); 
    end; 
end; 

end. 
संबंधित मुद्दे