static void eddsa_openssh_blob(ssh_key *key, BinarySink *bs) { struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk); assert(ek->curve->type == EC_EDWARDS); /* Encode the public and private points as strings */ strbuf *pub_sb = strbuf_new(); put_epoint(pub_sb, ek->publicKey, ek->curve, false); ptrlen pub = make_ptrlen(pub_sb->s + 4, pub_sb->len - 4); strbuf *priv_sb = strbuf_new_nm(); put_mp_le_unsigned(priv_sb, ek->privateKey); ptrlen priv = make_ptrlen(priv_sb->s + 4, priv_sb->len - 4); put_stringpl(bs, pub); /* Encode the private key as the concatenation of the * little-endian key integer and the public key again */ put_uint32(bs, priv.len + pub.len); put_datapl(bs, priv); put_datapl(bs, pub); strbuf_free(pub_sb); strbuf_free(priv_sb); }
static mp_int *ecdsa_signing_exponent_from_data( const struct ec_curve *curve, const struct ecsign_extra *extra, ptrlen data) { /* Hash the data being signed. */ unsigned char hash[MAX_HASH_LEN]; ssh_hash *h = ssh_hash_new(extra->hash); put_datapl(h, data); ssh_hash_final(h, hash); /* * Take the leftmost b bits of the hash of the signed data (where * b is the number of bits in order(G)), interpreted big-endian. */ mp_int *z = mp_from_bytes_be(make_ptrlen(hash, extra->hash->hlen)); size_t zbits = mp_get_nbits(z); size_t nbits = mp_get_nbits(curve->w.G_order); size_t shift = zbits - nbits; /* Bound the shift count below at 0, using bit twiddling to avoid * a conditional branch */ shift &= ~-(shift >> (CHAR_BIT * sizeof(size_t) - 1)); mp_int *toret = mp_rshift_safe(z, shift); mp_free(z); return toret; }
static void rsa2_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs) { RSAKey *rsa = container_of(key, RSAKey, sshk); unsigned char *bytes; size_t nbytes; mp_int *in, *out; const ssh_hashalg *halg; const char *sign_alg_name; halg = rsa2_hash_alg_for_flags(flags, &sign_alg_name); nbytes = (mp_get_nbits(rsa->modulus) + 7) / 8; bytes = rsa_pkcs1_signature_string(nbytes, halg, data); in = mp_from_bytes_be(make_ptrlen(bytes, nbytes)); smemclr(bytes, nbytes); sfree(bytes); out = rsa_privkey_op(in, rsa); mp_free(in); put_stringz(bs, sign_alg_name); nbytes = (mp_get_nbits(out) + 7) / 8; put_uint32(bs, nbytes); for (size_t i = 0; i < nbytes; i++) put_byte(bs, mp_get_byte(out, nbytes - 1 - i)); mp_free(out); }
bool rsa_ssh1_encrypt(unsigned char *data, int length, RSAKey *key) { mp_int *b1, *b2; int i; unsigned char *p; if (key->bytes < length + 4) return false; /* RSA key too short! */ memmove(data + key->bytes - length, data, length); data[0] = 0; data[1] = 2; size_t npad = key->bytes - length - 3; /* * Generate a sequence of nonzero padding bytes. We do this in a * reasonably uniform way and without having to loop round * retrying the random number generation, by first generating an * integer in [0,2^n) for an appropriately large n; then we * repeatedly multiply by 255 to give an integer in [0,255*2^n), * extract the top 8 bits to give an integer in [0,255), and mask * those bits off before multiplying up again for the next digit. * This gives us a sequence of numbers in [0,255), and of course * adding 1 to each of them gives numbers in [1,256) as we wanted. * * (You could imagine this being a sort of fixed-point operation: * given a uniformly random binary _fraction_, multiplying it by k * and subtracting off the integer part will yield you a sequence * of integers each in [0,k). I'm just doing that scaled up by a * power of 2 to avoid the fractions.) */ size_t random_bits = (npad + 16) * 8; mp_int *randval = mp_new(random_bits + 8); mp_int *tmp = mp_random_bits(random_bits); mp_copy_into(randval, tmp); mp_free(tmp); for (i = 2; i < key->bytes - length - 1; i++) { mp_mul_integer_into(randval, randval, 255); uint8_t byte = mp_get_byte(randval, random_bits / 8); assert(byte != 255); data[i] = byte + 1; mp_reduce_mod_2to(randval, random_bits); } mp_free(randval); data[key->bytes - length - 1] = 0; b1 = mp_from_bytes_be(make_ptrlen(data, key->bytes)); b2 = mp_modpow(b1, key->exponent, key->modulus); p = data; for (i = key->bytes; i--;) { *p++ = mp_get_byte(b2, i); } mp_free(b1); mp_free(b2); return true; }
static mp_int *eddsa_signing_exponent_from_data( struct eddsa_key *ek, const struct ecsign_extra *extra, ptrlen r_encoded, ptrlen data) { /* Hash (r || public key || message) */ unsigned char hash[MAX_HASH_LEN]; ssh_hash *h = ssh_hash_new(extra->hash); put_datapl(h, r_encoded); put_epoint(h, ek->publicKey, ek->curve, true); /* omit string header */ put_datapl(h, data); ssh_hash_final(h, hash); /* Convert to an integer */ mp_int *toret = mp_from_bytes_le(make_ptrlen(hash, extra->hash->hlen)); smemclr(hash, extra->hash->hlen); return toret; }
EdwardsPoint *eddsa_public(mp_int *private_key, const ssh_keyalg *alg) { const struct ecsign_extra *extra = (const struct ecsign_extra *)alg->extra; struct ec_curve *curve = extra->curve(); assert(curve->type == EC_EDWARDS); ssh_hash *h = ssh_hash_new(extra->hash); for (size_t i = 0; i < curve->fieldBytes; ++i) put_byte(h, mp_get_byte(private_key, i)); unsigned char hash[MAX_HASH_LEN]; ssh_hash_final(h, hash); mp_int *exponent = eddsa_exponent_from_hash( make_ptrlen(hash, extra->hash->hlen), curve); EdwardsPoint *toret = ecc_edwards_multiply(curve->e.G, exponent); mp_free(exponent); return toret; }
static mp_int *eddsa_exponent_from_hash( ptrlen hash, const struct ec_curve *curve) { /* * Make an integer out of the hash data, little-endian. */ assert(hash.len >= curve->fieldBytes); mp_int *e = mp_from_bytes_le(make_ptrlen(hash.ptr, curve->fieldBytes)); /* * Set the highest bit that fits in the modulus, and clear any * above that. */ mp_set_bit(e, curve->fieldBits - 1, 1); mp_reduce_mod_2to(e, curve->fieldBits); /* * Clear exactly three low bits. */ for (size_t bit = 0; bit < 3; bit++) mp_set_bit(e, bit, 0); return e; }
static void eddsa_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs) { struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ek->sshk.vt->extra; assert(ek->privateKey); /* * EdDSA prescribes a specific method of generating the random * nonce integer for the signature. (A verifier can't tell * whether you followed that method, but it's important to * follow it anyway, because test vectors will want a specific * signature for a given message, and because this preserves * determinism of signatures even if the same signature were * made twice by different software.) */ /* * First, we hash the private key integer (bare, little-endian) * into a hash generating 2*fieldBytes of output. */ unsigned char hash[MAX_HASH_LEN]; ssh_hash *h = ssh_hash_new(extra->hash); for (size_t i = 0; i < ek->curve->fieldBytes; ++i) put_byte(h, mp_get_byte(ek->privateKey, i)); ssh_hash_final(h, hash); /* * The first half of the output hash is converted into an * integer a, by the standard EdDSA transformation. */ mp_int *a = eddsa_exponent_from_hash( make_ptrlen(hash, ek->curve->fieldBytes), ek->curve); /* * The second half of the hash of the private key is hashed again * with the message to be signed, and used as an exponent to * generate the signature point r. */ h = ssh_hash_new(extra->hash); put_data(h, hash + ek->curve->fieldBytes, extra->hash->hlen - ek->curve->fieldBytes); put_datapl(h, data); ssh_hash_final(h, hash); mp_int *log_r_unreduced = mp_from_bytes_le( make_ptrlen(hash, extra->hash->hlen)); mp_int *log_r = mp_mod(log_r_unreduced, ek->curve->e.G_order); mp_free(log_r_unreduced); EdwardsPoint *r = ecc_edwards_multiply(ek->curve->e.G, log_r); /* * Encode r now, because we'll need its encoding for the next * hashing step as well as to write into the actual signature. */ strbuf *r_enc = strbuf_new(); put_epoint(r_enc, r, ek->curve, true); /* omit string header */ ecc_edwards_point_free(r); /* * Compute the hash of (r || public key || message) just as * eddsa_verify does. */ mp_int *H = eddsa_signing_exponent_from_data( ek, extra, ptrlen_from_strbuf(r_enc), data); /* And then s = (log(r) + H*a) mod order(G). */ mp_int *Ha = mp_modmul(H, a, ek->curve->e.G_order); mp_int *s = mp_modadd(log_r, Ha, ek->curve->e.G_order); mp_free(H); mp_free(a); mp_free(Ha); mp_free(log_r); /* Format the output */ put_stringz(bs, ek->sshk.vt->ssh_id); put_uint32(bs, r_enc->len + ek->curve->fieldBytes); put_data(bs, r_enc->u, r_enc->len); strbuf_free(r_enc); for (size_t i = 0; i < ek->curve->fieldBytes; ++i) put_byte(bs, mp_get_byte(s, i)); mp_free(s); }
strbuf *ssh_rsakex_encrypt(RSAKey *rsa, const ssh_hashalg *h, ptrlen in) { mp_int *b1, *b2; int k, i; char *p; const int HLEN = h->hlen; /* * Here we encrypt using RSAES-OAEP. Essentially this means: * * - we have a SHA-based `mask generation function' which * creates a pseudo-random stream of mask data * deterministically from an input chunk of data. * * - we have a random chunk of data called a seed. * * - we use the seed to generate a mask which we XOR with our * plaintext. * * - then we use _the masked plaintext_ to generate a mask * which we XOR with the seed. * * - then we concatenate the masked seed and the masked * plaintext, and RSA-encrypt that lot. * * The result is that the data input to the encryption function * is random-looking and (hopefully) contains no exploitable * structure such as PKCS1-v1_5 does. * * For a precise specification, see RFC 3447, section 7.1.1. * Some of the variable names below are derived from that, so * it'd probably help to read it anyway. */ /* k denotes the length in octets of the RSA modulus. */ k = (7 + mp_get_nbits(rsa->modulus)) / 8; /* The length of the input data must be at most k - 2hLen - 2. */ assert(in.len > 0 && in.len <= k - 2*HLEN - 2); /* The length of the output data wants to be precisely k. */ strbuf *toret = strbuf_new_nm(); int outlen = k; unsigned char *out = strbuf_append(toret, outlen); /* * Now perform EME-OAEP encoding. First set up all the unmasked * output data. */ /* Leading byte zero. */ out[0] = 0; /* At position 1, the seed: HLEN bytes of random data. */ random_read(out + 1, HLEN); /* At position 1+HLEN, the data block DB, consisting of: */ /* The hash of the label (we only support an empty label here) */ { ssh_hash *s = ssh_hash_new(h); ssh_hash_final(s, out + HLEN + 1); } /* A bunch of zero octets */ memset(out + 2*HLEN + 1, 0, outlen - (2*HLEN + 1)); /* A single 1 octet, followed by the input message data. */ out[outlen - in.len - 1] = 1; memcpy(out + outlen - in.len, in.ptr, in.len); /* * Now use the seed data to mask the block DB. */ oaep_mask(h, out+1, HLEN, out+HLEN+1, outlen-HLEN-1); /* * And now use the masked DB to mask the seed itself. */ oaep_mask(h, out+HLEN+1, outlen-HLEN-1, out+1, HLEN); /* * Now `out' contains precisely the data we want to * RSA-encrypt. */ b1 = mp_from_bytes_be(make_ptrlen(out, outlen)); b2 = mp_modpow(b1, rsa->exponent, rsa->modulus); p = (char *)out; for (i = outlen; i--;) { *p++ = mp_get_byte(b2, i); } mp_free(b1); mp_free(b2); /* * And we're done. */ return toret; }
int main(int argc, char **argv) { int *fdlist; int fd; int i, fdstate; size_t fdsize; unsigned long now; ssh_key **hostkeys = NULL; size_t nhostkeys = 0, hostkeysize = 0; RSAKey *hostkey1 = NULL; AuthPolicy ap; Conf *conf = conf_new(); load_open_settings(NULL, conf); ap.kbdint_state = 0; ap.ssh1keys = NULL; ap.ssh2keys = NULL; if (argc <= 1) { /* * We're going to terminate with an error message below, * because there are no host keys. But we'll display the help * as additional standard-error output, if nothing else so * that people see the giant safety warning. */ show_help(stderr); fputc('\n', stderr); } while (--argc > 0) { const char *arg = *++argv; const char *val; if (!strcmp(arg, "--help")) { show_help(stdout); exit(0); } else if (!strcmp(arg, "--version")) { show_version_and_exit(); } else if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { verbose = true; } else if (longoptarg(arg, "--hostkey", &val, &argc, &argv)) { Filename *keyfile; int keytype; const char *error; keyfile = filename_from_str(val); keytype = key_type(keyfile); if (keytype == SSH_KEYTYPE_SSH2) { ssh2_userkey *uk; ssh_key *key; uk = ssh2_load_userkey(keyfile, NULL, &error); filename_free(keyfile); if (!uk || !uk->key) { fprintf(stderr, "%s: unable to load host key '%s': " "%s\n", appname, val, error); exit(1); } char *invalid = ssh_key_invalid(uk->key, 0); if (invalid) { fprintf(stderr, "%s: host key '%s' is unusable: " "%s\n", appname, val, invalid); exit(1); } key = uk->key; sfree(uk->comment); sfree(uk); for (i = 0; i < nhostkeys; i++) if (ssh_key_alg(hostkeys[i]) == ssh_key_alg(key)) { fprintf(stderr, "%s: host key '%s' duplicates key " "type %s\n", appname, val, ssh_key_alg(key)->ssh_id); exit(1); } sgrowarray(hostkeys, hostkeysize, nhostkeys); hostkeys[nhostkeys++] = key; } else if (keytype == SSH_KEYTYPE_SSH1) { if (hostkey1) { fprintf(stderr, "%s: host key '%s' is a redundant " "SSH-1 host key\n", appname, val); exit(1); } hostkey1 = snew(RSAKey); if (!rsa_ssh1_loadkey(keyfile, hostkey1, NULL, &error)) { fprintf(stderr, "%s: unable to load host key '%s': " "%s\n", appname, val, error); exit(1); } } else { fprintf(stderr, "%s: '%s' is not loadable as a " "private key (%s)", appname, val, key_type_to_str(keytype)); exit(1); } } else if (longoptarg(arg, "--userkey", &val, &argc, &argv)) { Filename *keyfile; int keytype; const char *error; keyfile = filename_from_str(val); keytype = key_type(keyfile); if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { strbuf *sb = strbuf_new(); struct AuthPolicy_ssh2_pubkey *node; void *blob; if (!ssh2_userkey_loadpub(keyfile, NULL, BinarySink_UPCAST(sb), NULL, &error)) { fprintf(stderr, "%s: unable to load user key '%s': " "%s\n", appname, val, error); exit(1); } node = snew_plus(struct AuthPolicy_ssh2_pubkey, sb->len); blob = snew_plus_get_aux(node); memcpy(blob, sb->u, sb->len); node->public_blob = make_ptrlen(blob, sb->len); node->next = ap.ssh2keys; ap.ssh2keys = node; strbuf_free(sb); } else if (keytype == SSH_KEYTYPE_SSH1_PUBLIC) {