如何在 Delphi 中对消息进行 rsa-pss 签名

问题描述 投票:0回答:1

我们正在开发一个 Delphi (10.3) 项目,尝试使用 RSA-PSS 算法对消息进行签名 (https://www.openssl.org/docs/man3.0/man7/RSA-PSS.html) 使用适用于 Windows 和 Linux 的 OpenSSL 库。

现在,我陷入困境,不知道还能尝试什么。 代码运行没有错误,但返回长度为 256 的空签名(所有字节均为 0)。如果有关 salt 长度的代码未注释,则库过程 (EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen) 返回 -2,表示不支持该操作。 (https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen.html

密钥由第三方提供,应该是正确的。我在这里缺少什么?

这是我到目前为止所拥有的:

    class function TAuthenticationHelper.InternalSign_RSAPSS(const AInput: TBytes; AKey: EVP_PKEY): TBytes;
var
  mdCtx: EVP_MD_CTX;
  pkeyCtx: EVP_PKEY_CTX;
  sig: TBytes;
  iSiglen: NativeUInt;
begin
  mdCtx := EvpMdCtxNew();
  if not Assigned(mdCtx) then
    raise Exception.Create('mdCtx not assigned');

  pkeyCtx := EvpPkeyCtxNew(AKey, nil);
  if not Assigned(pkeyCtx) then
    raise Exception.Create('pkeyCtx not assigned');

  if EvpDigestSignInit(mdCtx, @pkeyCtx, EvpSha256(), nil, aKey) <= 0 then
    raise Exception.Create('DigestSignInit failed');

  if EvpPkeyCtxSetRsaPadding(pkeyCtx, RSA_PKCS1_PSS_PADDING) <= 0 then
    raise Exception.Create('ctx set RSA padding not succeeded');

//  if EvpPkeyCtxSetRsaPssKeygenSaltlen(pkeyCtx, 32) <= 0 then
//    raise Exception.Create('ctx set saltlen failed');

  iSigLen := EvpPkeySize(aKey);
  if iSigLen <= 0 then
    raise Exception.Create('iSiglen has an incorrect value');

  if EvpDigestSignUpdate(mdCtx, @aInput[0], Length(aInput)) <= 0 then
    raise Exception.Create('DigestSignUpdate failed');

  if EvpDigestSignFinal(mdCtx, @sig[0], @iSigLen) <= 0 then
    raise Exception.Create('DigestSignFinal failed');

  SetLength(sig, iSigLen);
  Result := sig;
end;
class function TAuthenticationHelper.LoadPrivateKey(const AKey: TBytes; const aPassword: PAnsiChar; aKeyType: PAnsiChar = nil): PEVP_PKEY;
var
  LBio: PBIO;
  lDecoder: POSSL_DECODER_CTX;
  lFormat: PAnsiChar;
  lStructure: PAnsiChar;
  lPkey: PEVP_PKEY;
  lSelection: Integer;
begin
  lBio := BioNew(BioSMem);
  lPkey := nil;
  lFormat := 'PEM';
  lStructure := nil;
  lSelection := 0; // = autodetect
  try
    BioWrite(LBio, @AKey[0], Length(AKey));
    lDecoder := OsslDecoderCtxNewForPkey(@lPkey, lFormat, lStructure, aKeyType, lSelection, nil, nil);

    if lDecoder = nil then
      raise EAuthentication.Create('No suitable potential decoders found');

    if aPassword <> nil then
     OsslDecoderCtxSetPassphrase(lDecoder, @aPassword[0], Length(aPassword));
    if OsslDecoderFromBio(lDecoder, LBio) <= 0 then
      raise EAuthentication.Create('Decoding failure');

    Result := lPkey;
    
    if Result = nil then
      raise EAuthentication.Create('Unable to load private key: ' + GetLastError);
  finally
    BioFree(LBio);
  end;
end;

class function TAuthenticationHelper.Sign_RSAPSS(const AInput, AKey: TBytes; aPwd: string): TBytes;
var
  lPkey: EVP_PKEY;
  tmpBytes: TBytes;
begin
  lPkey := LoadPrivateKey(AKey, PAnsiChar(Ansistring(aPwd)), nil);
  try
    tmpBytes := CreateDigest(aInput, 'SHA256');
    Result := InternalSign_RSAPSS(tmpBytes, lPkey);
  finally
    EvpPkeyFree(lPkey);
  end;
end;

class function TAuthenticationHelper.Sign_RSAPSS(const aKeyFile, aStringToSign, aPwd: string): string;
var
  bTxt: TBytes;
  bData: TBytes;
  bSign: TBytes;
  sUtf: string;
begin
  Result := '';
  { TODO -oLies -cGeneral : Test of dit ook werkt }
  // bTxt := TFile.ReadAllBytes(aKeyFile);

  sUtf := TFile.ReadAllText(aKeyFile);
  bTxt := TEncoding.UTF8.GetBytes(sUtf);
  bData := TEncoding.UTF8.GetBytes(aStringToSign);

  bSign := Sign_RSAPSS(bData, bTxt, aPwd);

  Result := TNetEncoding.base64.EncodeBytesToString(bSign);
  // is this necessary?
  Result := StringReplace(Result, sLineBreak, '', [rfReplaceAll]);
end;
delphi openssl cross-platform digital-signature
1个回答
0
投票

所以,我的代码无法正常工作的主要原因是我在调用 EvpDigestSignFinal 之前没有设置签名 (sig) 的长度。

此外,注释的代码不起作用,因为我试图设置 saltlen 来生成密钥。

© www.soinside.com 2019 - 2024. All rights reserved.