/* * Initialise DH for a standard group. */ void *dh_setup_group(const struct ssh_kex *kex) { struct dh_ctx *ctx = snew(struct dh_ctx); ctx->p = bignum_from_bytes(kex->pdata, kex->plen); ctx->g = bignum_from_bytes(kex->gdata, kex->glen); dh_init(ctx); return ctx; }
/* * Initialise DH for a standard group. */ void *dh_setup_group(const struct ssh_kex *kex) { const struct dh_extra *extra = (const struct dh_extra *)kex->extra; struct dh_ctx *ctx = snew(struct dh_ctx); ctx->p = bignum_from_bytes(extra->pdata, extra->plen); ctx->g = bignum_from_bytes(extra->gdata, extra->glen); dh_init(ctx); return ctx; }
int rsaencrypt(unsigned char *data, int length, struct RSAKey *key) { Bignum b1, b2; int i; unsigned char *p; if (key->bytes < length + 4) return 0; /* RSA key too short! */ memmove(data + key->bytes - length, data, length); data[0] = 0; data[1] = 2; for (i = 2; i < key->bytes - length - 1; i++) { do { data[i] = random_byte(); } while (data[i] == 0); } data[key->bytes - length - 1] = 0; b1 = bignum_from_bytes(data, key->bytes); b2 = modpow(b1, key->exponent, key->modulus); p = data; for (i = key->bytes; i--;) { *p++ = bignum_byte(b2, i); } freebn(b1); freebn(b2); return 1; }
void RSAKey::Sign( const CString &data, CString &out ) const { Bignum in; { unsigned char hash[20]; SHA_Simple(data.data(), data.size(), hash); int nbytes = (bignum_bitcount(this->modulus) - 1) / 8; unsigned char *bytes = new unsigned char[nbytes]; memset( bytes, 0xFF, nbytes ); bytes[0] = 1; memcpy( bytes + nbytes - 20, hash, 20 ); in = bignum_from_bytes(bytes, nbytes); delete [] bytes; } Bignum outnum = rsa_privkey_op(in, this); delete [] in; int siglen; unsigned char *bytes = bignum_to_bytes( outnum, &siglen ); delete [] outnum; out = CString( (const char *) bytes, siglen ); delete [] bytes; }
static Bignum get160(char **data, int *datalen) { Bignum b; b = bignum_from_bytes((unsigned char *)*data, 20); *data += 20; *datalen -= 20; return b; }
static Bignum getmp(char **data, int *datalen) { char *p; int length; Bignum b; getstring(data, datalen, &p, &length); if (!p) return NULL; b = bignum_from_bytes((unsigned char *)p, length); return b; }
static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) { struct dss_key *dss = (struct dss_key *) key; Bignum k, gkp, hash, kinv, hxr, r, s; unsigned char digest[20]; unsigned char *bytes; int nbytes, i; SHA_Simple(data, datalen, digest); k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x, digest, sizeof(digest)); kinv = modinv(k, dss->q); /* k^-1 mod q */ assert(kinv); /* * Now we have k, so just go ahead and compute the signature. */ gkp = modpow(dss->g, k, dss->p); /* g^k mod p */ r = bigmod(gkp, dss->q); /* r = (g^k mod p) mod q */ freebn(gkp); hash = bignum_from_bytes(digest, 20); hxr = bigmuladd(dss->x, r, hash); /* hash + x*r */ s = modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash + x*r) mod q */ freebn(hxr); freebn(kinv); freebn(k); freebn(hash); /* * Signature blob is * * string "ssh-dss" * string two 20-byte numbers r and s, end to end * * i.e. 4+7 + 4+40 bytes. */ nbytes = 4 + 7 + 4 + 40; bytes = snewn(nbytes, unsigned char); PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-dss", 7); PUT_32BIT(bytes + 4 + 7, 40); for (i = 0; i < 20; i++) { bytes[4 + 7 + 4 + i] = bignum_byte(r, 19 - i); bytes[4 + 7 + 4 + 20 + i] = bignum_byte(s, 19 - i); } freebn(r); freebn(s); *siglen = nbytes; return bytes; }
bool RSAKey::Encrypt( CString &buf ) const { Bignum bn = bignum_from_bytes( (unsigned char *) buf.data(), buf.size() ); Bignum encrypted_bn = Encrypt( bn ); delete [] bn; int len; unsigned char *bytes = bignum_to_buffer( encrypted_bn, &len ); buf = CString( (const char *) bytes, len ); delete [] encrypted_bn; return true; }
/* * DH stage 1: invent a number x between 1 and q, and compute e = * g^x mod p. Return e. * * If `nbits' is greater than zero, it is used as an upper limit * for the number of bits in x. This is safe provided that (a) you * use twice as many bits in x as the number of bits you expect to * use in your session key, and (b) the DH group is a safe prime * (which SSH demands that it must be). * * P. C. van Oorschot, M. J. Wiener * "On Diffie-Hellman Key Agreement with Short Exponents". * Advances in Cryptology: Proceedings of Eurocrypt '96 * Springer-Verlag, May 1996. */ Bignum dh_create_e(void *handle, int nbits) { struct dh_ctx *ctx = (struct dh_ctx *)handle; int i; int nbytes; unsigned char *buf; nbytes = (bignum_bitcount(ctx->qmask) + 7) / 8; buf = snewn(nbytes, unsigned char); do { /* * Create a potential x, by ANDing a string of random bytes * with qmask. */ if (ctx->x) freebn(ctx->x); if (nbits == 0 || nbits > bignum_bitcount(ctx->qmask)) { for (i = 0; i < nbytes; i++) buf[i] = bignum_byte(ctx->qmask, i) & random_byte(); ctx->x = bignum_from_bytes(buf, nbytes); } else { int b, nb; ctx->x = bn_power_2(nbits); b = nb = 0; for (i = 0; i < nbits; i++) { if (nb == 0) { nb = 8; b = random_byte(); } bignum_set_bit(ctx->x, i, b & 1); b >>= 1; nb--; } } } while (bignum_cmp(ctx->x, One) <= 0 || bignum_cmp(ctx->x, ctx->q) >= 0); sfree(buf); /* * Done. Now compute e = g^x mod p. */ ctx->e = modpow(ctx->g, ctx->x, ctx->p); return ctx->e; }
static unsigned char *rsa2_sign(void *key, char *data, int datalen, int *siglen) { struct RSAKey *rsa = (struct RSAKey *) key; unsigned char *bytes; int nbytes; unsigned char hash[20]; Bignum in, out; int i, j; SHA_Simple(data, datalen, hash); nbytes = (bignum_bitcount(rsa->modulus) - 1) / 8; assert(1 <= nbytes - 20 - ASN1_LEN); bytes = snewn(nbytes, unsigned char); bytes[0] = 1; for (i = 1; i < nbytes - 20 - ASN1_LEN; i++) bytes[i] = 0xFF; for (i = nbytes - 20 - ASN1_LEN, j = 0; i < nbytes - 20; i++, j++) bytes[i] = asn1_weird_stuff[j]; for (i = nbytes - 20, j = 0; i < nbytes; i++, j++) bytes[i] = hash[j]; in = bignum_from_bytes(bytes, nbytes); sfree(bytes); out = rsa_privkey_op(in, rsa); freebn(in); nbytes = (bignum_bitcount(out) + 7) / 8; bytes = snewn(4 + 7 + 4 + nbytes, unsigned char); PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-rsa", 7); PUT_32BIT(bytes + 4 + 7, nbytes); for (i = 0; i < nbytes; i++) bytes[4 + 7 + 4 + i] = bignum_byte(out, nbytes - 1 - i); freebn(out); *siglen = 4 + 7 + 4 + nbytes; return bytes; }
bool RSAKey::Verify( const CString &data, const CString &sig ) const { Bignum in, out; int bytes, i, j; unsigned char hash[20]; in = bignum_from_bytes( (const unsigned char *) sig.data(), sig.size() ); /* Base (in) must be smaller than the modulus. */ if( bignum_cmp(in, this->modulus) >= 0 ) { freebn(in); return false; } out = modpow(in, this->exponent, this->modulus); freebn(in); bool ret = true; bytes = (bignum_bitcount(this->modulus)+7) / 8; /* Top (partial) byte should be zero. */ if (bignum_byte(out, bytes - 1) != 0) ret = 0; /* First whole byte should be 1. */ if (bignum_byte(out, bytes - 2) != 1) ret = 0; /* Most of the rest should be FF. */ for (i = bytes - 3; i >= 20; i--) { if (bignum_byte(out, i) != 0xFF) ret = 0; } /* Finally, we expect to see the SHA-1 hash of the signed data. */ SHA_Simple( data.data(), data.size(), hash ); for (i = 19, j = 0; i >= 0; i--, j++) { if (bignum_byte(out, i) != hash[j]) ret = false; } freebn(out); return ret; }
static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) { /* * The basic DSS signing algorithm is: * * - invent a random k between 1 and q-1 (exclusive). * - Compute r = (g^k mod p) mod q. * - Compute s = k^-1 * (hash + x*r) mod q. * * This has the dangerous properties that: * * - if an attacker in possession of the public key _and_ the * signature (for example, the host you just authenticated * to) can guess your k, he can reverse the computation of s * and work out x = r^-1 * (s*k - hash) mod q. That is, he * can deduce the private half of your key, and masquerade * as you for as long as the key is still valid. * * - since r is a function purely of k and the public key, if * the attacker only has a _range of possibilities_ for k * it's easy for him to work through them all and check each * one against r; he'll never be unsure of whether he's got * the right one. * * - if you ever sign two different hashes with the same k, it * will be immediately obvious because the two signatures * will have the same r, and moreover an attacker in * possession of both signatures (and the public key of * course) can compute k = (hash1-hash2) * (s1-s2)^-1 mod q, * and from there deduce x as before. * * - the Bleichenbacher attack on DSA makes use of methods of * generating k which are significantly non-uniformly * distributed; in particular, generating a 160-bit random * number and reducing it mod q is right out. * * For this reason we must be pretty careful about how we * generate our k. Since this code runs on Windows, with no * particularly good system entropy sources, we can't trust our * RNG itself to produce properly unpredictable data. Hence, we * use a totally different scheme instead. * * What we do is to take a SHA-512 (_big_) hash of the private * key x, and then feed this into another SHA-512 hash that * also includes the message hash being signed. That is: * * proto_k = SHA512 ( SHA512(x) || SHA160(message) ) * * This number is 512 bits long, so reducing it mod q won't be * noticeably non-uniform. So * * k = proto_k mod q * * This has the interesting property that it's _deterministic_: * signing the same hash twice with the same key yields the * same signature. * * Despite this determinism, it's still not predictable to an * attacker, because in order to repeat the SHA-512 * construction that created it, the attacker would have to * know the private key value x - and by assumption he doesn't, * because if he knew that he wouldn't be attacking k! * * (This trick doesn't, _per se_, protect against reuse of k. * Reuse of k is left to chance; all it does is prevent * _excessively high_ chances of reuse of k due to entropy * problems.) * * Thanks to Colin Plumb for the general idea of using x to * ensure k is hard to guess, and to the Cambridge University * Computer Security Group for helping to argue out all the * fine details. */ struct dss_key *dss = (struct dss_key *) key; SHA512_State ss; unsigned char digest[20], digest512[64]; Bignum proto_k, k, gkp, hash, kinv, hxr, r, s; unsigned char *bytes; int nbytes, i; SHA_Simple(data, datalen, digest); /* * Hash some identifying text plus x. */ SHA512_Init(&ss); SHA512_Bytes(&ss, "DSA deterministic k generator", 30); sha512_mpint(&ss, dss->x); SHA512_Final(&ss, digest512); /* * Now hash that digest plus the message hash. */ SHA512_Init(&ss); SHA512_Bytes(&ss, digest512, sizeof(digest512)); SHA512_Bytes(&ss, digest, sizeof(digest)); SHA512_Final(&ss, digest512); memset(&ss, 0, sizeof(ss)); /* * Now convert the result into a bignum, and reduce it mod q. */ proto_k = bignum_from_bytes(digest512, 64); k = bigmod(proto_k, dss->q); freebn(proto_k); memset(digest512, 0, sizeof(digest512)); /* * Now we have k, so just go ahead and compute the signature. */ gkp = modpow(dss->g, k, dss->p); /* g^k mod p */ r = bigmod(gkp, dss->q); /* r = (g^k mod p) mod q */ freebn(gkp); hash = bignum_from_bytes(digest, 20); kinv = modinv(k, dss->q); /* k^-1 mod q */ hxr = bigmuladd(dss->x, r, hash); /* hash + x*r */ s = modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash + x*r) mod q */ freebn(hxr); freebn(kinv); freebn(hash); /* * Signature blob is * * string "ssh-dss" * string two 20-byte numbers r and s, end to end * * i.e. 4+7 + 4+40 bytes. */ nbytes = 4 + 7 + 4 + 40; bytes = snewn(nbytes, unsigned char); PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-dss", 7); PUT_32BIT(bytes + 4 + 7, 40); for (i = 0; i < 20; i++) { bytes[4 + 7 + 4 + i] = bignum_byte(r, 19 - i); bytes[4 + 7 + 4 + 20 + i] = bignum_byte(s, 19 - i); } freebn(r); freebn(s); *siglen = nbytes; return bytes; }
unsigned char *sc_sig(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *password_s, char *sigdata, int sigdata_len, int *sigblob_len) { CK_RV rv = 0; char msg[SC_STR_MAX_LEN] = ""; CK_SESSION_HANDLE session = 0; const char *pwd = password_s; /* TEMPLATES: */ CK_BBOOL bTrue = 1; CK_OBJECT_CLASS class_private_key = CKO_PRIVATE_KEY; CK_KEY_TYPE key_type = CKK_RSA; CK_ATTRIBUTE key_template[] = { { CKA_CLASS, &class_private_key, sizeof (class_private_key) }, { CKA_KEY_TYPE, &key_type, sizeof (key_type) }, { CKA_TOKEN, &bTrue, sizeof (bTrue) }, { CKA_SIGN, &bTrue, sizeof (bTrue) }, { CKA_PRIVATE, &bTrue, sizeof (bTrue) } }; CK_ATTRIBUTE key_getattributes[] = { {CKA_ID, NULL_PTR, 0}, /* ID to search the key */ {CKA_MODULUS, NULL_PTR, 0} }; /* STORE OBJECTS AND ATTRIBUTES */ int max_o = 20; CK_OBJECT_HANDLE list[max_o]; CK_ULONG found = 0; CK_OBJECT_HANDLE pO; int ii,j; unsigned char *ret = NULL; *sigblob_len = 0; session = sc_get_session(f, try_write_syslog, sclib->m_fl, token_label); if(session == 0) { return NULL; } rv = sclib->m_fl->C_Login(session, CKU_USER, (CK_CHAR_PTR)pwd, strlen(pwd)); if (CKR_OK != rv) { logevent(f, "sc: Login failed"); sclib->m_fl->C_CloseSession(session); return NULL; } rv = sclib->m_fl->C_FindObjectsInit(session, key_template, 4); if (CKR_OK != rv) { sprintf(msg, "sc: C_FindObjectsInit priv key failed, 0x%.4x", (int)rv); goto err; } rv = sclib->m_fl->C_FindObjects(session, list, max_o-1, &found); if (CKR_OK != rv) { sprintf(msg, "sc: C_FindObjects priv key failed, 0x%.4x", (int)rv); goto err; } rv = sclib->m_fl->C_FindObjectsFinal(session); if (CKR_OK != rv) { sprintf(msg, "sc: C_FindObjectsFinal priv key failed, 0x%.4x", (int)rv); goto err; } if (found < 1) { sprintf(msg, "sc: No priv keys found"); goto err; } for(ii=0; ii<found; ii++) { pO = list[ii]; int ts = 1;//sizeof (key_getattributes) / sizeof (CK_ATTRIBUTE); int nr; sc_write_syslog("1"); for(nr=0;nr<ts;nr++) { key_getattributes[nr].ulValueLen = 0; key_getattributes[nr].pValue = NULL; } rv = sclib->m_fl->C_GetAttributeValue(session, pO, key_getattributes, ts); if(CKR_OK == rv) { for(nr=0;nr<ts;nr++) { key_getattributes[nr].pValue = calloc(sizeof(char *),key_getattributes[nr].ulValueLen+1); } if(sclib->m_fl->C_GetAttributeValue(session, pO, key_getattributes, ts) == CKR_OK) { if(strncmp(key_getattributes[0].pValue, sclib->m_KeyID, key_getattributes[0].ulValueLen) == 0) { CK_BYTE signature[500]; CK_ULONG signature_length = 500; CK_MECHANISM mechanism = { CKM_RSA_PKCS, NULL_PTR, 0 }; unsigned char *bytes; Bignum out; int nbytes; int r; unsigned char hash_sha[20]; char p_buf[key_getattributes[0].ulValueLen+1]; memset(p_buf, 0, key_getattributes[0].ulValueLen+1); strncpy(p_buf, key_getattributes[0].pValue, key_getattributes[0].ulValueLen); sprintf(msg, "sc: Found pkey: %s", p_buf); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); rv = sclib->m_fl->C_SignInit(session, &mechanism, pO); if (CKR_OK != rv) { free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); sprintf(msg, "sc: SignInit failed, 0x%.4x", (int)rv); goto err; } /* rsa2_sign() */ SHA_Simple(sigdata, sigdata_len, hash_sha); // MD5Simple(sigdata, sigdata_len, hash_md5); { int message_len = sizeof(id_sha1) + sizeof(hash_sha); CK_BYTE message[message_len]; for(j=0;j<sizeof(id_sha1);j++) message[j] = id_sha1[j]; memcpy((char *) &message[sizeof(id_sha1)], hash_sha, sizeof(hash_sha)); rv = sclib->m_fl->C_Sign(session, message, message_len, signature, &signature_length); if (CKR_OK != rv) { free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); sprintf(msg, "sc: Sign failed, 0x%.4x", (int)rv); goto err; } } out = bignum_from_bytes(signature, signature_length); nbytes = (bignum_bitcount(out) + 7) / 8; *sigblob_len = 4 + 7 + 4 + nbytes; bytes = calloc(sizeof(char *), *sigblob_len); SC_PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-rsa", 7); SC_PUT_32BIT(bytes + 4 + 7, nbytes); for (r = 0; r < nbytes; r++) bytes[4 + 7 + 4 + r] = bignum_byte(out, nbytes - 1 - r); ret = bytes; free(out); free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); break; } } else { logevent(f, "sc: GetAttributeValue failed, no data loaded"); } free(key_getattributes[0].pValue); free(key_getattributes[1].pValue); } else { sprintf(msg, "sc: GetAttributeValue failed (pkey), 0x%.4x", (int)rv); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } } sclib->m_fl->C_Logout(session); sclib->m_fl->C_CloseSession(session); return ret; err: logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); sclib->m_fl->C_Logout(session); sclib->m_fl->C_CloseSession(session); if(ret != NULL) free(ret); /* just return an invalid signature ... */ *sigblob_len = 1; return " "; }
unsigned char *sc_get_pub(void *f, int try_write_syslog, sc_lib *sclib, const char *token_label, const char *cert_label, char **algorithm, int *blob_len) { /* return pub_key and blob_len */ unsigned char *pub_key = NULL; /* some local helper: */ int i; char msg[SC_STR_MAX_LEN] = ""; /* STORE OBJECTS AND ATTRIBUTES */ CK_SESSION_HANDLE session = 0; /* OPEN SESSION */ session = sc_get_session(f, try_write_syslog, sclib->m_fl, token_label); if(session == 0) { return NULL; } /* SEARCH THE SPECIFIED CERTIFICATE AND DETERMINE THE ID */ { sc_cert_list *cl; sc_cert_list *pcl; msg[0]='\0'; cl = sc_get_cert_list(sclib, session, msg); if(cl == NULL) goto err; if(strlen(msg) > 0) { logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } pcl = cl; while(pcl != NULL) { int len = strlen(cert_label); if(pcl->cert_attr[0].ulValueLen < len) len = pcl->cert_attr[0].ulValueLen; if(strncmp(cert_label, pcl->cert_attr[0].pValue, len) == 0) { sclib->m_KeyID = calloc(sizeof(char *), pcl->cert_attr[1].ulValueLen+1); strncpy(sclib->m_KeyID, pcl->cert_attr[1].pValue, pcl->cert_attr[1].ulValueLen); char p_buf[pcl->cert_attr[0].ulValueLen+1]; memset(p_buf, 0, pcl->cert_attr[0].ulValueLen+1); strncpy(p_buf, pcl->cert_attr[0].pValue, pcl->cert_attr[0].ulValueLen); sprintf(msg, "sc: Found cert: %s", p_buf); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); sprintf(msg, "sc: Found cert: %s", sclib->m_KeyID); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); break; } pcl = pcl->next; } sc_free_cert_list(cl); } /* NOW GET THE PUB KEY FOR THIS CERT */ if(sclib->m_KeyID == NULL) { sprintf(msg, "sc: No cert found: %s", cert_label); goto err; } { sc_pub_list *pl; sc_pub_list *ppl; msg[0]='\0'; pl = sc_get_pub_list(sclib, session, msg); if(pl == NULL) goto err; if(strlen(msg) > 0) { logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); } ppl = pl; while(ppl != NULL) { if(strncmp(sclib->m_KeyID, ppl->pub_attr[0].pValue, ppl->pub_attr[0].ulValueLen) == 0) { // attr 0: id // attr 2: modulus // attr 3: exponent unsigned char *p, *blob; unsigned char *expo, *modu; int elen, mlen; elen = ((8 * ppl->pub_attr[3].ulValueLen) + 8) / 8; mlen = ((8 * ppl->pub_attr[2].ulValueLen) + 8) / 8; char p_buf[ppl->pub_attr[0].ulValueLen+1]; memset(p_buf, 0, ppl->pub_attr[0].ulValueLen+1); strncpy(p_buf, ppl->pub_attr[0].pValue, ppl->pub_attr[0].ulValueLen); sprintf(msg, "sc: Found key: %s", p_buf); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); expo = bignum_from_bytes(ppl->pub_attr[3].pValue, ppl->pub_attr[3].ulValueLen); modu = bignum_from_bytes(ppl->pub_attr[2].pValue, ppl->pub_attr[2].ulValueLen); *algorithm = calloc(sizeof(char *), strlen("ssh-rsa")+1); strcpy(*algorithm, "ssh-rsa"); /* ugly (but used in pagent prototype) */ if(sclib->rsakey != NULL) { free(sclib->rsakey->exponent); free(sclib->rsakey->modulus); free(sclib->rsakey); } sclib->rsakey = calloc(1, sizeof(struct RSAKey)); sclib->rsakey->exponent = expo; sclib->rsakey->modulus = modu; *blob_len = 19 + elen + mlen; blob = calloc(sizeof(char *), *blob_len); p = blob; SC_PUT_32BIT(p, 7); p += 4; memcpy(p, "ssh-rsa", 7); p += 7; SC_PUT_32BIT(p, elen); p += 4; for (i = elen; i--;) *p++ = bignum_byte(expo, i); SC_PUT_32BIT(p, mlen); p += 4; for (i = mlen; i--;) *p++ = bignum_byte(modu, i); pub_key = blob; sclib->m_SshPK = calloc(sizeof(char *), *blob_len); memcpy(sclib->m_SshPK, blob, *blob_len); sclib->m_SshPK_len = *blob_len; sclib->m_SshPk_alg = calloc(sizeof(char *), strlen("ssh-rsa")+1); strcpy(sclib->m_SshPk_alg, "ssh-rsa"); sprintf(msg, "sc: Blob: %i (%i,%i)", *blob_len, elen, mlen); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); { char *buffi = sc_base64key(blob, *blob_len); sprintf(msg, "sc: ssh-rsa %s token-key", buffi); logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); free(buffi); } //used in sclib free(expo); //free(modu); break; } ppl = ppl->next; } sc_free_pub_list(pl); } if(sclib->m_SshPK == NULL) { sprintf(msg, "sc: No pub key found: %s", cert_label); goto err; } sclib->m_fl->C_CloseSession(session); return pub_key; err: logevent(f, msg); if(try_write_syslog) sc_write_syslog(msg); sclib->m_fl->C_CloseSession(session); return NULL; }
Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key, unsigned char *digest, int digest_len) { /* * The basic DSS signing algorithm is: * * - invent a random k between 1 and q-1 (exclusive). * - Compute r = (g^k mod p) mod q. * - Compute s = k^-1 * (hash + x*r) mod q. * * This has the dangerous properties that: * * - if an attacker in possession of the public key _and_ the * signature (for example, the host you just authenticated * to) can guess your k, he can reverse the computation of s * and work out x = r^-1 * (s*k - hash) mod q. That is, he * can deduce the private half of your key, and masquerade * as you for as long as the key is still valid. * * - since r is a function purely of k and the public key, if * the attacker only has a _range of possibilities_ for k * it's easy for him to work through them all and check each * one against r; he'll never be unsure of whether he's got * the right one. * * - if you ever sign two different hashes with the same k, it * will be immediately obvious because the two signatures * will have the same r, and moreover an attacker in * possession of both signatures (and the public key of * course) can compute k = (hash1-hash2) * (s1-s2)^-1 mod q, * and from there deduce x as before. * * - the Bleichenbacher attack on DSA makes use of methods of * generating k which are significantly non-uniformly * distributed; in particular, generating a 160-bit random * number and reducing it mod q is right out. * * For this reason we must be pretty careful about how we * generate our k. Since this code runs on Windows, with no * particularly good system entropy sources, we can't trust our * RNG itself to produce properly unpredictable data. Hence, we * use a totally different scheme instead. * * What we do is to take a SHA-512 (_big_) hash of the private * key x, and then feed this into another SHA-512 hash that * also includes the message hash being signed. That is: * * proto_k = SHA512 ( SHA512(x) || SHA160(message) ) * * This number is 512 bits long, so reducing it mod q won't be * noticeably non-uniform. So * * k = proto_k mod q * * This has the interesting property that it's _deterministic_: * signing the same hash twice with the same key yields the * same signature. * * Despite this determinism, it's still not predictable to an * attacker, because in order to repeat the SHA-512 * construction that created it, the attacker would have to * know the private key value x - and by assumption he doesn't, * because if he knew that he wouldn't be attacking k! * * (This trick doesn't, _per se_, protect against reuse of k. * Reuse of k is left to chance; all it does is prevent * _excessively high_ chances of reuse of k due to entropy * problems.) * * Thanks to Colin Plumb for the general idea of using x to * ensure k is hard to guess, and to the Cambridge University * Computer Security Group for helping to argue out all the * fine details. */ SHA512_State ss; unsigned char digest512[64]; Bignum proto_k, k; /* * Hash some identifying text plus x. */ SHA512_Init(&ss); SHA512_Bytes(&ss, id_string, strlen(id_string) + 1); sha512_mpint(&ss, private_key); SHA512_Final(&ss, digest512); /* * Now hash that digest plus the message hash. */ SHA512_Init(&ss); SHA512_Bytes(&ss, digest512, sizeof(digest512)); SHA512_Bytes(&ss, digest, digest_len); while (1) { SHA512_State ss2 = ss; /* structure copy */ SHA512_Final(&ss2, digest512); smemclr(&ss2, sizeof(ss2)); /* * Now convert the result into a bignum, and reduce it mod q. */ proto_k = bignum_from_bytes(digest512, 64); k = bigmod(proto_k, modulus); freebn(proto_k); if (bignum_cmp(k, One) != 0 && bignum_cmp(k, Zero) != 0) { smemclr(&ss, sizeof(ss)); smemclr(digest512, sizeof(digest512)); return k; } /* Very unlikely we get here, but if so, k was unsuitable. */ freebn(k); /* Perturb the hash to think of a different k. */ SHA512_Bytes(&ss, "x", 1); /* Go round and try again. */ } }