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); }
bool rsa_ssh1_decrypt_pkcs1(mp_int *input, RSAKey *key, strbuf *outbuf) { strbuf *data = strbuf_new_nm(); bool success = false; BinarySource src[1]; { mp_int *b = rsa_ssh1_decrypt(input, key); for (size_t i = (mp_get_nbits(key->modulus) + 7) / 8; i-- > 0 ;) { put_byte(data, mp_get_byte(b, i)); } mp_free(b); } BinarySource_BARE_INIT(src, data->u, data->len); /* Check PKCS#1 formatting prefix */ if (get_byte(src) != 0) goto out; if (get_byte(src) != 2) goto out; while (1) { unsigned char byte = get_byte(src); if (get_err(src)) goto out; if (byte == 0) break; } /* Everything else is the payload */ success = true; put_data(outbuf, get_ptr(src), get_avail(src)); out: strbuf_free(data); return success; }
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 platform_make_x11_server(Plug *plug, const char *progname, int mindisp, const char *screen_number_suffix, ptrlen authproto, ptrlen authdata, Socket **sockets, Conf *conf) { char *tmpdir; char *authfilename = NULL; strbuf *authfiledata = NULL; char *unix_path = NULL; SockAddr *a_tcp = NULL, *a_unix = NULL; int authfd; FILE *authfp; int displayno; authfiledata = strbuf_new_nm(); int nsockets = 0; /* * Look for a free TCP port to run our server on. */ for (displayno = mindisp;; displayno++) { const char *err; int tcp_port = displayno + 6000; int addrtype = ADDRTYPE_IPV4; sockets[nsockets] = new_listener( NULL, tcp_port, plug, false, conf, addrtype); err = sk_socket_error(sockets[nsockets]); if (!err) { char *hostname = get_hostname(); if (hostname) { char *canonicalname = NULL; a_tcp = name_lookup(hostname, tcp_port, &canonicalname, conf, addrtype, NULL, ""); sfree(canonicalname); } sfree(hostname); nsockets++; break; /* success! */ } else { sk_close(sockets[nsockets]); } if (!strcmp(err, strerror(EADDRINUSE))) /* yuck! */ goto out; } if (a_tcp) { x11_format_auth_for_authfile( BinarySink_UPCAST(authfiledata), a_tcp, displayno, authproto, authdata); } /* * Try to establish the Unix-domain analogue. That may or may not * work - file permissions in /tmp may prevent it, for example - * but it's worth a try, and we don't consider it a fatal error if * it doesn't work. */ unix_path = dupprintf("/tmp/.X11-unix/X%d", displayno); a_unix = unix_sock_addr(unix_path); sockets[nsockets] = new_unix_listener(a_unix, plug); if (!sk_socket_error(sockets[nsockets])) { x11_format_auth_for_authfile( BinarySink_UPCAST(authfiledata), a_unix, displayno, authproto, authdata); nsockets++; } else { sk_close(sockets[nsockets]); sfree(unix_path); unix_path = NULL; } /* * Decide where the authority data will be written. */ tmpdir = getenv("TMPDIR"); if (!tmpdir || !*tmpdir) tmpdir = "/tmp"; authfilename = dupcat(tmpdir, "/", progname, "-Xauthority-XXXXXX", NULL); { int oldumask = umask(077); authfd = mkstemp(authfilename); umask(oldumask); } if (authfd < 0) { while (nsockets-- > 0) sk_close(sockets[nsockets]); goto out; } /* * Spawn a subprocess which will try to reliably delete our * auth file when we terminate, in case we die unexpectedly. */ { int cleanup_pipe[2]; pid_t pid; /* Don't worry if pipe or fork fails; it's not _that_ critical. */ if (!pipe(cleanup_pipe)) { if ((pid = fork()) == 0) { int buf[1024]; /* * Our parent process holds the writing end of * this pipe, and writes nothing to it. Hence, * we expect read() to return EOF as soon as * that process terminates. */ close(0); close(1); close(2); setpgid(0, 0); close(cleanup_pipe[1]); close(authfd); while (read(cleanup_pipe[0], buf, sizeof(buf)) > 0); unlink(authfilename); if (unix_path) unlink(unix_path); _exit(0); } else if (pid < 0) { close(cleanup_pipe[0]); close(cleanup_pipe[1]); } else { close(cleanup_pipe[0]); cloexec(cleanup_pipe[1]); } } } authfp = fdopen(authfd, "wb"); fwrite(authfiledata->u, 1, authfiledata->len, authfp); fclose(authfp); { char *display = dupprintf(":%d%s", displayno, screen_number_suffix); conf_set_str_str(conf, CONF_environmt, "DISPLAY", display); sfree(display); } conf_set_str_str(conf, CONF_environmt, "XAUTHORITY", authfilename); /* * FIXME: return at least the DISPLAY and XAUTHORITY env settings, * and perhaps also the display number */ out: if (a_tcp) sk_addr_free(a_tcp); /* a_unix doesn't need freeing, because new_unix_listener took it over */ sfree(authfilename); strbuf_free(authfiledata); sfree(unix_path); return nsockets; }