|
@@ -0,0 +1,618 @@
|
|
|
|
|
+{ *********************************************************************************** }
|
|
|
|
|
+{ * CryptoLib Library * }
|
|
|
|
|
+{ * Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe * }
|
|
|
|
|
+{ * Github Repository <https://github.com/Xor-el> * }
|
|
|
|
|
+
|
|
|
|
|
+{ * Distributed under the MIT software license, see the accompanying file LICENSE * }
|
|
|
|
|
+{ * or visit http://www.opensource.org/licenses/mit-license.php. * }
|
|
|
|
|
+
|
|
|
|
|
+{ * Acknowledgements: * }
|
|
|
|
|
+{ * * }
|
|
|
|
|
+{ * Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring * }
|
|
|
|
|
+{ * development of this library * }
|
|
|
|
|
+
|
|
|
|
|
+{ * ******************************************************************************* * }
|
|
|
|
|
+
|
|
|
|
|
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
|
|
|
|
|
+
|
|
|
|
|
+unit ClpDsaParametersGenerator;
|
|
|
|
|
+
|
|
|
|
|
+{$I ..\..\Include\CryptoLib.inc}
|
|
|
|
|
+
|
|
|
|
|
+interface
|
|
|
|
|
+
|
|
|
|
|
+uses
|
|
|
|
|
+ Math,
|
|
|
|
|
+ SysUtils,
|
|
|
|
|
+ HlpSHA1,
|
|
|
|
|
+ ClpIDigest,
|
|
|
|
|
+ ClpISecureRandom,
|
|
|
|
|
+ ClpDsaParameters,
|
|
|
|
|
+ ClpIDsaParameters,
|
|
|
|
|
+ ClpDsaValidationParameters,
|
|
|
|
|
+ ClpIDsaValidationParameters,
|
|
|
|
|
+ ClpIDsaParametersGenerator,
|
|
|
|
|
+ ClpIDsaParameterGenerationParameters,
|
|
|
|
|
+ ClpHex,
|
|
|
|
|
+ ClpDigestUtilities,
|
|
|
|
|
+ ClpBigInteger,
|
|
|
|
|
+ ClpBigIntegers,
|
|
|
|
|
+ ClpCryptoLibTypes;
|
|
|
|
|
+
|
|
|
|
|
+resourcestring
|
|
|
|
|
+ SInvalidLValue =
|
|
|
|
|
+ 'L Values Must be Between 1024 and 3072 and a Multiple of 1024';
|
|
|
|
|
+ SInvalidNValueForSpecifiedL = 'N Must be " %d " for L = " %d "';
|
|
|
|
|
+ SInvalidNValueForSpecifiedL_Two = 'N Must be " %d " or " %d " for L = " %d "';
|
|
|
|
|
+ SDigestOutputSizeTooSmallForN =
|
|
|
|
|
+ 'Digest Output Size Too Small for Value of N Which is " %d "';
|
|
|
|
|
+ SUnsupportedDigest =
|
|
|
|
|
+ 'Can Only Use SHA-1 For Generating FIPS 186-2 Parameters';
|
|
|
|
|
+ SInvalidDsaKeyStrength =
|
|
|
|
|
+ 'Size Must Be From %d - %d and a multiple of %d, "%d"';
|
|
|
|
|
+
|
|
|
|
|
+type
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Generate suitable parameters for DSA, in line with FIPS 186-2, or FIPS
|
|
|
|
|
+ /// 186-3.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ TDsaParametersGenerator = class(TInterfacedObject, IDsaParametersGenerator)
|
|
|
|
|
+
|
|
|
|
|
+ strict private
|
|
|
|
|
+ Fdigest: IDigest;
|
|
|
|
|
+ FL, FN, Fcertainty, Fiterations, FusageIndex: Int32;
|
|
|
|
|
+ Frandom: ISecureRandom;
|
|
|
|
|
+ Fuse186_3: Boolean;
|
|
|
|
|
+
|
|
|
|
|
+ function IsProbablePrime(const x: TBigInteger): Boolean; inline;
|
|
|
|
|
+
|
|
|
|
|
+ function GenerateParameters_FIPS186_2(): IDsaParameters;
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// generate suitable parameters for DSA, in line with <i>FIPS 186-3 A.1
|
|
|
|
|
+ /// Generation of the FFC Primes p and q</i>
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ function GenerateParameters_FIPS186_3(): IDsaParameters;
|
|
|
|
|
+
|
|
|
|
|
+ class function IsValidDsaStrength(strength: Int32): Boolean; static; inline;
|
|
|
|
|
+
|
|
|
|
|
+ class function GetDefaultN(L: Int32): Int32; static; inline;
|
|
|
|
|
+ class function GetMinimumIterations(L: Int32): Int32; static; inline;
|
|
|
|
|
+ class procedure Hash(const d: IDigest; input, output: TCryptoLibByteArray;
|
|
|
|
|
+ outputPos: Int32); static; inline;
|
|
|
|
|
+
|
|
|
|
|
+ class procedure Inc(buf: TCryptoLibByteArray); static; inline;
|
|
|
|
|
+
|
|
|
|
|
+ class function CalculateGenerator_FIPS186_2(const p, q: TBigInteger;
|
|
|
|
|
+ const r: ISecureRandom): TBigInteger; static; inline;
|
|
|
|
|
+
|
|
|
|
|
+ class function CalculateGenerator_FIPS186_3_Unverifiable(const p,
|
|
|
|
|
+ q: TBigInteger; const r: ISecureRandom): TBigInteger; static; inline;
|
|
|
|
|
+
|
|
|
|
|
+ class function CalculateGenerator_FIPS186_3_Verifiable(const d: IDigest;
|
|
|
|
|
+ const p, q: TBigInteger; seed: TCryptoLibByteArray; index: Int32)
|
|
|
|
|
+ : TBigInteger; static; inline;
|
|
|
|
|
+
|
|
|
|
|
+ public
|
|
|
|
|
+ constructor Create(); overload;
|
|
|
|
|
+ constructor Create(const digest: IDigest); overload;
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// initialise the key generator.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="size">
|
|
|
|
|
+ /// size of the key (range 2^512 -&gt; 2^1024 - 64 bit increments)
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ /// <param name="certainty">
|
|
|
|
|
+ /// measure of robustness of prime (for FIPS 186-2 compliance this should
|
|
|
|
|
+ /// be at least 80).
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ /// <param name="random">
|
|
|
|
|
+ /// random byte source.
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ procedure Init(size, certainty: Int32;
|
|
|
|
|
+ const random: ISecureRandom); overload;
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// initialise the key generator.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="size">
|
|
|
|
|
+ /// size of the key (range 2^512 -&gt; 2^1024 - 64 bit increments)
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ /// <param name="certainty">
|
|
|
|
|
+ /// measure of robustness of prime (for FIPS 186-2 compliance this should
|
|
|
|
|
+ /// be at least 80).
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ /// <param name="iterations">
|
|
|
|
|
+ /// iterations
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ /// <param name="random">
|
|
|
|
|
+ /// random byte source.
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ procedure Init(size, certainty, iterations: Int32;
|
|
|
|
|
+ const random: ISecureRandom); overload;
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// <para>
|
|
|
|
|
+ /// Initialise the key generator for DSA 2.
|
|
|
|
|
+ /// </para>
|
|
|
|
|
+ /// <para>
|
|
|
|
|
+ /// Use this init method if you need to generate parameters for DSA 2
|
|
|
|
|
+ /// keys.
|
|
|
|
|
+ /// </para>
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="params">
|
|
|
|
|
+ /// DSA 2 key generation parameters.
|
|
|
|
|
+ /// </param>
|
|
|
|
|
+ procedure Init(const params: IDsaParameterGenerationParameters); overload;
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// <para>
|
|
|
|
|
+ /// which generates the p and g values from the given parameters,
|
|
|
|
|
+ /// returning the DSAParameters object.
|
|
|
|
|
+ /// </para>
|
|
|
|
|
+ /// <para>
|
|
|
|
|
+ /// Note: can take a while...
|
|
|
|
|
+ /// </para>
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <returns>
|
|
|
|
|
+ /// a generated DSA parameters object.
|
|
|
|
|
+ /// </returns>
|
|
|
|
|
+ function GenerateParameters(): IDsaParameters; inline;
|
|
|
|
|
+
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+implementation
|
|
|
|
|
+
|
|
|
|
|
+{ TDsaParametersGenerator }
|
|
|
|
|
+
|
|
|
|
|
+function TDsaParametersGenerator.IsProbablePrime(const x: TBigInteger): Boolean;
|
|
|
|
|
+begin
|
|
|
|
|
+ result := x.IsProbablePrime(Fcertainty);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class function TDsaParametersGenerator.IsValidDsaStrength
|
|
|
|
|
+ (strength: Int32): Boolean;
|
|
|
|
|
+begin
|
|
|
|
|
+ // result := (strength >= 512) and (strength <= 1024) and ((strength mod 64) = 0);
|
|
|
|
|
+ result := (strength >= 512) and (strength <= 1024) and
|
|
|
|
|
+ ((strength and 63) = 0);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class function TDsaParametersGenerator.GetDefaultN(L: Int32): Int32;
|
|
|
|
|
+begin
|
|
|
|
|
+ if L > 1024 then
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := 256
|
|
|
|
|
+ end
|
|
|
|
|
+ else
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := 160;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class function TDsaParametersGenerator.GetMinimumIterations(L: Int32): Int32;
|
|
|
|
|
+begin
|
|
|
|
|
+ // Values based on FIPS 186-4 C.3 Table C.1
|
|
|
|
|
+ if L <= 1024 then
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := 40;
|
|
|
|
|
+ end
|
|
|
|
|
+ else
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := (48 + 8 * ((L - 1) div 1024))
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class procedure TDsaParametersGenerator.Hash(const d: IDigest;
|
|
|
|
|
+ input, output: TCryptoLibByteArray; outputPos: Int32);
|
|
|
|
|
+begin
|
|
|
|
|
+ d.BlockUpdate(input, 0, System.Length(input));
|
|
|
|
|
+ d.DoFinal(output, outputPos);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class procedure TDsaParametersGenerator.Inc(buf: TCryptoLibByteArray);
|
|
|
|
|
+var
|
|
|
|
|
+ i: Int32;
|
|
|
|
|
+ b: Byte;
|
|
|
|
|
+begin
|
|
|
|
|
+ i := System.Length(buf) - 1;
|
|
|
|
|
+ while i >= 0 do
|
|
|
|
|
+ begin
|
|
|
|
|
+ b := Byte((buf[i] + 1) and $FF);
|
|
|
|
|
+ buf[i] := b;
|
|
|
|
|
+
|
|
|
|
|
+ if (b <> 0) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ break;
|
|
|
|
|
+ end;
|
|
|
|
|
+ System.Dec(i);
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+constructor TDsaParametersGenerator.Create;
|
|
|
|
|
+begin
|
|
|
|
|
+ Create(TDigestUtilities.GetDigest('SHA-1'));
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class function TDsaParametersGenerator.CalculateGenerator_FIPS186_2(const p,
|
|
|
|
|
+ q: TBigInteger; const r: ISecureRandom): TBigInteger;
|
|
|
|
|
+var
|
|
|
|
|
+ e, pSub2, h, g: TBigInteger;
|
|
|
|
|
+begin
|
|
|
|
|
+ result := Default (TBigInteger);
|
|
|
|
|
+ e := p.subtract(TBigInteger.One).Divide(q);
|
|
|
|
|
+ pSub2 := p.subtract(TBigInteger.Two);
|
|
|
|
|
+
|
|
|
|
|
+ while True do
|
|
|
|
|
+ begin
|
|
|
|
|
+ h := TBigIntegers.CreateRandomInRange(TBigInteger.Two, pSub2, r);
|
|
|
|
|
+ g := h.ModPow(e, p);
|
|
|
|
|
+ if (g.BitLength > 1) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := g;
|
|
|
|
|
+ Exit;
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class function TDsaParametersGenerator.CalculateGenerator_FIPS186_3_Unverifiable
|
|
|
|
|
+ (const p, q: TBigInteger; const r: ISecureRandom): TBigInteger;
|
|
|
|
|
+begin
|
|
|
|
|
+ result := CalculateGenerator_FIPS186_2(p, q, r);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+class function TDsaParametersGenerator.CalculateGenerator_FIPS186_3_Verifiable
|
|
|
|
|
+ (const d: IDigest; const p, q: TBigInteger; seed: TCryptoLibByteArray;
|
|
|
|
|
+ index: Int32): TBigInteger;
|
|
|
|
|
+var
|
|
|
|
|
+ e, W, g: TBigInteger;
|
|
|
|
|
+ ggen, U, smallw: TCryptoLibByteArray;
|
|
|
|
|
+ count: Int32;
|
|
|
|
|
+begin
|
|
|
|
|
+ // A.2.3 Verifiable Canonical Generation of the Generator g
|
|
|
|
|
+ e := p.subtract(TBigInteger.One).Divide(q);
|
|
|
|
|
+ ggen := THex.Decode('6767656E');
|
|
|
|
|
+
|
|
|
|
|
+ // 7. U = domain_parameter_seed || "ggen" || index || count.
|
|
|
|
|
+ System.SetLength(U, System.Length(seed) + System.Length(ggen) + 1 + 2);
|
|
|
|
|
+ System.Move(seed[0], U[0], System.Length(seed) * System.SizeOf(Byte));
|
|
|
|
|
+ System.Move(ggen[0], U[System.Length(seed)], System.Length(ggen) *
|
|
|
|
|
+ System.SizeOf(Byte));
|
|
|
|
|
+ U[System.Length(U) - 3] := Byte(index);
|
|
|
|
|
+
|
|
|
|
|
+ System.SetLength(smallw, d.GetDigestSize());
|
|
|
|
|
+
|
|
|
|
|
+ count := 1;
|
|
|
|
|
+ while count < (1 shl 16) do
|
|
|
|
|
+ begin
|
|
|
|
|
+ Inc(U);
|
|
|
|
|
+ Hash(d, U, smallw, 0);
|
|
|
|
|
+ W := TBigInteger.Create(1, smallw);
|
|
|
|
|
+ g := W.ModPow(e, p);
|
|
|
|
|
+ if (g.CompareTo(TBigInteger.Two) >= 0) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := g;
|
|
|
|
|
+ Exit;
|
|
|
|
|
+ end;
|
|
|
|
|
+ System.Inc(count);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ result := Default (TBigInteger);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+function TDsaParametersGenerator.GenerateParameters_FIPS186_2: IDsaParameters;
|
|
|
|
|
+var
|
|
|
|
|
+ seed, part1, part2, U, W, offset: TCryptoLibByteArray;
|
|
|
|
|
+ n, i, counter, k, remaining: Int32;
|
|
|
|
|
+ q, x, c, p, g: TBigInteger;
|
|
|
|
|
+begin
|
|
|
|
|
+ result := Nil;
|
|
|
|
|
+ System.SetLength(seed, 20);
|
|
|
|
|
+ System.SetLength(part1, 20);
|
|
|
|
|
+ System.SetLength(part2, 20);
|
|
|
|
|
+ System.SetLength(U, 20);
|
|
|
|
|
+ n := (FL - 1) div 160;
|
|
|
|
|
+ System.SetLength(W, FL div 8);
|
|
|
|
|
+
|
|
|
|
|
+ if (not {$IFDEF FPC} (Supports(Fdigest.GetUnderlyingIHash, TSHA1))
|
|
|
|
|
+{$ELSE} (Fdigest.GetUnderlyingIHash is TSHA1) {$ENDIF FPC}) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EInvalidParameterCryptoLibException.CreateRes(@SUnsupportedDigest);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ while True do
|
|
|
|
|
+ begin
|
|
|
|
|
+ Frandom.NextBytes(seed);
|
|
|
|
|
+
|
|
|
|
|
+ Hash(Fdigest, seed, part1, 0);
|
|
|
|
|
+ System.Move(seed[0], part2[0], System.Length(seed) * System.SizeOf(Byte));
|
|
|
|
|
+ Inc(part2);
|
|
|
|
|
+ Hash(Fdigest, part2, part2, 0);
|
|
|
|
|
+
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ while i <> System.Length(U) do
|
|
|
|
|
+ begin
|
|
|
|
|
+ U[i] := Byte(part1[i] xor part2[i]);
|
|
|
|
|
+ System.Inc(i);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ U[0] := U[0] or Byte($80);
|
|
|
|
|
+ U[19] := U[19] or Byte($01);
|
|
|
|
|
+
|
|
|
|
|
+ q := TBigInteger.Create(1, U);
|
|
|
|
|
+
|
|
|
|
|
+ if (not IsProbablePrime(q)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ continue;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ offset := System.Copy(seed);
|
|
|
|
|
+ Inc(offset);
|
|
|
|
|
+ counter := 0;
|
|
|
|
|
+ while counter < 4096 do
|
|
|
|
|
+ begin
|
|
|
|
|
+
|
|
|
|
|
+ k := 1;
|
|
|
|
|
+ while k <= n do
|
|
|
|
|
+ begin
|
|
|
|
|
+ Inc(offset);
|
|
|
|
|
+ Hash(Fdigest, offset, W, System.Length(W) - (k * System.Length(part1)));
|
|
|
|
|
+ System.Inc(k);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ remaining := System.Length(W) - (n * System.Length(part1));
|
|
|
|
|
+ Inc(offset);
|
|
|
|
|
+ Hash(Fdigest, offset, part1, 0);
|
|
|
|
|
+ System.Move(part1[System.Length(part1) - remaining], W[0], remaining);
|
|
|
|
|
+
|
|
|
|
|
+ W[0] := W[0] or Byte($80);
|
|
|
|
|
+
|
|
|
|
|
+ x := TBigInteger.Create(1, W);
|
|
|
|
|
+
|
|
|
|
|
+ c := x.&Mod(q.ShiftLeft(1));
|
|
|
|
|
+
|
|
|
|
|
+ p := x.subtract(c.subtract(TBigInteger.One));
|
|
|
|
|
+
|
|
|
|
|
+ if (p.BitLength <> FL) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ System.Inc(counter);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ if (IsProbablePrime(p)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ g := CalculateGenerator_FIPS186_2(p, q, Frandom);
|
|
|
|
|
+
|
|
|
|
|
+ result := TDsaParameters.Create(p, q, g,
|
|
|
|
|
+ TDsaValidationParameters.Create(seed, counter)
|
|
|
|
|
+ as IDsaValidationParameters);
|
|
|
|
|
+ Exit;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ System.Inc(counter);
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+function TDsaParametersGenerator.GenerateParameters_FIPS186_3: IDsaParameters;
|
|
|
|
|
+var
|
|
|
|
|
+ d: IDigest;
|
|
|
|
|
+ outlen, seedlen, n, { b, } counterLimit, counter, j, remaining: Int32;
|
|
|
|
|
+ seed, W, output, offset: TCryptoLibByteArray;
|
|
|
|
|
+ U, q, x, c, p, g: TBigInteger;
|
|
|
|
|
+begin
|
|
|
|
|
+ result := Nil;
|
|
|
|
|
+ // A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
|
|
|
|
|
+ // TODO FIXME This should be configurable (digest size in bits must be >= N)
|
|
|
|
|
+ d := Fdigest;
|
|
|
|
|
+ outlen := d.GetDigestSize() * 8;
|
|
|
|
|
+
|
|
|
|
|
+ // 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
|
|
|
|
|
+ // the pair is not in the list, then return INVALID.
|
|
|
|
|
+ // Note: checked at initialisation
|
|
|
|
|
+
|
|
|
|
|
+ // 2. If (seedlen < N), then return INVALID.
|
|
|
|
|
+ // TODO FIXME This should be configurable (must be >= N)
|
|
|
|
|
+ seedlen := FN;
|
|
|
|
|
+ System.SetLength(seed, seedlen div 8);
|
|
|
|
|
+
|
|
|
|
|
+ // 3. n = ceiling(L / outlen) - 1.
|
|
|
|
|
+ n := (FL - 1) div outlen;
|
|
|
|
|
+
|
|
|
|
|
+ // 4. b = L - 1 - (n * outlen).
|
|
|
|
|
+ // b := (FL - 1) mod outlen;
|
|
|
|
|
+
|
|
|
|
|
+ System.SetLength(W, FL div 8);
|
|
|
|
|
+
|
|
|
|
|
+ System.SetLength(output, d.GetDigestSize());
|
|
|
|
|
+
|
|
|
|
|
+ while True do
|
|
|
|
|
+ begin
|
|
|
|
|
+ // 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
|
|
|
|
|
+ Frandom.NextBytes(seed);
|
|
|
|
|
+
|
|
|
|
|
+ // 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
|
|
|
|
|
+ Hash(d, seed, output, 0);
|
|
|
|
|
+
|
|
|
|
|
+ U := TBigInteger.Create(1, output).&Mod(TBigInteger.One.ShiftLeft(FN - 1));
|
|
|
|
|
+
|
|
|
|
|
+ // 7. q = 2^(N–1) + U + 1 – ( U mod 2).
|
|
|
|
|
+ q := U.SetBit(0).SetBit(FN - 1);
|
|
|
|
|
+
|
|
|
|
|
+ // 8. Test whether or not q is prime as specified in Appendix C.3.
|
|
|
|
|
+ if (not IsProbablePrime(q)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ // 9. If q is not a prime, then go to step 5.
|
|
|
|
|
+ continue;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ // 10. offset = 1.
|
|
|
|
|
+ // Note: 'offset' value managed incrementally
|
|
|
|
|
+ offset := System.Copy(seed);
|
|
|
|
|
+
|
|
|
|
|
+ // 11. For counter = 0 to (4L – 1) do
|
|
|
|
|
+ counterLimit := 4 * FL;
|
|
|
|
|
+ counter := 0;
|
|
|
|
|
+ while counter < counterLimit do
|
|
|
|
|
+ begin
|
|
|
|
|
+ // 11.1 For j = 0 to n do
|
|
|
|
|
+ // Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
|
|
|
|
|
+ // 11.2 W = V0 + (V1 * 2^outlen) + ... + (V^(n–1) * 2^((n–1) * outlen)) + ((Vn mod 2^b) * 2^(n * outlen)).
|
|
|
|
|
+
|
|
|
|
|
+ j := 1;
|
|
|
|
|
+ while j <= n do
|
|
|
|
|
+ begin
|
|
|
|
|
+ Inc(offset);
|
|
|
|
|
+ Hash(d, offset, W, System.Length(W) - (j * System.Length(output)));
|
|
|
|
|
+ System.Inc(j);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ remaining := System.Length(W) - (n * System.Length(output));
|
|
|
|
|
+ Inc(offset);
|
|
|
|
|
+ Hash(d, offset, output, 0);
|
|
|
|
|
+ System.Move(output[System.Length(output) - remaining], W[0], remaining);
|
|
|
|
|
+
|
|
|
|
|
+ // 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2^(L–1); hence, 2^(L–1) ≤ X < 2^L.
|
|
|
|
|
+ W[0] := W[0] or Byte($80);
|
|
|
|
|
+
|
|
|
|
|
+ x := TBigInteger.Create(1, W);
|
|
|
|
|
+
|
|
|
|
|
+ // 11.4 c = X mod 2q.
|
|
|
|
|
+ c := x.&Mod(q.ShiftLeft(1));
|
|
|
|
|
+
|
|
|
|
|
+ // 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
|
|
|
|
|
+ p := x.subtract(c.subtract(TBigInteger.One));
|
|
|
|
|
+
|
|
|
|
|
+ // 11.6 If (p < 2^(L-1)), then go to step 11.9
|
|
|
|
|
+ if (p.BitLength <> FL) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ System.Inc(counter);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ // 11.7 Test whether or not p is prime as specified in Appendix C.3.
|
|
|
|
|
+ if (IsProbablePrime(p)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ // 11.8 If p is determined to be prime, then return VALID and the values of p, q and
|
|
|
|
|
+ // (optionally) the values of domain_parameter_seed and counter.
|
|
|
|
|
+ if (FusageIndex >= 0) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ g := CalculateGenerator_FIPS186_3_Verifiable(d, p, q, seed,
|
|
|
|
|
+ FusageIndex);
|
|
|
|
|
+ if (g.IsInitialized) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := TDsaParameters.Create(p, q, g,
|
|
|
|
|
+ TDsaValidationParameters.Create(seed, counter, FusageIndex)
|
|
|
|
|
+ as IDsaValidationParameters);
|
|
|
|
|
+ Exit;
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ g := CalculateGenerator_FIPS186_3_Unverifiable(p, q, Frandom);
|
|
|
|
|
+
|
|
|
|
|
+ result := TDsaParameters.Create(p, q, g,
|
|
|
|
|
+ TDsaValidationParameters.Create(seed, counter)
|
|
|
|
|
+ as IDsaValidationParameters);
|
|
|
|
|
+ Exit;
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ // 11.9 offset = offset + n + 1. Comment: Increment offset; then, as part of
|
|
|
|
|
+ // the loop in step 11, increment counter; if
|
|
|
|
|
+ // counter < 4L, repeat steps 11.1 through 11.8.
|
|
|
|
|
+ // Note: 'offset' value already incremented in inner loop
|
|
|
|
|
+ System.Inc(counter);
|
|
|
|
|
+ end;
|
|
|
|
|
+ // 12. Go to step 5.
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+function TDsaParametersGenerator.GenerateParameters: IDsaParameters;
|
|
|
|
|
+begin
|
|
|
|
|
+ if Fuse186_3 then
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := GenerateParameters_FIPS186_3()
|
|
|
|
|
+ end
|
|
|
|
|
+ else
|
|
|
|
|
+ begin
|
|
|
|
|
+ result := GenerateParameters_FIPS186_2();
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+constructor TDsaParametersGenerator.Create(const digest: IDigest);
|
|
|
|
|
+begin
|
|
|
|
|
+ Inherited Create();
|
|
|
|
|
+ Fdigest := digest;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TDsaParametersGenerator.Init(size, certainty: Int32;
|
|
|
|
|
+ const random: ISecureRandom);
|
|
|
|
|
+begin
|
|
|
|
|
+ Init(size, certainty, Max(GetMinimumIterations(size),
|
|
|
|
|
+ (certainty + 1) div 2), random);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TDsaParametersGenerator.Init(size, certainty, iterations: Int32;
|
|
|
|
|
+ const random: ISecureRandom);
|
|
|
|
|
+begin
|
|
|
|
|
+ if (not IsValidDsaStrength(size)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EArgumentCryptoLibException.CreateResFmt(@SInvalidDsaKeyStrength,
|
|
|
|
|
+ [512, 1024, 64, size]);
|
|
|
|
|
+ end;
|
|
|
|
|
+ FL := size;
|
|
|
|
|
+ FN := GetDefaultN(size);
|
|
|
|
|
+ Fcertainty := certainty;
|
|
|
|
|
+ Fiterations := iterations;
|
|
|
|
|
+ Frandom := random;
|
|
|
|
|
+ Fuse186_3 := false;
|
|
|
|
|
+ FusageIndex := -1;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TDsaParametersGenerator.Init(const params
|
|
|
|
|
+ : IDsaParameterGenerationParameters);
|
|
|
|
|
+var
|
|
|
|
|
+ L, n: Int32;
|
|
|
|
|
+begin
|
|
|
|
|
+ L := params.L;
|
|
|
|
|
+ n := params.n;
|
|
|
|
|
+
|
|
|
|
|
+ // if (((L < 1024) or (L > 3072)) or ((L mod 1024) <> 0))
|
|
|
|
|
+ if (((L < 1024) or (L > 3072)) or ((L and 1023) <> 0)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EInvalidParameterCryptoLibException.CreateRes(@SInvalidLValue);
|
|
|
|
|
+ end
|
|
|
|
|
+ else if ((L = 1024) and (n <> 160)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EInvalidParameterCryptoLibException.CreateResFmt
|
|
|
|
|
+ (@SInvalidNValueForSpecifiedL, [160, 1024]);
|
|
|
|
|
+ end
|
|
|
|
|
+ else if ((L = 2048) and ((n <> 224) and (n <> 256))) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EInvalidParameterCryptoLibException.CreateResFmt
|
|
|
|
|
+ (@SInvalidNValueForSpecifiedL_Two, [224, 256, 2048]);
|
|
|
|
|
+ end
|
|
|
|
|
+ else if ((L = 3072) and (n <> 256)) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EInvalidParameterCryptoLibException.CreateResFmt
|
|
|
|
|
+ (@SInvalidNValueForSpecifiedL, [256, 3072]);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ if ((Fdigest.GetDigestSize * 8) < n) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ raise EInvalidParameterCryptoLibException.CreateResFmt
|
|
|
|
|
+ (@SDigestOutputSizeTooSmallForN, [n]);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ FL := L;
|
|
|
|
|
+ FN := n;
|
|
|
|
|
+ Fcertainty := params.certainty;
|
|
|
|
|
+ Fiterations := Max(GetMinimumIterations(L), (Fcertainty + 1) div 2);
|
|
|
|
|
+ Frandom := params.random;
|
|
|
|
|
+ Fuse186_3 := True;
|
|
|
|
|
+ FusageIndex := params.UsageIndex;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+end.
|