/* ----------------------------------------------------------------------
* Progress report code. This is really horrible :-)
*/
-#define PHASE1TOTAL 0x10000
-#define PHASE2TOTAL 0x10000
-#define PHASE3TOTAL 0x04000
-#define PHASE1START 0
-#define PHASE2START (PHASE1TOTAL)
-#define PHASE3START (PHASE1TOTAL + PHASE2TOTAL)
-#define TOTALTOTAL (PHASE1TOTAL + PHASE2TOTAL + PHASE3TOTAL)
-#define PROGRESSBIGRANGE 65535
-#define DIVISOR ((TOTALTOTAL + PROGRESSBIGRANGE - 1) / PROGRESSBIGRANGE)
-#define PROGRESSRANGE (TOTALTOTAL / DIVISOR)
+#define PROGRESSRANGE 65535
+#define MAXPHASE 5
struct progress {
- unsigned phase1param, phase1current, phase1n;
- unsigned phase2param, phase2current, phase2n;
- unsigned phase3mult;
+ int nphases;
+ struct {
+ int exponential;
+ unsigned startpoint, total;
+ unsigned param, current, n; /* if exponential */
+ unsigned mult; /* if linear */
+ } phases[MAXPHASE];
+ unsigned total, divisor, range;
HWND progbar;
};
-static void progress_update(void *param, int phase, int iprogress)
+static void progress_update(void *param, int action, int phase, int iprogress)
{
struct progress *p = (struct progress *) param;
unsigned progress = iprogress;
int position;
- switch (phase) {
- case -1:
- p->phase1param = 0x10000 + progress;
- p->phase1current = 0x10000;
- p->phase1n = 0;
- return;
- case -2:
- p->phase2param = 0x10000 + progress;
- p->phase2current = 0x10000;
- p->phase2n = 0;
- return;
- case -3:
- p->phase3mult = PHASE3TOTAL / progress;
- return;
- case 1:
- while (p->phase1n < progress) {
- p->phase1n++;
- p->phase1current *= p->phase1param;
- p->phase1current /= 0x10000;
- }
- position = PHASE1START + 0x10000 - p->phase1current;
+ if (action < PROGFN_READY && p->nphases < phase)
+ p->nphases = phase;
+ switch (action) {
+ case PROGFN_INITIALISE:
+ p->nphases = 0;
+ break;
+ case PROGFN_LIN_PHASE:
+ p->phases[phase-1].exponential = 0;
+ p->phases[phase-1].mult = p->phases[phase].total / progress;
+ break;
+ case PROGFN_EXP_PHASE:
+ p->phases[phase-1].exponential = 1;
+ p->phases[phase-1].param = 0x10000 + progress;
+ p->phases[phase-1].current = p->phases[phase-1].total;
+ p->phases[phase-1].n = 0;
break;
- case 2:
- while (p->phase2n < progress) {
- p->phase2n++;
- p->phase2current *= p->phase2param;
- p->phase2current /= 0x10000;
+ case PROGFN_PHASE_EXTENT:
+ p->phases[phase-1].total = progress;
+ break;
+ case PROGFN_READY:
+ {
+ unsigned total = 0;
+ int i;
+ for (i = 0; i < p->nphases; i++) {
+ p->phases[i].startpoint = total;
+ total += p->phases[i].total;
+ }
+ p->total = total;
+ p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
+ p->range = p->total / p->divisor;
+ SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
}
- position = PHASE2START + 0x10000 - p->phase2current;
break;
- case 3:
- position = PHASE3START + progress * p->phase3mult;
+ case PROGFN_PROGRESS:
+ if (p->phases[phase-1].exponential) {
+ while (p->phases[phase-1].n < progress) {
+ p->phases[phase-1].n++;
+ p->phases[phase-1].current *= p->phases[phase-1].param;
+ p->phases[phase-1].current /= 0x10000;
+ }
+ position = (p->phases[phase-1].startpoint +
+ p->phases[phase-1].total - p->phases[phase-1].current);
+ } else {
+ position = (p->phases[phase-1].startpoint +
+ progress * p->phases[phase-1].mult);
+ }
+ SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0);
break;
}
-
- SendMessage(p->progbar, PBM_SETPOS, position / DIVISOR, 0);
}
extern char ver[];
HWND progressbar; /* notify this with progress */
HWND dialog; /* notify this on completion */
int keysize; /* bits in key */
+ int is_dsa;
struct RSAKey *key;
+ struct dss_key *dsskey;
};
static DWORD WINAPI generate_rsa_key_thread(void *param)
{
struct progress prog;
prog.progbar = params->progressbar;
- rsa_generate(params->key, params->keysize, progress_update, &prog);
+ progress_update(&prog, PROGFN_INITIALISE, 0, 0);
+
+ if (params->is_dsa)
+ dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
+ else
+ rsa_generate(params->key, params->keysize, progress_update, &prog);
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
int key_exists;
int entropy_got, entropy_required, entropy_size;
int keysize;
- int ssh2;
+ int ssh2, is_dsa;
char **commentptr; /* points to key.comment or ssh2key.comment */
struct ssh2_userkey ssh2key;
unsigned *entropy;
struct RSAKey key;
+ struct dss_key dsskey;
};
static void hidemany(HWND hwnd, const int *ids, int hideit)
}
}
-static void setupbigedit1(HWND hwnd, int id, struct RSAKey *key)
+static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
{
char *buffer;
char *dec1, *dec2;
sprintf(buffer, "%d %s %s %s",
bignum_bitcount(key->modulus), dec1, dec2, key->comment);
SetDlgItemText(hwnd, id, buffer);
+ SetDlgItemText(hwnd, idstatic,
+ "&Public key for pasting into authorized_keys file:");
sfree(dec1);
sfree(dec2);
sfree(buffer);
}
-static void setupbigedit2(HWND hwnd, int id, struct ssh2_userkey *key)
+static void setupbigedit2(HWND hwnd, int id, int idstatic,
+ struct ssh2_userkey *key)
{
unsigned char *pub_blob;
char *buffer, *p;
*p++ = ' ';
strcpy(p, key->comment);
SetDlgItemText(hwnd, id, buffer);
+ SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
+ "OpenSSH authorized_keys2 file:");
sfree(pub_blob);
sfree(buffer);
}
+static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
+{
+ char *dec1, *dec2;
+ FILE *fp;
+
+ dec1 = bignum_decimal(key->exponent);
+ dec2 = bignum_decimal(key->modulus);
+ fp = fopen(filename, "wb");
+ if (!fp)
+ return 0;
+ fprintf(fp, "%d %s %s %s\n",
+ bignum_bitcount(key->modulus), dec1, dec2, key->comment);
+ fclose(fp);
+ sfree(dec1);
+ sfree(dec2);
+ return 1;
+}
+
+static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key)
+{
+ unsigned char *pub_blob;
+ char *p;
+ int pub_len;
+ int i, column;
+ FILE *fp;
+
+ pub_blob = key->alg->public_blob(key->data, &pub_len);
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ return 0;
+
+ fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
+
+ fprintf(fp, "Comment: \"");
+ for (p = key->comment; *p; p++) {
+ if (*p == '\\' || *p == '\"')
+ fputc('\\', fp);
+ fputc(*p, fp);
+ }
+ fprintf(fp, "\"\n");
+
+ i = 0;
+ column = 0;
+ while (i < pub_len) {
+ char buf[5];
+ int n = (pub_len - i < 3 ? pub_len - i : 3);
+ base64_encode_atom(pub_blob + i, n, buf);
+ i += n;
+ buf[4] = '\0';
+ fputs(buf, fp);
+ if (++column >= 16) {
+ fputc('\n', fp);
+ column = 0;
+ }
+ }
+ if (column > 0)
+ fputc('\n', fp);
+
+ fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
+ fclose(fp);
+ sfree(pub_blob);
+ return 1;
+}
+
/*
* Dialog-box function for the main PuTTYgen dialog box.
*/
IDC_BOX_ACTIONS,
IDC_GENSTATIC, IDC_GENERATE,
IDC_LOADSTATIC, IDC_LOAD,
- IDC_SAVESTATIC, IDC_SAVE,
+ IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
IDC_BOX_PARAMS,
- IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA,
+ IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
IDC_BITSSTATIC, IDC_BITS,
IDC_ABOUT,
};
{
struct ctlpos cp, cp2;
- /* Accelerators used: acglops */
+ /* Accelerators used: acglops1rbd */
- ctlposinit(&cp, hwnd, 10, 10, 10);
+ ctlposinit(&cp, hwnd, 4, 4, 4);
bartitle(&cp, "Public and private key generation for PuTTY",
IDC_TITLE);
beginbox(&cp, "Key", IDC_BOX_KEY);
cp2 = cp;
- statictext(&cp2, "No key.", IDC_NOKEY);
+ statictext(&cp2, "No key.", 1, IDC_NOKEY);
cp2 = cp;
- statictext(&cp2, "", IDC_GENERATING);
+ statictext(&cp2, "", 1, IDC_GENERATING);
progressbar(&cp2, IDC_PROGRESS);
bigeditctrl(&cp,
"&Public key for pasting into authorized_keys file:",
- IDC_PKSTATIC, IDC_KEYDISPLAY, 7);
+ IDC_PKSTATIC, IDC_KEYDISPLAY, 5);
SendDlgItemMessage(hwnd, IDC_KEYDISPLAY, EM_SETREADONLY, 1, 0);
staticedit(&cp, "Key fingerprint:", IDC_FPSTATIC,
IDC_FINGERPRINT, 75);
IDC_GENSTATIC, "&Generate", IDC_GENERATE);
staticbtn(&cp, "Load an existing private key file",
IDC_LOADSTATIC, "&Load", IDC_LOAD);
- staticbtn(&cp, "Save the generated key to a new file",
- IDC_SAVESTATIC, "&Save", IDC_SAVE);
+ static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
+ "Save p&ublic key", IDC_SAVEPUB,
+ "&Save private key", IDC_SAVE);
endbox(&cp);
beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
- radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 2,
+ radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 3,
"SSH&1 (RSA)", IDC_KEYSSH1,
- "SSH2 &RSA", IDC_KEYSSH2RSA, NULL);
+ "SSH2 &RSA", IDC_KEYSSH2RSA,
+ "SSH2 &DSA", IDC_KEYSSH2DSA, NULL);
staticedit(&cp, "Number of &bits in a generated key:",
IDC_BITSSTATIC, IDC_BITS, 20);
endbox(&cp);
}
- CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH1);
+ CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, IDC_KEYSSH1);
SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE);
/*
* Initially, hide the progress bar and the key display,
* and show the no-key display. Also disable the Save
- * button, because with no key we obviously can't save
+ * buttons, because with no key we obviously can't save
* anything.
*/
hidemany(hwnd, nokey_ids, FALSE);
hidemany(hwnd, generating_ids, TRUE);
hidemany(hwnd, gotkey_ids, TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
return 1;
case WM_MOUSEMOVE:
params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS);
params->dialog = hwnd;
params->keysize = state->keysize;
+ params->is_dsa = state->is_dsa;
params->key = &state->key;
+ params->dsskey = &state->dsskey;
if (!CreateThread(NULL, 0, generate_rsa_key_thread,
params, 0, &threadid)) {
*state->commentptr = smalloc(len + 1);
GetWindowText(editctl, *state->commentptr, len + 1);
if (state->ssh2) {
- setupbigedit2(hwnd, IDC_KEYDISPLAY,
+ setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
&state->ssh2key);
} else {
- setupbigedit1(hwnd, IDC_KEYDISPLAY, &state->key);
+ setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
+ &state->key);
}
}
}
state->keysize = DEFAULT_KEYSIZE;
/* If we ever introduce a new key type, check it here! */
state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1);
+ state->is_dsa = IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA);
if (state->keysize < 256) {
int ret = MessageBox(hwnd,
"PuTTYgen will not generate a key"
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
state->key_exists = FALSE;
SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
state->collecting_entropy = TRUE;
}
}
break;
+ case IDC_SAVEPUB:
+ state =
+ (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
+ if (state->key_exists) {
+ char filename[FILENAME_MAX];
+ if (prompt_keyfile(hwnd, "Save public key as:",
+ filename, 1)) {
+ int ret;
+ FILE *fp = fopen(filename, "r");
+ if (fp) {
+ char buffer[FILENAME_MAX + 80];
+ fclose(fp);
+ sprintf(buffer, "Overwrite existing file\n%.*s?",
+ FILENAME_MAX, filename);
+ ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
+ MB_YESNO | MB_ICONWARNING);
+ if (ret != IDYES)
+ break;
+ }
+ if (state->ssh2) {
+ ret = save_ssh2_pubkey(filename, &state->ssh2key);
+ } else {
+ ret = save_ssh1_pubkey(filename, &state->key);
+ }
+ if (ret <= 0) {
+ MessageBox(hwnd, "Unable to save key file",
+ "PuTTYgen Error", MB_OK | MB_ICONERROR);
+ }
+ }
+ }
+ break;
case IDC_LOAD:
state =
(struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
char *comment;
struct PassphraseProcStruct pps;
struct RSAKey newkey1;
- struct ssh2_userkey *newkey2;
+ struct ssh2_userkey *newkey2 = NULL;
ver = keyfile_version(filename);
if (ver == 0) {
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
/*
* Now update the key controls with all the
* key data.
* .ssh/authorized_keys on a Unix box.
*/
setupbigedit1(hwnd, IDC_KEYDISPLAY,
- &state->key);
+ IDC_PKSTATIC, &state->key);
} else {
char *fp;
char *savecomment;
sfree(fp);
setupbigedit2(hwnd, IDC_KEYDISPLAY,
- &state->ssh2key);
+ IDC_PKSTATIC, &state->ssh2key);
}
SetDlgItemText(hwnd, IDC_COMMENTEDIT,
*state->commentptr);
state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
state->generation_thread_exists = FALSE;
state->key_exists = TRUE;
- SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE,
- 0);
+ SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETRANGE, 0,
+ MAKELPARAM(0, PROGRESSRANGE));
+ SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0);
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
if (state->ssh2) {
- state->ssh2key.data = &state->key;
- state->ssh2key.alg = &ssh_rsa;
+ if (state->is_dsa) {
+ state->ssh2key.data = &state->dsskey;
+ state->ssh2key.alg = &ssh_dss;
+ } else {
+ state->ssh2key.data = &state->key;
+ state->ssh2key.alg = &ssh_rsa;
+ }
state->commentptr = &state->ssh2key.comment;
} else {
state->commentptr = &state->key.comment;
struct tm *tm;
time(&t);
tm = localtime(&t);
- strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", tm);
+ if (state->is_dsa)
+ strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", tm);
+ else
+ strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", tm);
}
/*
*state->commentptr = savecomment;
/*
* Construct a decimal representation of the key, for
- * pasting into .ssh/authorized_keys on a Unix box.
+ * pasting into .ssh/authorized_keys or
+ * .ssh/authorized_keys2 on a Unix box.
*/
if (state->ssh2) {
- setupbigedit2(hwnd, IDC_KEYDISPLAY, &state->ssh2key);
+ setupbigedit2(hwnd, IDC_KEYDISPLAY,
+ IDC_PKSTATIC, &state->ssh2key);
} else {
- setupbigedit1(hwnd, IDC_KEYDISPLAY, &state->key);
+ setupbigedit1(hwnd, IDC_KEYDISPLAY,
+ IDC_PKSTATIC, &state->key);
}
}
/*