| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 | //---------------------------------------------------------------------------#include <vcl.h>#pragma hdrstop// CompThread.pas must be linked to project#include <CompThread.hpp>#define THREAD_CLASS TCompThread#else#include <Classes.hpp>#define THREAD_CLASS TThread#endif#include <Common.h>#include "TextsCore.h"#include <PuttyIntf.h>#include "KeyGen.h"//---------------------------------------------------------------------------#pragma package(smart_init)//---------------------------------------------------------------------------extern "C" void KeyGenerationProgressUpdate(void * Thread,    int Action, int Phase, int IProgress);//---------------------------------------------------------------------------class TKeyGenerationThread : public THREAD_CLASS{public:  #define PROGRESSRANGE 65535  #define MAXPHASE 5  struct  {    int NPhases;    struct    {      bool Exponential;      unsigned StartPoint, Total;      unsigned Param, Current, N;   /* if exponential */      unsigned Mult;                    /* if linear */    } Phases[MAXPHASE];    unsigned Total, Divisor, Range;    unsigned Position;    TKeyGenerationComplete Complete;  } Progress;  TKeyGenerator * FGenerator;  __fastcall TKeyGenerationThread(TKeyGenerator * AGenerator):    THREAD_CLASS(true)  {    FGenerator = AGenerator;    Resume();  }  void __fastcall DistributeProgressUpdate()  {    FGenerator->ProgressUpdate(Progress.Range, Progress.Position, Progress.Complete);  }  void __fastcall ProgressUpdate(int Action, int Phase, unsigned IProgress)  {    int Position;    if (Action < PROGFN_READY && Progress.NPhases < Phase)        Progress.NPhases = Phase;    switch (Action)    {      case PROGFN_INITIALISE:        Progress.NPhases = 0;        Progress.Complete = kgInProgress;        break;      case PROGFN_LIN_PHASE:        Progress.Phases[Phase-1].Exponential = false;        Progress.Phases[Phase-1].Mult = Progress.Phases[Phase].Total / IProgress;        break;      case PROGFN_EXP_PHASE:        Progress.Phases[Phase-1].Exponential = true;        Progress.Phases[Phase-1].Param = 0x10000 + IProgress;        Progress.Phases[Phase-1].Current = Progress.Phases[Phase-1].Total;        Progress.Phases[Phase-1].N = 0;        break;      case PROGFN_PHASE_EXTENT:        Progress.Phases[Phase-1].Total = IProgress;        break;      case PROGFN_READY:        {          unsigned Total = 0;          int i;          for (i = 0; i < Progress.NPhases; i++)          {            Progress.Phases[i].StartPoint = Total;            Total += Progress.Phases[i].Total;          }          Progress.Total = Total;          Progress.Divisor = ((Progress.Total + PROGRESSRANGE - 1) / PROGRESSRANGE);          Progress.Range = Progress.Total / Progress.Divisor;          Synchronize(DistributeProgressUpdate);        }        break;      case PROGFN_PROGRESS:        if (Progress.Phases[Phase-1].Exponential)        {          while (Progress.Phases[Phase-1].N < IProgress)          {            Progress.Phases[Phase-1].N++;            Progress.Phases[Phase-1].Current *= Progress.Phases[Phase-1].Param;            Progress.Phases[Phase-1].Current /= 0x10000;          }          Position = (Progress.Phases[Phase-1].StartPoint +            Progress.Phases[Phase-1].Total - Progress.Phases[Phase-1].Current);        }        else        {          Position = (Progress.Phases[Phase-1].StartPoint +            IProgress * Progress.Phases[Phase-1].Mult);        }        Progress.Position = Position / Progress.Divisor;        Synchronize(DistributeProgressUpdate);        break;    }  }  virtual void __fastcall Execute()  {    try    {      ProgressUpdate(PROGFN_INITIALISE, 0, 0);      if (FGenerator->KeyType == ktDSA)      {        dsa_generate(FGenerator->FDSSKey, FGenerator->KeySize,          KeyGenerationProgressUpdate, this);      }      else      {        rsa_generate(FGenerator->FRSAKey, FGenerator->KeySize,          KeyGenerationProgressUpdate, this);      }      Progress.Complete = kgSuccess;    }    catch(...)    {      Progress.Complete = kgFailure;    }    Synchronize(DistributeProgressUpdate);  }#pragma warn +lvc};//---------------------------------------------------------------------------void KeyGenerationProgressUpdate(void * Thread,  int Action, int Phase, int IProgress){  DebugAssert(Thread);  ((TKeyGenerationThread*)Thread)->ProgressUpdate(Action, Phase, IProgress);}//---------------------------------------------------------------------------__fastcall TKeyGenerator::TKeyGenerator():  TObject(){  FSSH2Key = new ssh2_userkey;  FRSAKey = new RSAKey;  FDSSKey = new dss_key;  FEntropy = NULL;  FState = kgInitializing;  FOnGenerating = NULL;  FGenerationRange = -1;  KeyType = ktRSA2;  KeySize = 1024;}//---------------------------------------------------------------------------__fastcall TKeyGenerator::~TKeyGenerator(){  DebugAssert(FState != kgGenerating);  if (FEntropy) delete FEntropy;  delete FSSH2Key;  delete FRSAKey;  delete FDSSKey;}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::SetKeySize(int value){  DebugAssert(FState != kgGenerating);  FState = kgInitializing;  FKeySize = value;  FEntropyRequired = (KeySize / 2) * 2;  FEntropyGot = 0;  if (FEntropy) delete FEntropy;  FEntropy = new TEntropyBit[FEntropyRequired];}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::SetKeyType(TKeyType value){  DebugAssert(FState != kgGenerating);  FState = kgInitializing;  FKeyType = value;}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::AddEntropy(TEntropyBit Entropy){  DebugAssert(FState == kgInitializing);  DebugAssert(FEntropy);  DebugAssert(FEntropyGot < FEntropyRequired);  FEntropy[FEntropyGot++] = Entropy;  if (FEntropyGot == FEntropyRequired)  {    FState = kgInitialized;    random_add_heavynoise(FEntropy, FEntropyRequired * sizeof(TEntropyBit));    delete FEntropy;    FEntropy = NULL;  }}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::ResetKey(){  DebugAssert(FSSH2Key);  switch (KeyType) {    case ktDSA:      FSSH2Key->data = FDSSKey;      FSSH2Key->alg = &ssh_dss;      break;    case ktRSA2:      FSSH2Key->data = FRSAKey;      FSSH2Key->alg = &ssh_rsa;      break;  }  FFingerprint = "";  FPublicKey = "";  if (Comment.IsEmpty())  {    Comment = FORMAT("%s-key-%s",      ((KeyType == ktDSA ? "dsa" : "rsa"), FormatDateTime("yyyymmdd", Now())));  }}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::StartGenerationThread(){  DebugAssert(FState == kgInitialized);  FState = kgGenerating;  new TKeyGenerationThread(this);}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::Generate(){  DebugAssert(FState == kgInitialized);  THREAD_CLASS * Thread;  FState = kgGenerating;  Thread = new TKeyGenerationThread(this);  Thread->WaitFor();}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::ProgressUpdate(int Range, int Position,  TKeyGenerationComplete Complete){  DebugAssert(FState == kgGenerating);  if (Complete == kgSuccess)  {    FState = kgComplete;    ResetKey();  }  FGenerationRange = Range;  FGenerationPosition = Position;  if (FOnGenerating) FOnGenerating(this, Range, Position, Complete);}//---------------------------------------------------------------------------int __fastcall TKeyGenerator::GetPercentGenerated(){  switch (FState) {    case kgComplete: return 100;    case kgGenerating: return (FGenerationPosition * 100) / FGenerationRange;    default: return 0;  }}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::SetComment(AnsiString value){  if (FComment != value)  {    FComment = value;    FPublicKey = "";    DebugAssert(FSSH2Key);    FSSH2Key->comment = FComment.c_str();    FRSAKey->comment = FComment.c_str();  }}//---------------------------------------------------------------------------AnsiString __fastcall TKeyGenerator::GetFingerprint(){  if (FFingerprint.IsEmpty())  {    if (IsSSH2)    {      DebugAssert(FSSH2Key);      FFingerprint = FSSH2Key->alg->fingerprint(FSSH2Key->data);    }    else    {      char Buf[128];      rsa_fingerprint(Buf, sizeof(Buf), FRSAKey);      FFingerprint = Buf;    }  }  return FFingerprint;}//---------------------------------------------------------------------------bool __fastcall TKeyGenerator::GetIsSSH2(){  return (KeyType == ktDSA || KeyType == ktRSA2);}//---------------------------------------------------------------------------AnsiString __fastcall TKeyGenerator::GetPublicKey(){  if (FPublicKey.IsEmpty())  {    unsigned char *pub_blob;    char *buffer, *p;    int pub_len;    int i;    DebugAssert(FSSH2Key);    pub_blob = FSSH2Key->alg->public_blob(FSSH2Key->data, &pub_len);    buffer = new char[4 * ((pub_len + 2) / 3) + 1];    p = buffer;    i = 0;    while (i < pub_len)    {      int n = (pub_len - i < 3 ? pub_len - i : 3);      base64_encode_atom(pub_blob + i, n, p);      i += n;      p += 4;    }    *p = '\0';    FPublicKey = buffer;    sfree(pub_blob);    delete [] buffer;  }  return FPublicKey;}//---------------------------------------------------------------------------AnsiString __fastcall TKeyGenerator::GetAuthorizedKeysLine(){  DebugAssert(FSSH2Key);  return FORMAT("%s %s %s", (FSSH2Key->alg->name, PublicKey, Comment));}//---------------------------------------------------------------------------void __fastcall TKeyGenerator::SaveKey(const AnsiString FileName,  const AnsiString Passphrase, TKeyFormat Format){  DebugAssert(FSSH2Key);  DebugAssert(FState == kgComplete);  DebugAssert((Format != kfOpenSSH && Format != kfSSHCom) || IsSSH2);  int Result;  if (IsSSH2)  {    switch (Format)    {      case kfPutty:        Result = ssh2_save_userkey(FileName.c_str(), FSSH2Key,          (char*)Passphrase.data());        break;      case kfOpenSSH:        Result = export_ssh2(FileName.c_str(), SSH_KEYTYPE_OPENSSH, FSSH2Key,          (char*)Passphrase.data());        break;      case kfSSHCom:        Result = export_ssh2(FileName.c_str(), SSH_KEYTYPE_SSHCOM, FSSH2Key,          (char*)Passphrase.data());        break;      default:        DebugFail();    }  }  else  {    DebugAssert(Format == kfPutty);    Result = saversakey(FileName.c_str(), FRSAKey,      (char*)Passphrase.data());  }  if (Result <= 0)    throw Exception(FMTLOAD(SAVE_KEY_ERROR, (FileName)));}
 |