unit IdFIPS;

interface

{$I IdCompilerDefines.inc}

{
  IMPORTANT!!!

  This unit does not directly provide FIPS support.  It centalizes some Indy
  encryption functions and exposes a function to get and set a FIPS mode that is
  implemented by the library that hooks this unit.

  The idea is that Indy will not have a FIPS certification per se but will be
  able to utilize cryptographic modules that are FIPS complient.

  In addition, this unit provides a way of centralizing all hashing and HMAC
  functions and to control dependancies in Indy.
}
uses
  IdException, IdGlobal
  {$IFDEF DOTNET}
  , System.Security.Cryptography
  {$ENDIF}
  ;

type
{$IFDEF DOTNET}
  TIdHashIntCtx = System.Security.Cryptography.HashAlgorithm;
  TIdHMACIntCtx = System.Security.Cryptography.HMAC;
{$ELSE}
  TIdHashIntCtx = Pointer;
  TIdHMACIntCtx = Pointer;
{$ENDIF}

  EIdFIPSAlgorithmNotAllowed = class(EIdException);
  TGetFIPSMode = function: Boolean;
  TSetFIPSMode = function(const AMode: Boolean): Boolean;
  TIsHashingIntfAvail = function: Boolean;
  TGetHashInst = function: TIdHashIntCtx;
  TUpdateHashInst = procedure(ACtx: TIdHashIntCtx; const AIn: TIdBytes);
  TFinalHashInst = function(ACtx: TIdHashIntCtx): TIdBytes;
  TIsHMACAvail = function : Boolean;
  TIsHMACIntfAvail = function : Boolean;
  TGetHMACInst = function (const AKey : TIdBytes) : TIdHMACIntCtx;
  TUpdateHMACInst = procedure(ACtx : TIdHMACIntCtx; const AIn: TIdBytes);
  TFinalHMACInst = function(ACtx: TIdHMACIntCtx): TIdBytes;

var
  GetFIPSMode: TGetFIPSMode;
  SetFIPSMode: TSetFIPSMode;
  IsHashingIntfAvail: TIsHashingIntfAvail;
  GetMD2HashInst: TGetHashInst;
  IsMD2HashIntfAvail: TIsHashingIntfAvail;
  GetMD4HashInst: TGetHashInst;
  IsMD4HashIntfAvail: TIsHashingIntfAvail;
  GetMD5HashInst: TGetHashInst;
  IsMD5HashIntfAvail: TIsHashingIntfAvail;
  GetSHA1HashInst: TGetHashInst;
  IsSHA1HashIntfAvail: TIsHashingIntfAvail;
  GetSHA224HashInst: TGetHashInst;
  IsSHA224HashIntfAvail: TIsHashingIntfAvail;
  GetSHA256HashInst: TGetHashInst;
  IsSHA256HashIntfAvail: TIsHashingIntfAvail;
  GetSHA384HashInst: TGetHashInst;
  IsSHA384HashIntfAvail: TIsHashingIntfAvail;
  GetSHA512HashInst: TGetHashInst;
  IsSHA512HashIntfAvail: TIsHashingIntfAvail;
  UpdateHashInst: TUpdateHashInst;
  FinalHashInst: TFinalHashInst;
  IsHMACAvail : TIsHMACAvail;
  IsHMACMD5Avail : TIsHMACIntfAvail;
  GetHMACMD5HashInst: TGetHMACInst;
  IsHMACSHA1Avail  : TIsHMACIntfAvail;
  GetHMACSHA1HashInst: TGetHMACInst;
  IsHMACSHA224Avail : TIsHMACIntfAvail;
  GetHMACSHA224HashInst: TGetHMACInst;
  IsHMACSHA256Avail : TIsHMACIntfAvail;
  GetHMACSHA256HashInst: TGetHMACInst;
  IsHMACSHA384Avail : TIsHMACIntfAvail;
  GetHMACSHA384HashInst: TGetHMACInst;
  IsHMACSHA512Avail : TIsHMACIntfAvail;
  GetHMACSHA512HashInst: TGetHMACInst;
  UpdateHMACInst : TUpdateHMACInst;
  FinalHMACInst : TFinalHMACInst;

  procedure CheckMD2Permitted;
  procedure CheckMD4Permitted;
  procedure CheckMD5Permitted;
  procedure FIPSAlgorithmNotAllowed(const AAlgorithm: String);

implementation

uses
  IdResourceStringsProtocols, SysUtils;

// TODO: for .NET, implement functions that use .NET Hash/HMAC classes

procedure CheckMD2Permitted; {$IFDEF USE_INLINE} inline; {$ENDIF}
begin
  if GetFIPSMode then begin
    FIPSAlgorithmNotAllowed('MD2');
  end;
end;

procedure CheckMD4Permitted; {$IFDEF USE_INLINE} inline; {$ENDIF}
begin
  if GetFIPSMode then begin
    FIPSAlgorithmNotAllowed('MD4');
  end;
end;

procedure CheckMD5Permitted; {$IFDEF USE_INLINE} inline; {$ENDIF}
begin
  if GetFIPSMode then begin
    FIPSAlgorithmNotAllowed('MD5');
  end;
end;

procedure FIPSAlgorithmNotAllowed(const AAlgorithm: String);
{$IFDEF USE_INLINE} inline; {$ENDIF}
begin
  raise EIdFIPSAlgorithmNotAllowed.Create(Format(RSFIPSAlgorithmNotAllowed,
      [AAlgorithm]));
end;

// fips mode default procs
function DefGetFIPSMode: Boolean;
begin
  Result := False;
end;

function DefSetFIPSMode(const AMode: Boolean): Boolean;
begin
  // leave this empty as we may not be using something that supports FIPS
  Result := False;
end;

function DefIsHashingIntfAvail: Boolean;
begin
  Result := False;
end;

function DefIsHashIntfAvail: Boolean;
begin
  Result := False;
end;

function DefGetHashInst : TIdHashIntCtx;
begin
  Result := nil;
end;

procedure DefUpdateHashInst(ACtx: TIdHashIntCtx; const AIn: TIdBytes);
begin
end;

function DefFinalHashInst(ACtx: TIdHashIntCtx): TIdBytes;
begin
  SetLength(Result, 0);
end;

function DefIsHMACAvail : Boolean;
begin
  Result := False;
end;

function DefIsHMACIntfAvail: Boolean;
begin
  Result := False;
end;

function DefGetHMACInst(const AKey : TIdBytes) : TIdHMACIntCtx;
begin
  Result := nil;
end;

procedure DefUpdateHMACInst(ACtx : TIdHMACIntCtx; const AIn: TIdBytes);
begin
end;

function DefFinalHMACInst(ACtx: TIdHMACIntCtx): TIdBytes;
begin
  SetLength(Result, 0);
end;

initialization

  GetFIPSMode := DefGetFIPSMode;
  SetFIPSMode := DefSetFIPSMode;

  IsHashingIntfAvail := DefIsHashingIntfAvail;

  IsMD2HashIntfAvail := DefIsHashIntfAvail;
  GetMD2HashInst := DefGetHashInst;
  IsMD4HashIntfAvail := DefIsHashIntfAvail;
  GetMD4HashInst := DefGetHashInst;
  IsMD5HashIntfAvail := DefIsHashIntfAvail;
  GetMD5HashInst := DefGetHashInst;
  IsSHA1HashIntfAvail := DefIsHashIntfAvail;
  GetSHA1HashInst := DefGetHashInst;
  IsSHA224HashIntfAvail := DefIsHashIntfAvail;
  GetSHA224HashInst := DefGetHashInst;

  IsSHA256HashIntfAvail := DefIsHashIntfAvail;
  GetSHA256HashInst := DefGetHashInst;
  IsSHA384HashIntfAvail := DefIsHashIntfAvail;
  GetSHA384HashInst := DefGetHashInst;
  IsSHA512HashIntfAvail := DefIsHashIntfAvail;
  GetSHA512HashInst := DefGetHashInst;
  UpdateHashInst := DefUpdateHashInst;
  FinalHashInst := DefFinalHashInst;
  IsHMACAvail := DefIsHMACAvail;
  IsHMACMD5Avail := DefIsHMACIntfAvail;
  GetHMACMD5HashInst := DefGetHMACInst;
  IsHMACSHA1Avail  := DefIsHMACIntfAvail;
  GetHMACSHA1HashInst := DefGetHMACInst;
  IsHMACSHA224Avail  := DefIsHMACIntfAvail;
  GetHMACSHA224HashInst := DefGetHMACInst;
  IsHMACSHA256Avail  :=  DefIsHMACIntfAvail;
  GetHMACSHA256HashInst := DefGetHMACInst;
  IsHMACSHA384Avail  := DefIsHMACIntfAvail;
  GetHMACSHA384HashInst := DefGetHMACInst;
  IsHMACSHA512Avail  := DefIsHMACIntfAvail;
  GetHMACSHA512HashInst := DefGetHMACInst;

  UpdateHMACInst := DefUpdateHMACInst;
  FinalHMACInst := DefFinalHMACInst;

end.
