mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-18 13:59:47 +02:00
fcl-hash: added PSS helper functions I2OSP, MGF1SHA256
This commit is contained in:
parent
a81e527e1d
commit
7d98462c1c
@ -42,6 +42,7 @@ Procedure BytesToHexStr(out aHexStr : AnsiString; aBytes : PByte; aSize : Intege
|
||||
Procedure BytesToHexStr(out aHexStr : AnsiString; aBytes : TBytes); overload;
|
||||
Function BytesToHexStr(aBytes : TBytes) : AnsiString; overload;
|
||||
Procedure BytesToHexStrAppend(aBytes : TBytes;var aHexStr : AnsiString);
|
||||
Function StringToHex(const s: string): string; overload;
|
||||
|
||||
Procedure BytesEncodeBase64(Source: Tbytes; out Dest: AnsiString; const IsURL, MultiLines, Padding: Boolean);
|
||||
Function BytesEncodeBase64(Source: Tbytes; const IsURL, MultiLines, Padding: Boolean) : AnsiString;
|
||||
@ -59,6 +60,9 @@ var
|
||||
|
||||
implementation
|
||||
|
||||
Const
|
||||
HexDigits: Array[0..15] of AnsiChar = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
|
||||
|
||||
procedure BytesFromVar(out aBytes: TBytes; aLocation: Pointer; aSize: Integer);
|
||||
|
||||
begin
|
||||
@ -151,10 +155,6 @@ begin
|
||||
end;
|
||||
|
||||
procedure BytesToHexStr(out aHexStr : AnsiString; aBytes : PByte; aSize : Integer);
|
||||
|
||||
Const
|
||||
Digits: Array[0..15] of AnsiChar = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
|
||||
|
||||
var
|
||||
I: Integer;
|
||||
PB : Pbyte;
|
||||
@ -169,9 +169,9 @@ begin
|
||||
PC:=PChar(aHexStr);
|
||||
for I:=0 to aSize-1 do
|
||||
begin
|
||||
PC^:=Digits[(PB^ shr 4) and $0f];
|
||||
PC^:=HexDigits[PB^ shr 4];
|
||||
Inc(PC);
|
||||
PC^:=Digits[PB^ and $0f];
|
||||
PC^:=HexDigits[PB^ and $f];
|
||||
Inc(PC);
|
||||
Inc(PB);
|
||||
end;
|
||||
@ -195,6 +195,12 @@ begin
|
||||
aHexStr:=aHexStr+BytesToHexStr(aBytes);
|
||||
end;
|
||||
|
||||
function StringToHex(const s: string): string;
|
||||
begin
|
||||
if s='' then exit;
|
||||
BytesToHexStr(Result,@s[1],length(s));
|
||||
end;
|
||||
|
||||
function GetBase64EncodedSize(const SourceSize: Int32; const MultiLines: Boolean): Int32;
|
||||
var
|
||||
Lines: Int32;
|
||||
|
@ -9,7 +9,7 @@ interface
|
||||
{off $DEFINE CRYPTO_DEBUG}
|
||||
|
||||
uses
|
||||
sysutils, Classes, fpTLSBigInt, fphashutils, fpasn, basenenc;
|
||||
sysutils, Classes, sha1, fpsha256, fpTLSBigInt, fphashutils, fpasn, basenenc;
|
||||
|
||||
const
|
||||
RSAPublicKeyOID = '1.2.840.113549.1.1.1';
|
||||
@ -106,6 +106,17 @@ function TestRS256Verify: Boolean;
|
||||
|
||||
function EncodeDigestInfoSHA(SHAType, len: byte): TBytes;
|
||||
|
||||
// integer <-> octetstring
|
||||
function I2OSP(c: DWord; Len: integer): string;
|
||||
function OSP2I(const Octet: string): DWord;
|
||||
|
||||
// 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 MGF1SHA1(const InputStr: string; Len: integer): string;
|
||||
function MGF1SHA256(const InputStr: string; Len: integer): string;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
@ -678,6 +689,80 @@ begin
|
||||
];
|
||||
end;
|
||||
|
||||
function I2OSP(c: DWord; Len: integer): string;
|
||||
var
|
||||
i: DWord;
|
||||
begin
|
||||
if Len>4 then
|
||||
raise Exception.Create('20220501190110');
|
||||
SetLength(Result{%H-},Len);
|
||||
for i:=Len downto 1 do
|
||||
begin
|
||||
Result[i]:=chr(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;
|
||||
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]);
|
||||
end;
|
||||
|
||||
function MGF1(const InputStr: string; Len: integer; HashFunc: THashFunction
|
||||
): string;
|
||||
var
|
||||
Counter: DWord;
|
||||
begin
|
||||
Counter:=0;
|
||||
Result:='';
|
||||
while length(Result)<Len do
|
||||
begin
|
||||
Result:=Result+HashFunc(InputStr+I2OSP(Counter,4));
|
||||
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 ;
|
||||
end;
|
||||
|
||||
function MGF1SHA1(const InputStr: string; Len: integer): string;
|
||||
begin
|
||||
Result:=MGF1(InputStr,Len,@SHA1StrToDigest);
|
||||
end;
|
||||
|
||||
function SHA256StrToDigest(const InputStr: string): string;
|
||||
var
|
||||
SHA256: TSHA256;
|
||||
begin
|
||||
SHA256.Init;
|
||||
SHA256.Update(@InputStr[1],length(InputStr));
|
||||
SHA256.Final;
|
||||
|
||||
SetLength(Result{%H-},length(SHA256.Digest));
|
||||
System.Move(SHA256.Digest[0],Result[1],length(SHA256.Digest));
|
||||
end;
|
||||
|
||||
function MGF1SHA256(const InputStr: string; Len: integer): string;
|
||||
begin
|
||||
Result:=MGF1(InputStr,Len,@SHA256StrToDigest);
|
||||
end;
|
||||
|
||||
{ TX509RSAPrivateKey }
|
||||
|
||||
procedure TX509RSAPrivateKey.InitWithHexStrings(const n, e, d, p, q, dp, dq, qi: string
|
||||
|
@ -28,6 +28,7 @@ type
|
||||
end;
|
||||
|
||||
{ TTestJWT }
|
||||
|
||||
TTestJWT= class(TTestCase)
|
||||
private
|
||||
FJWT: TJWT;
|
||||
@ -42,18 +43,28 @@ type
|
||||
published
|
||||
procedure TestSignNone;
|
||||
procedure TestVerifyNone;
|
||||
|
||||
// SHA
|
||||
procedure TestSignSHA256;
|
||||
procedure TestVerifySHA256;
|
||||
procedure TestSignSHA512;
|
||||
procedure TestVerifySHA512;
|
||||
procedure TestSignSHA384;
|
||||
procedure TestVerifySHA384;
|
||||
|
||||
// ES
|
||||
procedure TestVerifyES256;
|
||||
procedure TestVerifyES256Pem;
|
||||
|
||||
// RSA
|
||||
procedure TestVerifyRS256Pem;
|
||||
procedure TestVerifyRS384Pem;
|
||||
procedure TestVerifyRS512Pem;
|
||||
procedure TestVerifyRS256_rfc7515;
|
||||
procedure TestI2OSP;
|
||||
procedure TestOSP2I;
|
||||
procedure TestMGF1SHA1;
|
||||
procedure TestMGF1SHA256;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -236,7 +247,6 @@ begin
|
||||
AssertEquals('Have correct sub','1234567890',FVerifyResult.Claims.sub);
|
||||
AssertEquals('Have correct name','John Doe',(TMyJWT(FVerifyResult).Claims as TMyClaims).Name);
|
||||
AssertEquals('Have correct admin',true,(TMyJWT(FVerifyResult).Claims as TMyClaims).Admin);
|
||||
|
||||
end;
|
||||
|
||||
procedure TTestJWT.TestVerifyES256Pem;
|
||||
@ -396,6 +406,82 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestJWT.TestI2OSP;
|
||||
|
||||
procedure t(c: DWord; Len: integer; const Expected: string);
|
||||
var
|
||||
Actual: String;
|
||||
begin
|
||||
Actual:=I2OSP(c,Len);
|
||||
if Actual<>Expected then
|
||||
Fail('I2OSP('+IntToStr(c)+','+IntToStr(Len)+') expected "'+StringToHex(Expected)+'", but got "'+StringToHex(Actual)+'"');
|
||||
end;
|
||||
|
||||
begin
|
||||
t(0,0,'');
|
||||
t(0,1,#0);
|
||||
t(1,1,#1);
|
||||
t(1,2,#0#1);
|
||||
t(258,2,#1#2);
|
||||
t($10203,3,#1#2#3);
|
||||
t($1020304,4,#1#2#3#4);
|
||||
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);
|
||||
var
|
||||
ActualHex: string;
|
||||
begin
|
||||
ActualHex:=StringToHex(MGF1SHA1(InputStr,Len));
|
||||
if ActualHex<>ExpectedHex then
|
||||
Fail('MGF1SHA1('+StringToHex(InputStr)+','+IntToStr(Len)+') expected "'+ExpectedHex+'", but got "'+ActualHex+'"');
|
||||
end;
|
||||
|
||||
begin
|
||||
t('foo',3,'1AC907');
|
||||
t('foo',5,'1AC9075CD4');
|
||||
t('bar',5,'BC0C655E01');
|
||||
t('bar',50,'BC0C655E016BC2931D85A2E675181ADCEF7F581F76DF2739DA74FAAC41627BE2F7F415C89E983FD0CE80CED9878641CB4876');
|
||||
end;
|
||||
|
||||
procedure TTestJWT.TestMGF1SHA256;
|
||||
|
||||
procedure t(const InputStr: string; Len: integer; const ExpectedHex: String);
|
||||
var
|
||||
ActualHex: string;
|
||||
begin
|
||||
ActualHex:=StringToHex(MGF1SHA256(InputStr,Len));
|
||||
if ActualHex<>ExpectedHex then
|
||||
Fail('MGF1SHA256('+StringToHex(InputStr)+','+IntToStr(Len)+') expected "'+ExpectedHex+'", but got "'+ActualHex+'"');
|
||||
end;
|
||||
|
||||
begin
|
||||
t('bar',50,'382576A7841021CC28FC4C0948753FB8312090CEA942EA4C4E735D10DC724B155F9F6069F289D61DACA0CB814502EF04EAE1');
|
||||
end;
|
||||
|
||||
procedure TTestJWT.SetUp;
|
||||
begin
|
||||
Inherited;
|
||||
|
Loading…
Reference in New Issue
Block a user