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)));
- }
|