SilcBool silc_pkcs1_verify_no_oid(void *public_key, unsigned char *signature, SilcUInt32 signature_len, unsigned char *data, SilcUInt32 data_len, SilcHash hash) { RsaPublicKey *key = public_key; SilcBool ret = FALSE; SilcMPInt mp_tmp2; SilcMPInt mp_dst; unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN]; SilcUInt32 verify_len, len = (key->bits + 7) / 8; SILC_LOG_DEBUG(("Verify signature")); silc_mp_init(&mp_tmp2); silc_mp_init(&mp_dst); /* Format the signature into MP int */ silc_mp_bin2mp(signature, signature_len, &mp_tmp2); /* Verify */ silc_rsa_public_operation(key, &mp_tmp2, &mp_dst); /* MP to data */ verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); /* Unpad data */ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len, unpadded, sizeof(unpadded), &len)) { memset(verify, 0, verify_len); silc_free(verify); silc_mp_uninit(&mp_tmp2); silc_mp_uninit(&mp_dst); return FALSE; } /* Hash data if requested */ if (hash) { silc_hash_make(hash, data, data_len, hashr); data = hashr; data_len = silc_hash_len(hash); } /* Compare */ if (len == data_len && !memcmp(data, unpadded, len)) ret = TRUE; memset(verify, 0, verify_len); memset(unpadded, 0, sizeof(unpadded)); silc_free(verify); silc_mp_uninit(&mp_tmp2); silc_mp_uninit(&mp_dst); if (hash) memset(hashr, 0, sizeof(hashr)); return ret; }
void silc_pkcs1_public_key_free(void *public_key) { RsaPublicKey *key = public_key; silc_mp_uninit(&key->n); silc_mp_uninit(&key->e); silc_free(key); }
SilcBool silc_pkcs1_sign_no_oid(void *private_key, unsigned char *src, SilcUInt32 src_len, unsigned char *signature, SilcUInt32 signature_size, SilcUInt32 *ret_signature_len, SilcBool compute_hash, SilcHash hash) { RsaPrivateKey *key = private_key; SilcMPInt mp_tmp; SilcMPInt mp_dst; unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN]; SilcUInt32 len = (key->bits + 7) / 8; SILC_LOG_DEBUG(("Sign")); if (sizeof(padded) < len) return FALSE; if (signature_size < len) return FALSE; /* Compute hash if requested */ if (compute_hash) { silc_hash_make(hash, src, src_len, hashr); src = hashr; src_len = silc_hash_len(hash); } /* Pad data */ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len, padded, len, NULL)) return FALSE; silc_mp_init(&mp_tmp); silc_mp_init(&mp_dst); /* Data to MP */ silc_mp_bin2mp(padded, len, &mp_tmp); /* Sign */ silc_rsa_private_operation(key, &mp_tmp, &mp_dst); /* MP to data */ silc_mp_mp2bin_noalloc(&mp_dst, signature, len); *ret_signature_len = len; memset(padded, 0, sizeof(padded)); silc_mp_uninit(&mp_tmp); silc_mp_uninit(&mp_dst); if (compute_hash) memset(hashr, 0, sizeof(hashr)); return TRUE; }
SilcBool silc_pkcs1_decrypt(void *private_key, unsigned char *src, SilcUInt32 src_len, unsigned char *dst, SilcUInt32 dst_size, SilcUInt32 *ret_dst_len) { RsaPrivateKey *key = private_key; SilcMPInt mp_tmp; SilcMPInt mp_dst; unsigned char *padded, unpadded[2048 + 1]; SilcUInt32 padded_len; if (dst_size < (key->bits + 7) / 8) return FALSE; silc_mp_init(&mp_tmp); silc_mp_init(&mp_dst); /* Data to MP */ silc_mp_bin2mp(src, src_len, &mp_tmp); /* Decrypt */ silc_rsa_private_operation(key, &mp_tmp, &mp_dst); /* MP to data */ padded = silc_mp_mp2bin(&mp_dst, (key->bits + 7) / 8, &padded_len); /* Unpad data */ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PUB, padded, padded_len, unpadded, sizeof(unpadded), ret_dst_len)) { memset(padded, 0, padded_len); silc_free(padded); silc_mp_uninit(&mp_tmp); silc_mp_uninit(&mp_dst); return FALSE; } /* Copy to destination */ memcpy(dst, unpadded, *ret_dst_len); memset(padded, 0, padded_len); memset(unpadded, 0, sizeof(unpadded)); silc_free(padded); silc_mp_uninit(&mp_tmp); silc_mp_uninit(&mp_dst); return TRUE; }
SilcBool silc_rsa_private_operation(RsaPrivateKey *key, SilcMPInt *src, SilcMPInt *dst) { SilcMPInt tmp; silc_mp_init(&tmp); /* dst = (src ^ dP mod p) */ silc_mp_pow_mod(dst, src, &key->dP, &key->p); /* tmp = (src ^ dQ mod q) */ silc_mp_pow_mod(&tmp, src, &key->dQ, &key->q); /* dst = (dst - tmp) * qP mod p */ silc_mp_sub(dst, dst, &tmp); silc_mp_mul(dst, dst, &key->qP); silc_mp_mod(dst, dst, &key->p); /* dst = (q * dst) + tmp */ silc_mp_mul(dst, dst, &key->q); silc_mp_add(dst, dst, &tmp); silc_mp_uninit(&tmp); return TRUE; }
SilcBool silc_pkcs1_generate_key(SilcUInt32 keylen, SilcRng rng, void **ret_public_key, void **ret_private_key) { SilcUInt32 prime_bits = keylen / 2; SilcMPInt p, q; SilcBool found = FALSE; if (keylen < 768 || keylen > 16384) return FALSE; silc_mp_init(&p); silc_mp_init(&q); /* Find p and q */ while (!found) { silc_math_gen_prime(&p, prime_bits, FALSE, rng); silc_math_gen_prime(&q, prime_bits, FALSE, rng); if ((silc_mp_cmp(&p, &q)) != 0) found = TRUE; } /* If p is smaller than q, switch them */ if ((silc_mp_cmp(&p, &q)) > 0) { SilcMPInt hlp; silc_mp_init(&hlp); silc_mp_set(&hlp, &p); silc_mp_set(&p, &q); silc_mp_set(&q, &hlp); silc_mp_uninit(&hlp); } /* Generate the actual keys */ if (!silc_rsa_generate_keys(keylen, &p, &q, ret_public_key, ret_private_key)) return FALSE; silc_mp_uninit(&p); silc_mp_uninit(&q); return TRUE; }
SilcBool silc_pkcs1_encrypt(void *public_key, unsigned char *src, SilcUInt32 src_len, unsigned char *dst, SilcUInt32 dst_size, SilcUInt32 *ret_dst_len, SilcRng rng) { RsaPublicKey *key = public_key; SilcMPInt mp_tmp; SilcMPInt mp_dst; unsigned char padded[2048 + 1]; SilcUInt32 len = (key->bits + 7) / 8; if (sizeof(padded) < len) return FALSE; if (dst_size < len) return FALSE; /* Pad data */ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PUB, src, src_len, padded, len, rng)) return FALSE; silc_mp_init(&mp_tmp); silc_mp_init(&mp_dst); /* Data to MP */ silc_mp_bin2mp(padded, len, &mp_tmp); /* Encrypt */ silc_rsa_public_operation(key, &mp_tmp, &mp_dst); /* MP to data */ silc_mp_mp2bin_noalloc(&mp_dst, dst, len); *ret_dst_len = len; memset(padded, 0, sizeof(padded)); silc_mp_uninit(&mp_tmp); silc_mp_uninit(&mp_dst); return TRUE; }
SilcBool silc_mp_modinv(SilcMPInt *inv, SilcMPInt *a, SilcMPInt *n) { int i; SilcMPInt y; SilcMPInt x; ModInv g[3]; ModInv v[3]; /* init MP vars */ silc_mp_init(&y); silc_mp_init(&x); silc_mp_init(&v[0].x); silc_mp_init(&v[1].x); silc_mp_set_ui(&v[0].x, 0L); /* v(0) = 0 */ silc_mp_set_ui(&v[1].x, 1L); /* v(1) = 1 */ silc_mp_init(&v[2].x); silc_mp_init(&g[0].x); silc_mp_init(&g[1].x); silc_mp_set(&g[0].x, n); /* g(0) = n */ silc_mp_set(&g[1].x, a); /* g(1) = a */ silc_mp_init(&g[2].x); i = 1; while(silc_mp_cmp_ui(&g[i].x, 0) != 0) { silc_mp_div(&y, &g[minus1].x, &g[i].x); /* y = n / a */ silc_mp_mod(&g[plus1].x, &g[minus1].x, &g[i].x); /* remainder */ silc_mp_mul(&x, &y, &v[i].x); silc_mp_set(&v[plus1].x, &v[minus1].x); silc_mp_sub(&v[plus1].x, &v[plus1].x, &x); i = plus1; } /* set the inverse */ silc_mp_set(inv, &v[minus1].x); /* if inverse is negative, add n to inverse */ if (silc_mp_cmp_ui(inv, 0) < 0) silc_mp_add(inv, inv, n); /* clear the vars */ memset(&g, 0, sizeof(g)); memset(&v, 0, sizeof(v)); silc_mp_uninit(&y); silc_mp_uninit(&x); silc_mp_uninit(&g[0].x); silc_mp_uninit(&g[1].x); silc_mp_uninit(&g[2].x); silc_mp_uninit(&v[0].x); silc_mp_uninit(&v[1].x); silc_mp_uninit(&v[2].x); return TRUE; }
void silc_pkcs1_private_key_free(void *private_key) { RsaPrivateKey *key = private_key; silc_mp_uninit(&key->n); silc_mp_uninit(&key->e); silc_mp_uninit(&key->d); silc_mp_uninit(&key->dP); silc_mp_uninit(&key->dQ); silc_mp_uninit(&key->qP); silc_mp_uninit(&key->p); silc_mp_uninit(&key->q); silc_free(key); }
void silc_mp_mp2bin_noalloc(SilcMPInt *val, unsigned char *dst, SilcUInt32 dst_len) { int i; SilcUInt32 size = dst_len; SilcMPInt tmp; silc_mp_init(&tmp); silc_mp_set(&tmp, val); for (i = size; i > 0; i--) { dst[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff); silc_mp_div_2exp(&tmp, &tmp, 8); } silc_mp_uninit(&tmp); }
SilcBool silc_rsa_generate_keys(SilcUInt32 bits, SilcMPInt *p, SilcMPInt *q, void **ret_public_key, void **ret_private_key) { RsaPublicKey *pubkey; RsaPrivateKey *privkey; SilcMPInt phi, hlp; SilcMPInt div, lcm; SilcMPInt pm1, qm1; *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey)); if (!pubkey) return FALSE; *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey)); if (!privkey) return FALSE; /* Default hash shall be sha1 */ silc_hash_alloc("sha1", &pubkey->hash); silc_hash_alloc("sha1", &privkey->hash); /* Initialize variables */ silc_mp_init(&privkey->n); silc_mp_init(&privkey->e); silc_mp_init(&privkey->d); silc_mp_init(&privkey->dP); silc_mp_init(&privkey->dQ); silc_mp_init(&privkey->qP); silc_mp_init(&phi); silc_mp_init(&hlp); silc_mp_init(&div); silc_mp_init(&lcm); silc_mp_init(&pm1); silc_mp_init(&qm1); /* Set modulus length */ privkey->bits = bits; /* Compute modulus, n = p * q */ silc_mp_mul(&privkey->n, p, q); /* phi = (p - 1) * (q - 1) */ silc_mp_sub_ui(&pm1, p, 1); silc_mp_sub_ui(&qm1, q, 1); silc_mp_mul(&phi, &pm1, &qm1); /* Set e, the public exponent. We try to use same public exponent for all keys. Also, to make encryption faster we use small number. */ silc_mp_set_ui(&privkey->e, 65533); retry_e: /* See if e is relatively prime to phi. gcd == greates common divisor, if gcd equals 1 they are relatively prime. */ silc_mp_gcd(&hlp, &privkey->e, &phi); if ((silc_mp_cmp_ui(&hlp, 1)) > 0) { silc_mp_add_ui(&privkey->e, &privkey->e, 2); goto retry_e; } /* Find d, the private exponent, e ^ -1 mod lcm(phi). */ silc_mp_gcd(&div, &pm1, &qm1); silc_mp_div(&lcm, &phi, &div); silc_mp_modinv(&privkey->d, &privkey->e, &lcm); /* Optimize d with CRT. */ silc_mp_mod(&privkey->dP, &privkey->d, &pm1); silc_mp_mod(&privkey->dQ, &privkey->d, &qm1); silc_mp_modinv(&privkey->qP, q, p); silc_mp_set(&privkey->p, p); silc_mp_set(&privkey->q, q); silc_mp_uninit(&phi); silc_mp_uninit(&hlp); silc_mp_uninit(&div); silc_mp_uninit(&lcm); silc_mp_uninit(&pm1); silc_mp_uninit(&qm1); /* Set public key */ silc_mp_init(&pubkey->n); silc_mp_init(&pubkey->e); pubkey->bits = privkey->bits; silc_mp_set(&pubkey->n, &privkey->n); silc_mp_set(&pubkey->e, &privkey->e); return TRUE; }
SilcBool silc_pkcs1_verify(void *public_key, unsigned char *signature, SilcUInt32 signature_len, unsigned char *data, SilcUInt32 data_len, SilcHash hash) { RsaPublicKey *key = public_key; SilcBool ret = FALSE; SilcMPInt mp_tmp2; SilcMPInt mp_dst; unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN]; SilcUInt32 verify_len, len = (key->bits + 7) / 8; SilcBufferStruct di, ldi; SilcHash ihash = NULL; SilcAsn1 asn1 = NULL; char *oid; SILC_LOG_DEBUG(("Verify signature")); asn1 = silc_asn1_alloc(); if (!asn1) return FALSE; silc_mp_init(&mp_tmp2); silc_mp_init(&mp_dst); /* Format the signature into MP int */ silc_mp_bin2mp(signature, signature_len, &mp_tmp2); /* Verify */ silc_rsa_public_operation(key, &mp_tmp2, &mp_dst); /* MP to data */ verify = silc_mp_mp2bin(&mp_dst, len, &verify_len); /* Unpad data */ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len, unpadded, sizeof(unpadded), &len)) goto err; silc_buffer_set(&di, unpadded, len); /* If hash isn't given, allocate the one given in digest info */ if (!hash) { /* Decode digest info */ if (!silc_asn1_decode(asn1, &di, SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL), SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE, SILC_ASN1_OID(&oid), SILC_ASN1_END, SILC_ASN1_END, SILC_ASN1_END)) goto err; if (!silc_hash_alloc_by_oid(oid, &ihash)) { SILC_LOG_DEBUG(("Unknown OID %s", oid)); goto err; } hash = ihash; } /* Hash the data */ silc_hash_make(hash, data, data_len, hashr); data = hashr; data_len = silc_hash_len(hash); oid = (char *)silc_hash_get_oid(hash); /* Encode digest info for comparison */ memset(&ldi, 0, sizeof(ldi)); if (!silc_asn1_encode(asn1, &ldi, SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL), SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE, SILC_ASN1_OID(oid), SILC_ASN1_NULL, SILC_ASN1_END, SILC_ASN1_OCTET_STRING(data, data_len), SILC_ASN1_END, SILC_ASN1_END)) goto err; SILC_LOG_HEXDUMP(("DigestInfo remote"), silc_buffer_data(&di), silc_buffer_len(&di)); SILC_LOG_HEXDUMP(("DigestInfo local"), silc_buffer_data(&ldi), silc_buffer_len(&ldi)); /* Compare */ if (silc_buffer_len(&di) == silc_buffer_len(&ldi) && !memcmp(silc_buffer_data(&di), silc_buffer_data(&ldi), silc_buffer_len(&ldi))) ret = TRUE; memset(verify, 0, verify_len); memset(unpadded, 0, sizeof(unpadded)); silc_free(verify); silc_mp_uninit(&mp_tmp2); silc_mp_uninit(&mp_dst); if (hash) memset(hashr, 0, sizeof(hashr)); if (ihash) silc_hash_free(ihash); silc_asn1_free(asn1); return ret; err: memset(verify, 0, verify_len); silc_free(verify); silc_mp_uninit(&mp_tmp2); silc_mp_uninit(&mp_dst); if (ihash) silc_hash_free(ihash); silc_asn1_free(asn1); return FALSE; }
SilcBool silc_pkcs1_sign(void *private_key, unsigned char *src, SilcUInt32 src_len, unsigned char *signature, SilcUInt32 signature_size, SilcUInt32 *ret_signature_len, SilcBool compute_hash, SilcHash hash) { RsaPrivateKey *key = private_key; unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN]; SilcMPInt mp_tmp; SilcMPInt mp_dst; SilcBufferStruct di; SilcUInt32 len = (key->bits + 7) / 8; const char *oid; SilcAsn1 asn1; SILC_LOG_DEBUG(("Sign")); if (sizeof(padded) < len) return FALSE; if (signature_size < len) return FALSE; oid = silc_hash_get_oid(hash); if (!oid) return FALSE; asn1 = silc_asn1_alloc(); if (!asn1) return FALSE; /* Compute hash */ if (compute_hash) { silc_hash_make(hash, src, src_len, hashr); src = hashr; src_len = silc_hash_len(hash); } /* Encode digest info */ memset(&di, 0, sizeof(di)); if (!silc_asn1_encode(asn1, &di, SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE, SILC_ASN1_OID(oid), SILC_ASN1_NULL, SILC_ASN1_END, SILC_ASN1_OCTET_STRING(src, src_len), SILC_ASN1_END, SILC_ASN1_END)) { silc_asn1_free(asn1); return FALSE; } SILC_LOG_HEXDUMP(("DigestInfo"), silc_buffer_data(&di), silc_buffer_len(&di)); /* Pad data */ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, silc_buffer_data(&di), silc_buffer_len(&di), padded, len, NULL)) { silc_asn1_free(asn1); return FALSE; } silc_mp_init(&mp_tmp); silc_mp_init(&mp_dst); /* Data to MP */ silc_mp_bin2mp(padded, len, &mp_tmp); /* Sign */ silc_rsa_private_operation(key, &mp_tmp, &mp_dst); /* MP to data */ silc_mp_mp2bin_noalloc(&mp_dst, signature, len); *ret_signature_len = len; memset(padded, 0, sizeof(padded)); silc_mp_uninit(&mp_tmp); silc_mp_uninit(&mp_dst); if (compute_hash) memset(hashr, 0, sizeof(hashr)); silc_asn1_free(asn1); return TRUE; }