在Delphi中使用OpenSSL验证SHA256签名失败
我正在尝试使用OpenSSL libeay32.dll在Delphi中实现SHA256签名和验证.因此,在第一步中,我使用以下OpenSSL命令创建了一个RSA 2048位密钥对:
openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -outform PEM -pubout -out public.pem 那么容易.我做的下一步是创建一个能够从PEM文件中读取公钥和私钥的函数: 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,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,locKey ); EVP_DigestSignUpdate( locCtx,PAnsiChar(locData),Length(locData) ); EVP_DigestSignFinal( locCtx,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的文件,计算签名并将该sig存储到message.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,EVP_sha256(),locKey ); //Returns 1 EVP_DigestVerifyUpdate( locCtx,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 RSA中的错误,函数int_rsa_verify,原因是签名长度错误.我搜索了谷歌,但我没有找到任何关于该错误的有用信息.我也试图了解OpenSSL的来源,但我不是那么深入C,看起来它可能需要很长时间,直到我能够弄明白. 我个人的感觉是我在阅读公钥时做错了什么.但这只是一种感觉,我不知道如何以不同的方式做到这一点.我的第二个猜测是我在验证过程中对上下文做了一些错误.但我不知道那可能是什么. 为什么签名验证失败? 解决方法
签名不是文本签名.它由一个字节数组成,字节可以有任何值.您正在将该字节数组直接转换为ANSI字符串.如果数组包含ANSI范围之外的值(无论可能是什么,我假设ASCII),那将失败.
您需要将签名视为二进制数据.如果需要将其视为字符串(包含文本),则可以使用base 64编解码器. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |