Ugochukwu Mmaduekwe 3 недель назад
Родитель
Сommit
892acab7ad

+ 3 - 0
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -428,6 +428,8 @@ uses
   ClpPssSigner in '..\..\CryptoLib\src\Crypto\Signers\ClpPssSigner.pas',
   ClpIGenericSigner in '..\..\CryptoLib\src\Interfaces\ClpIGenericSigner.pas',
   ClpGenericSigner in '..\..\CryptoLib\src\Crypto\Signers\ClpGenericSigner.pas',
+  ClpIsoTrailers in '..\..\CryptoLib\src\Crypto\Signers\ClpIsoTrailers.pas',
+  ClpX931Signer in '..\..\CryptoLib\src\Crypto\Signers\ClpX931Signer.pas',
   ClpIPrehash in '..\..\CryptoLib\src\Interfaces\ClpIPrehash.pas',
   ClpPrehash in '..\..\CryptoLib\src\Crypto\Digests\ClpPrehash.pas',
   ClpX509Asn1Objects in '..\..\CryptoLib\src\Asn1\X509\ClpX509Asn1Objects.pas',
@@ -596,6 +598,7 @@ uses
   PemReaderTests in '..\src\Utils\Pem\PemReaderTests.pas',
   CertificateTests in '..\src\Asn1\X509\CertificateTests.pas',
   DeltaCertificateTests in '..\src\Asn1\X509\DeltaCertificateTests.pas',
+  X931SignerTests in '..\src\Crypto\X931SignerTests.pas',
   CryptoLibTestBase in '..\src\CryptoLibTestBase.pas';
 
 begin

+ 250 - 0
CryptoLib.Tests/src/Crypto/X931SignerTests.pas

@@ -0,0 +1,250 @@
+{ *********************************************************************************** }
+{ *                              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 X931SignerTests;
+
+interface
+
+{$IFDEF FPC}
+{$MODE DELPHI}
+{$ENDIF FPC}
+
+uses
+  SysUtils,
+{$IFDEF FPC}
+  fpcunit,
+  testregistry,
+{$ELSE}
+  TestFramework,
+{$ENDIF FPC}
+  ClpBigInteger,
+  ClpIRsaKeyParameters,
+  ClpRsaKeyParameters,
+  ClpIRsaPrivateCrtKeyParameters,
+  ClpRsaPrivateCrtKeyParameters,
+  ClpRsaEngine,
+  ClpIRsaEngine,
+  ClpX931Signer,
+  ClpDigestUtilities,
+  ClpIDigest,
+  ClpISigner,
+  ClpEncoders,
+  ClpArrayUtils,
+  ClpCryptoLibTypes,
+  CryptoLibTestBase;
+
+type
+
+  TTestX931Signer = class(TCryptoLibAlgorithmTestCase)
+  private
+    procedure ShouldPassSignatureTest1;
+    procedure ShouldPassSignatureTest2;
+    procedure ShouldPassSignatureTest3;
+
+  published
+    procedure TestX931Signer;
+
+  end;
+
+implementation
+
+{ TTestX931Signer }
+
+procedure TTestX931Signer.TestX931Signer;
+var
+  LRsaPubMod, LRsaPubExp, LRsaPrivMod, LRsaPrivDP, LRsaPrivDQ, LRsaPrivExp,
+    LRsaPrivP, LRsaPrivQ, LRsaPrivQinv: TBigInteger;
+  LRsaPublic: IRsaKeyParameters;
+  LRsaPrivate: IRsaPrivateCrtKeyParameters;
+  LMsg, LSig: TCryptoLibByteArray;
+  LSigner: IX931Signer;
+begin
+  LRsaPubMod := TBigInteger.Create(TBase64.Decode('AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt'));
+  LRsaPubExp := TBigInteger.Create(TBase64.Decode('EQ=='));
+  LRsaPrivMod := TBigInteger.Create(TBase64.Decode('AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt'));
+  LRsaPrivDP := TBigInteger.Create(TBase64.Decode('JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ=='));
+  LRsaPrivDQ := TBigInteger.Create(TBase64.Decode('YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ=='));
+  LRsaPrivExp := TBigInteger.Create(TBase64.Decode('DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E='));
+  LRsaPrivP := TBigInteger.Create(TBase64.Decode('AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE='));
+  LRsaPrivQ := TBigInteger.Create(TBase64.Decode('AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0='));
+  LRsaPrivQinv := TBigInteger.Create(TBase64.Decode('Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg=='));
+
+  LRsaPublic := TRsaKeyParameters.Create(False, LRsaPubMod, LRsaPubExp);
+  LRsaPrivate := TRsaPrivateCrtKeyParameters.Create(LRsaPrivMod, LRsaPubExp,
+    LRsaPrivExp, LRsaPrivP, LRsaPrivQ, LRsaPrivDP, LRsaPrivDQ, LRsaPrivQinv);
+
+  LMsg := TCryptoLibByteArray.Create(1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23);
+
+  LSigner := TX931Signer.Create(TRsaEngine.Create() as IRsaEngine,
+    TDigestUtilities.GetDigest('SHA-1'));
+  LSigner.Init(True, LRsaPrivate);
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+  LSig := LSigner.GenerateSignature();
+
+  LSigner := TX931Signer.Create(TRsaEngine.Create() as IRsaEngine,
+    TDigestUtilities.GetDigest('SHA-1'));
+  LSigner.Init(False, LRsaPublic);
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+  CheckTrue(LSigner.VerifySignature(LSig), 'X9.31 Signer failed.');
+
+  ShouldPassSignatureTest1();
+  ShouldPassSignatureTest2();
+  ShouldPassSignatureTest3();
+end;
+
+procedure TTestX931Signer.ShouldPassSignatureTest1;
+var
+  LN, LE: TBigInteger;
+  LMsg, LSig: TCryptoLibByteArray;
+  LRsaPublic: IRsaKeyParameters;
+  LSigner: IX931Signer;
+begin
+  LN := TBigInteger.Create(
+  'c9be1b28f8caccca65d86cc3c9bbcc13eccc059df3b80bd2292b811eff3aa0dd75e1e85c333b8e3fa9bed53bb20f5359ff4e' +
+  '6900c5e9a388e3a4772a583a79e2299c76582c2b27694b65e9ba22e66bfb817f8b70b22206d7d8ae488c86dbb7137c26d5ef' +
+  'f9b33c90e6cee640630313b7a715802e15142fef498c404a8de19674974785f0f852e2d470fe85a2e54ffca9f5851f672b71' +
+  'df691785a5cdabe8f14aa628942147de7593b2cf962414a5b59c632c4e14f1768c0ab2e9250824beea60a3529f11bf5e070c' +
+  'e90a47686eb0be1086fb21f0827f55295b4a48307db0b048c05a4aec3f488c576ca6f1879d354224c7e84cbcd8e76dd217a3' +
+  'de54dba73c35', 16);
+
+  LE := TBigInteger.Create('e75b1b', 16);
+
+  LMsg := THex.Decode(
+  '5bb0d1c0ef9b5c7af2477fe08d45523d3842a4b2db943f7033126c2a7829bacb3d2cfc6497ec91688189e81b7f8742488224' +
+  'ba320ce983ce9480722f2cc5bc42611f00bb6311884f660ccc244788378673532edb05284fd92e83f6f6dab406209032e6af' +
+  '9a33c998677933e32d6fb95fd27408940d7728f9c9c40267ca1d20ce');
+
+  LSig := THex.Decode(
+  '0fe8bb8e3109a1eb7489ef35bf4c1a0780071da789c8bd226a4170538eafefdd30b732d628f0e87a0b9450051feae9754d4f' +
+  'b61f57862d10f0bacc4f660d13281d0cd1141c006ade5186ff7d961a4c6cd0a4b352fc1295c5afd088f80ac1f8e192ef116a' +
+  '010a442655fe8ff5eeacea15807906fb0f0dfa86e680d4c005872357f7ece9aa4e20b15d5f709b30f08648ecaa34f2fbf54e' +
+  'b6b414fa2ff6f87561f70163235e69ccb4ac82a2e46d3be214cc2ef5263b569b2d8fd839b21a9e102665105ea762bda25bb4' +
+  '46cfd831487a6b846100dee113ae95ae64f4af22c428c87bab809541c962bb3a56d4c86588e0af4ebc7fcc66dadced311051' +
+  '356d3ea745f7');
+
+  LRsaPublic := TRsaKeyParameters.Create(False, LN, LE);
+  LSigner := TX931Signer.Create(TRsaEngine.Create() as IRsaEngine,
+    TDigestUtilities.GetDigest('SHA-1'));
+
+  LSigner.Init(False, LRsaPublic);
+
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+
+  CheckTrue(LSigner.VerifySignature(LSig), 'RSA X931 verify test 1 failed.');
+end;
+
+procedure TTestX931Signer.ShouldPassSignatureTest2;
+var
+  LN, LE: TBigInteger;
+  LMsg, LSig: TCryptoLibByteArray;
+  LRsaPublic: IRsaKeyParameters;
+  LSigner: IX931Signer;
+begin
+  LN := TBigInteger.Create(
+  'b746ba6c3c0be64bbe33aa55b2929b0af4e86d773d44bfe5914db9287788c4663984b61a418d2eecca30d752ff6b620a07ec' +
+  '72eeb2b422d2429da352407b99982800b9dd7697be6a7b1baa98ca5f4fc2fe33400f20b9dba337ac25c987804165d4a6e0ee' +
+  '4d18eabd6de5abdfe578cae6713ff91d16c80a5bb20217fe614d9509e75a43e1825327b9da8f0a9f6eeaa1c04b69fb4bacc0' +
+  '73569fff4ab491becbe6d0441d437fc3fa823239c4a0f75321666b68dd3f66e2dd394089a15bcc288a68a4eb0a48e17d6397' +
+  '43b9dea0a91cc35820544732aff253f8ca9967c609dc01c2f8cd0313a7a91cfa94ff74289a1d2b6f19d1811f4b9a65f4cce9' +
+  'e5759b4cc64f', 16);
+
+  LE := TBigInteger.Create('dcbbdb', 16);
+  LMsg := THex.Decode('a5d3c8a060f897bbbc20ae0955052f37fbc70986b6e11c65075c9f457142bfa93856897c69020aa81a91b5e4f39e05cdeecc' +
+  '63395ab849c8262ca8bc5c96870aecb8edb0aba0024a9bdb71e06de6100344e5c318bc979ef32b8a49a8278ba99d4861bce4' +
+  '2ebbc5c8c666aaa6cac39aff8779f2cae367620f9edd4cb1d80b6c8c');
+
+  LSig := THex.Decode(
+  '39fbbd1804c689a533b0043f84da0f06081038c0fbf31e443e46a05e58f50de5198bbca40522afefaba3aed7082a6cb93b1d' +
+  'a39f1f5a42246bf64930781948d300549bef0f8d554ecfca60a1b1ecba95a7014ee4545ad4f0c4e3a31942c6738b4ccd6244' +
+  'b6a21267dadf0826a5f713f13b1f5a9ab8501d957a26d4948278ac67851071a315674bdab173bfef2c2690c8373da6bf3d69' +
+  'f30c0e5da8883de872f59521b40793854085641adf98d13db991c5d0a8aaa0222934fa33332e90ef0b954e195cb267d6ffb3' +
+  '6c96e14d1ec7b915a87598b4461a3146566354dc2ae748c84ee0cd46543b53ebff8cdf47725b280a1f799fb6ebb4a31ad2bd' +
+  'd5178250f83a');
+
+  LRsaPublic := TRsaKeyParameters.Create(False, LN, LE);
+  LSigner := TX931Signer.Create(TRsaEngine.Create() as IRsaEngine,
+    TDigestUtilities.GetDigest('SHA-224'));
+
+  LSigner.Init(False, LRsaPublic);
+
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+
+  CheckTrue(LSigner.VerifySignature(LSig), 'RSA X931 verify test 2 failed.');
+end;
+
+procedure TTestX931Signer.ShouldPassSignatureTest3;
+var
+  LN, LE, LD: TBigInteger;
+  LMsg, LSig, LS: TCryptoLibByteArray;
+  LRsaPublic: IRsaKeyParameters;
+  LRsaPrivate: IRsaKeyParameters;
+  LSigner: IX931Signer;
+begin
+  LN := TBigInteger.Create(
+  'dcb5686a3d2063a3f9cf7b9b32d2d3765b4c449b09b4960245a9111cd3b0cbd3260496885b8e1fa5db33b03efcc759d9c1af' +
+  'e29d93c6faebc7e0efada334b5b9a29655e2da2c8f11103d8203be311feab7ae88e9f1b2ec7d8fc655d77202b1681dd9717e' +
+  'c0f525b35584987e19539635a1ed23ca482a00149c609a23dc1645fd', 16);
+
+  LE := TBigInteger.Create(
+  '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +
+  '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +
+  '000000000000000000000000000000000000000000000000000dc9f7', 16);
+
+  LD := TBigInteger.Create('189d6345099098992e0c9ca5f281e1338092342fa0acc85cc2a111f30f9bd2fb4753cd1a48ef0ddca9bf1af33ec76fb2e23a' +
+  '9fb4896c26f2235b516f7c05ef7ae81e70f4b491a5fedba9b935e9c76d761a813ce7776ff8a1e5efe1166ff2eca26aa900da' +
+  '88c908d51af9de26977fe39719cc781df32216fa41b838f0c63803c3'
+  , 16);
+
+  LMsg := THex.Decode('911475c6e210ef4ac65b6fe8d2bfe5e01b959771b137c4ef69b88716e0d2ff9ebc1fad0f358c1dd7d50cc99a7b893ac9a620' +
+  '7076f08d8467d9e48c69c683bfe64a44dabaa3f7c243880f6ab7229bf7bb587822314fc5de5131983bfb2eef8b4bc1eac36f' +
+  '353724b567cd1ae8cddd64ddb7057549d5c81ad5fa3b5e751f00abf5');
+
+  LSig := THex.Decode(
+  '02c50ec0ac8a7f38ef5630c396964d6a6daaa7e3083ab5b57fa2a2632f3b70e2e85c8456cd774d45d7e44fcb063f0f04fff9' +
+  'f1e3adfda11272535a92cb59320b190b5ee4261f23d6ceaa925df3a7bfa42e26bf61ea9645d9d64b3c90a820802768a6e209' +
+  'c9f83705375a3867afccc037e8242a98fa4c3db6b2d9877754d47289');
+
+  LRsaPublic := TRsaKeyParameters.Create(False, LN, LE);
+  LSigner := TX931Signer.Create(TRsaEngine.Create() as IRsaEngine,
+    TDigestUtilities.GetDigest('SHA-1'));
+
+  LRsaPrivate := TRsaKeyParameters.Create(True, LN, LD);
+
+  LSigner.Init(True, LRsaPrivate);
+
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+
+  LS := LSigner.GenerateSignature();
+
+  CheckTrue(TArrayUtils.AreEqual(LSig, LS), 'RSA X931 sig test 3 failed.');
+
+  LSigner.Init(False, LRsaPublic);
+
+  LSigner.BlockUpdate(LMsg, 0, System.Length(LMsg));
+
+  CheckTrue(LSigner.VerifySignature(LSig), 'RSA X931 verify test 3 failed.');
+end;
+
+initialization
+
+{$IFDEF FPC}
+  RegisterTest(TTestX931Signer);
+{$ELSE}
+  RegisterTest(TTestX931Signer.Suite);
+{$ENDIF FPC}
+
+end.

+ 128 - 0
CryptoLib/src/Crypto/Signers/ClpIsoTrailers.pas

@@ -0,0 +1,128 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIsoTrailers;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  Generics.Collections,
+  ClpCryptoLibComparers,
+  ClpCryptoLibTypes,
+  ClpIDigest;
+
+type
+  /// <summary>
+  /// Utility class for ISO/IEC 10118 trailer values used in X9.31 and ISO9796-2 signing.
+  /// </summary>
+  TIsoTrailers = class sealed(TObject)
+
+  public
+  const
+    TRAILER_IMPLICIT = Int32($BC);
+    TRAILER_RIPEMD160 = Int32($31CC);
+    TRAILER_RIPEMD128 = Int32($32CC);
+    TRAILER_SHA1 = Int32($33CC);
+    TRAILER_SHA256 = Int32($34CC);
+    TRAILER_SHA512 = Int32($35CC);
+    TRAILER_SHA384 = Int32($36CC);
+    TRAILER_WHIRLPOOL = Int32($37CC);
+    TRAILER_SHA224 = Int32($38CC);
+    TRAILER_SHA512_224 = Int32($39CC);
+    TRAILER_SHA512_256 = Int32($40CC);
+
+  strict private
+  class var
+    FTrailerMap: TDictionary<String, Int32>;
+
+    class function CreateTrailerMap: TDictionary<String, Int32>; static;
+    class constructor Create;
+    class destructor Destroy;
+
+  public
+    /// <summary>
+    /// Get the trailer value for the specified digest.
+    /// </summary>
+    /// <param name="digest">The digest to get the trailer for.</param>
+    /// <returns>The trailer value.</returns>
+    /// <exception cref="EInvalidOperationCryptoLibException">If no trailer is available for the digest.</exception>
+    class function GetTrailer(const digest: IDigest): Int32; static;
+
+    /// <summary>
+    /// Check if a trailer is available for the specified digest.
+    /// </summary>
+    /// <param name="digest">The digest to check.</param>
+    /// <returns>True if no trailer is available, False otherwise.</returns>
+    class function NoTrailerAvailable(const digest: IDigest): Boolean; static;
+
+  end;
+
+implementation
+
+{ TIsoTrailers }
+
+class function TIsoTrailers.CreateTrailerMap: TDictionary<String, Int32>;
+begin
+  Result := TDictionary<String, Int32>.Create(TCryptoLibComparers.OrdinalIgnoreCaseEqualityComparer);
+
+  Result.Add('RIPEMD128', TRAILER_RIPEMD128);
+  Result.Add('RIPEMD160', TRAILER_RIPEMD160);
+
+  Result.Add('SHA-1', TRAILER_SHA1);
+  Result.Add('SHA-224', TRAILER_SHA224);
+  Result.Add('SHA-256', TRAILER_SHA256);
+  Result.Add('SHA-384', TRAILER_SHA384);
+  Result.Add('SHA-512', TRAILER_SHA512);
+  Result.Add('SHA-512/224', TRAILER_SHA512_224);
+  Result.Add('SHA-512/256', TRAILER_SHA512_256);
+
+  Result.Add('Whirlpool', TRAILER_WHIRLPOOL);
+end;
+
+class constructor TIsoTrailers.Create;
+begin
+  FTrailerMap := CreateTrailerMap;
+end;
+
+class destructor TIsoTrailers.Destroy;
+begin
+  FTrailerMap.Free;
+end;
+
+class function TIsoTrailers.GetTrailer(const digest: IDigest): Int32;
+var
+  LTrailer: Int32;
+begin
+  if FTrailerMap.TryGetValue(digest.AlgorithmName, LTrailer) then
+  begin
+    Result := LTrailer;
+  end
+  else
+  begin
+    raise EInvalidOperationCryptoLibException.Create('No trailer for digest');
+  end;
+end;
+
+class function TIsoTrailers.NoTrailerAvailable(const digest: IDigest): Boolean;
+begin
+  Result := not FTrailerMap.ContainsKey(digest.AlgorithmName);
+end;
+
+end.

+ 276 - 0
CryptoLib/src/Crypto/Signers/ClpX931Signer.pas

@@ -0,0 +1,276 @@
+{ *********************************************************************************** }
+{ *                              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 ClpX931Signer;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  SysUtils,
+  ClpICipherParameters,
+  ClpIAsymmetricBlockCipher,
+  ClpIDigest,
+  ClpISigner,
+  ClpIRsaKeyParameters,
+  ClpIsoTrailers,
+  ClpParameterUtilities,
+  ClpBigInteger,
+  ClpBigIntegers,
+  ClpArrayUtils,
+  ClpCryptoLibTypes;
+
+resourcestring
+  SNoValidTrailer = 'no valid trailer';
+
+type
+  /// <summary>
+  /// Interface for X9.31 signer.
+  /// </summary>
+  IX931Signer = interface(ISigner)
+    ['{B3C4D5E6-F7A8-9B0C-1D2E-3F4A5B6C7D8E}']
+  end;
+
+  /// <summary>
+  /// X9.31-1998 - signing using a hash.
+  /// <para>
+  /// The message digest hash, H, is encapsulated to form a byte string as follows
+  /// </para>
+  /// <pre>
+  /// EB = 06 || PS || 0xBA || H || TRAILER
+  /// </pre>
+  /// where PS is a string of bytes all of value 0xBB of length such that |EB|=|n|, and TRAILER is the ISO/IEC 10118 part number for the digest. The byte string, EB, is converted to an integer value, the message representative, f.
+  /// </summary>
+  TX931Signer = class(TInterfacedObject, ISigner, IX931Signer)
+
+  strict private
+  var
+    FDigest: IDigest;
+    FCipher: IAsymmetricBlockCipher;
+    FKParam: IRsaKeyParameters;
+    FTrailer: Int32;
+    FKeyBits: Int32;
+    FBlock: TCryptoLibByteArray;
+
+    procedure CreateSignatureBlock;
+
+  strict protected
+    function GetAlgorithmName: String;
+
+  public
+    /// <summary>
+    /// Constructor for a signer with an explicit digest trailer.
+    /// </summary>
+    /// <param name="ACipher">cipher to use.</param>
+    /// <param name="ADigest">digest to sign with.</param>
+    constructor Create(const ACipher: IAsymmetricBlockCipher;
+      const ADigest: IDigest); overload;
+
+    /// <summary>
+    /// Generate a signer with either implicit or explicit trailers for X9.31.
+    /// </summary>
+    /// <param name="ACipher">base cipher to use for signature creation/verification</param>
+    /// <param name="ADigest">digest to use.</param>
+    /// <param name="AIsImplicit">whether or not the trailer is implicit or gives the hash.</param>
+    constructor Create(const ACipher: IAsymmetricBlockCipher;
+      const ADigest: IDigest; AIsImplicit: Boolean); overload;
+
+    procedure Init(AForSigning: Boolean; const AParameters: ICipherParameters);
+    procedure Update(AInput: Byte);
+    procedure BlockUpdate(const AInput: TCryptoLibByteArray; AOffset, ALength: Int32);
+    function GetMaxSignatureSize: Int32;
+    function GenerateSignature: TCryptoLibByteArray;
+    function VerifySignature(const ASignature: TCryptoLibByteArray): Boolean;
+    procedure Reset;
+
+    property AlgorithmName: String read GetAlgorithmName;
+
+  end;
+
+implementation
+
+{ TX931Signer }
+
+constructor TX931Signer.Create(const ACipher: IAsymmetricBlockCipher;
+  const ADigest: IDigest);
+begin
+  Create(ACipher, ADigest, False);
+end;
+
+constructor TX931Signer.Create(const ACipher: IAsymmetricBlockCipher;
+  const ADigest: IDigest; AIsImplicit: Boolean);
+begin
+  inherited Create();
+  FCipher := ACipher;
+  FDigest := ADigest;
+
+  if AIsImplicit then
+  begin
+    FTrailer := TIsoTrailers.TRAILER_IMPLICIT;
+  end
+  else if TIsoTrailers.NoTrailerAvailable(ADigest) then
+  begin
+    raise EArgumentCryptoLibException.CreateRes(@SNoValidTrailer);
+  end
+  else
+  begin
+    FTrailer := TIsoTrailers.GetTrailer(ADigest);
+  end;
+end;
+
+function TX931Signer.GetAlgorithmName: String;
+begin
+  Result := FDigest.AlgorithmName + 'with' + FCipher.AlgorithmName + '/X9.31';
+end;
+
+procedure TX931Signer.Init(AForSigning: Boolean;
+  const AParameters: ICipherParameters);
+var
+  LKeyParams: ICipherParameters;
+begin
+  LKeyParams := TParameterUtilities.IgnoreRandom(AParameters);
+
+  if not Supports(LKeyParams, IRsaKeyParameters, FKParam) then
+  begin
+    raise EInvalidKeyCryptoLibException.Create('Expected RSA key parameter');
+  end;
+
+  FCipher.Init(AForSigning, AParameters);
+
+  FKeyBits := FKParam.Modulus.BitLength;
+
+  System.SetLength(FBlock, (FKeyBits + 7) div 8);
+
+  Reset();
+end;
+
+procedure TX931Signer.Update(AInput: Byte);
+begin
+  FDigest.Update(AInput);
+end;
+
+procedure TX931Signer.BlockUpdate(const AInput: TCryptoLibByteArray;
+  AOffset, ALength: Int32);
+begin
+  FDigest.BlockUpdate(AInput, AOffset, ALength);
+end;
+
+function TX931Signer.GetMaxSignatureSize: Int32;
+begin
+  Result := TBigIntegers.GetUnsignedByteLength(FKParam.Modulus);
+end;
+
+function TX931Signer.GenerateSignature: TCryptoLibByteArray;
+var
+  LSize: Int32;
+  LT: TBigInteger;
+begin
+  CreateSignatureBlock();
+
+  LT := TBigInteger.Create(1, FCipher.ProcessBlock(FBlock, 0,
+    System.Length(FBlock)));
+  TArrayUtils.Fill(FBlock, 0, System.Length(FBlock), Byte($00));
+
+  LT := LT.Min(FKParam.Modulus.Subtract(LT));
+
+  LSize := TBigIntegers.GetUnsignedByteLength(FKParam.Modulus);
+  Result := TBigIntegers.AsUnsignedByteArray(LSize, LT);
+end;
+
+function TX931Signer.VerifySignature(const ASignature: TCryptoLibByteArray): Boolean;
+var
+  LT, LF: TBigInteger;
+  LFBlock: TCryptoLibByteArray;
+  LRv: Boolean;
+begin
+  try
+    FBlock := FCipher.ProcessBlock(ASignature, 0, System.Length(ASignature));
+  except
+    Result := False;
+    Exit;
+  end;
+
+  LT := TBigInteger.Create(1, FBlock);
+
+  if ((LT.Int32Value and 15) = 12) then
+  begin
+    LF := LT;
+  end
+  else
+  begin
+    LT := FKParam.Modulus.Subtract(LT);
+    if ((LT.Int32Value and 15) = 12) then
+    begin
+      LF := LT;
+    end
+    else
+    begin
+      Result := False;
+      Exit;
+    end;
+  end;
+
+  CreateSignatureBlock();
+
+  System.SetLength(LFBlock, System.Length(FBlock));
+  LFBlock := TBigIntegers.AsUnsignedByteArray(System.Length(FBlock), LF);
+
+  LRv := TArrayUtils.ConstantTimeAreEqual(FBlock, LFBlock);
+
+  TArrayUtils.Fill(FBlock, 0, System.Length(FBlock), Byte($00));
+  TArrayUtils.Fill(LFBlock, 0, System.Length(LFBlock), Byte($00));
+
+  Result := LRv;
+end;
+
+procedure TX931Signer.Reset;
+begin
+  FDigest.Reset();
+end;
+
+procedure TX931Signer.CreateSignatureBlock;
+var
+  LDigSize, LDelta, I: Int32;
+begin
+  LDigSize := FDigest.GetDigestSize();
+
+  if FTrailer = TIsoTrailers.TRAILER_IMPLICIT then
+  begin
+    LDelta := System.Length(FBlock) - LDigSize - 1;
+    FDigest.DoFinal(FBlock, LDelta);
+    FBlock[System.Length(FBlock) - 1] := Byte(TIsoTrailers.TRAILER_IMPLICIT);
+  end
+  else
+  begin
+    LDelta := System.Length(FBlock) - LDigSize - 2;
+    FDigest.DoFinal(FBlock, LDelta);
+    FBlock[System.Length(FBlock) - 2] := Byte(FTrailer shr 8);
+    FBlock[System.Length(FBlock) - 1] := Byte(FTrailer);
+  end;
+
+  FBlock[0] := $6B;
+  I := LDelta - 2;
+  while I <> 0 do
+  begin
+    FBlock[I] := $BB;
+    System.Dec(I);
+  end;
+  FBlock[LDelta - 1] := $BA;
+end;
+
+end.

+ 26 - 46
CryptoLib/src/Security/ClpSignerUtilities.pas

@@ -30,6 +30,7 @@ uses
   ClpCryptoLibComparers,
   ClpECNRSigner,
   ClpICipherParameters,
+  ClpIAsymmetricBlockCipher,
   ClpIECNRSigner,
   ClpIDigest,
   ClpDigestUtilities,
@@ -69,6 +70,7 @@ uses
   ClpIPssSigner,
   ClpGenericSigner,
   ClpIGenericSigner,
+  ClpX931Signer,
   ClpRsaBlindedEngine,
   ClpIRsaBlindedEngine,
   ClpPkcs1Encoding,
@@ -864,8 +866,8 @@ var
   LDigest: IDigest;
   LWithPos, LEndPos: Int32;
   LCipherName: String;
-  // LX931: String;  // For X9.31 section (commented out)
-  // LCipher: IAsymmetricBlockCipher;  // For X9.31 section (commented out)
+  LX931: String;
+  LCipher: IAsymmetricBlockCipher;
 begin
   Result := nil;
 
@@ -958,50 +960,28 @@ begin
     Exit;
   end;
 
-  // Skip SM2, GOST3410, ECGOST3410, X9.31, MLDsa, SlhDsa as requested
-
-  // ISO9796-2 is not yet implemented
-  // if TPlatform.EndsWith(AMechanism, '/ISO9796-2') then
-  // begin
-  //   if AMechanism = 'SHA1WITHRSA/ISO9796-2' then
-  //   begin
-  //     Result := TIso9796d2Signer.Create(TRsaBlindedEngine.Create(), TDigestUtilities.GetDigest('SHA-1'), True);
-  //     Exit;
-  //   end;
-  //   if AMechanism = 'MD5WITHRSA/ISO9796-2' then
-  //   begin
-  //     Result := TIso9796d2Signer.Create(TRsaBlindedEngine.Create(), TDigestUtilities.GetDigest('MD5'), True);
-  //     Exit;
-  //   end;
-  //   if AMechanism = 'RIPEMD160WITHRSA/ISO9796-2' then
-  //   begin
-  //     Result := TIso9796d2Signer.Create(TRsaBlindedEngine.Create(), TDigestUtilities.GetDigest('RIPEMD160'), True);
-  //     Exit;
-  //   end;
-  // end;
-
-  // X9.31 section - commented out as requested
-  // if TPlatform.EndsWith(AMechanism, '/X9.31') then
-  // begin
-  //   LX931 := TPlatform.Substring(AMechanism, 1, System.Length(AMechanism) - System.Length('/X9.31'));
-  //   LWithPos := TPlatform.IndexOf(LX931, 'WITH');
-  //   if LWithPos > 0 then
-  //   begin
-  //     LEndPos := LWithPos + System.Length('WITH');
-  //
-  //     LCipherName := TPlatform.Substring(LX931, LEndPos, System.Length(LX931) - LEndPos + 1);
-  //     if LCipherName = 'RSA' then
-  //     begin
-  //       LCipher := TRsaBlindedEngine.Create();
-  //
-  //       LDigestName := TPlatform.Substring(LX931, 1, LWithPos - 1);
-  //       LDigest := TDigestUtilities.GetDigest(LDigestName);
-  //
-  //       Result := TX931Signer.Create(LCipher, LDigest);
-  //       Exit;
-  //     end;
-  //   end;
-  // end;
+  // X9.31 section
+  if TPlatform.EndsWith(AMechanism, '/X9.31') then
+  begin
+    LX931 := TPlatform.Substring(AMechanism, 1, System.Length(AMechanism) - System.Length('/X9.31'));
+    LWithPos := TPlatform.IndexOf(LX931, 'WITH');
+    if LWithPos > 0 then
+    begin
+      LEndPos := LWithPos + System.Length('WITH');
+
+      LCipherName := TPlatform.Substring(LX931, LEndPos, System.Length(LX931) - LEndPos + 1);
+      if LCipherName = 'RSA' then
+      begin
+        LCipher := TRsaBlindedEngine.Create();
+
+        LDigestName := TPlatform.Substring(LX931, 1, LWithPos - 1);
+        LDigest := TDigestUtilities.GetDigest(LDigestName);
+
+        Result := TX931Signer.Create(LCipher, LDigest);
+        Exit;
+      end;
+    end;
+  end;
 end;
 
 class function TSignerUtilities.InitSigner(const AAlgorithmOid: IDerObjectIdentifier;