📄 lbdsa.pas
字号:
U, SHAseed, SHAseed1 : TLbBigInt;
Digest : TSHA1Digest;
Counter : Word; {!!.06}
begin
U := TLbBigInt.Create(SizeOf(TLbDSABlock));
SHAseed := TLbBigInt.Create(SizeOf(TLbDSABlock));
SHAseed1 := TLbBigInt.Create(SizeOf(TLbDSABlock));
Counter := 0;
try
{ Step 2: U = SHA(seed) xor SHA((seed+1) mod 2^g) }
SHAseed.CopyBuffer(ASeed, SizeOf(ASeed));
repeat
FQ.Clear;
{ SHA(Seed) }
HashSHA1(Digest, SHAseed.IntBuf^, SHAseed.Size);
SHAseed.CopyBuffer(Digest, SizeOf(Digest)); { SHASeed is big to little }
SHAseed.ReverseBytes; { SHASeed -> little to big for math }
{ SHA((seed+1) mod 2^g }
SHAseed1.CopyBuffer(ASeed, SizeOf(ASeed)); { SHASeed1 is big to little }
SHASeed1.ReverseBytes; { SHASeed1 -> little to big for math }
SHAseed1.AddByte(1);
SHAseed1.Modulus(F2Tog);
SHASeed1.ReverseBytes; { SHASeed1 -> big to little for SHA }
HashSHA1(Digest, SHAseed1.IntBuf^, SHAseed1.Size);
SHAseed1.CopyBuffer(Digest, SizeOf(Digest));
SHASeed1.ReverseBytes; { SHASeed1 -> little to big for math }
{ U = SHASeed xor SHASeed1 }
U.Copy(SHAseed);
U.XOR_(SHAseed1);
{ Step 3: q = q or 2^159 or 1 }
FQ.Copy(U);
FQ.OR_(FMostLeast);
{ Step 4,5: fail if q is composite }
Result := not FQ.IsComposite(FPrimeTestIterations);
{ if q is not composite then try again with another random seed }
if not Result then begin
Inc(Counter);
SHASeed.RandomBytes(SizeOf(TLbDSABlock));
end;
until Result or (Counter >= MaxTries);
finally
U.Free;
SHAseed.Free;
SHAseed1.Free;
end;
end;
{ -------------------------------------------------------------------------- }
function TLbDSAParameters.GenerateP(const ASeed : TLbDSABlock) : Boolean;
{ generate parameter p }
const
MaxTries = 4096;
var
V, W, TwoToN, ModN, c, X : TLbBigInt;
tmp : TLbBigInt;
Lminus1, Counter : DWord;
Offset : word;
k, N, B : Byte;
Digest : TSHA1Digest;
Abort : Boolean;
Prime : Boolean;
begin
Abort := False;
Prime := False;
V := TLbBigInt.Create(SizeOf(TLbDSABlock));
W := TLbBigInt.Create(SizeOf(TLbDSABlock));
TwoToN := TLbBigInt.Create(SizeOf(TLbDSABlock));
ModN := TLbBigInt.Create(SizeOf(TLbDSABlock));
c := TLbBigInt.Create(SizeOf(TLbDSABlock));
X := TLbBigInt.Create(SizeOf(TLbDSABlock));
tmp := TLbBigInt.Create(SizeOf(TLbDSABlock));
{ L-1 = sizeof(P) - 1 }
Lminus1 := (cLbAsymKeyBytes[FKeySize] * 8) - 1;
N := Lminus1 div 160;
B := Lminus1 mod 160;
Counter := 0;
Offset := 2;
try
while not (Prime or Abort) or (Counter > MaxTries) do begin
{ 2^0 }
W.CopyByte(0);
for k := 0 to n do begin
{ Step 7: V = SHA((seed+offset+k) mod 2^g) }
V.CopyBuffer(ASeed, SizeOf(ASeed)); { V = Seed, is big to little }
V.ReverseBytes; { V -> little to big for math }
tmp.Clear;
tmp.CopyDWord(k + Offset);
V.Add( tmp );
V.Modulus(F2Tog);
V.ReverseBytes; { V -> big to little for SHA }
HashSHA1(Digest, V.IntBuf^, V.Size);
V.CopyBuffer(Digest, SizeOf(Digest));
V.ReverseBytes; { V -> little to big for math }
{ Step 8: W = W + V*2^(160 * k) }
if (k = n) then begin
{ mod last V to b bits }
ModN.CopyByte( 1 );
ModN.Shl_( b );
V.Modulus(ModN);
end;
V.Shl_(160 * k);
W.Add(V);
end;
{ more Step 8: X = W + 2^(L-1) }
TwoToN.CopyByte(1);
TwoToN.Shl_(Lminus1);
X.Copy(W);
X.Add(TwoToN);
{ Step 9: c = X mod 2q }
c.Copy(X);
ModN.Copy(FQ);
ModN.Shl_(1);
c.Modulus(ModN);
{ more Step 9: p = X - (c - 1) }
FP.Copy(X);
FP.Subtract(c);
FP.AddByte(1);
{ Step 10: fail if p < 2^(L-1) }
if (FP.Compare(TwoToN) <> cLESS_THAN) then
{ Step 11: fail if p is composite }
Prime := not FP.IsComposite(FPrimeTestIterations);
{ see if caller wants to abort }
if not Prime then
if Assigned(FCallBack) then
FCallBack(Abort);
{ Step 13: bump counter and offset }
Inc(Counter);
Inc(Offset, n+1);
end;
finally
V.Free;
W.Free;
TwoToN.Free;
ModN.Free;
X.Free;
c.Free;
tmp.Free;
end;
Result := Prime;
end;
{ -------------------------------------------------------------------------- }
function TLbDSAParameters.GenerateG : Boolean;
{ generate parameter g }
var
h, p1q, tmp, c1 : TLbBigInt;
begin
Result := False;
if (FP.Size < 2) then
Exit;
h := TLbBigInt.Create(20);
p1q := TLbBigInt.Create(20);
tmp := TLbBigInt.Create(20);
c1 := TLbBigInt.Create(20);
try
c1.CopyByte(1);
{ (p-1)/q }
p1q.Copy(FP);
p1q.SubtractByte(1);
p1q.Divide(FQ);
h.CopyByte( $01 );
repeat { until valid h }
h.AddByte( $01 );
tmp.Copy(h);
tmp.PowerAndMod(p1q, FP);
until (tmp.Compare(c1) = cGREATER_THAN);
{ g = h^((p-1)/q) }
FG.Copy(h);
FG.PowerAndMod(p1q, FP);
Result := True;
finally
h.Free;
p1q.Free;
tmp.Free;
c1.Free;
end;
end;
{ == TLbDSAPrivateKey =================================================== }
constructor TLbDSAPrivateKey.Create(aKeySize : TLbAsymKeySize);
{initialization }
begin
inherited Create(aKeySize);
FX := TLbBigInt.Create(SizeOf(TLbDSABlock));
FillChar(FXKey, SizeOf(FXKey), #0);
end;
{ -------------------------------------------------------------------------- }
destructor TLbDSAPrivateKey.Destroy;
{ finalization }
begin
FX.Free;
inherited Destroy;
end;
{ -------------------------------------------------------------------------- }
procedure TLbDSAPrivateKey.Clear;
{ reset everything }
begin
inherited Clear;
FX.Clear;
FillChar(FXKey, SizeOf(FXKey), #0);
end;
{ -------------------------------------------------------------------------- }
procedure TLbDSAPrivateKey.GenerateX(const AXKey : TLbDSABlock);
{ generate parameter x }
var
XVal : TSHA1Digest;
begin
Move(AXKey, FXKey, SizeOf(FXKey));
FillChar(XVal, SizeOf(XVal), #0);
{ X = SHA(XKey), XKey is big to little }
HashSHA1(XVal, FXKey, SizeOf(FXKey));
FX.CopyBuffer(XVal, SizeOf(XVal));
FX.ReverseBytes; { X -> little to big for math }
{ X = XVal mod q, }
FX.Modulus(FQ);
end;
{ -------------------------------------------------------------------------- }
function TLbDSAPrivateKey.GetXAsString : string;
{ return "big to little" hex string representation of x }
begin
Result := FX.IntStr;
end;
{ -------------------------------------------------------------------------- }
procedure TLbDSAPrivateKey.SetXAsString(const Value : string);
{ set x to value represented by "big to little" hex string }
var
Buf : TLbDSABlock;
begin
FillChar(Buf, SizeOf(Buf), #0);
HexToBuffer(Value, Buf, SizeOf(Buf));
FX.CopyBuffer(Buf, SizeOf(Buf));
FX.Trim;
end;
{ -------------------------------------------------------------------------- }
{!!.06}
function TLbDSAPrivateKey.CreateASNKey(Input : pByteArray; Length : Integer) : Integer;
const
TAG30 = $30;
var
PSize : Integer;
QSize : Integer;
GSize : Integer;
XSize : Integer;
Total : Integer;
pInput : PByteArray;
Max : Integer;
begin
pInput := Input;
Max := Length;
PSize := EncodeASN1(FP, pInput, Max);
QSize := EncodeASN1(FQ, pInput, Max);
GSize := EncodeASN1(FG, pInput, Max);
XSize := EncodeASN1(FX, pInput, Max);
Total := PSize + QSize + GSize + XSize;
CreateASN1(Input^, Total, TAG30);
Result := Total;
end;
{ -------------------------------------------------------------------------- }
{!!.06}
function TLbDSAPrivateKey.ParseASNKey(Input : PByte; Length : Integer ) : Boolean;
var
Tag : Integer;
Max : Integer;
pInput : PByte;
begin
Max := Length;
pInput := Input;
{ check for sequence }
Tag := GetASN1StructNum(pInput, Max);
GetASN1StructLen(pInput, Max);
if (Tag <> ASN1_TYPE_SEQUENCE) then
raise Exception.Create(sDSAKeyBadKey);
ParseASN1(pInput, Max, FP);
ParseASN1(pInput, Max, FQ);
ParseASN1(pInput, Max, FG);
ParseASN1(pInput, Max, FX);
Result := (Max = 0);
end;
{ == TLbDSAPublicKey ==================================================== }
constructor TLbDSAPublicKey.Create(aKeySize : TLbAsymKeySize);
{initialization }
begin
inherited Create(aKeySize);
FY := TLbBigInt.Create(cLbAsymKeyBytes[FKeySize]);
end;
{ -------------------------------------------------------------------------- }
destructor TLbDSAPublicKey.Destroy;
{ finalization }
begin
FY.Free;
inherited Destroy;
end;
{ -------------------------------------------------------------------------- }
procedure TLbDSAPublicKey.Clear;
{ reset everything }
begin
inherited Clear;
FY.Clear;
end;
{ -------------------------------------------------------------------------- }
procedure TLbDSAPublicKey.GenerateY(aX : TLbBigInt);
{ generate parameter y }
begin
FY.Copy(FG);
FY.PowerAndMod(aX, FP);
end;
{ -------------------------------------------------------------------------- }
function TLbDSAPublicKey.GetYAsString : string;
{ return "big to little" hex string representation of y }
begin
Result := FY.IntStr;
end;
{ -------------------------------------------------------------------------- }
procedure TLbDSAPublicKey.SetYAsString(const Value : string);
{ set y to value represented by "big to little" hex string }
var
Buf : array[Byte] of Byte;
begin
FillChar(Buf, SizeOf(Buf), #0);
HexToBuffer(Value, Buf, cLbAsymKeyBytes[FKeySize]);
FY.CopyBuffer(Buf, cLbAsymKeyBytes[FKeySize]);
FY.Trim;
end;
{ -------------------------------------------------------------------------- }
{!!.06}
function TLbDSAPublicKey.CreateASNKey(Input : pByteArray; Length : Integer) : Integer;
const
TAG30 = $30;
var
PSize : Integer;
QSize : Integer;
GSize : Integer;
YSize : Integer;
Total : Integer;
pInput : PByteArray;
Max : Integer;
begin
pInput := Input;
Max := Length;
PSize := EncodeASN1(FP, pInput, Max);
QSize := EncodeASN1(FQ, pInput, Max);
GSize := EncodeASN1(FG, pInput, Max);
YSize := EncodeASN1(FY, pInput, Max);
Total := PSize + QSize + GSize + YSize;
CreateASN1(Input^, Total, TAG30);
Result := Total;
end;
{ -------------------------------------------------------------------------- }
{!!.06}
function TLbDSAPublicKey.ParseASNKey(input : pByte; length : Integer) : Boolean;
var
Tag : Integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -