From 3072edb696d5a35041174e9e64985fa688133ccb Mon Sep 17 00:00:00 2001 From: toddouska Date: Fri, 29 Aug 2014 14:25:58 -0700 Subject: [PATCH] add compressed key support --- certs/ecc-key-comp.pem | 4 + certs/include.am | 2 + certs/server-ecc-comp.pem | 15 ++ certs/taoCert.txt | 2 + configure.ac | 2 +- ctaocrypt/src/ecc.c | 432 +++++++++++++++++++++++++++++++++++-- ctaocrypt/src/integer.c | 72 ++++--- ctaocrypt/src/tfm.c | 130 ++++++----- ctaocrypt/test/test.c | 32 ++- cyassl/ctaocrypt/ecc.h | 4 + cyassl/ctaocrypt/integer.h | 3 + cyassl/ctaocrypt/tfm.h | 9 +- cyassl/version.h | 4 +- 13 files changed, 602 insertions(+), 109 deletions(-) create mode 100644 certs/ecc-key-comp.pem create mode 100644 certs/server-ecc-comp.pem diff --git a/certs/ecc-key-comp.pem b/certs/ecc-key-comp.pem new file mode 100644 index 000000000..de76b8e03 --- /dev/null +++ b/certs/ecc-key-comp.pem @@ -0,0 +1,4 @@ +-----BEGIN EC PRIVATE KEY----- +MFcCAQEEIEW2aQJznGyFoThbcujox6zEA41TNQT6bCjcNI3hqAmMoAoGCCqGSM49 +AwEHoSQDIgACuzOsTCdQSsZKpQTDPN6fNttyLc6U6iv6yyAJOSwW6GE= +-----END EC PRIVATE KEY----- diff --git a/certs/include.am b/certs/include.am index 32a2bfd0d..42a936435 100644 --- a/certs/include.am +++ b/certs/include.am @@ -9,6 +9,7 @@ EXTRA_DIST += \ certs/client-keyEnc.pem \ certs/client-key.pem \ certs/ecc-key.pem \ + certs/ecc-key-comp.pem \ certs/ecc-keyPkcs8.pem \ certs/ecc-client-key.pem \ certs/client-ecc-cert.pem \ @@ -16,6 +17,7 @@ EXTRA_DIST += \ certs/dh2048.pem \ certs/server-cert.pem \ certs/server-ecc.pem \ + certs/server-ecc-comp.pem \ certs/server-ecc-rsa.pem \ certs/server-keyEnc.pem \ certs/server-key.pem \ diff --git a/certs/server-ecc-comp.pem b/certs/server-ecc-comp.pem new file mode 100644 index 000000000..e3d0b55b2 --- /dev/null +++ b/certs/server-ecc-comp.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICZzCCAg2gAwIBAgIJAOpbhU0jW8ssMAoGCCqGSM49BAMCMIGfMQswCQYDVQQG +EwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHRWRtb25kczEcMBoG +A1UECgwTRWxsaXB0aWMgQ29tcHJlc3NlZDERMA8GA1UECwwIRUNDIENvbXAxGDAW +BgNVBAMMD3d3dy53b2xmc3NsLmNvbTEeMBwGCSqGSIb3DQEJARYPd3d3LndvbGZz +c2wuY29tMB4XDTE0MDgyNzIyNTczOVoXDTE3MDUyMzIyNTczOVowgZ8xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdFZG1vbmRzMRww +GgYDVQQKDBNFbGxpcHRpYyBDb21wcmVzc2VkMREwDwYDVQQLDAhFQ0MgQ29tcDEY +MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR4wHAYJKoZIhvcNAQkBFg93d3cud29s +ZnNzbC5jb20wOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAAK7M6xMJ1BKxkqlBMM8 +3p8223ItzpTqK/rLIAk5LBboYaNQME4wHQYDVR0OBBYEFIw4Omu4JLffbvRZrFZO +quJYploYMB8GA1UdIwQYMBaAFIw4Omu4JLffbvRZrFZOquJYploYMAwGA1UdEwQF +MAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgCNYOU7G50eHWoHoaadAXswKrN5Vj6nyh +YUGS3zttSk4CIQD1Abqc61PBUQF6LO4OmBy79zEtWv9PRNH95iJ7V58vXA== +-----END CERTIFICATE----- diff --git a/certs/taoCert.txt b/certs/taoCert.txt index 798660767..6f0d500b1 100644 --- a/certs/taoCert.txt +++ b/certs/taoCert.txt @@ -123,6 +123,8 @@ openssl dhparam -in dh2048.param -text > dh2048.pem make a new key openssl ecparam -genkey -text -name secp256r1 -out ecc-key.pem + convert to compressed + openssl ec -in ecc-key.pem -conv_form compressed -out ecc-key-comp.pem *** CRL *** diff --git a/configure.ac b/configure.ac index 180ef759d..bf6c7e086 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ # # -AC_INIT([cyassl],[3.1.1],[https://github.com/cyassl/cyassl/issues],[cyassl],[http://www.wolfssl.com]) +AC_INIT([cyassl],[3.1.2],[https://github.com/cyassl/cyassl/issues],[cyassl],[http://www.wolfssl.com]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/ctaocrypt/src/ecc.c b/ctaocrypt/src/ecc.c index aa74a9650..981940ac1 100644 --- a/ctaocrypt/src/ecc.c +++ b/ctaocrypt/src/ecc.c @@ -65,6 +65,7 @@ const ecc_set_type ecc_sets[] = { 14, "SECP112R1", "DB7C2ABF62E35E668076BEAD208B", + "DB7C2ABF62E35E668076BEAD2088", "659EF8BA043916EEDE8911702B22", "DB7C2ABF62E35E7628DFAC6561C5", "09487239995A5EE76B55F9C2F098", @@ -76,6 +77,7 @@ const ecc_set_type ecc_sets[] = { 16, "SECP128R1", "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", "E87579C11079F43DD824993C2CEE5ED3", "FFFFFFFE0000000075A30D1B9038A115", "161FF7528B899B2D0C28607CA52C5B86", @@ -87,6 +89,7 @@ const ecc_set_type ecc_sets[] = { 20, "SECP160R1", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", "0100000000000000000001F4C8F927AED3CA752257", "4A96B5688EF573284664698968C38BB913CBFC82", @@ -98,6 +101,7 @@ const ecc_set_type ecc_sets[] = { 24, "ECC-192", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", @@ -109,6 +113,7 @@ const ecc_set_type ecc_sets[] = { 28, "ECC-224", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", @@ -120,6 +125,7 @@ const ecc_set_type ecc_sets[] = { 32, "ECC-256", "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", @@ -131,6 +137,7 @@ const ecc_set_type ecc_sets[] = { 48, "ECC-384", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", @@ -142,6 +149,7 @@ const ecc_set_type ecc_sets[] = { 66, "ECC-521", "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", @@ -150,7 +158,7 @@ const ecc_set_type ecc_sets[] = { #endif { 0, - NULL, NULL, NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -169,6 +177,13 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, ecc_point* C, mp_int* modulus); #endif +int mp_jacobi(mp_int* a, mp_int* p, int* c); +int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret); +int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d); + +#ifdef HAVE_COMP_KEY +static int ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); +#endif /* helper for either lib */ static int get_digit_count(mp_int* a) @@ -2197,10 +2212,26 @@ int ecc_export_x963(ecc_key* key, byte* out, word32* outLen) } +/* export public ECC key in ANSI X9.63 format, extended with + * compression option */ +int ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, int compressed) +{ + if (compressed == 0) + return ecc_export_x963(key, out, outLen); +#ifdef HAVE_COMP_KEY + else + return ecc_export_x963_compressed(key, out, outLen); +#endif + + return NOT_COMPILED_IN; +} + + /* import public ECC key in ANSI X9.63 format */ int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) { int x, err; + int compressed = 0; if (in == NULL || key == NULL) return ECC_BAD_ARG_E; @@ -2217,24 +2248,25 @@ int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) } err = MP_OKAY; - /* check for 4, 6 or 7 */ - if (in[0] != 4 && in[0] != 6 && in[0] != 7) { + /* check for 4, 2, or 3 */ + if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) { err = ASN_PARSE_E; } - /* read data */ - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1); - - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->pubkey.y, (byte*)in+1+((inLen-1)>>1), - (inLen-1)>>1); - - if (err == MP_OKAY) - mp_set(&key->pubkey.z, 1); + if (in[0] == 0x02 || in[0] == 0x03) { +#ifdef HAVE_COMP_KEY + compressed = 1; +#else + err = NOT_COMPILED_IN; +#endif + } if (err == MP_OKAY) { - /* determine the idx */ + /* determine the idx */ + + if (compressed) + inLen = (inLen-1)*2 + 1; /* used uncompressed len */ + for (x = 0; ecc_sets[x].size != 0; x++) { if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) { break; @@ -2250,6 +2282,74 @@ int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) } } + /* read data */ + if (err == MP_OKAY) + err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1); + +#ifdef HAVE_COMP_KEY + if (err == MP_OKAY && compressed == 1) { /* build y */ + mp_int t1, t2, prime, a, b; + + if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY) + err = MEMORY_E; + + /* load prime */ + if (err == MP_OKAY) + err = mp_read_radix(&prime, (char *)key->dp->prime, 16); + + /* load a */ + if (err == MP_OKAY) + err = mp_read_radix(&a, (char *)key->dp->Af, 16); + + /* load b */ + if (err == MP_OKAY) + err = mp_read_radix(&b, (char *)key->dp->Bf, 16); + + /* compute x^3 */ + if (err == MP_OKAY) + err = mp_sqr(&key->pubkey.x, &t1); + + if (err == MP_OKAY) + err = mp_mulmod(&t1, &key->pubkey.x, &prime, &t1); + + /* compute x^3 + a*x */ + if (err == MP_OKAY) + err = mp_mulmod(&a, &key->pubkey.x, &prime, &t2); + + if (err == MP_OKAY) + err = mp_add(&t1, &t2, &t1); + + /* compute x^3 + a*x + b */ + if (err == MP_OKAY) + err = mp_add(&t1, &b, &t1); + + /* compute sqrt(x^3 + a*x + b) */ + if (err == MP_OKAY) + err = mp_sqrtmod_prime(&t1, &prime, &t2); + + /* adjust y */ + if (err == MP_OKAY) { + if ((mp_isodd(&t2) && in[0] == 0x03) || + (!mp_isodd(&t2) && in[0] == 0x02)) { + err = mp_mod(&t2, &prime, &key->pubkey.y); + } + else { + err = mp_submod(&prime, &t2, &prime, &key->pubkey.y); + } + } + + mp_clear(&prime); + mp_clear(&t2); + mp_clear(&t1); + } +#endif + + if (err == MP_OKAY && compressed == 0) + err = mp_read_unsigned_bin(&key->pubkey.y, (byte*)in+1+((inLen-1)>>1), + (inLen-1)>>1); + if (err == MP_OKAY) + mp_set(&key->pubkey.z, 1); + if (err != MP_OKAY) { mp_clear(&key->pubkey.x); mp_clear(&key->pubkey.y); @@ -4315,4 +4415,308 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, #endif /* HAVE_ECC_ENCRYPT */ + +#ifdef HAVE_COMP_KEY + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int mp_jacobi(mp_int* a, mp_int* p, int* c) +{ + mp_int a1, p1; + int k, s, r, res; + mp_digit residue; + + /* if p <= 0 return MP_VAL */ + if (mp_cmp_d(p, 0) != MP_GT) { + return MP_VAL; + } + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2**k */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&p1)) != MP_OKAY) { + mp_clear(&a1); + return res; + } + + /* divide out larger power of two */ + k = mp_cnt_lsb(&a1); + res = mp_div_2d(&a1, k, &a1, NULL); + + if (res == MP_OKAY) { + /* step 4. if e is even set s=1 */ + if ((k & 1) == 0) { + s = 1; + } else { + /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ + residue = p->dp[0] & 7; + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + s = -s; + } + } + + if (res == MP_OKAY) { + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + res = mp_mod (p, &a1, &p1); + if (res == MP_OKAY) + res = mp_jacobi (&p1, &a1, &r); + + if (res == MP_OKAY) + *c = s * r; + } + } + + /* done */ + mp_clear (&p1); + mp_clear (&a1); + + return res; +} + + +int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) +{ + int res, legendre, done = 0; + mp_int t1, C, Q, S, Z, M, T, R, two; + mp_digit i; + + /* first handle the simple cases */ + if (mp_cmp_d(n, 0) == MP_EQ) { + mp_zero(ret); + return MP_OKAY; + } + if (mp_cmp_d(prime, 2) == MP_EQ) return MP_VAL; /* prime must be odd */ + /* TAO removed + if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY) return res; + if (legendre == -1) return MP_VAL; */ /* quadratic non-residue mod prime */ + + if ((res = mp_init_multi(&t1, &C, &Q, &S, &Z, &M)) != MP_OKAY) + return res; + + if ((res = mp_init_multi(&T, &R, &two, NULL, NULL, NULL)) + != MP_OKAY) { + mp_clear(&t1); mp_clear(&C); mp_clear(&Q); mp_clear(&S); mp_clear(&Z); + mp_clear(&M); + return res; + } + + /* SPECIAL CASE: if prime mod 4 == 3 + * compute directly: res = n^(prime+1)/4 mod prime + * Handbook of Applied Cryptography algorithm 3.36 + */ + res = mp_mod_d(prime, 4, &i); + if (res == MP_OKAY && i == 3) { + res = mp_add_d(prime, 1, &t1); + + if (res == MP_OKAY) + res = mp_div_2(&t1, &t1); + if (res == MP_OKAY) + res = mp_div_2(&t1, &t1); + if (res == MP_OKAY) + res = mp_exptmod(n, &t1, prime, ret); + + done = 1; + } + + + /* NOW: TonelliShanks algorithm */ + + if (res == MP_OKAY && done == 0) { + + /* factor out powers of 2 from prime-1, defining Q and S + * as: prime-1 = Q*2^S */ + + res = mp_copy(prime, &Q); + if (res == MP_OKAY) + res = mp_sub_d(&Q, 1, &Q); + /* Q = prime - 1 */ + if (res == MP_OKAY) + mp_zero(&S); + /* S = 0 */ + while (res == MP_OKAY && mp_iseven(&Q)) { + res = mp_div_2(&Q, &Q); + /* Q = Q / 2 */ + if (res == MP_OKAY) + res = mp_add_d(&S, 1, &S); + /* S = S + 1 */ + } + + /* find a Z such that the Legendre symbol (Z|prime) == -1 */ + if (res == MP_OKAY) + res = mp_set_int(&Z, 2); + /* Z = 2 */ + while (res == MP_OKAY) { + res = mp_jacobi(&Z, prime, &legendre); + if (legendre == -1) + break; + if (res == MP_OKAY) + res = mp_add_d(&Z, 1, &Z); + /* Z = Z + 1 */ + } + + if (res == MP_OKAY) + res = mp_exptmod(&Z, &Q, prime, &C); + /* C = Z ^ Q mod prime */ + if (res == MP_OKAY) + res = mp_add_d(&Q, 1, &t1); + if (res == MP_OKAY) + res = mp_div_2(&t1, &t1); + /* t1 = (Q + 1) / 2 */ + if (res == MP_OKAY) + res = mp_exptmod(n, &t1, prime, &R); + /* R = n ^ ((Q + 1) / 2) mod prime */ + if (res == MP_OKAY) + res = mp_exptmod(n, &Q, prime, &T); + /* T = n ^ Q mod prime */ + if (res == MP_OKAY) + res = mp_copy(&S, &M); + /* M = S */ + if (res == MP_OKAY) + res = mp_set_int(&two, 2); + + if (res == MP_OKAY) + res = MP_VAL; + while (res == MP_OKAY && done == 0) { + res = mp_copy(&T, &t1); + i = 0; + while (res == MP_OKAY) { + if (mp_cmp_d(&t1, 1) == MP_EQ) + break; + res = mp_exptmod(&t1, &two, prime, &t1); + if (res == MP_OKAY) + i++; + } + if (res == MP_OKAY && i == 0) { + mp_copy(&R, ret); + res = MP_OKAY; + done = 1; + } + + if (done == 0) { + if (res == MP_OKAY) + res = mp_sub_d(&M, i, &t1); + if (res == MP_OKAY) + res = mp_sub_d(&t1, 1, &t1); + if (res == MP_OKAY) + res = mp_exptmod(&two, &t1, prime, &t1); + /* t1 = 2 ^ (M - i - 1) */ + if (res == MP_OKAY) + res = mp_exptmod(&C, &t1, prime, &t1); + /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ + if (res == MP_OKAY) + res = mp_sqrmod(&t1, prime, &C); + /* C = (t1 * t1) mod prime */ + if (res == MP_OKAY) + res = mp_mulmod(&R, &t1, prime, &R); + /* R = (R * t1) mod prime */ + if (res == MP_OKAY) + res = mp_mulmod(&T, &C, prime, &T); + /* T = (T * C) mod prime */ + if (res == MP_OKAY) + mp_set(&M, i); + /* M = i */ + } + } + } + + /* done */ + mp_clear(&t1); + mp_clear(&C); + mp_clear(&Q); + mp_clear(&S); + mp_clear(&Z); + mp_clear(&M); + mp_clear(&T); + mp_clear(&R); + mp_clear(&two); + + return res; +} + + +/* export public ECC key in ANSI X9.63 format compressed */ +int ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen) +{ + word32 numlen; + int ret = MP_OKAY; + + if (key == NULL || out == NULL || outLen == NULL) + return ECC_BAD_ARG_E; + + if (ecc_is_valid_idx(key->idx) == 0) { + return ECC_BAD_ARG_E; + } + numlen = key->dp->size; + + if (*outLen < (1 + numlen)) { + *outLen = 1 + numlen; + return BUFFER_E; + } + + /* store first byte */ + out[0] = mp_isodd(&key->pubkey.y) ? 0x03 : 0x02; + + /* pad and store x */ + XMEMSET(out+1, 0, numlen); + ret = mp_to_unsigned_bin(&key->pubkey.x, + out+1 + (numlen - mp_unsigned_bin_size(&key->pubkey.x))); + *outLen = 1 + numlen; + return ret; +} + + +/* d = a - b (mod c) */ +int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + + return res; +} + + +#endif /* HAVE_COMP_KEY */ + #endif /* HAVE_ECC */ diff --git a/ctaocrypt/src/integer.c b/ctaocrypt/src/integer.c index b39a36f9f..e9fb02281 100644 --- a/ctaocrypt/src/integer.c +++ b/ctaocrypt/src/integer.c @@ -3932,9 +3932,41 @@ int mp_sub_d (mp_int * a, mp_digit b, mp_int * c) #endif /* defined(HAVE_ECC) || !defined(NO_PWDBASED) */ -#ifdef CYASSL_KEY_GEN +#if defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + + -int mp_cnt_lsb(mp_int *a); static int s_is_power_of_two(mp_digit b, int *p) { @@ -4030,11 +4062,14 @@ static int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) } -static int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) { return mp_div_d(a, b, NULL, c); } +#endif /* defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) */ + +#ifdef CYASSL_KEY_GEN const mp_digit ltm_prime_tab[] = { 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, @@ -4291,37 +4326,6 @@ LBL_T: } -static const int lnz[16] = { - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 -}; - -/* Counts the number of lsbs which are zero before the first zero bit */ -int mp_cnt_lsb(mp_int *a) -{ - int x; - mp_digit q, qq; - - /* easy out */ - if (mp_iszero(a) == 1) { - return 0; - } - - /* scan lower digits until non-zero */ - for (x = 0; x < a->used && a->dp[x] == 0; x++); - q = a->dp[x]; - x *= DIGIT_BIT; - - /* now scan this digit until a 1 is found */ - if ((q & 1) == 0) { - do { - qq = q & 15; - x += lnz[qq]; - q >>= 4; - } while (qq == 0); - } - return x; -} - /* Greatest Common Divisor using the binary method */ int mp_gcd (mp_int * a, mp_int * b, mp_int * c) diff --git a/ctaocrypt/src/tfm.c b/ctaocrypt/src/tfm.c index 5fb6b2efc..55cee1c94 100644 --- a/ctaocrypt/src/tfm.c +++ b/ctaocrypt/src/tfm.c @@ -2035,34 +2035,40 @@ int mp_montgomery_calc_normalization(mp_int *a, mp_int *b) #endif /* CYASSL_KEYGEN || HAVE_ECC */ -#ifdef CYASSL_KEY_GEN +#if defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) -void fp_gcd(fp_int *a, fp_int *b, fp_int *c); -void fp_lcm(fp_int *a, fp_int *b, fp_int *c); -int fp_isprime(fp_int *a); -int fp_cnt_lsb(fp_int *a); +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; -int mp_gcd(fp_int *a, fp_int *b, fp_int *c) +/* Counts the number of lsbs which are zero before the first zero bit */ +int fp_cnt_lsb(fp_int *a) { - fp_gcd(a, b, c); - return MP_OKAY; + int x; + fp_digit q, qq; + + /* easy out */ + if (fp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; } -int mp_lcm(fp_int *a, fp_int *b, fp_int *c) -{ - fp_lcm(a, b, c); - return MP_OKAY; -} - - -int mp_prime_is_prime(mp_int* a, int t, int* result) -{ - (void)t; - *result = fp_isprime(a); - return MP_OKAY; -} - static int s_is_power_of_two(fp_digit b, int *p) @@ -2155,6 +2161,39 @@ static int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c) return fp_div_d(a, b, NULL, c); } +int mp_mod_d(fp_int *a, fp_digit b, fp_digit *c) +{ + return fp_mod_d(a, b, c); +} + +#endif /* defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) */ + +#ifdef CYASSL_KEY_GEN + +void fp_gcd(fp_int *a, fp_int *b, fp_int *c); +void fp_lcm(fp_int *a, fp_int *b, fp_int *c); +int fp_isprime(fp_int *a); + +int mp_gcd(fp_int *a, fp_int *b, fp_int *c) +{ + fp_gcd(a, b, c); + return MP_OKAY; +} + + +int mp_lcm(fp_int *a, fp_int *b, fp_int *c) +{ + fp_lcm(a, b, c); + return MP_OKAY; +} + + +int mp_prime_is_prime(mp_int* a, int t, int* result) +{ + (void)t; + *result = fp_isprime(a); + return MP_OKAY; +} /* Miller-Rabin test of "a" to the base of "b" as described in * HAC pp. 139 Algorithm 4.24 @@ -2304,37 +2343,6 @@ void fp_lcm(fp_int *a, fp_int *b, fp_int *c) } -static const int lnz[16] = { - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 -}; - -/* Counts the number of lsbs which are zero before the first zero bit */ -int fp_cnt_lsb(fp_int *a) -{ - int x; - fp_digit q, qq; - - /* easy out */ - if (fp_iszero(a) == 1) { - return 0; - } - - /* scan lower digits until non-zero */ - for (x = 0; x < a->used && a->dp[x] == 0; x++); - q = a->dp[x]; - x *= DIGIT_BIT; - - /* now scan this digit until a 1 is found */ - if ((q & 1) == 0) { - do { - qq = q & 15; - x += lnz[qq]; - q >>= 4; - } while (qq == 0); - } - return x; -} - /* c = (a, b) */ void fp_gcd(fp_int *a, fp_int *b, fp_int *c) @@ -2508,6 +2516,22 @@ int mp_init_copy(fp_int * a, fp_int * b) } +#ifdef HAVE_COMP_KEY + +int mp_cnt_lsb(fp_int* a) +{ + fp_cnt_lsb(a); + return MP_OKAY; +} + +int mp_div_2d(fp_int* a, int b, fp_int* c, fp_int* d) +{ + fp_div_2d(a, b, c, d); + return MP_OKAY; +} + +#endif /* HAVE_COMP_KEY */ + #endif /* HAVE_ECC */ diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index 78817abe7..1ddb5874b 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -4472,8 +4472,32 @@ int ecc_test(void) return -1008; if (memcmp(sharedA, sharedB, y)) + return -1009; + +#ifdef HAVE_COMP_KEY + /* try compressed export / import too */ + x = sizeof(exportBuf); + ret = ecc_export_x963_ex(&userA, exportBuf, &x, 1); + if (ret != 0) return -1010; + ecc_free(&pubKey); + ecc_init(&pubKey); + ret = ecc_import_x963(exportBuf, x, &pubKey); + + if (ret != 0) + return -1011; +#endif + + y = sizeof(sharedB); + ret = ecc_shared_secret(&userB, &pubKey, sharedB, &y); + + if (ret != 0) + return -1012; + + if (memcmp(sharedA, sharedB, y)) + return -1013; + /* test DSA sign hash */ for (i = 0; i < (int)sizeof(digest); i++) digest[i] = (byte)i; @@ -4482,21 +4506,21 @@ int ecc_test(void) ret = ecc_sign_hash(digest, sizeof(digest), sig, &x, &rng, &userA); if (ret != 0) - return -1016; + return -1014; verify = 0; ret = ecc_verify_hash(sig, x, digest, sizeof(digest), &verify, &userA); if (ret != 0) - return -1011; + return -1015; if (verify != 1) - return -1012; + return -1016; x = sizeof(exportBuf); ret = ecc_export_private_only(&userA, exportBuf, &x); if (ret != 0) - return -1013; + return -1017; ecc_free(&pubKey); ecc_free(&userB); diff --git a/cyassl/ctaocrypt/ecc.h b/cyassl/ctaocrypt/ecc.h index a885abf63..b9aac3428 100644 --- a/cyassl/ctaocrypt/ecc.h +++ b/cyassl/ctaocrypt/ecc.h @@ -49,6 +49,7 @@ typedef struct { int size; /* The size of the curve in octets */ const char* name; /* name of this curve */ const char* prime; /* prime that defines the field, curve is in (hex) */ + const char* Af; /* fields A param (hex) */ const char* Bf; /* fields B param (hex) */ const char* order; /* order of the curve (hex) */ const char* Gx; /* x coordinate of the base point on curve (hex) */ @@ -105,6 +106,9 @@ void ecc_fp_free(void); CYASSL_API int ecc_export_x963(ecc_key*, byte* out, word32* outLen); CYASSL_API +int ecc_export_x963_ex(ecc_key*, byte* out, word32* outLen, int compressed); + /* extended functionality with compressed option */ +CYASSL_API int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key); CYASSL_API int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, diff --git a/cyassl/ctaocrypt/integer.h b/cyassl/ctaocrypt/integer.h index 77b5552c7..f8c2b7147 100644 --- a/cyassl/ctaocrypt/integer.h +++ b/cyassl/ctaocrypt/integer.h @@ -310,6 +310,9 @@ int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, int mp_lcm (mp_int * a, mp_int * b, mp_int * c); #endif +int mp_cnt_lsb(mp_int *a); +int mp_mod_d(mp_int* a, mp_digit b, mp_digit* c); + #ifdef __cplusplus } #endif diff --git a/cyassl/ctaocrypt/tfm.h b/cyassl/ctaocrypt/tfm.h index f4e98c152..fae7141bf 100644 --- a/cyassl/ctaocrypt/tfm.h +++ b/cyassl/ctaocrypt/tfm.h @@ -398,7 +398,7 @@ void fp_mul_2(fp_int *a, fp_int *c); void fp_div_2(fp_int *a, fp_int *c); /* Counts the number of lsbs which are zero before the first zero bit */ -/*int fp_cnt_lsb(fp_int *a);*/ +int fp_cnt_lsb(fp_int *a); /* c = a + b */ void fp_add(fp_int *a, fp_int *b, fp_int *c); @@ -630,11 +630,14 @@ void fp_sqr_comba64(fp_int *a, fp_int *b); #define MP_LT FP_LT /* less than */ #define MP_EQ FP_EQ /* equal to */ #define MP_GT FP_GT /* greater than */ + #define MP_VAL FP_VAL /* invalid */ #define MP_OKAY FP_OKAY /* ok result */ #define MP_NO FP_NO /* yes/no result */ #define MP_YES FP_YES /* yes/no result */ /* Prototypes */ +#define mp_zero(a) fp_zero(a) +#define mp_iseven(a) fp_iseven(a) int mp_init (mp_int * a); void mp_clear (mp_int * a); int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f); @@ -686,6 +689,10 @@ int mp_lcm(fp_int *a, fp_int *b, fp_int *c); int mp_prime_is_prime(mp_int* a, int t, int* result); #endif /* CYASSL_KEY_GEN */ +int mp_cnt_lsb(fp_int *a); +int mp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d); +int mp_mod_d(fp_int* a, fp_digit b, fp_digit* c); + CYASSL_API word32 CheckRunTimeFastMath(void); /* If user uses RSA, DH, DSA, or ECC math lib directly then fast math FP_SIZE diff --git a/cyassl/version.h b/cyassl/version.h index c6274891b..5e5f03fd3 100644 --- a/cyassl/version.h +++ b/cyassl/version.h @@ -26,8 +26,8 @@ extern "C" { #endif -#define LIBCYASSL_VERSION_STRING "3.1.1" -#define LIBCYASSL_VERSION_HEX 0x03001001 +#define LIBCYASSL_VERSION_STRING "3.1.2" +#define LIBCYASSL_VERSION_HEX 0x03001002 #ifdef __cplusplus }