void ecdsasign(ECdomain *dom, ECpriv *priv, uchar *dig, int len, mpint *r, mpint *s) { ECpriv tmp; mpint *E, *t; tmp.x = mpnew(0); tmp.y = mpnew(0); tmp.d = mpnew(0); E = betomp(dig, len, nil); t = mpnew(0); if(mpsignif(dom->n) < 8*len) mpright(E, 8*len - mpsignif(dom->n), E); for(;;){ ecgen(dom, &tmp); mpmod(tmp.x, dom->n, r); if(mpcmp(r, mpzero) == 0) continue; mpmul(r, priv->d, s); mpadd(E, s, s); mpinvert(tmp.d, dom->n, t); mpmul(s, t, s); mpmod(s, dom->n, s); if(mpcmp(s, mpzero) != 0) break; } mpfree(t); mpfree(E); mpfree(tmp.x); mpfree(tmp.y); mpfree(tmp.d); }
/* generate an rsa secret key with same params as a public key */ static void* rsa_genfrompk(void *vpub) { RSApub *pub; pub = vpub; return rsagen(mpsignif(pub->n), mpsignif(pub->ek), 0); }
static void send_ssh_cmsg_session_key(Conn *c) { int i, n, buflen, serverkeylen, hostkeylen; mpint *b; uchar *buf; Msg *m; RSApub *ksmall, *kbig; m = allocmsg(c, SSH_CMSG_SESSION_KEY, 2048); putbyte(m, c->cipher->id); putbytes(m, c->cookie, COOKIELEN); serverkeylen = mpsignif(c->serverkey->n); hostkeylen = mpsignif(c->hostkey->n); ksmall = kbig = nil; if(serverkeylen+128 <= hostkeylen){ ksmall = c->serverkey; kbig = c->hostkey; }else if(hostkeylen+128 <= serverkeylen){ ksmall = c->hostkey; kbig = c->serverkey; }else error("server session and host keys do not differ by at least 128 bits"); buflen = (mpsignif(kbig->n)+7)/8; buf = emalloc(buflen); debug(DBG_CRYPTO, "session key is %.*H\n", SESSKEYLEN, c->sesskey); memmove(buf, c->sesskey, SESSKEYLEN); for(i = 0; i < SESSIDLEN; i++) buf[i] ^= c->sessid[i]; debug(DBG_CRYPTO, "munged session key is %.*H\n", SESSKEYLEN, buf); b = rsaencryptbuf(ksmall, buf, SESSKEYLEN); n = (mpsignif(ksmall->n)+7) / 8; mptoberjust(b, buf, n); mpfree(b); debug(DBG_CRYPTO, "encrypted with ksmall is %.*H\n", n, buf); b = rsaencryptbuf(kbig, buf, n); putmpint(m, b); debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b); mpfree(b); memset(buf, 0, buflen); free(buf); putlong(m, c->flags); sendmsg(m); }
int base58dec(char *src, uchar *dst, int len) { mpint *n, *b, *r; char *t; int l; n = mpnew(0); r = mpnew(0); b = uitomp(58, nil); for(; *src; src++){ t = strchr(code, *src); if(t == nil){ mpfree(n); mpfree(r); mpfree(b); werrstr("invalid base58 char"); return -1; } uitomp(t - code, r); mpmul(n, b, n); mpadd(n, r, n); } memset(dst, 0, len); l = (mpsignif(n) + 7) / 8; mptobe(n, dst + (len - l), l, nil); mpfree(n); mpfree(r); mpfree(b); return 0; }
void main(int argc, char **argv) { RSApriv *key; Attr *a; char *s; fmtinstall('A', _attrfmt); fmtinstall('B', mpfmt); quotefmtinstall(); ARGBEGIN{ default: usage(); }ARGEND if(argc > 1) usage(); if((key = getkey(argc, argv, 0, &a)) == nil) sysfatal("%r"); s = smprint("key %A size=%d ek=%lB n=%lB\n", a, mpsignif(key->pub.n), key->pub.ek, key->pub.n); if(s == nil) sysfatal("smprint: %r"); write(1, s, strlen(s)); exits(nil); }
int rsaverify(RSApub *key, DigestAlg *hash, uchar *digest, uint dlen, uchar *sig, uint siglen) { uchar asn1[512], *buf; int n, len, pad; mpint *m, *mm, *s; /* * Create ASN.1 */ n = mkasn1(asn1, hash, digest, dlen); /* * Create number to sign. */ len = (mpsignif(key->n)+7)/8 - 1; if(len < n+2) { werrstr("rsa key too short"); return -1; } pad = len - (n+2); if(siglen < len) { werrstr("signature buffer too short"); return -1; } buf = malloc(len); if(buf == nil) return -1; buf[0] = 0x01; memset(buf+1, 0xFF, pad); buf[1+pad] = 0x00; memmove(buf+1+pad+1, asn1, n); m = betomp(buf, len, nil); free(buf); if(m == nil) return -1; /* * Extract plaintext of signature. */ s = betomp(sig, siglen, nil); if(s == nil) return -1; mm = rsaencrypt(key, s, nil); mpfree(s); if(mm == nil) return -1; if(mpcmp(m, mm) != 0) { werrstr("signature did not verify"); mpfree(mm); mpfree(m); return -1; } mpfree(mm); mpfree(m); return 0; }
void main(int argc, char **argv) { char *s; unsigned char *buf; int fd; int32_t n, tot; char *tag, *file; RSApriv *key; fmtinstall('B', mpfmt); tag = nil; ARGBEGIN{ case 't': tag = EARGF(usage()); break; default: usage(); } ARGEND if(argc != 0 && argc != 1) usage(); if(argc == 1) file = argv[0]; else file = "#d/0"; if((fd = open(file, OREAD)) < 0) sysfatal("open %s: %r", file); buf = nil; tot = 0; for(;;) { buf = realloc(buf, tot+8192); if(buf == nil) sysfatal("realloc: %r"); if((n = read(fd, buf+tot, 8192)) < 0) sysfatal("read: %r"); if(n == 0) break; tot += n; } key = asn1toRSApriv(buf, tot); if(key == nil) sysfatal("couldn't parse asn1 key"); s = smprint("key proto=rsa %s%ssize=%d ek=%B !dk=%B n=%B !p=%B !q=%B !kp=%B !kq=%B !c2=%B\n", tag ? tag : "", tag ? " " : "", mpsignif(key->pub.n), key->pub.ek, key->dk, key->pub.n, key->p, key->q, key->kp, key->kq, key->c2); if(s == nil) sysfatal("smprint: %r"); write(1, s, strlen(s)); exits(0); }
int ecdsaverify(ECdomain *dom, ECpub *pub, uchar *dig, int len, mpint *r, mpint *s) { mpint *E, *t, *u1, *u2; ECpoint R, S; int ret; if(mpcmp(r, mpone) < 0 || mpcmp(s, mpone) < 0 || mpcmp(r, dom->n) >= 0 || mpcmp(r, dom->n) >= 0) return 0; E = betomp(dig, len, nil); if(mpsignif(dom->n) < 8*len) mpright(E, 8*len - mpsignif(dom->n), E); t = mpnew(0); u1 = mpnew(0); u2 = mpnew(0); R.x = mpnew(0); R.y = mpnew(0); S.x = mpnew(0); S.y = mpnew(0); mpinvert(s, dom->n, t); mpmul(E, t, u1); mpmod(u1, dom->n, u1); mpmul(r, t, u2); mpmod(u2, dom->n, u2); ecmul(dom, dom->G, u1, &R); ecmul(dom, pub, u2, &S); ecadd(dom, &R, &S, &R); ret = 0; if(!R.inf){ mpmod(R.x, dom->n, t); ret = mpcmp(r, t) == 0; } mpfree(t); mpfree(u1); mpfree(u2); mpfree(R.x); mpfree(R.y); mpfree(S.x); mpfree(S.y); return ret; }
/* generate an rsa secret key */ static void* rsa_gen(int len) { RSApriv *key; for(;;){ key = rsagen(len, 6, 0); if(mpsignif(key->pub.n) == len) return key; rsaprivfree(key); } }
static int binput(Fmt *f, Const *c) { mpint *n, *x; int rc, i, j, k; mpdigit p, q; n = mpcopy(c->n); x = mpcopy(c->x); j = mpsignif(n); k = mpsignif(x); i = j > k ? j : k; if(x->sign == -1){ mptrunc(n, ++i, n); mptrunc(x, i, x); }else if(k >= j) i++; if(n->sign == -1) return fmtstrcpy(f, "(invalid)"); if(i == 0) i = 1; j = (i + 31) / (sizeof(mpdigit) * 8); i = (i + sizeof(mpdigit) * 8 - 1) % (sizeof(mpdigit) * 8) + 1; rc = fmtstrcpy(f, "'b"); while(--j >= 0){ p = j >= n->top ? 0 : n->p[j]; q = j >= x->top ? 0 : x->p[j]; while(--i >= 0){ k = (mpdigit)1<<i; rc += fmtstrcpy(f, (q & k) != 0 ? ((p & k) != 0 ? "z" : "x") : ((p & k) != 0 ? "1" : "0")); } i = sizeof(mpdigit) * 8; } mpfree(n); mpfree(x); return rc; }
static int parsepubkey(char *s, RSApub *key, char **sp, int base) { int n; char *host, *p, *z; z = nil; n = strtoul(s, &p, 10); host = nil; if(n < Arbsz || !isspace(*p)){ /* maybe this is a host name */ host = s; s = strpbrk(s, " \t"); if(s == nil) return -1; z = s; *s++ = '\0'; s += strspn(s, " \t"); n = strtoul(s, &p, 10); if(n < Arbsz || !isspace(*p)){ if(z) *z = ' '; return -1; } } /* Arbsz is just a sanity check */ if((key->ek = strtomp(p, &p, base, nil)) == nil || (key->n = strtomp(p, &p, base, nil)) == nil || (*p != '\0' && !isspace(*p)) || mpsignif(key->n) < Arbsz) { mpfree(key->ek); mpfree(key->n); key->ek = nil; key->n = nil; if(z) *z = ' '; return -1; } if(host == nil){ if(*p != '\0'){ p += strspn(p, " \t"); if(*p != '\0'){ host = emalloc9p(strlen(p)+1); strcpy(host, p); } } free(s); } *sp = host; return 0; }
int rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen, uchar *sig, uint siglen) { uchar asn1[64], *buf; int n, len, pad; mpint *m, *s; /* * Create ASN.1 */ n = mkasn1(asn1, hash, digest, dlen); /* * Create number to sign. */ len = (mpsignif(key->pub.n)+7)/8 - 1; if(len < n+2) { werrstr("rsa key too short"); return -1; } pad = len - (n+2); if(siglen < len) { werrstr("signature buffer too short"); return -1; } buf = malloc(len); if(buf == nil) return -1; buf[0] = 0x01; memset(buf+1, 0xFF, pad); buf[1+pad] = 0x00; memmove(buf+1+pad+1, asn1, n); m = betomp(buf, len, nil); free(buf); if(m == nil) return -1; /* * Sign it. */ s = rsadecrypt(key, m, nil); mpfree(m); if(s == nil) return -1; mptoberjust(s, sig, len+1); mpfree(s); return len+1; }
DSAsig* dsasign(DSApriv *priv, mpint *m) { DSApub *pub = &priv->pub; DSAsig *sig; mpint *qm1, *k, *kinv, *r, *s; mpint *q = pub->q, *p = pub->p, *alpha = pub->alpha; int qlen = mpsignif(q); qm1 = mpnew(0); kinv = mpnew(0); r = mpnew(0); s = mpnew(0); k = mpnew(0); mpsub(pub->q, mpone, qm1); // find a k that has an inverse mod q while(1){ mprand(qlen, genrandom, k); if((mpcmp(mpone, k) > 0) || (mpcmp(k, qm1) >= 0)) continue; mpextendedgcd(k, q, r, kinv, s); if(mpcmp(r, mpone) != 0) continue; break; } // make kinv positive mpmod(kinv, qm1, kinv); // r = ((alpha**k) mod p) mod q mpexp(alpha, k, p, r); mpmod(r, q, r); // s = (kinv*(m + ar)) mod q mpmul(r, priv->secret, s); mpadd(s, m, s); mpmul(s, kinv, s); mpmod(s, q, s); sig = dsasigalloc(); sig->r = r; sig->s = s; mpfree(qm1); mpfree(k); mpfree(kinv); return sig; }
void main(int argc, char **argv) { RSApriv *k; int ssh2; char *comment; fmtinstall('B', mpfmt); fmtinstall('[', encodefmt); ssh2 = 0; comment = ""; ARGBEGIN{ case 'c': comment = EARGF(usage()); break; case '2': ssh2 = 1; break; default: usage(); }ARGEND if(argc > 1) usage(); if((k = getkey(argc, argv, 0, nil)) == nil) sysfatal("%r"); if(ssh2) { uchar buf[8192], *p; p = buf; p = put4(p, 7); p = putn(p, "ssh-rsa", 7); p = putmp2(p, k->pub.ek); p = putmp2(p, k->pub.n); print("ssh-rsa %.*[ %s\n", (int)(p-buf), buf, comment); } else { print("%d %.10B %.10B %s\n", mpsignif(k->pub.n), k->pub.ek, k->pub.n, comment); } exits(nil); }
static mpint* halfpt(ECdomain *dom, char *s, char **rptr, mpint *out) { char *buf, *r; int n; mpint *ret; n = ((mpsignif(dom->p)+7)/8)*2; if(strlen(s) < n) return 0; buf = malloc(n+1); buf[n] = 0; memcpy(buf, s, n); ret = strtomp(buf, &r, 16, out); *rptr = s + (r - buf); free(buf); return ret; }
ECpriv* ecgen(ECdomain *dom, ECpriv *p) { if(p == nil){ p = mallocz(sizeof(*p), 1); if(p == nil) return nil; p->x = mpnew(0); p->y = mpnew(0); p->d = mpnew(0); } for(;;){ mprand(mpsignif(dom->n), genrandom, p->d); if(mpcmp(p->d, mpzero) > 0 && mpcmp(p->d, dom->n) < 0) break; } ecmul(dom, dom->G, p->d, p); return p; }
int appendkey(char *keyfile, char *host, RSApub *key) { int fd; if((fd = open(keyfile, OWRITE)) < 0){ fd = create(keyfile, OWRITE, 0666); if(fd < 0){ fprint(2, "cannot open nor create %s: %r\n", keyfile); return -1; } } if(seek(fd, 0, 2) < 0 || fprint(fd, "%s %d %.10B %.10B\n", host, mpsignif(key->n), key->ek, key->n) < 0){ close(fd); return -1; } close(fd); return 0; }
int appendkey(char *keyfile, char *host, RSApub *key) { int fd, ret; ret = -1; if((fd = open(keyfile, OWRITE)) < 0){ fd = create(keyfile, OWRITE, 0666); if(fd < 0){ fprint(2, "%s: can't open nor create %s: %r\n", argv0, keyfile); return -1; } } if(seek(fd, 0, 2) >= 0 && fprint(fd, "%s %d %.10M %.10M\n", host, mpsignif(key->n), key->ek, key->n) >= 0) ret = 0; close(fd); return ret; }
void main(int argc, char **argv) { RSApriv *k; fmtinstall('B', mpfmt); ARGBEGIN{ default: usage(); }ARGEND if(argc > 1) usage(); if((k = getkey(argc, argv, 0, nil)) == nil) sysfatal("%r"); print("%d %.10B %.10B\n", mpsignif(k->pub.n), k->pub.ek, k->pub.n); exits(nil); }
// Miller-Rabin probabilistic primality testing // Knuth (1981) Seminumerical Algorithms, p.379 // Menezes et al () Handbook, p.39 // 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep int probably_prime(mpint *n, int nrep) { int j, k, rep, nbits, isprime = 1; mpint *nm1, *q, *x, *y, *r; if(n->sign < 0) sysfatal("negative prime candidate"); if(nrep <= 0) nrep = 18; k = mptoi(n); if(k == 2) // 2 is prime return 1; if(k < 2) // 1 is not prime return 0; if((n->p[0] & 1) == 0) // even is not prime return 0; // test against small prime numbers if(smallprimetest(n) < 0) return 0; // fermat test, 2^n mod n == 2 if p is prime x = uitomp(2, nil); y = mpnew(0); mpexp(x, n, n, y); k = mptoi(y); if(k != 2){ mpfree(x); mpfree(y); return 0; } nbits = mpsignif(n); nm1 = mpnew(nbits); mpsub(n, mpone, nm1); // nm1 = n - 1 */ k = mplowbits0(nm1); q = mpnew(0); mpright(nm1, k, q); // q = (n-1)/2**k for(rep = 0; rep < nrep; rep++){ // x = random in [2, n-2] r = mprand(nbits, prng, nil); mpmod(r, nm1, x); mpfree(r); if(mpcmp(x, mpone) <= 0) continue; // y = x**q mod n mpexp(x, q, n, y); if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0) goto done; for(j = 1; j < k; j++){ mpmul(y, y, x); mpmod(x, n, y); // y = y*y mod n if(mpcmp(y, nm1) == 0) goto done; if(mpcmp(y, mpone) == 0){ isprime = 0; goto done; } } isprime = 0; } done: mpfree(y); mpfree(x); mpfree(q); mpfree(nm1); return isprime; }
/* * Miller-Rabin probabilistic primality testing * Knuth (1981) Seminumerical Algorithms, p.379 * Menezes et al () Handbook, p.39 * 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep */ int probably_prime(mpint *n, int nrep) { int j, k, rep, nbits, isprime; mpint *nm1, *q, *x, *y, *r; if(n->sign < 0) sysfatal("negative prime candidate"); if(nrep <= 0) nrep = 18; k = mptoi(n); if(k == 2) /* 2 is prime */ return 1; if(k < 2) /* 1 is not prime */ return 0; if((n->p[0] & 1) == 0) /* even is not prime */ return 0; /* test against small prime numbers */ if(smallprimetest(n) < 0) return 0; /* fermat test, 2^n mod n == 2 if p is prime */ x = uitomp(2, nil); y = mpnew(0); mpexp(x, n, n, y); k = mptoi(y); if(k != 2){ mpfree(x); mpfree(y); return 0; } nbits = mpsignif(n); nm1 = mpnew(nbits); mpsub(n, mpone, nm1); /* nm1 = n - 1 */ k = mplowbits0(nm1); q = mpnew(0); mpright(nm1, k, q); /* q = (n-1)/2**k */ for(rep = 0; rep < nrep; rep++){ for(;;){ /* find x = random in [2, n-2] */ r = mprand(nbits, prng, nil); mpmod(r, nm1, x); mpfree(r); if(mpcmp(x, mpone) > 0) break; } /* y = x**q mod n */ mpexp(x, q, n, y); if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0) continue; for(j = 1;; j++){ if(j >= k) { isprime = 0; goto done; } mpmul(y, y, x); mpmod(x, n, y); /* y = y*y mod n */ if(mpcmp(y, nm1) == 0) break; if(mpcmp(y, mpone) == 0){ isprime = 0; goto done; } } } isprime = 1; done: mpfree(y); mpfree(x); mpfree(q); mpfree(nm1); return isprime; }
void handlefullmsg(Conn *c, Achan *a) { int i; uint32_t chan, len, n, rt; uint8_t type; Msg *m, mm; Msg *r; Key *k; int nk; mpint *mod, *ek, *chal; uint8_t sessid[16]; uint8_t chalbuf[32]; uint8_t digest[16]; DigestState *s; static int first; assert(a->len == a->ndata); chan = a->chan; mm.rp = a->data; mm.ep = a->data+a->ndata; mm.c = c; m = &mm; type = getbyte(m); if(first == 0){ first++; fmtinstall('H', encodefmt); } switch(type){ default: debug(DBG_AUTH, "unknown msg type\n"); Failure: debug(DBG_AUTH, "agent sending failure\n"); r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13); putlong(r, chan); putlong(r, 5); putlong(r, 1); putbyte(r, SSH_AGENT_FAILURE); sendmsg(r); return; case SSH_AGENTC_REQUEST_RSA_IDENTITIES: debug(DBG_AUTH, "agent request identities\n"); nk = listkeys(&k); if(nk < 0) goto Failure; len = 1+4; /* type, nk */ for(i=0; i<nk; i++){ len += 4; len += 2+(mpsignif(k[i].ek)+7)/8; len += 2+(mpsignif(k[i].mod)+7)/8; len += 4+strlen(k[i].comment); } r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len); putlong(r, chan); putlong(r, len+4); putlong(r, len); putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER); putlong(r, nk); for(i=0; i<nk; i++){ debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment); putlong(r, mpsignif(k[i].mod)); putmpint(r, k[i].ek); putmpint(r, k[i].mod); putstring(r, k[i].comment); mpfree(k[i].ek); mpfree(k[i].mod); free(k[i].comment); } free(k); sendmsg(r); break; case SSH_AGENTC_RSA_CHALLENGE: n = getlong(m); USED(n); /* number of bits in key; who cares? */ ek = getmpint(m); mod = getmpint(m); chal = getmpint(m); memmove(sessid, getbytes(m, 16), 16); rt = getlong(m); debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n", ek, mod, chal, rt, m->rp, m->ep); if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){ mpfree(ek); mpfree(mod); mpfree(chal); goto Failure; } s = md5(chalbuf, 32, nil, nil); md5(sessid, 16, digest, s); r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16); putlong(r, chan); putlong(r, 4+16+1); putlong(r, 16+1); putbyte(r, SSH_AGENT_RSA_RESPONSE); putbytes(r, digest, 16); debug(DBG_AUTH, "digest %.16H\n", digest); sendmsg(r); mpfree(ek); mpfree(mod); mpfree(chal); return; case SSH_AGENTC_ADD_RSA_IDENTITY: goto Failure; /* n = getlong(m); pubmod = getmpint(m); pubexp = getmpint(m); privexp = getmpint(m); pinversemodq = getmpint(m); p = getmpint(m); q = getmpint(m); comment = getstring(m); add to factotum; send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE; */ case SSH_AGENTC_REMOVE_RSA_IDENTITY: goto Failure; /* n = getlong(m); pubmod = getmpint(m); pubexp = getmpint(m); tell factotum to del key send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE; */ } }
RSApriv* getkey(int argc, char **argv, int needprivate, Attr **pa) { char *file, *s, *p; int sz; RSApriv *key; Biobuf *b; int regen; Attr *a; if(argc == 0) file = "#d/0"; else file = argv[0]; key = mallocz(sizeof(RSApriv), 1); if(key == nil) return nil; if((b = Bopen(file, OREAD)) == nil) { werrstr("open %s: %r", file); return nil; } s = Brdstr(b, '\n', 1); if(s == nil) { werrstr("read %s: %r", file); return nil; } if(strncmp(s, "key ", 4) != 0) { werrstr("bad key format"); return nil; } regen = 0; a = _parseattr(s+4); if(a == nil) { werrstr("empty key"); return nil; } if((p = _strfindattr(a, "proto")) == nil) { werrstr("no proto"); return nil; } if(strcmp(p, "rsa") != 0) { werrstr("proto not rsa"); return nil; } if((p = _strfindattr(a, "ek")) == nil) { werrstr("no ek"); return nil; } if((key->pub.ek = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad ek"); return nil; } if((p = _strfindattr(a, "n")) == nil) { werrstr("no n"); return nil; } if((key->pub.n = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad n"); return nil; } if((p = _strfindattr(a, "size")) == nil) fprint(2, "warning: missing size; will add\n"); else if((sz = strtol(p, &p, 10)) == 0 || *p != 0) fprint(2, "warning: bad size; will correct\n"); else if(sz != mpsignif(key->pub.n)) fprint(2, "warning: wrong size (got %d, expected %d); will correct\n", sz, mpsignif(key->pub.n)); if(!needprivate) goto call; if((p = _strfindattr(a, "!dk")) == nil) { werrstr("no !dk"); return nil; } if((key->dk = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !dk"); return nil; } if((p = _strfindattr(a, "!p")) == nil) { werrstr("no !p"); return nil; } if((key->p = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !p"); return nil; } if((p = _strfindattr(a, "!q")) == nil) { werrstr("no !q"); return nil; } if((key->q = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !q"); return nil; } if((p = _strfindattr(a, "!kp")) == nil) { fprint(2, "warning: no !kp\n"); regen = 1; goto regen; } if((key->kp = strtomp(p, &p, 16, nil)) == nil || *p != 0) { fprint(2, "warning: bad !kp\n"); regen = 1; goto regen; } if((p = _strfindattr(a, "!kq")) == nil) { fprint(2, "warning: no !kq\n"); regen = 1; goto regen; } if((key->kq = strtomp(p, &p, 16, nil)) == nil || *p != 0) { fprint(2, "warning: bad !kq\n"); regen = 1; goto regen; } if((p = _strfindattr(a, "!c2")) == nil) { fprint(2, "warning: no !c2\n"); regen = 1; goto regen; } if((key->c2 = strtomp(p, &p, 16, nil)) == nil || *p != 0) { fprint(2, "warning: bad !c2\n"); regen = 1; goto regen; } regen: if(regen) { RSApriv *k2; k2 = rsafill(key->pub.n, key->pub.ek, key->dk, key->p, key->q); if(k2 == nil) { werrstr("regenerating chinese-remainder parts failed: %r"); return nil; } key = k2; } call: a = _delattr(a, "ek"); a = _delattr(a, "n"); a = _delattr(a, "size"); a = _delattr(a, "!dk"); a = _delattr(a, "!p"); a = _delattr(a, "!q"); a = _delattr(a, "!c2"); a = _delattr(a, "!kp"); a = _delattr(a, "!kq"); if(pa) *pa = a; return key; }
static void recv_ssh_cmsg_session_key(Conn *c, AuthRpc *rpc) { int i, id, n, serverkeylen, hostkeylen; mpint *a, *b; uchar *buf; Msg *m; RSApriv *ksmall, *kbig; m = recvmsg(c, SSH_CMSG_SESSION_KEY); id = getbyte(m); c->cipher = nil; for(i=0; i<c->nokcipher; i++) if(c->okcipher[i]->id == id) c->cipher = c->okcipher[i]; if(c->cipher == nil) sysfatal("invalid cipher selected"); if(memcmp(getbytes(m, COOKIELEN), c->cookie, COOKIELEN) != 0) sysfatal("bad cookie"); serverkeylen = mpsignif(c->serverkey->n); hostkeylen = mpsignif(c->hostkey->n); ksmall = kbig = nil; if(serverkeylen+128 <= hostkeylen){ ksmall = c->serverpriv; kbig = nil; }else if(hostkeylen+128 <= serverkeylen){ ksmall = nil; kbig = c->serverpriv; }else sysfatal("server session and host keys do not differ by at least 128 bits"); b = getmpint(m); debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b); if(kbig){ a = rsadecrypt(kbig, b, nil); mpfree(b); b = a; }else b = rpcdecrypt(rpc, b); a = rsaunpad(b); mpfree(b); b = a; debug(DBG_CRYPTO, "encrypted with ksmall is %B\n", b); if(ksmall){ a = rsadecrypt(ksmall, b, nil); mpfree(b); b = a; }else b = rpcdecrypt(rpc, b); a = rsaunpad(b); mpfree(b); b = a; debug(DBG_CRYPTO, "munged is %B\n", b); n = (mpsignif(b)+7)/8; if(n > SESSKEYLEN) sysfatal("client sent short session key"); buf = emalloc(SESSKEYLEN); mptoberjust(b, buf, SESSKEYLEN); mpfree(b); for(i=0; i<SESSIDLEN; i++) buf[i] ^= c->sessid[i]; memmove(c->sesskey, buf, SESSKEYLEN); debug(DBG_CRYPTO, "unmunged is %.*H\n", SESSKEYLEN, buf); c->flags = getlong(m); free(m); }
int replacekey(char *keyfile, char *host, RSApub *hostkey) { int ret; char *h, *nkey, *p; Biobuf *br, *bw; Dir *d, nd; RSApub *k; ret = -1; d = nil; nkey = smprint("%s.new", keyfile); if(nkey == nil) return -1; if((br = Bopen(keyfile, OREAD)) == nil) goto out; if((bw = Bopen(nkey, OWRITE)) == nil){ Bterm(br); goto out; } while((k = readpublickey(br, &h)) != nil){ if(match(h, host) != 0) Bprint(bw, "%s %d %.10M %.10M\n", h, mpsignif(k->n), k->ek, k->n); free(h); rsapubfree(k); } Bprint(bw, "%s %d %.10M %.10M\n", host, mpsignif(hostkey->n), hostkey->ek, hostkey->n); Bterm(bw); Bterm(br); d = dirstat(nkey); if(d == nil){ fprint(2, "new key file disappeared?\n"); goto out; } p = strrchr(d->name, '.'); if(p == nil || strcmp(p, ".new") != 0){ fprint(2, "%s: new key file changed names? %s to %s\n", argv0, nkey, d->name); goto out; } *p = '\0'; nulldir(&nd); nd.name = d->name; if(remove(keyfile) < 0){ fprint(2, "%s: error removing %s: %r\n", argv0, keyfile); goto out; } if(dirwstat(nkey, &nd) < 0){ fprint(2, "%s: error renaming %s to %s: %r\n", argv0, nkey, d->name); goto out; } ret = 0; out: free(d); free(nkey); return ret; }
static int authrsafn(Conn *c) { uint8_t chalbuf[32+SESSIDLEN], response[MD5dlen]; char *s, *p; int afd, ret; AuthRpc *rpc; Msg *m; mpint *chal, *decr, *unpad, *mod; debug(DBG_AUTH, "rsa!\n"); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n"); return -1; } if((rpc = auth_allocrpc(afd)) == nil){ debug(DBG_AUTH, "auth_allocrpc: %r\n"); close(afd); return -1; } s = "proto=rsa role=client"; if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){ debug(DBG_AUTH, "auth_rpc start %s failed: %r\n", s); auth_freerpc(rpc); close(afd); return -1; } ret = -1; debug(DBG_AUTH, "trying factotum rsa keys\n"); while(auth_rpc(rpc, "read", nil, 0) == ARok){ debug(DBG_AUTH, "try %s\n", (char*)rpc->arg); mod = strtomp(rpc->arg, nil, 16, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA, 16+(mpsignif(mod)+7/8)); putmpint(m, mod); sendmsg(m); mpfree(mod); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: debug(DBG_AUTH, "\tnot accepted %s\n", (char*)rpc->arg); free(m); continue; default: badmsg(m, 0); case SSH_SMSG_AUTH_RSA_CHALLENGE: break; } chal = getmpint(m); debug(DBG_AUTH, "\tgot challenge %B\n", chal); free(m); p = mptoa(chal, 16, nil, 0); mpfree(chal); if(p == nil){ debug(DBG_AUTH, "\tmptoa failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ debug(DBG_AUTH, "\tauth_rpc write failed: %r\n"); free(p); unpad = mpnew(0); /* it will fail, we'll go round again */ goto Keepgoing; } free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok){ debug(DBG_AUTH, "\tauth_rpc read failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } decr = strtomp(rpc->arg, nil, 16, nil); debug(DBG_AUTH, "\tdecrypted %B\n", decr); unpad = rsaunpad(decr); debug(DBG_AUTH, "\tunpadded %B\n", unpad); mpfree(decr); Keepgoing: mptoberjust(unpad, chalbuf, 32); mpfree(unpad); debug(DBG_AUTH, "\trjusted %.*H\n", 32, chalbuf); memmove(chalbuf+32, c->sessid, SESSIDLEN); debug(DBG_AUTH, "\tappend sesskey %.*H\n", 32, chalbuf); md5(chalbuf, 32+SESSIDLEN, response, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE, MD5dlen); putbytes(m, response, MD5dlen); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: free(m); continue; default: badmsg(m, 0); case SSH_SMSG_SUCCESS: break; } ret = 0; break; } auth_freerpc(rpc); close(afd); return ret; }
RSApriv* rsagen(int nlen, int elen, int rounds) { mpint *p, *q, *e, *d, *phi, *n, *t1, *t2, *kp, *kq, *c2; RSApriv *rsa; p = mpnew(nlen/2); q = mpnew(nlen/2); n = mpnew(nlen); e = mpnew(elen); d = mpnew(0); phi = mpnew(nlen); // create the prime factors and euclid's function genprime(p, nlen/2, rounds); genprime(q, nlen - mpsignif(p) + 1, rounds); mpmul(p, q, n); mpsub(p, mpone, e); mpsub(q, mpone, d); mpmul(e, d, phi); // find an e relatively prime to phi t1 = mpnew(0); t2 = mpnew(0); mprand(elen, genrandom, e); if(mpcmp(e,mptwo) <= 0) itomp(3, e); // See Menezes et al. p.291 "8.8 Note (selecting primes)" for discussion // of the merits of various choices of primes and exponents. e=3 is a // common and recommended exponent, but doesn't necessarily work here // because we chose strong rather than safe primes. for(;;){ mpextendedgcd(e, phi, t1, d, t2); if(mpcmp(t1, mpone) == 0) break; mpadd(mpone, e, e); } mpfree(t1); mpfree(t2); // compute chinese remainder coefficient c2 = mpnew(0); mpinvert(p, q, c2); // for crt a**k mod p == (a**(k mod p-1)) mod p kq = mpnew(0); kp = mpnew(0); mpsub(p, mpone, phi); mpmod(d, phi, kp); mpsub(q, mpone, phi); mpmod(d, phi, kq); rsa = rsaprivalloc(); rsa->pub.ek = e; rsa->pub.n = n; rsa->dk = d; rsa->kp = kp; rsa->kq = kq; rsa->p = p; rsa->q = q; rsa->c2 = c2; mpfree(phi); return rsa; }
static int mpsqrt(mpint *n, mpint *p, mpint *r) { mpint *a, *t, *s, *xp, *xq, *yp, *yq, *zp, *zq, *N; if(mpleg(n, p) == -1) return 0; a = mpnew(0); t = mpnew(0); s = mpnew(0); N = mpnew(0); xp = mpnew(0); xq = mpnew(0); yp = mpnew(0); yq = mpnew(0); zp = mpnew(0); zq = mpnew(0); for(;;){ for(;;){ mprand(mpsignif(p), genrandom, a); if(mpcmp(a, mpzero) > 0 && mpcmp(a, p) < 0) break; } mpmul(a, a, t); mpsub(t, n, t); mpmod(t, p, t); if(mpleg(t, p) == -1) break; } mpadd(p, mpone, N); mpright(N, 1, N); mpmul(a, a, t); mpsub(t, n, t); mpassign(a, xp); uitomp(1, xq); uitomp(1, yp); uitomp(0, yq); while(mpcmp(N, mpzero) != 0){ if(N->p[0] & 1){ mpmul(xp, yp, zp); mpmul(xq, yq, zq); mpmul(zq, t, zq); mpadd(zp, zq, zp); mpmod(zp, p, zp); mpmul(xp, yq, zq); mpmul(xq, yp, s); mpadd(zq, s, zq); mpmod(zq, p, yq); mpassign(zp, yp); } mpmul(xp, xp, zp); mpmul(xq, xq, zq); mpmul(zq, t, zq); mpadd(zp, zq, zp); mpmod(zp, p, zp); mpmul(xp, xq, zq); mpadd(zq, zq, zq); mpmod(zq, p, xq); mpassign(zp, xp); mpright(N, 1, N); } if(mpcmp(yq, mpzero) != 0) abort(); mpassign(yp, r); mpfree(a); mpfree(t); mpfree(s); mpfree(N); mpfree(xp); mpfree(xq); mpfree(yp); mpfree(yq); mpfree(zp); mpfree(zq); return 1; }