加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

在Delphi中使用OpenSSL验证SHA256签名失败

发布时间:2020-12-15 09:27:23 所属栏目:大数据 来源:网络整理
导读:我正在尝试使用OpenSSL libeay32.dll在Delphi中实现SHA256签名和验证.因此,在第一步中,我使用以下OpenSSL命令创建了一个RSA 2048位密钥对: openssl genrsa -out private.pem 2048openssl rsa -in private.pem -outform PEM -pubout -out public.pem 那么容
我正在尝试使用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编解码器.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读