void PuttyInitialize() { SaveRandomSeed = true; // make sure random generator is initialised, so random_save_seed() // in destructor can proceed random_ref(); flags = FLAG_VERBOSE/* | FLAG_SYNCAGENT*/; // verbose log sk_init(); AnsiString VersionString = AnsiString(GetSshVersionString()); DebugAssert(!VersionString.IsEmpty() && (static_cast<size_t>(VersionString.Length()) < _countof(sshver))); strncpy(sshver, VersionString.c_str(), sizeof(sshver)); AnsiString AppName = AnsiString(GetAppNameString()); DebugAssert(!AppName.IsEmpty() && (static_cast<size_t>(AppName.Length()) < _countof(appname_))); strncpy(appname_, AppName.c_str(), sizeof(appname_)); }
//--------------------------------------------------------------------------- void __fastcall PuttyInitialize() { SaveRandomSeed = true; InitializeCriticalSection(&putty_section); // make sure random generator is initialised, so random_save_seed() // in destructor can proceed random_ref(); flags = FLAG_VERBOSE | FLAG_SYNCAGENT; // verbose log sk_init(); AnsiString VersionString = SshVersionString(); assert(!VersionString.IsEmpty() && (static_cast<size_t>(VersionString.Length()) < LENOF(sshver))); strcpy(sshver, VersionString.c_str()); AnsiString AppName = AppNameString(); assert(!AppName.IsEmpty() && (static_cast<size_t>(AppName.Length()) < LENOF(appname_))); strcpy(appname_, AppName.c_str()); }
int main(int argc, char **argv) { char *infile = NULL; Filename infilename; enum { NOKEYGEN, RSA1, RSA2, DSA } keytype = NOKEYGEN; char *outfile = NULL, *outfiletmp = NULL; Filename outfilename; enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH, SSHCOM } outtype = PRIVATE; int bits = 2048; char *comment = NULL, *origcomment = NULL; int change_passphrase = FALSE; int errs = FALSE, nogo = FALSE; int intype = SSH_KEYTYPE_UNOPENABLE; int sshver = 0; struct ssh2_userkey *ssh2key = NULL; struct RSAKey *ssh1key = NULL; unsigned char *ssh2blob = NULL; char *ssh2alg = NULL; const struct ssh_signkey *ssh2algf = NULL; int ssh2bloblen; char *passphrase = NULL; int load_encrypted; progfn_t progressfn = is_interactive() ? progress_update : no_progress; /* ------------------------------------------------------------------ * Parse the command line to figure out what we've been asked to do. */ /* * If run with no arguments at all, print the usage message and * return success. */ if (argc <= 1) { usage(TRUE); return 0; } /* * Parse command line arguments. */ while (--argc) { char *p = *++argv; if (*p == '-') { /* * An option. */ while (p && *++p) { char c = *p; switch (c) { case '-': /* * Long option. */ { char *opt, *val; opt = p++; /* opt will have _one_ leading - */ while (*p && *p != '=') p++; /* find end of option */ if (*p == '=') { *p++ = '\0'; val = p; } else val = NULL; if (!strcmp(opt, "-help")) { if (val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { help(); nogo = TRUE; } } else if (!strcmp(opt, "-version")) { if (val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { showversion(); nogo = TRUE; } } else if (!strcmp(opt, "-pgpfp")) { if (val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { /* support --pgpfp for consistency */ pgp_fingerprints(); nogo = TRUE; } } /* * For long options requiring an argument, add * code along the lines of * * else if (!strcmp(opt, "-output")) { * if (!val) { * errs = TRUE; * fprintf(stderr, "puttygen: option `-%s'" * " expects an argument\n", opt); * } else * ofile = val; * } */ else { errs = TRUE; fprintf(stderr, "puttygen: no such option `-%s'\n", opt); } } p = NULL; break; case 'h': case 'V': case 'P': case 'l': case 'L': case 'p': case 'q': /* * Option requiring no parameter. */ switch (c) { case 'h': help(); nogo = TRUE; break; case 'V': showversion(); nogo = TRUE; break; case 'P': change_passphrase = TRUE; break; case 'l': outtype = FP; break; case 'L': outtype = PUBLICO; break; case 'p': outtype = PUBLIC; break; case 'q': progressfn = no_progress; break; } break; case 't': case 'b': case 'C': case 'O': case 'o': /* * Option requiring parameter. */ p++; if (!*p && argc > 1) --argc, p = *++argv; else if (!*p) { fprintf(stderr, "puttygen: option `-%c' expects a" " parameter\n", c); errs = TRUE; } /* * Now c is the option and p is the parameter. */ switch (c) { case 't': if (!strcmp(p, "rsa") || !strcmp(p, "rsa2")) keytype = RSA2, sshver = 2; else if (!strcmp(p, "rsa1")) keytype = RSA1, sshver = 1; else if (!strcmp(p, "dsa") || !strcmp(p, "dss")) keytype = DSA, sshver = 2; else { fprintf(stderr, "puttygen: unknown key type `%s'\n", p); errs = TRUE; } break; case 'b': bits = atoi(p); break; case 'C': comment = p; break; case 'O': if (!strcmp(p, "public")) outtype = PUBLIC; else if (!strcmp(p, "public-openssh")) outtype = PUBLICO; else if (!strcmp(p, "private")) outtype = PRIVATE; else if (!strcmp(p, "fingerprint")) outtype = FP; else if (!strcmp(p, "private-openssh")) outtype = OPENSSH, sshver = 2; else if (!strcmp(p, "private-sshcom")) outtype = SSHCOM, sshver = 2; else { fprintf(stderr, "puttygen: unknown output type `%s'\n", p); errs = TRUE; } break; case 'o': outfile = p; break; } p = NULL; /* prevent continued processing */ break; default: /* * Unrecognised option. */ errs = TRUE; fprintf(stderr, "puttygen: no such option `-%c'\n", c); break; } } } else { /* * A non-option argument. */ if (!infile) infile = p; else { errs = TRUE; fprintf(stderr, "puttygen: cannot handle more than one" " input file\n"); } } } if (errs) return 1; if (nogo) return 0; /* * If run with at least one argument _but_ not the required * ones, print the usage message and return failure. */ if (!infile && keytype == NOKEYGEN) { usage(TRUE); return 1; } /* ------------------------------------------------------------------ * Figure out further details of exactly what we're going to do. */ /* * Bomb out if we've been asked to both load and generate a * key. */ if (keytype != NOKEYGEN && infile) { fprintf(stderr, "puttygen: cannot both load and generate a key\n"); return 1; } /* * We must save the private part when generating a new key. */ if (keytype != NOKEYGEN && (outtype != PRIVATE && outtype != OPENSSH && outtype != SSHCOM)) { fprintf(stderr, "puttygen: this would generate a new key but " "discard the private part\n"); return 1; } /* * Analyse the type of the input file, in case this affects our * course of action. */ if (infile) { infilename = filename_from_str(infile); intype = key_type(&infilename); switch (intype) { /* * It would be nice here to be able to load _public_ * key files, in any of a number of forms, and (a) * convert them to other public key types, (b) print * out their fingerprints. Or, I suppose, for real * orthogonality, (c) change their comment! * * In fact this opens some interesting possibilities. * Suppose ssh2_userkey_loadpub() were able to load * public key files as well as extracting the public * key from private ones. And suppose I did the thing * I've been wanting to do, where specifying a * particular private key file for authentication * causes any _other_ key in the agent to be discarded. * Then, if you had an agent forwarded to the machine * you were running Unix PuTTY or Plink on, and you * needed to specify which of the keys in the agent it * should use, you could do that by supplying a * _public_ key file, thus not needing to trust even * your encrypted private key file to the network. Ooh! */ case SSH_KEYTYPE_UNOPENABLE: case SSH_KEYTYPE_UNKNOWN: fprintf(stderr, "puttygen: unable to load file `%s': %s\n", infile, key_type_to_str(intype)); return 1; case SSH_KEYTYPE_SSH1: if (sshver == 2) { fprintf(stderr, "puttygen: conversion from SSH-1 to SSH-2 keys" " not supported\n"); return 1; } sshver = 1; break; case SSH_KEYTYPE_SSH2: case SSH_KEYTYPE_OPENSSH: case SSH_KEYTYPE_SSHCOM: if (sshver == 1) { fprintf(stderr, "puttygen: conversion from SSH-2 to SSH-1 keys" " not supported\n"); return 1; } sshver = 2; break; } } /* * Determine the default output file, if none is provided. * * This will usually be equal to stdout, except that if the * input and output file formats are the same then the default * output is to overwrite the input. * * Also in this code, we bomb out if the input and output file * formats are the same and no other action is performed. */ if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) || (intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) || (intype == SSH_KEYTYPE_OPENSSH && outtype == OPENSSH) || (intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) { if (!outfile) { outfile = infile; outfiletmp = dupcat(outfile, ".tmp", NULL); } if (!change_passphrase && !comment) { fprintf(stderr, "puttygen: this command would perform no useful" " action\n"); return 1; } } else { if (!outfile) { /* * Bomb out rather than automatically choosing to write * a private key file to stdout. */ if (outtype==PRIVATE || outtype==OPENSSH || outtype==SSHCOM) { fprintf(stderr, "puttygen: need to specify an output file\n"); return 1; } } } /* * Figure out whether we need to load the encrypted part of the * key. This will be the case if either (a) we need to write * out a private key format, or (b) the entire input key file * is encrypted. */ if (outtype == PRIVATE || outtype == OPENSSH || outtype == SSHCOM || intype == SSH_KEYTYPE_OPENSSH || intype == SSH_KEYTYPE_SSHCOM) load_encrypted = TRUE; else load_encrypted = FALSE; /* ------------------------------------------------------------------ * Now we're ready to actually do some stuff. */ /* * Either load or generate a key. */ if (keytype != NOKEYGEN) { char *entropy; char default_comment[80]; struct tm tm; struct progress prog; prog.phase = -1; prog.current = -1; tm = ltime(); if (keytype == DSA) strftime(default_comment, 30, "dsa-key-%Y%m%d", &tm); else strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm); random_ref(); entropy = get_random_data(bits / 8); if (!entropy) { fprintf(stderr, "puttygen: failed to collect entropy, " "could not generate key\n"); return 1; } random_add_heavynoise(entropy, bits / 8); memset(entropy, 0, bits/8); sfree(entropy); if (keytype == DSA) { struct dss_key *dsskey = snew(struct dss_key); dsa_generate(dsskey, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); ssh2key->data = dsskey; ssh2key->alg = &ssh_dss; ssh1key = NULL; } else {
int main(int argc, char **argv) { char *infile = NULL; Filename *infilename = NULL, *outfilename = NULL; enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, ED25519 } keytype = NOKEYGEN; char *outfile = NULL, *outfiletmp = NULL; enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_AUTO, OPENSSH_NEW, SSHCOM } outtype = PRIVATE; int bits = -1; char *comment = NULL, *origcomment = NULL; int change_passphrase = FALSE; int errs = FALSE, nogo = FALSE; int intype = SSH_KEYTYPE_UNOPENABLE; int sshver = 0; struct ssh2_userkey *ssh2key = NULL; struct RSAKey *ssh1key = NULL; unsigned char *ssh2blob = NULL; char *ssh2alg = NULL; const struct ssh_signkey *ssh2algf = NULL; int ssh2bloblen; char *old_passphrase = NULL, *new_passphrase = NULL; int load_encrypted; progfn_t progressfn = is_interactive() ? progress_update : no_progress; const char *random_device = NULL; /* ------------------------------------------------------------------ * Parse the command line to figure out what we've been asked to do. */ /* * If run with no arguments at all, print the usage message and * return success. */ if (argc <= 1) { usage(TRUE); return 0; } /* * Parse command line arguments. */ while (--argc) { char *p = *++argv; if (*p == '-') { /* * An option. */ while (p && *++p) { char c = *p; switch (c) { case '-': /* * Long option. */ { char *opt, *val; opt = p++; /* opt will have _one_ leading - */ while (*p && *p != '=') p++; /* find end of option */ if (*p == '=') { *p++ = '\0'; val = p; } else val = NULL; if (!strcmp(opt, "-help")) { if (val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { help(); nogo = TRUE; } } else if (!strcmp(opt, "-version")) { if (val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { showversion(); nogo = TRUE; } } else if (!strcmp(opt, "-pgpfp")) { if (val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects no argument\n", opt); } else { /* support --pgpfp for consistency */ pgp_fingerprints(); nogo = TRUE; } } else if (!strcmp(opt, "-old-passphrase")) { if (!val && argc > 1) --argc, val = *++argv; if (!val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects an argument\n", opt); } else { old_passphrase = readpassphrase(val); if (!old_passphrase) errs = TRUE; } } else if (!strcmp(opt, "-new-passphrase")) { if (!val && argc > 1) --argc, val = *++argv; if (!val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects an argument\n", opt); } else { new_passphrase = readpassphrase(val); if (!new_passphrase) errs = TRUE; } } else if (!strcmp(opt, "-random-device")) { if (!val && argc > 1) --argc, val = *++argv; if (!val) { errs = TRUE; fprintf(stderr, "puttygen: option `-%s'" " expects an argument\n", opt); } else { random_device = val; } } else { errs = TRUE; fprintf(stderr, "puttygen: no such option `-%s'\n", opt); } } p = NULL; break; case 'h': case 'V': case 'P': case 'l': case 'L': case 'p': case 'q': /* * Option requiring no parameter. */ switch (c) { case 'h': help(); nogo = TRUE; break; case 'V': showversion(); nogo = TRUE; break; case 'P': change_passphrase = TRUE; break; case 'l': outtype = FP; break; case 'L': outtype = PUBLICO; break; case 'p': outtype = PUBLIC; break; case 'q': progressfn = no_progress; break; } break; case 't': case 'b': case 'C': case 'O': case 'o': /* * Option requiring parameter. */ p++; if (!*p && argc > 1) --argc, p = *++argv; else if (!*p) { fprintf(stderr, "puttygen: option `-%c' expects a" " parameter\n", c); errs = TRUE; } /* * Now c is the option and p is the parameter. */ switch (c) { case 't': if (!strcmp(p, "rsa") || !strcmp(p, "rsa2")) keytype = RSA2, sshver = 2; else if (!strcmp(p, "rsa1")) keytype = RSA1, sshver = 1; else if (!strcmp(p, "dsa") || !strcmp(p, "dss")) keytype = DSA, sshver = 2; else if (!strcmp(p, "ecdsa")) keytype = ECDSA, sshver = 2; else if (!strcmp(p, "ed25519")) keytype = ED25519, sshver = 2; else { fprintf(stderr, "puttygen: unknown key type `%s'\n", p); errs = TRUE; } break; case 'b': bits = atoi(p); break; case 'C': comment = p; break; case 'O': if (!strcmp(p, "public")) outtype = PUBLIC; else if (!strcmp(p, "public-openssh")) outtype = PUBLICO; else if (!strcmp(p, "private")) outtype = PRIVATE; else if (!strcmp(p, "fingerprint")) outtype = FP; else if (!strcmp(p, "private-openssh")) outtype = OPENSSH_AUTO, sshver = 2; else if (!strcmp(p, "private-openssh-new")) outtype = OPENSSH_NEW, sshver = 2; else if (!strcmp(p, "private-sshcom")) outtype = SSHCOM, sshver = 2; else { fprintf(stderr, "puttygen: unknown output type `%s'\n", p); errs = TRUE; } break; case 'o': outfile = p; break; } p = NULL; /* prevent continued processing */ break; default: /* * Unrecognised option. */ errs = TRUE; fprintf(stderr, "puttygen: no such option `-%c'\n", c); break; } } } else { /* * A non-option argument. */ if (!infile) infile = p; else { errs = TRUE; fprintf(stderr, "puttygen: cannot handle more than one" " input file\n"); } } } if (bits == -1) { /* * No explicit key size was specified. Default varies * depending on key type. */ switch (keytype) { case ECDSA: bits = 384; break; case ED25519: bits = 256; break; default: bits = DEFAULT_RSADSA_BITS; break; } } if (keytype == ECDSA && (bits != 256 && bits != 384 && bits != 521)) { fprintf(stderr, "puttygen: invalid bits for ECDSA, choose 256, 384 or 521\n"); errs = TRUE; } if (keytype == ED25519 && (bits != 256)) { fprintf(stderr, "puttygen: invalid bits for ED25519, choose 256\n"); errs = TRUE; } if (keytype == RSA2 || keytype == RSA1 || keytype == DSA) { if (bits < 256) { fprintf(stderr, "puttygen: cannot generate %s keys shorter than" " 256 bits\n", (keytype == DSA ? "DSA" : "RSA")); errs = TRUE; } else if (bits < DEFAULT_RSADSA_BITS) { fprintf(stderr, "puttygen: warning: %s keys shorter than" " %d bits are probably not secure\n", (keytype == DSA ? "DSA" : "RSA"), DEFAULT_RSADSA_BITS); /* but this is just a warning, so proceed anyway */ } } if (errs) return 1; if (nogo) return 0; /* * If run with at least one argument _but_ not the required * ones, print the usage message and return failure. */ if (!infile && keytype == NOKEYGEN) { usage(TRUE); return 1; } /* ------------------------------------------------------------------ * Figure out further details of exactly what we're going to do. */ /* * Bomb out if we've been asked to both load and generate a * key. */ if (keytype != NOKEYGEN && infile) { fprintf(stderr, "puttygen: cannot both load and generate a key\n"); return 1; } /* * We must save the private part when generating a new key. */ if (keytype != NOKEYGEN && (outtype != PRIVATE && outtype != OPENSSH_AUTO && outtype != OPENSSH_NEW && outtype != SSHCOM)) { fprintf(stderr, "puttygen: this would generate a new key but " "discard the private part\n"); return 1; } /* * Analyse the type of the input file, in case this affects our * course of action. */ if (infile) { infilename = filename_from_str(infile); intype = key_type(infilename); switch (intype) { case SSH_KEYTYPE_UNOPENABLE: case SSH_KEYTYPE_UNKNOWN: fprintf(stderr, "puttygen: unable to load file `%s': %s\n", infile, key_type_to_str(intype)); return 1; case SSH_KEYTYPE_SSH1: case SSH_KEYTYPE_SSH1_PUBLIC: if (sshver == 2) { fprintf(stderr, "puttygen: conversion from SSH-1 to SSH-2 keys" " not supported\n"); return 1; } sshver = 1; break; case SSH_KEYTYPE_SSH2: case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716: case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH: case SSH_KEYTYPE_OPENSSH_PEM: case SSH_KEYTYPE_OPENSSH_NEW: case SSH_KEYTYPE_SSHCOM: if (sshver == 1) { fprintf(stderr, "puttygen: conversion from SSH-2 to SSH-1 keys" " not supported\n"); return 1; } sshver = 2; break; case SSH_KEYTYPE_OPENSSH_AUTO: default: assert(0 && "Should never see these types on an input file"); } } /* * Determine the default output file, if none is provided. * * This will usually be equal to stdout, except that if the * input and output file formats are the same then the default * output is to overwrite the input. * * Also in this code, we bomb out if the input and output file * formats are the same and no other action is performed. */ if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) || (intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) || (intype == SSH_KEYTYPE_OPENSSH_PEM && outtype == OPENSSH_AUTO) || (intype == SSH_KEYTYPE_OPENSSH_NEW && outtype == OPENSSH_NEW) || (intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) { if (!outfile) { outfile = infile; outfiletmp = dupcat(outfile, ".tmp", NULL); } if (!change_passphrase && !comment) { fprintf(stderr, "puttygen: this command would perform no useful" " action\n"); return 1; } } else { if (!outfile) { /* * Bomb out rather than automatically choosing to write * a private key file to stdout. */ if (outtype == PRIVATE || outtype == OPENSSH_AUTO || outtype == OPENSSH_NEW || outtype == SSHCOM) { fprintf(stderr, "puttygen: need to specify an output file\n"); return 1; } } } /* * Figure out whether we need to load the encrypted part of the * key. This will be the case if either (a) we need to write * out a private key format, or (b) the entire input key file * is encrypted. */ if (outtype == PRIVATE || outtype == OPENSSH_AUTO || outtype == OPENSSH_NEW || outtype == SSHCOM || intype == SSH_KEYTYPE_OPENSSH_PEM || intype == SSH_KEYTYPE_OPENSSH_NEW || intype == SSH_KEYTYPE_SSHCOM) load_encrypted = TRUE; else load_encrypted = FALSE; if (load_encrypted && (intype == SSH_KEYTYPE_SSH1_PUBLIC || intype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || intype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH)) { fprintf(stderr, "puttygen: cannot perform this action on a " "public-key-only input file\n"); return 1; } /* ------------------------------------------------------------------ * Now we're ready to actually do some stuff. */ /* * Either load or generate a key. */ if (keytype != NOKEYGEN) { char *entropy; char default_comment[80]; struct tm tm; struct progress prog; prog.phase = -1; prog.current = -1; tm = ltime(); if (keytype == DSA) strftime(default_comment, 30, "dsa-key-%Y%m%d", &tm); else if (keytype == ECDSA) strftime(default_comment, 30, "ecdsa-key-%Y%m%d", &tm); else if (keytype == ED25519) strftime(default_comment, 30, "ed25519-key-%Y%m%d", &tm); else strftime(default_comment, 30, "rsa-key-%Y%m%d", &tm); random_ref(); entropy = get_random_data(bits / 8, random_device); if (!entropy) { fprintf(stderr, "puttygen: failed to collect entropy, " "could not generate key\n"); return 1; } random_add_heavynoise(entropy, bits / 8); smemclr(entropy, bits/8); sfree(entropy); if (keytype == DSA) { struct dss_key *dsskey = snew(struct dss_key); dsa_generate(dsskey, bits, progressfn, &prog); ssh2key = snew(struct ssh2_userkey); ssh2key->data = dsskey; ssh2key->alg = &ssh_dss; ssh1key = NULL; } else if (keytype == ECDSA) {