/** Perform on the ECC system @return CRYPT_OK if successful */ int ecc_test(void) { void *modulus, *order; ecc_point *G, *GG; int i, err, primality; if ((err = mp_init_multi(&modulus, &order, NULL)) != CRYPT_OK) { return err; } G = ltc_ecc_new_point(); GG = ltc_ecc_new_point(); if (G == NULL || GG == NULL) { mp_clear_multi(modulus, order, NULL); ltc_ecc_del_point(G); ltc_ecc_del_point(GG); return CRYPT_MEM; } for (i = 0; ltc_ecc_sets[i].size; i++) { #if 0 printf("Testing %d\n", ltc_ecc_sets[i].size); #endif if ((err = mp_read_radix(modulus, (char *)ltc_ecc_sets[i].prime, 16)) != CRYPT_OK) { goto done; } if ((err = mp_read_radix(order, (char *)ltc_ecc_sets[i].order, 16)) != CRYPT_OK) { goto done; } /* is prime actually prime? */ if ((err = mp_prime_is_prime(modulus, 8, &primality)) != CRYPT_OK) { goto done; } if (primality == 0) { err = CRYPT_FAIL_TESTVECTOR; goto done; } /* is order prime ? */ if ((err = mp_prime_is_prime(order, 8, &primality)) != CRYPT_OK) { goto done; } if (primality == 0) { err = CRYPT_FAIL_TESTVECTOR; goto done; } if ((err = mp_read_radix(G->x, (char *)ltc_ecc_sets[i].Gx, 16)) != CRYPT_OK) { goto done; } if ((err = mp_read_radix(G->y, (char *)ltc_ecc_sets[i].Gy, 16)) != CRYPT_OK) { goto done; } mp_set(G->z, 1); /* then we should have G == (order + 1)G */ if ((err = mp_add_d(order, 1, order)) != CRYPT_OK) { goto done; } if ((err = ltc_mp.ecc_ptmul(order, G, GG, modulus, 1)) != CRYPT_OK) { goto done; } if (mp_cmp(G->x, GG->x) != LTC_MP_EQ || mp_cmp(G->y, GG->y) != LTC_MP_EQ) { err = CRYPT_FAIL_TESTVECTOR; goto done; } } err = CRYPT_OK; goto done; done: ltc_ecc_del_point(GG); ltc_ecc_del_point(G); mp_clear_multi(order, modulus, NULL); return err; }
/** Create an ECC shared secret between two keys @param private_key The private ECC key @param public_key The public key @param out [out] Destination of the shared secret (Conforms to EC-DH from ANSI X9.63) @param outlen [in/out] The max size and resulting size of the shared secret @return CRYPT_OK if successful */ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, unsigned char *out, unsigned long *outlen) { unsigned long x; ecc_point *result; void *prime; int err; LTC_ARGCHK(private_key != NULL); LTC_ARGCHK(public_key != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); /* type valid? */ if (private_key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } if (ltc_ecc_is_valid_idx(private_key->idx) == 0 || ltc_ecc_is_valid_idx(public_key->idx) == 0) { return CRYPT_INVALID_ARG; } if (XSTRCMP(private_key->dp->name, public_key->dp->name) != 0) { return CRYPT_PK_TYPE_MISMATCH; } /* make new point */ result = ltc_ecc_new_point(); if (result == NULL) { return CRYPT_MEM; } if ((err = mp_init(&prime)) != CRYPT_OK) { ltc_ecc_del_point(result); return err; } if ((err = mp_read_radix(prime, (char *)private_key->dp->prime, 16)) != CRYPT_OK) { goto done; } if ((err = ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1)) != CRYPT_OK) { goto done; } x = (unsigned long)mp_unsigned_bin_size(prime); if (*outlen < x) { *outlen = x; err = CRYPT_BUFFER_OVERFLOW; goto done; } zeromem(out, x); if ((err = mp_to_unsigned_bin(result->x, out + (x - mp_unsigned_bin_size(result->x)))) != CRYPT_OK) { goto done; } err = CRYPT_OK; *outlen = x; done: mp_clear(prime); ltc_ecc_del_point(result); return err; }
void ecc_gen(void) { FILE *out; unsigned char str[512]; void *k, *order, *modulus; ecc_point *G, *R; int x; out = fopen("ecc_tv.txt", "w"); fprintf(out, "ecc vectors. These are for kG for k=1,3,9,27,...,3**n until k > order of the curve outputs are <k,x,y> triplets\n\n"); G = ltc_ecc_new_point(); R = ltc_ecc_new_point(); mp_init(&k); mp_init(&order); mp_init(&modulus); for (x = 0; ltc_ecc_sets[x].size != 0; x++) { fprintf(out, "ECC-%d\n", ltc_ecc_sets[x].size*8); mp_set(k, 1); mp_read_radix(order, (char *)ltc_ecc_sets[x].order, 16); mp_read_radix(modulus, (char *)ltc_ecc_sets[x].prime, 16); mp_read_radix(G->x, (char *)ltc_ecc_sets[x].Gx, 16); mp_read_radix(G->y, (char *)ltc_ecc_sets[x].Gy, 16); mp_set(G->z, 1); while (mp_cmp(k, order) == LTC_MP_LT) { ltc_mp.ecc_ptmul(k, G, R, modulus, 1); mp_tohex(k, (char*)str); fprintf(out, "%s, ", (char*)str); mp_tohex(R->x, (char*)str); fprintf(out, "%s, ", (char*)str); mp_tohex(R->y, (char*)str); fprintf(out, "%s\n", (char*)str); mp_mul_d(k, 3, k); } } mp_clear_multi(k, order, modulus, NULL); ltc_ecc_del_point(G); ltc_ecc_del_point(R); fclose(out); }
/** Verify an ECC signature @param sig The signature to verify @param siglen The length of the signature (octets) @param hash The hash (message digest) that was signed @param hashlen The length of the hash (octets) @param stat Result of signature, 1==valid, 0==invalid @param key The corresponding public ECC key @return CRYPT_OK if successful (even if the signature is not valid) */ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int *stat, ecc_key *key) { ecc_point *mG, *mQ; void *r, *s, *v, *w, *u1, *u2, *e, *p, *m; void *mp; int err; LTC_ARGCHK(sig != NULL); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid signature */ *stat = 0; mp = NULL; /* is the IDX valid ? */ if (ltc_ecc_is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } /* allocate ints */ if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != CRYPT_OK) { return CRYPT_MEM; } /* allocate points */ mG = ltc_ecc_new_point(); mQ = ltc_ecc_new_point(); if (mQ == NULL || mG == NULL) { err = CRYPT_MEM; goto error; } /* parse header */ if ((err = der_decode_sequence_multi(sig, siglen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; } /* get the order */ if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } /* get the modulus */ if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } /* check for zero */ if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; goto error; } /* read hash */ if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, (int)hashlen)) != CRYPT_OK) { goto error; } /* w = s^-1 mod n */ if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; } /* u1 = ew */ if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; } /* u2 = rw */ if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } /* find mG and mQ */ if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } /* compute u1*mG + u2*mQ = mG */ if (ltc_mp.ecc_mul2add == NULL) { if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK) { goto error; } if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK) { goto error; } /* find the montgomery mp */ if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } /* add them */ if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK) { goto error; } /* reduce */ if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } } else { /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m)) != CRYPT_OK) { goto error; } } /* v = X_x1 mod n */ if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } /* does v == r */ if (mp_cmp(v, r) == LTC_MP_EQ) { *stat = 1; } /* clear up and return */ err = CRYPT_OK; error: ltc_ecc_del_point(mG); ltc_ecc_del_point(mQ); mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL); if (mp != NULL) { mp_montgomery_free(mp); } return err; }
int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp) { int err; ecc_point *base; void *prime; unsigned char *buf; int keysize; LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); LTC_ARGCHK(dp != NULL); /* good prng? */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } key->idx = -1; key->dp = dp; keysize = dp->size; /* allocate ram */ base = NULL; buf = XMALLOC(ECC_MAXSIZE); if (buf == NULL) { return CRYPT_MEM; } /* make up random string */ if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { err = CRYPT_ERROR_READPRNG; goto ERR_BUF; } /* setup the key variables */ if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, NULL)) != CRYPT_OK) { goto ERR_BUF; } base = ltc_ecc_new_point(); if (base == NULL) { err = CRYPT_MEM; goto errkey; } /* read in the specs for this key */ if ((err = mp_read_radix(prime, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_set(base->z, 1)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto errkey; } /* make the public key */ if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK) { goto errkey; } key->type = PK_PRIVATE; /* free up ram */ err = CRYPT_OK; goto cleanup; errkey: mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); cleanup: ltc_ecc_del_point(base); mp_clear(prime); ERR_BUF: #ifdef LTC_CLEAN_STACK zeromem(buf, ECC_MAXSIZE); #endif XFREE(buf); return err; }
int ecc_test_shamir(void) { void *modulus, *mp, *kA, *kB, *rA, *rB; ecc_point *G, *A, *B, *C1, *C2; int x, y, z; unsigned char buf[ECC_BUF_SIZE]; DO(mp_init_multi(&kA, &kB, &rA, &rB, &modulus, NULL)); LTC_ARGCHK((G = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((A = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((B = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((C1 = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((C2 = ltc_ecc_new_point()) != NULL); for (x = 0; x < (int)(sizeof(sizes)/sizeof(sizes[0])); x++) { /* get the base point */ for (z = 0; ltc_ecc_sets[z].name; z++) { if (sizes[z] < ltc_ecc_sets[z].size) break; } LTC_ARGCHK(ltc_ecc_sets[z].name != NULL); /* load it */ DO(mp_read_radix(G->x, ltc_ecc_sets[z].Gx, 16)); DO(mp_read_radix(G->y, ltc_ecc_sets[z].Gy, 16)); DO(mp_set(G->z, 1)); DO(mp_read_radix(modulus, ltc_ecc_sets[z].prime, 16)); DO(mp_montgomery_setup(modulus, &mp)); /* do 100 random tests */ for (y = 0; y < 100; y++) { /* pick a random r1, r2 */ LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(rA, buf, sizes[x])); LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(rB, buf, sizes[x])); /* compute rA * G = A */ DO(ltc_mp.ecc_ptmul(rA, G, A, modulus, 1)); /* compute rB * G = B */ DO(ltc_mp.ecc_ptmul(rB, G, B, modulus, 1)); /* pick a random kA, kB */ LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(kA, buf, sizes[x])); LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(kB, buf, sizes[x])); /* now, compute kA*A + kB*B = C1 using the older method */ DO(ltc_mp.ecc_ptmul(kA, A, C1, modulus, 0)); DO(ltc_mp.ecc_ptmul(kB, B, C2, modulus, 0)); DO(ltc_mp.ecc_ptadd(C1, C2, C1, modulus, mp)); DO(ltc_mp.ecc_map(C1, modulus, mp)); /* now compute using mul2add */ DO(ltc_mp.ecc_mul2add(A, kA, B, kB, C2, modulus)); /* is they the sames? */ if ((mp_cmp(C1->x, C2->x) != LTC_MP_EQ) || (mp_cmp(C1->y, C2->y) != LTC_MP_EQ) || (mp_cmp(C1->z, C2->z) != LTC_MP_EQ)) { fprintf(stderr, "ECC failed shamir test: size=%d, testno=%d\n", sizes[x], y); return 1; } } mp_montgomery_free(mp); } ltc_ecc_del_point(C2); ltc_ecc_del_point(C1); ltc_ecc_del_point(B); ltc_ecc_del_point(A); ltc_ecc_del_point(G); mp_clear_multi(kA, kB, rA, rB, modulus, NULL); return 0; }
/** Make a new ECC key @param prng An active PRNG state @param wprng The index of the PRNG you wish to use @param keysize The keysize for the new key (in octets from 20 to 65 bytes) @param key [out] Destination of the newly created key @return CRYPT_OK if successful, upon error all allocated memory will be freed */ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) { int x, err; ecc_point *base; void *prime; unsigned char *buf; LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); /* good prng? */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } /* find key size */ for (x = 0; (keysize > ltc_ecc_sets[x].size) && (ltc_ecc_sets[x].size != 0); x++); keysize = ltc_ecc_sets[x].size; if (keysize > ECC_MAXSIZE || ltc_ecc_sets[x].size == 0) { return CRYPT_INVALID_KEYSIZE; } key->idx = x; /* allocate ram */ base = NULL; buf = XMALLOC(ECC_MAXSIZE); if (buf == NULL) { return CRYPT_MEM; } /* make up random string */ if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR2; } /* setup the key variables */ if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, NULL)) != CRYPT_OK) { goto done; } base = ltc_ecc_new_point(); if (base == NULL) { mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, prime, NULL); err = CRYPT_MEM; goto done; } /* read in the specs for this key */ if ((err = mp_read_radix(prime, (char *)ltc_ecc_sets[key->idx].prime, 16)) != CRYPT_OK) { goto done; } if ((err = mp_read_radix(base->x, (char *)ltc_ecc_sets[key->idx].Gx, 16)) != CRYPT_OK) { goto done; } if ((err = mp_read_radix(base->y, (char *)ltc_ecc_sets[key->idx].Gy, 16)) != CRYPT_OK) { goto done; } mp_set(base->z, 1); if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto done; } /* make the public key */ if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK) { goto done; } key->type = PK_PRIVATE; /* free up ram */ err = CRYPT_OK; done: ltc_ecc_del_point(base); mp_clear(prime); LBL_ERR2: #ifdef LTC_CLEAN_STACK zeromem(buf, ECC_MAXSIZE); #endif XFREE(buf); return err; }
int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp) { int err; ecc_point *base; void *prime, *order, *a; unsigned char *buf; int keysize, orderbits; LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); LTC_ARGCHK(dp != NULL); /* good prng? */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } key->idx = -1; key->dp = dp; keysize = dp->size; /* allocate ram */ base = NULL; buf = XMALLOC(ECC_MAXSIZE); if (buf == NULL) { return CRYPT_MEM; } /* make up random string */ if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { err = CRYPT_ERROR_READPRNG; goto ERR_BUF; } /* setup the key variables */ if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, &order, &a, NULL)) != CRYPT_OK) { goto ERR_BUF; } base = ltc_ecc_new_point(); if (base == NULL) { err = CRYPT_MEM; goto errkey; } /* read in the specs for this key */ if ((err = mp_read_radix(prime, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(order, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_set(base->z, 1)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto errkey; } /* ECC key pair generation according to FIPS-186-4 (B.4.2 Key Pair Generation by Testing Candidates): * the generated private key k should be the range [1, order–1] * a/ N = bitlen(order) * b/ generate N random bits and convert them into big integer k * c/ if k not in [1, order-1] go to b/ * e/ Q = k*G */ orderbits = mp_count_bits(order); do { if ((err = rand_bn_bits(key->k, orderbits, prng, wprng)) != CRYPT_OK) { goto errkey; } } while (mp_iszero(key->k) || mp_cmp(key->k, order) != LTC_MP_LT); /* make the public key */ if ((err = mp_read_radix(a, (char *)key->dp->A, 16)) != CRYPT_OK) { goto errkey; } if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, a, prime, 1)) != CRYPT_OK) { goto errkey; } key->type = PK_PRIVATE; /* free up ram */ err = CRYPT_OK; goto cleanup; errkey: mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); cleanup: ltc_ecc_del_point(base); mp_clear_multi(prime, order, a, NULL); ERR_BUF: #ifdef LTC_CLEAN_STACK zeromem(buf, ECC_MAXSIZE); #endif XFREE(buf); return err; }