我们正在开发一个 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;
所以,我的代码无法正常工作的主要原因是我在调用 EvpDigestSignFinal 之前没有设置签名 (sig) 的长度。
此外,注释的代码不起作用,因为我试图设置 saltlen 来生成密钥。