|
@@ -1,393 +0,0 @@
|
|
|
-//---------------------------------------------------------------------------
|
|
|
-#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)));
|
|
|
-}
|