mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-30 10:41:15 +02:00
fcl-hash: started RSASSA_PSS_SIGN
This commit is contained in:
parent
f5742f21a0
commit
de5c056ef3
@ -35,7 +35,8 @@ type
|
||||
DP: PBigInt; // d mod (p-1)
|
||||
DQ: PBigInt; // d mod (q-1)
|
||||
QInv: PBigInt; // q^-1 mod p
|
||||
ModulusLen: Integer;
|
||||
ModulusLen: Integer; // in bytes
|
||||
ModulusBits: Integer; // in bits
|
||||
Context: TBigIntContext;
|
||||
end;
|
||||
|
||||
@ -83,22 +84,22 @@ procedure RSAInitFromPrivateKeyDER(var RSA: TRSA; const PrivateKeyDER: TBytes);
|
||||
procedure X509RsaPrivateKeyInitFromDER(out RSA: TX509RSAPrivateKey; const PrivateKeyDER: TBytes);
|
||||
|
||||
{ Perform PKCS1.5 Encryption or Signing
|
||||
Context: The RSA context containing Private and/or Public keys
|
||||
RSA: The RSA context containing Private and/or Public keys
|
||||
Input: The data to be encrypted
|
||||
Len: The size of the input data in bytes (Must be <= Modulus length - 11 to
|
||||
make the padding at least 8 bytes as recommended by RFC2313)
|
||||
Output: The buffer for the encrypted result (Must always be Modulus length)
|
||||
Sign: If true then sign instead of encrypting
|
||||
Return: The number of bytes encrypted or -1 on error }
|
||||
Result: The number of bytes encrypted or -1 on error }
|
||||
function RSAEncryptSign(var RSA: TRSA; const Input: PByte; Len: Integer; Output: PByte; Sign: Boolean): Integer;
|
||||
|
||||
{ Perform PKCS1.5 Decryption or Verification
|
||||
Context: The RSA context containing Private and/or Public keys
|
||||
RSA: The RSA context containing Private and/or Public keys
|
||||
Input: The data to be decrypted (Must always be Modulus length)
|
||||
Output: The buffer for the decrypted result
|
||||
Len: The size of the output buffer in bytes
|
||||
Verify: If true then verify instead of decrypting
|
||||
Return: The number of bytes decrypted or -1 on error }
|
||||
Result: The number of bytes decrypted or -1 on error }
|
||||
function RSADecryptVerify(var RSA: TRSA; const Input: PByte; Output: PByte; Len: Integer; Verify: Boolean): Integer;
|
||||
|
||||
function RS256VerifyFromPublicKeyHexa(const PublicKeyHexa, SignatureBaseHash, Signature: String): Boolean;
|
||||
@ -106,14 +107,41 @@ function TestRS256Verify: Boolean;
|
||||
|
||||
function EncodeDigestInfoSHA(SHAType, len: byte): TBytes;
|
||||
|
||||
// integer <-> octetstring
|
||||
function I2OSP(c: DWord; Len: integer): string;
|
||||
function OSP2I(const Octet: string): DWord;
|
||||
const
|
||||
RSA_PSS_SaltLen_HashLen = -1;
|
||||
RSA_PSS_SaltLen_Max = -2;
|
||||
type
|
||||
TRSAHashFunction = procedure(Input: PByte; InLen: Integer; Output: PByte);
|
||||
|
||||
{ TRSAHashFuncInfo }
|
||||
|
||||
TRSAHashFuncInfo = record
|
||||
Func: TRSAHashFunction;
|
||||
DigestLen: Word;
|
||||
procedure InitSHA1;
|
||||
procedure InitSHA256;
|
||||
end;
|
||||
PRSAHashFuncInfo = ^TRSAHashFuncInfo;
|
||||
|
||||
{ Perform PSASSA-PSS using MGF1 and a hash function
|
||||
RSA: The RSA context containing the private key
|
||||
Input: The data to be signed
|
||||
Len: The size of the input data in bytes (Must be <= Modulus length - 11 to
|
||||
Output: The buffer for the encrypted result (Must always be RSA.ModulusLen)
|
||||
Result: The number of bytes encrypted or -1 on error }
|
||||
function RSASSA_PSS_SIGN(var RSA: TRSA; Input: PByte; Len: Integer;
|
||||
HashFunc: PRSAHashFuncInfo; Output: PByte; SaltLen: integer = RSA_PSS_SaltLen_HashLen): Integer;
|
||||
|
||||
procedure EMSA_PSS_ENCODE(Input: PByte; InLen: Integer; HashFunc: PRSAHashFuncInfo;
|
||||
Output: PByte; OutLen: integer; ModBits: integer; SaltLen: integer = RSA_PSS_SaltLen_HashLen);
|
||||
|
||||
// integer to octetstring
|
||||
function I2OSP(c: DWord; Len: integer): string; overload;
|
||||
procedure I2OSP(c: DWord; Dest: PByte; Len: integer); overload;
|
||||
|
||||
// MGF1 (Mask Generating Function 1) of PKCS1 (Public Key Cryptography Standard #1)
|
||||
type
|
||||
THashFunction = function(const s: string): string; // string to hash digest
|
||||
function MGF1(const InputStr: string; Len: integer; HashFunc: THashFunction): string;
|
||||
function MGF1(const InputStr: string; HashFunc: PRSAHashFuncInfo; Len: integer): string; overload;
|
||||
procedure MGF1(Input: PByte; InLen: Integer; HashFunc: PRSAHashFuncInfo; Output: PByte; OutLen: integer); overload;
|
||||
function MGF1SHA1(const InputStr: string; Len: integer): string;
|
||||
function MGF1SHA256(const InputStr: string; Len: integer): string;
|
||||
|
||||
@ -159,6 +187,7 @@ procedure RsaInitFromPublicKey(var RSA: TRSA; const Modulus, Exponent: String);
|
||||
begin
|
||||
RSA.ModulusLen := length(Modulus);
|
||||
RSA.M := BIImport(RSA.Context, Modulus);
|
||||
RSA.ModulusBits := BIBitCount(RSA.M);
|
||||
BISetMod(RSA.Context, RSA.M, BIGINT_M_OFFSET);
|
||||
RSA.E := BIImport(RSA.Context, Exponent);
|
||||
BIPermanent(RSA.E);
|
||||
@ -173,6 +202,7 @@ begin
|
||||
Exit;
|
||||
RSA.ModulusLen := length(RSAPublicKey.Modulus);
|
||||
RSA.M := BIImport(RSA.Context, RSAPublicKey.Modulus);
|
||||
RSA.ModulusBits := BIBitCount(RSA.M);
|
||||
BISetMod(RSA.Context, RSA.M, BIGINT_M_OFFSET);
|
||||
RSA.E := BIImport(RSA.Context, RSAPublicKey.Exponent);
|
||||
BIPermanent(RSA.E);
|
||||
@ -189,7 +219,7 @@ end;
|
||||
procedure X509RsaPublicKeyInitFromDER(out RSA: TX509RSAPublicKey;
|
||||
const PublicKeyDER: TBytes);
|
||||
var
|
||||
ASNType, ASNSize: integer;
|
||||
ASNType, ASNSize, i: integer;
|
||||
List: TStringList;
|
||||
begin
|
||||
RSA:=Default(TX509RSAPublicKey);
|
||||
@ -201,7 +231,7 @@ begin
|
||||
ASNDebugList('X509RsaPublicKeyInitFromDER',List);
|
||||
{$ENDIF}
|
||||
|
||||
if List.Count<7 then
|
||||
if List.Count<6 then
|
||||
raise Exception.Create('20220428180055');
|
||||
|
||||
// check sequence
|
||||
@ -221,24 +251,29 @@ begin
|
||||
if List[2]<>RSAPublicKeyOID then
|
||||
raise Exception.Create('20220428181542');
|
||||
|
||||
// check null
|
||||
ASNParse_GetItem(List,3,ASNType,ASNSize);
|
||||
if ASNType<>ASN1_NULL then
|
||||
raise Exception.Create('20220428181659');
|
||||
// check optional null
|
||||
i:=3;
|
||||
ASNParse_GetItem(List,i,ASNType,ASNSize);
|
||||
if ASNType=ASN1_NULL then
|
||||
inc(i);
|
||||
|
||||
// check optional algorithm params
|
||||
ASNParse_GetItem(List,4,ASNType,ASNSize);
|
||||
// check algorithm params
|
||||
ASNParse_GetItem(List,i,ASNType,ASNSize);
|
||||
if ASNType<>ASN1_BITSTR then
|
||||
raise Exception.Create('20220428181913');
|
||||
inc(i);
|
||||
|
||||
if i+2>List.Count then
|
||||
raise Exception.Create('20220428180055');
|
||||
|
||||
// check sequence
|
||||
ASNParse_GetItem(List,5,ASNType,ASNSize);
|
||||
ASNParse_GetItem(List,i,ASNType,ASNSize);
|
||||
if ASNType<>ASN1_SEQ then
|
||||
raise Exception.Create('20220428181933');
|
||||
|
||||
// public key
|
||||
RSA.Modulus:=ASNParse_GetIntBytes(List,6,20220428182235);
|
||||
RSA.Exponent:=ASNParse_GetIntBytes(List,7,20220428182241);
|
||||
RSA.Modulus:=ASNParse_GetIntBytes(List,i+1,20220428182235);
|
||||
RSA.Exponent:=ASNParse_GetIntBytes(List,i+2,20220428182241);
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
writeln('X509RsaPublicKeyInitFromDER: ');
|
||||
@ -271,6 +306,7 @@ begin
|
||||
Exit;
|
||||
RSA.ModulusLen := length(RSAPrivateKey.Modulus);
|
||||
RSA.M := BIImport(RSA.Context, RSAPrivateKey.Modulus);
|
||||
RSA.ModulusBits := BIBitCount(RSA.M);
|
||||
BISetMod(RSA.Context, RSA.M, BIGINT_M_OFFSET);
|
||||
RSA.E := BIImport(RSA.Context, RSAPrivateKey.PublicExponent);
|
||||
BIPermanent(RSA.E);
|
||||
@ -689,78 +725,199 @@ begin
|
||||
];
|
||||
end;
|
||||
|
||||
function I2OSP(c: DWord; Len: integer): string;
|
||||
function RSASSA_PSS_SIGN(var RSA: TRSA; Input: PByte; Len: Integer;
|
||||
HashFunc: PRSAHashFuncInfo; Output: PByte; SaltLen: integer): Integer;
|
||||
var
|
||||
i: DWord;
|
||||
EncodedMsg: TBytes;
|
||||
ModBits: Integer;
|
||||
begin
|
||||
Result:=-1;
|
||||
|
||||
ModBits:=(RSA.ModulusBits-1) and 7;
|
||||
if ModBits=0 then
|
||||
raise Exception.Create('20220502000942 RSA n too small');
|
||||
|
||||
SetLength(EncodedMsg{%H-},RSA.ModulusLen);
|
||||
EMSA_PSS_ENCODE(Input,Len, HashFunc, @EncodedMsg[0], length(EncodedMsg), ModBits, SaltLen);
|
||||
|
||||
raise Exception.Create('20220502000942 implement me');
|
||||
|
||||
//Result:=RSASP1(RSA,EncodedMsg,Output);
|
||||
end;
|
||||
|
||||
procedure EMSA_PSS_ENCODE(Input: PByte; InLen: Integer;
|
||||
HashFunc: PRSAHashFuncInfo; Output: PByte; OutLen: integer; ModBits: integer;
|
||||
SaltLen: integer);
|
||||
// RFC 3447 9.1.1 Encoding operation
|
||||
var
|
||||
ZeroesHashSalt, H, DB, DBMask, MaskedDB: TBytes;
|
||||
MsgHashP, SaltP: PByte;
|
||||
Padding, HashLen, i: Integer;
|
||||
begin
|
||||
HashLen:=HashFunc^.DigestLen;
|
||||
|
||||
if SaltLen = RSA_PSS_SaltLen_HashLen then
|
||||
SaltLen:=HashLen
|
||||
else if SaltLen = RSA_PSS_SaltLen_Max then
|
||||
SaltLen:=OutLen-HashLen-2
|
||||
else if SaltLen < RSA_PSS_SaltLen_Max then
|
||||
raise Exception.Create('20220501233610');
|
||||
|
||||
// check OutLen
|
||||
if HashLen + SaltLen + 2 > OutLen then
|
||||
raise Exception.Create('20220501221837');
|
||||
|
||||
// ZeroesHashSalt := 8 zeroes + InputHash + Salt
|
||||
SetLength(ZeroesHashSalt{%H-},8+HashLen+SaltLen);
|
||||
FillByte(ZeroesHashSalt[0],8,0);
|
||||
MsgHashP:=@ZeroesHashSalt[8];
|
||||
HashFunc^.Func(Input,InLen,MsgHashP);
|
||||
SaltP:=MsgHashP+HashLen;
|
||||
if SaltLen>0 then
|
||||
if not CryptoGetRandomBytes(SaltP,SaltLen) then
|
||||
raise Exception.Create('20220501222748');
|
||||
|
||||
// hash ZeroesHashSalt
|
||||
SetLength(H{%H-},HashLen);
|
||||
HashFunc^.Func(@ZeroesHashSalt[0],length(ZeroesHashSalt),@H[0]);
|
||||
|
||||
// DB := padding zeroes + #1 + Salt
|
||||
SetLength(DB{%H-},OutLen-HashLen-1);
|
||||
Padding:=length(DB)-SaltLen-1;
|
||||
if Padding>0 then
|
||||
FillByte(DB[0],Padding,0);
|
||||
DB[Padding]:=1;
|
||||
System.Move(SaltP^,DB[Padding+1],SaltLen);
|
||||
|
||||
// dbMask := MGF(H, OutLen - HashLen - 1)
|
||||
SetLength(DBMask{%H-},length(DB));
|
||||
MGF1(@H[0],HashLen,HashFunc,@DBMask[0],length(DB));
|
||||
|
||||
// MaskedDB := DB xor DBMask
|
||||
SetLength(MaskedDB{%H-},length(DB));
|
||||
for i:=0 to length(DB) do
|
||||
MaskedDB[i]:=DB[i] xor DBMask[i];
|
||||
|
||||
// set the leftmost bits of leftmost byte to zero
|
||||
if ModBits>0 then
|
||||
MaskedDB[0] := MaskedDB[0] and ($ff shr (8-ModBits));
|
||||
|
||||
System.Move(MaskedDB[0],Output^,length(MaskedDB));
|
||||
inc(Output,length(MaskedDB));
|
||||
System.Move(H[0],Output^,length(H));
|
||||
inc(Output,length(H));
|
||||
Output^:=$bc;
|
||||
end;
|
||||
|
||||
function I2OSP(c: DWord; Len: integer): string;
|
||||
begin
|
||||
if Len>4 then
|
||||
raise Exception.Create('20220501190110');
|
||||
SetLength(Result{%H-},Len);
|
||||
for i:=Len downto 1 do
|
||||
I2OSP(c,@Result[1],Len);
|
||||
end;
|
||||
|
||||
procedure I2OSP(c: DWord; Dest: PByte; Len: integer);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i:=Len-1 downto 0 do
|
||||
begin
|
||||
Result[i]:=chr(c and $ff);
|
||||
Dest[i]:=c and $ff;
|
||||
c:=c shr 8;
|
||||
end;
|
||||
if c>0 then
|
||||
raise Exception.Create('20220501190124');
|
||||
end;
|
||||
|
||||
function OSP2I(const Octet: string): DWord;
|
||||
var
|
||||
i: Integer;
|
||||
function MGF1(const InputStr: string; HashFunc: PRSAHashFuncInfo; Len: integer): string;
|
||||
begin
|
||||
Result:=0;
|
||||
if length(Octet)>4 then
|
||||
raise Exception.Create('20220501190308');
|
||||
for i:=1 to length(Octet) do
|
||||
Result:=Result shl 8 + ord(Octet[i]);
|
||||
SetLength(Result{%H-},Len);
|
||||
if Len=0 then exit;
|
||||
MGF1(PByte(PChar(InputStr)){InputStr might be empty!},length(InputStr), HashFunc, @Result[1], Len);
|
||||
end;
|
||||
|
||||
function MGF1(const InputStr: string; Len: integer; HashFunc: THashFunction
|
||||
): string;
|
||||
procedure MGF1(Input: PByte; InLen: Integer; HashFunc: PRSAHashFuncInfo;
|
||||
Output: PByte; OutLen: integer);
|
||||
var
|
||||
p, CounterP, InpP: PByte;
|
||||
i, r: Integer;
|
||||
HashLen: Word;
|
||||
InputCounted, Tmp: TBytes;
|
||||
Counter: DWord;
|
||||
begin
|
||||
Counter:=0;
|
||||
Result:='';
|
||||
while length(Result)<Len do
|
||||
HashLen:=HashFunc^.DigestLen;
|
||||
SetLength(InputCounted{%H-},InLen+4);
|
||||
InpP:=@InputCounted[0];
|
||||
if InLen>0 then
|
||||
System.Move(Input^,InpP^,InLen);
|
||||
CounterP:=InpP+InLen;
|
||||
p:=Output;
|
||||
for i:=1 to (OutLen div HashLen) do
|
||||
begin
|
||||
Result:=Result+HashFunc(InputStr+I2OSP(Counter,4));
|
||||
I2OSP(Counter,CounterP,4);
|
||||
HashFunc^.Func(InpP,InLen+4,p);
|
||||
inc(p,HashLen);
|
||||
inc(Counter);
|
||||
end;
|
||||
SetLength(Result,Len);
|
||||
end;
|
||||
|
||||
function SHA1StrToDigest(const InputStr: string): string;
|
||||
var
|
||||
Digest: TSHA1Digest;
|
||||
begin
|
||||
Digest:=SHA1String(InputStr);
|
||||
SetLength(Result{%H-},length(Digest));
|
||||
System.Move(Digest[0],Result[1],length(Digest));
|
||||
if Digest[0]=0 then ;
|
||||
r:=OutLen mod HashLen;
|
||||
if r>0 then
|
||||
begin
|
||||
I2OSP(Counter,CounterP,4);
|
||||
SetLength(Tmp{%H-},HashLen);
|
||||
HashFunc^.Func(InpP,InLen+4,@Tmp[0]);
|
||||
System.Move(Tmp[0],p^,r);
|
||||
end;
|
||||
end;
|
||||
|
||||
function MGF1SHA1(const InputStr: string; Len: integer): string;
|
||||
var
|
||||
HashFunc: TRSAHashFuncInfo;
|
||||
begin
|
||||
Result:=MGF1(InputStr,Len,@SHA1StrToDigest);
|
||||
HashFunc.InitSHA1;
|
||||
Result:=MGF1(InputStr,@HashFunc,Len);
|
||||
end;
|
||||
|
||||
function SHA256StrToDigest(const InputStr: string): string;
|
||||
function MGF1SHA256(const InputStr: string; Len: integer): string;
|
||||
var
|
||||
HashFunc: TRSAHashFuncInfo;
|
||||
begin
|
||||
HashFunc.InitSHA256;
|
||||
Result:=MGF1(InputStr,@HashFunc,Len);
|
||||
end;
|
||||
|
||||
procedure HashFuncSHA1(Input: PByte; InLen: Integer; Output: PByte);
|
||||
var
|
||||
Context: TSHA1Context;
|
||||
Digest: TSHA1Digest;
|
||||
begin
|
||||
SHA1Init(Context);
|
||||
SHA1Update(Context,Input^,InLen);
|
||||
SHA1Final(Context,Digest);
|
||||
System.Move(Digest[0],Output^,SizeOf(Digest));
|
||||
end;
|
||||
|
||||
procedure HashFuncSHA256(Input: PByte; InLen: Integer; Output: PByte);
|
||||
var
|
||||
SHA256: TSHA256;
|
||||
begin
|
||||
SHA256.Init;
|
||||
SHA256.Update(@InputStr[1],length(InputStr));
|
||||
SHA256.Update(Input,InLen);
|
||||
SHA256.Final;
|
||||
|
||||
SetLength(Result{%H-},length(SHA256.Digest));
|
||||
System.Move(SHA256.Digest[0],Result[1],length(SHA256.Digest));
|
||||
System.Move(SHA256.Digest[0],Output^,SHA256_DIGEST_SIZE);
|
||||
end;
|
||||
|
||||
function MGF1SHA256(const InputStr: string; Len: integer): string;
|
||||
{ TRSAHashFuncInfo }
|
||||
|
||||
procedure TRSAHashFuncInfo.InitSHA1;
|
||||
begin
|
||||
Result:=MGF1(InputStr,Len,@SHA256StrToDigest);
|
||||
Func:=@HashFuncSHA1;
|
||||
DigestLen:=SizeOf(TSHA1Digest);
|
||||
end;
|
||||
|
||||
procedure TRSAHashFuncInfo.InitSHA256;
|
||||
begin
|
||||
Func:=@HashFuncSHA256;
|
||||
DigestLen:=SHA256_DIGEST_SIZE;
|
||||
end;
|
||||
|
||||
{ TX509RSAPrivateKey }
|
||||
|
@ -85,6 +85,7 @@ function BIImport(var Context: TBigIntContext; Data: PByte; const Size: Integer)
|
||||
function BIImport(var Context: TBigIntContext; const Data: TBytes): PBigInt; overload;
|
||||
function BIImport(var Context: TBigIntContext; const Data: AnsiString): PBigInt; overload;
|
||||
function IntToBI(var Context: TBigIntContext; I: TBIComponent): PBigInt;
|
||||
function BIBitCount(BI: PBigInt): integer;
|
||||
|
||||
function BIAdd(var Context: TBigIntContext; BIA, BIB: PBigInt): PBigInt;
|
||||
function BISubtract(var Context: TBigIntContext; BIA, BIB: PBigInt;out IsNegative: Boolean): PBigInt;
|
||||
@ -667,6 +668,25 @@ begin
|
||||
Result^.Components[0] := I;
|
||||
end;
|
||||
|
||||
function BIBitCount(BI: PBigInt): integer;
|
||||
var
|
||||
i: Integer;
|
||||
c: TBIComponent;
|
||||
begin
|
||||
i:=BI^.Size-1;
|
||||
while (i>=0) and (BI^.Components[i]=0) do
|
||||
dec(i);
|
||||
if i<0 then
|
||||
exit(0);
|
||||
Result:=i*BIGINT_COMP_BIT_SIZE;
|
||||
c:=BI^.Components[i];
|
||||
while (c>0) do
|
||||
begin
|
||||
inc(Result);
|
||||
c:=c shr 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
function BIAdd(var Context: TBigIntContext; BIA, BIB: PBigInt): PBigInt;
|
||||
var
|
||||
N: Integer;
|
||||
|
@ -62,9 +62,9 @@ type
|
||||
procedure TestVerifyRS512Pem;
|
||||
procedure TestVerifyRS256_rfc7515;
|
||||
procedure TestI2OSP;
|
||||
procedure TestOSP2I;
|
||||
procedure TestMGF1SHA1;
|
||||
procedure TestMGF1SHA256;
|
||||
procedure TestVerifyPS256; // ToDo
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -428,27 +428,6 @@ begin
|
||||
t($ffffffff,4,#255#255#255#255);
|
||||
end;
|
||||
|
||||
procedure TTestJWT.TestOSP2I;
|
||||
|
||||
procedure t(const Octet: string; const Expected: DWord);
|
||||
var
|
||||
Actual: DWord;
|
||||
begin
|
||||
Actual:=OSP2I(Octet);
|
||||
if Actual<>Expected then
|
||||
Fail('OSP2I('+StringToHex(Octet)+') expected "'+HexStr(Expected,8)+'", but got "'+HexStr(Actual,8)+'"');
|
||||
end;
|
||||
|
||||
begin
|
||||
t('',0);
|
||||
t(#0,0);
|
||||
t(#0#0,0);
|
||||
t(#0#0#0,0);
|
||||
t(#0#0#0#0,0);
|
||||
t(#1#0#0#0,$1000000);
|
||||
t(#255#255#255#255,$ffffffff);
|
||||
end;
|
||||
|
||||
procedure TTestJWT.TestMGF1SHA1;
|
||||
|
||||
procedure t(const InputStr: string; Len: integer; const ExpectedHex: String);
|
||||
@ -479,9 +458,16 @@ procedure TTestJWT.TestMGF1SHA256;
|
||||
end;
|
||||
|
||||
begin
|
||||
t('bar',1,'38');
|
||||
t('bar',50,'382576A7841021CC28FC4C0948753FB8312090CEA942EA4C4E735D10DC724B155F9F6069F289D61DACA0CB814502EF04EAE1');
|
||||
end;
|
||||
|
||||
procedure TTestJWT.TestVerifyPS256;
|
||||
begin
|
||||
// RSASSA-PSS using SHA-256 and MGF1 with SHA-256
|
||||
|
||||
end;
|
||||
|
||||
procedure TTestJWT.SetUp;
|
||||
begin
|
||||
Inherited;
|
||||
|
Loading…
Reference in New Issue
Block a user