/* Construct ECGroup from named parameters. */ ECGroup * ECGroup_fromName(const ECCurveName name) { ECGroup *group = NULL; ECCurveParams *params = NULL; mp_err res = MP_OKAY; params = EC_GetNamedCurveParams(name); if (params == NULL) { res = MP_UNDEF; goto CLEANUP; } /* construct actual group */ group = ecgroup_fromNameAndHex(name, params); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } CLEANUP: EC_FreeCurveParams(params); if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Allocate memory for a new ECGroup object. */ ECGroup * ECGroup_new() { mp_err res = MP_OKAY; ECGroup *group; group = (ECGroup *) malloc(sizeof(ECGroup)); if (group == NULL) return NULL; group->constructed = MP_YES; group->meth = NULL; group->text = NULL; MP_DIGITS(&group->curvea) = 0; MP_DIGITS(&group->curveb) = 0; MP_DIGITS(&group->genx) = 0; MP_DIGITS(&group->geny) = 0; MP_DIGITS(&group->order) = 0; group->base_point_mul = NULL; group->points_mul = NULL; group->validate_point = NULL; group->extra1 = NULL; group->extra2 = NULL; group->extra_free = NULL; MP_CHECKOK(mp_init(&group->curvea)); MP_CHECKOK(mp_init(&group->curveb)); MP_CHECKOK(mp_init(&group->genx)); MP_CHECKOK(mp_init(&group->geny)); MP_CHECKOK(mp_init(&group->order)); CLEANUP: if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Tests a number of curves optimized using floating point arithmetic */ int main(void) { mp_err res = MP_OKAY; ECGroup *ecgroup = NULL; /* specific arithmetic tests */ M_TestCurve("SECG-160R1", ECCurve_SECG_PRIME_160R1); M_TestCurve("SECG-192R1", ECCurve_SECG_PRIME_192R1); M_TestCurve("SEGC-224R1", ECCurve_SECG_PRIME_224R1); CLEANUP: ECGroup_free(ecgroup); if (res != MP_OKAY) { printf("Error: exiting with error value %i\n", res); } return res; }
/* Construct a generic ECGroup for elliptic curves over prime fields with * field arithmetic implemented in Montgomery coordinates. */ ECGroup * ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea, const mp_int *curveb, const mp_int *genx, const mp_int *geny, const mp_int *order, int cofactor) { mp_err res = MP_OKAY; ECGroup *group = NULL; group = ECGroup_new(); if (group == NULL) return NULL; group->meth = GFMethod_consGFp_mont(irr); if (group->meth == NULL) { res = MP_MEM; goto CLEANUP; } MP_CHECKOK(group->meth-> field_enc(curvea, &group->curvea, group->meth)); MP_CHECKOK(group->meth-> field_enc(curveb, &group->curveb, group->meth)); MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth)); MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth)); MP_CHECKOK(mp_copy(order, &group->order)); group->cofactor = cofactor; group->point_add = &ec_GFp_pt_add_aff; group->point_sub = &ec_GFp_pt_sub_aff; group->point_dbl = &ec_GFp_pt_dbl_aff; group->point_mul = &ec_GFp_pt_mul_jm_wNAF; group->base_point_mul = NULL; group->points_mul = &ec_GFp_pts_mul_jac; group->validate_point = &ec_GFp_validate_point; CLEANUP: if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Construct a generic ECGroup for elliptic curves over binary polynomial * fields. */ ECGroup * ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5], const mp_int *curvea, const mp_int *curveb, const mp_int *genx, const mp_int *geny, const mp_int *order, int cofactor) { mp_err res = MP_OKAY; ECGroup *group = NULL; group = ECGroup_new(); if (group == NULL) return NULL; group->meth = GFMethod_consGF2m(irr, irr_arr); if (group->meth == NULL) { res = MP_MEM; goto CLEANUP; } MP_CHECKOK(mp_copy(curvea, &group->curvea)); MP_CHECKOK(mp_copy(curveb, &group->curveb)); MP_CHECKOK(mp_copy(genx, &group->genx)); MP_CHECKOK(mp_copy(geny, &group->geny)); MP_CHECKOK(mp_copy(order, &group->order)); group->cofactor = cofactor; group->point_add = &ec_GF2m_pt_add_aff; group->point_sub = &ec_GF2m_pt_sub_aff; group->point_dbl = &ec_GF2m_pt_dbl_aff; group->point_mul = &ec_GF2m_pt_mul_mont; group->base_point_mul = NULL; group->points_mul = &ec_pts_mul_basic; group->validate_point = &ec_GF2m_validate_point; CLEANUP: if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Allocate memory for a new ECGroup object. */ ECGroup * ECGroup_new(int kmflag) { mp_err res = MP_OKAY; ECGroup *group; #ifdef _KERNEL group = (ECGroup *) kmem_alloc(sizeof(ECGroup), kmflag); #else group = (ECGroup *) malloc(sizeof(ECGroup)); #endif if (group == NULL) return NULL; group->constructed = MP_YES; group->meth = NULL; group->text = NULL; MP_DIGITS(&group->curvea) = 0; MP_DIGITS(&group->curveb) = 0; MP_DIGITS(&group->genx) = 0; MP_DIGITS(&group->geny) = 0; MP_DIGITS(&group->order) = 0; group->base_point_mul = NULL; group->points_mul = NULL; group->validate_point = NULL; group->extra1 = NULL; group->extra2 = NULL; group->extra_free = NULL; MP_CHECKOK(mp_init(&group->curvea, kmflag)); MP_CHECKOK(mp_init(&group->curveb, kmflag)); MP_CHECKOK(mp_init(&group->genx, kmflag)); MP_CHECKOK(mp_init(&group->geny, kmflag)); MP_CHECKOK(mp_init(&group->order, kmflag)); CLEANUP: if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Validates an EC public key as described in Section 5.2.2 of * X9.62. The ECDH primitive when used without the cofactor does * not address small subgroup attacks, which may occur when the * public key is not valid. These attacks can be prevented by * validating the public key before using ECDH. */ SECStatus EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue) { #ifndef NSS_DISABLE_ECC mp_int Px, Py; ECGroup *group = NULL; SECStatus rv = SECFailure; mp_err err = MP_OKAY; int len; if (!ecParams || !publicValue) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* NOTE: We only support uncompressed points for now */ len = (ecParams->fieldID.size + 7) >> 3; if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) { PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); return SECFailure; } else if (publicValue->len != (2 * len + 1)) { PORT_SetError(SEC_ERROR_BAD_KEY); return SECFailure; } MP_DIGITS(&Px) = 0; MP_DIGITS(&Py) = 0; CHECK_MPI_OK( mp_init(&Px) ); CHECK_MPI_OK( mp_init(&Py) ); /* Initialize Px and Py */ CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) ); /* construct from named params */ group = ECGroup_fromName(ecParams->name); if (group == NULL) { /* * ECGroup_fromName fails if ecParams->name is not a valid * ECCurveName value, or if we run out of memory, or perhaps * for other reasons. Unfortunately if ecParams->name is a * valid ECCurveName value, we don't know what the right error * code should be because ECGroup_fromName doesn't return an * error code to the caller. Set err to MP_UNDEF because * that's what ECGroup_fromName uses internally. */ if ((ecParams->name <= ECCurve_noName) || (ecParams->name >= ECCurve_pastLastCurve)) { err = MP_BADARG; } else { err = MP_UNDEF; } goto cleanup; } /* validate public point */ if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) { if (err == MP_NO) { PORT_SetError(SEC_ERROR_BAD_KEY); rv = SECFailure; err = MP_OKAY; /* don't change the error code */ } goto cleanup; } rv = SECSuccess; cleanup: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); return SECFailure; #endif /* NSS_DISABLE_ECC */ }
/* * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for * the curve whose parameters are encoded in params with base point G. */ SECStatus ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2, const SECItem *pointP, SECItem *pointQ) { mp_int Px, Py, Qx, Qy; mp_int Gx, Gy, order, irreducible, a, b; #if 0 /* currently don't support non-named curves */ unsigned int irr_arr[5]; #endif ECGroup *group = NULL; SECStatus rv = SECFailure; mp_err err = MP_OKAY; int len; #if EC_DEBUG int i; char mpstr[256]; printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len); for (i = 0; i < params->DEREncoding.len; i++) printf("%02x:", params->DEREncoding.data[i]); printf("\n"); if (k1 != NULL) { mp_tohex(k1, mpstr); printf("ec_points_mul: scalar k1: %s\n", mpstr); mp_todecimal(k1, mpstr); printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr); } if (k2 != NULL) { mp_tohex(k2, mpstr); printf("ec_points_mul: scalar k2: %s\n", mpstr); mp_todecimal(k2, mpstr); printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr); } if (pointP != NULL) { printf("ec_points_mul: pointP [len=%d]:", pointP->len); for (i = 0; i < pointP->len; i++) printf("%02x:", pointP->data[i]); printf("\n"); } #endif /* NOTE: We only support uncompressed points for now */ len = (params->fieldID.size + 7) >> 3; if (pointP != NULL) { if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || (pointP->len != (2 * len + 1))) { PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); return SECFailure; }; } MP_DIGITS(&Px) = 0; MP_DIGITS(&Py) = 0; MP_DIGITS(&Qx) = 0; MP_DIGITS(&Qy) = 0; MP_DIGITS(&Gx) = 0; MP_DIGITS(&Gy) = 0; MP_DIGITS(&order) = 0; MP_DIGITS(&irreducible) = 0; MP_DIGITS(&a) = 0; MP_DIGITS(&b) = 0; CHECK_MPI_OK( mp_init(&Px) ); CHECK_MPI_OK( mp_init(&Py) ); CHECK_MPI_OK( mp_init(&Qx) ); CHECK_MPI_OK( mp_init(&Qy) ); CHECK_MPI_OK( mp_init(&Gx) ); CHECK_MPI_OK( mp_init(&Gy) ); CHECK_MPI_OK( mp_init(&order) ); CHECK_MPI_OK( mp_init(&irreducible) ); CHECK_MPI_OK( mp_init(&a) ); CHECK_MPI_OK( mp_init(&b) ); if ((k2 != NULL) && (pointP != NULL)) { /* Initialize Px and Py */ CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) ); } /* construct from named params, if possible */ if (params->name != ECCurve_noName) { group = ECGroup_fromName(params->name); } #if 0 /* currently don't support non-named curves */ if (group == NULL) { /* Set up mp_ints containing the curve coefficients */ CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, (mp_size) len) ); SECITEM_TO_MPINT( params->order, &order ); SECITEM_TO_MPINT( params->curve.a, &a ); SECITEM_TO_MPINT( params->curve.b, &b ); if (params->fieldID.type == ec_field_GFp) { SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible ); group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor); } else { SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible ); irr_arr[0] = params->fieldID.size; irr_arr[1] = params->fieldID.k1; irr_arr[2] = params->fieldID.k2; irr_arr[3] = params->fieldID.k3; irr_arr[4] = 0; group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor); } } #endif if (group == NULL) goto cleanup; if ((k2 != NULL) && (pointP != NULL)) { CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) ); } else { CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) ); } /* Construct the SECItem representation of point Q */ pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED; CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len, (mp_size) len) ); rv = SECSuccess; #if EC_DEBUG printf("ec_points_mul: pointQ [len=%d]:", pointQ->len); for (i = 0; i < pointQ->len; i++) printf("%02x:", pointQ->data[i]); printf("\n"); #endif cleanup: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); mp_clear(&Qx); mp_clear(&Qy); mp_clear(&Gx); mp_clear(&Gy); mp_clear(&order); mp_clear(&irreducible); mp_clear(&a); mp_clear(&b); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* Construct ECGroup from hex parameters and name, if any. Called by * ECGroup_fromHex and ECGroup_fromName. */ ECGroup * ecgroup_fromNameAndHex(const ECCurveName name, const ECCurveParams * params) { mp_int irr, curvea, curveb, genx, geny, order; int bits; ECGroup *group = NULL; mp_err res = MP_OKAY; /* initialize values */ MP_DIGITS(&irr) = 0; MP_DIGITS(&curvea) = 0; MP_DIGITS(&curveb) = 0; MP_DIGITS(&genx) = 0; MP_DIGITS(&geny) = 0; MP_DIGITS(&order) = 0; MP_CHECKOK(mp_init(&irr)); MP_CHECKOK(mp_init(&curvea)); MP_CHECKOK(mp_init(&curveb)); MP_CHECKOK(mp_init(&genx)); MP_CHECKOK(mp_init(&geny)); MP_CHECKOK(mp_init(&order)); MP_CHECKOK(mp_read_radix(&irr, params->irr, 16)); MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16)); MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16)); MP_CHECKOK(mp_read_radix(&genx, params->genx, 16)); MP_CHECKOK(mp_read_radix(&geny, params->geny, 16)); MP_CHECKOK(mp_read_radix(&order, params->order, 16)); /* determine number of bits */ bits = mpl_significant_bits(&irr) - 1; if (bits < MP_OKAY) { res = bits; goto CLEANUP; } /* determine which optimizations (if any) to use */ if (params->field == ECField_GFp) { switch (name) { #ifdef NSS_ECC_MORE_THAN_SUITE_B #ifdef ECL_USE_FP case ECCurve_SECG_PRIME_160R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_secp160r1_fp(group)); break; #endif case ECCurve_SECG_PRIME_192R1: #ifdef ECL_USE_FP group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_nistp192_fp(group)); #else group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp192(group, name)); #endif break; case ECCurve_SECG_PRIME_224R1: #ifdef ECL_USE_FP group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_nistp224_fp(group)); #else group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp224(group, name)); #endif break; #endif /* NSS_ECC_MORE_THAN_SUITE_B */ case ECCurve_SECG_PRIME_256R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp256(group, name)); MP_CHECKOK(ec_group_set_gfp256_32(group, name)); break; case ECCurve_SECG_PRIME_521R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp521(group, name)); break; default: /* use generic arithmetic */ group = ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } } #ifdef NSS_ECC_MORE_THAN_SUITE_B } else if (params->field == ECField_GF2m) { group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } if ((name == ECCurve_NIST_K163) || (name == ECCurve_NIST_B163) || (name == ECCurve_SECG_CHAR2_163R1)) { MP_CHECKOK(ec_group_set_gf2m163(group, name)); } else if ((name == ECCurve_SECG_CHAR2_193R1) || (name == ECCurve_SECG_CHAR2_193R2)) { MP_CHECKOK(ec_group_set_gf2m193(group, name)); } else if ((name == ECCurve_NIST_K233) || (name == ECCurve_NIST_B233)) { MP_CHECKOK(ec_group_set_gf2m233(group, name)); } #endif } else { res = MP_UNDEF; goto CLEANUP; } /* set name, if any */ if ((group != NULL) && (params->text != NULL)) { group->text = strdup(params->text); if (group->text == NULL) { res = MP_MEM; } } CLEANUP: mp_clear(&irr); mp_clear(&curvea); mp_clear(&curveb); mp_clear(&genx); mp_clear(&geny); mp_clear(&order); if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Performs tests of elliptic curve cryptography over prime fields If * tests fail, then it prints an error message, aborts, and returns an * error code. Otherwise, returns 0. */ int main(int argv, char **argc) { int ectestTime = 0; int ectestPrint = 0; int i; ECGroup *group = NULL; ECCurveParams *params = NULL; mp_err res; /* read command-line arguments */ for (i = 1; i < argv; i++) { if ((strcasecmp(argc[i], "time") == 0) || (strcasecmp(argc[i], "-time") == 0) || (strcasecmp(argc[i], "--time") == 0)) { ectestTime = 1; } else if ((strcasecmp(argc[i], "print") == 0) || (strcasecmp(argc[i], "-print") == 0) || (strcasecmp(argc[i], "--print") == 0)) { ectestPrint = 1; } else { printUsage(); return 0; } } /* generic arithmetic tests */ ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); /* specific arithmetic tests */ ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1); ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6); ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7); ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8); ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9); ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12); ECTEST_NAMED_GFP("Curve25519", ECCurve25519); CLEANUP: EC_FreeCurveParams(params); ECGroup_free(group); if (res != MP_OKAY) { printf("Error: exiting with error value %i\n", res); } return res; }
/* * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for * the curve whose parameters are encoded in params with base point G. */ SECStatus ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2, const SECItem *pointP, SECItem *pointQ, int kmflag) { mp_int Px, Py, Qx, Qy; mp_int Gx, Gy, order, irreducible, a, b; ECGroup *group = NULL; SECStatus rv = SECFailure; mp_err err = MP_OKAY; int len; #if EC_DEBUG int i; char mpstr[256]; if (k1 != NULL) { mp_tohex(k1, mpstr); printf("ec_points_mul: scalar k1: %s\n", mpstr); mp_todecimal(k1, mpstr); printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr); } if (k2 != NULL) { mp_tohex(k2, mpstr); printf("ec_points_mul: scalar k2: %s\n", mpstr); mp_todecimal(k2, mpstr); printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr); } if (pointP != NULL) { printf("ec_points_mul: pointP [len=%d]:", pointP->len); for (i = 0; i < pointP->len; i++) printf("%02x:", pointP->data[i]); printf("\n"); } #endif /* NOTE: We only support uncompressed points for now */ len = (params->fieldID.size + 7) >> 3; if (pointP != NULL) { if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || (pointP->len != (unsigned int)(2 * len + 1))) { return SECFailure; }; } MP_DIGITS(&Px) = 0; MP_DIGITS(&Py) = 0; MP_DIGITS(&Qx) = 0; MP_DIGITS(&Qy) = 0; MP_DIGITS(&Gx) = 0; MP_DIGITS(&Gy) = 0; MP_DIGITS(&order) = 0; MP_DIGITS(&irreducible) = 0; MP_DIGITS(&a) = 0; MP_DIGITS(&b) = 0; CHECK_MPI_OK( mp_init(&Px) ); CHECK_MPI_OK( mp_init(&Py) ); CHECK_MPI_OK( mp_init(&Qx) ); CHECK_MPI_OK( mp_init(&Qy) ); CHECK_MPI_OK( mp_init(&Gx) ); CHECK_MPI_OK( mp_init(&Gy) ); CHECK_MPI_OK( mp_init(&order) ); CHECK_MPI_OK( mp_init(&irreducible) ); CHECK_MPI_OK( mp_init(&a) ); CHECK_MPI_OK( mp_init(&b) ); if ((k2 != NULL) && (pointP != NULL)) { /* Initialize Px and Py */ CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) ); } /* construct from named params, if possible */ if (params->name != ECCurve_noName) { group = ECGroup_fromName(params->name); } if (group == NULL) goto cleanup; if ((k2 != NULL) && (pointP != NULL)) { CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) ); } else { CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) ); } /* Construct the SECItem representation of point Q */ pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED; CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len, (mp_size) len) ); rv = SECSuccess; #if EC_DEBUG printf("ec_points_mul: pointQ [len=%d]:", pointQ->len); for (i = 0; i < pointQ->len; i++) printf("%02x:", pointQ->data[i]); printf("\n"); #endif cleanup: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); mp_clear(&Qx); mp_clear(&Qy); mp_clear(&Gx); mp_clear(&Gy); mp_clear(&order); mp_clear(&irreducible); mp_clear(&a); mp_clear(&b); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* Performs tests of elliptic curve cryptography over binary polynomial * fields. If tests fail, then it prints an error message, aborts, and * returns an error code. Otherwise, returns 0. */ int main(int argv, char **argc) { int ectestTime = 0; int ectestPrint = 0; int i; ECGroup *group = NULL; ECCurveParams *params = NULL; mp_err res; /* read command-line arguments */ for (i = 1; i < argv; i++) { if ((strcasecmp(argc[i], "time") == 0) || (strcasecmp(argc[i], "-time") == 0) || (strcasecmp(argc[i], "--time") == 0)) { ectestTime = 1; } else if ((strcasecmp(argc[i], "print") == 0) || (strcasecmp(argc[i], "-print") == 0) || (strcasecmp(argc[i], "--print") == 0)) { ectestPrint = 1; } else { printUsage(); return 0; } } /* generic arithmetic tests */ ECTEST_GENERIC_GF2M("SECT-131R1", ECCurve_SECG_CHAR2_131R1); /* specific arithmetic tests */ ECTEST_NAMED_GF2M("NIST-K163", ECCurve_NIST_K163); ECTEST_NAMED_GF2M("NIST-B163", ECCurve_NIST_B163); ECTEST_NAMED_GF2M("NIST-K233", ECCurve_NIST_K233); ECTEST_NAMED_GF2M("NIST-B233", ECCurve_NIST_B233); ECTEST_NAMED_GF2M("NIST-K283", ECCurve_NIST_K283); ECTEST_NAMED_GF2M("NIST-B283", ECCurve_NIST_B283); ECTEST_NAMED_GF2M("NIST-K409", ECCurve_NIST_K409); ECTEST_NAMED_GF2M("NIST-B409", ECCurve_NIST_B409); ECTEST_NAMED_GF2M("NIST-K571", ECCurve_NIST_K571); ECTEST_NAMED_GF2M("NIST-B571", ECCurve_NIST_B571); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V1", ECCurve_X9_62_CHAR2_PNB163V1); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V2", ECCurve_X9_62_CHAR2_PNB163V2); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V3", ECCurve_X9_62_CHAR2_PNB163V3); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB176V1", ECCurve_X9_62_CHAR2_PNB176V1); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V1", ECCurve_X9_62_CHAR2_TNB191V1); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V2", ECCurve_X9_62_CHAR2_TNB191V2); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V3", ECCurve_X9_62_CHAR2_TNB191V3); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB208W1", ECCurve_X9_62_CHAR2_PNB208W1); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V1", ECCurve_X9_62_CHAR2_TNB239V1); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V2", ECCurve_X9_62_CHAR2_TNB239V2); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V3", ECCurve_X9_62_CHAR2_TNB239V3); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB272W1", ECCurve_X9_62_CHAR2_PNB272W1); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB304W1", ECCurve_X9_62_CHAR2_PNB304W1); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB359V1", ECCurve_X9_62_CHAR2_TNB359V1); ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB368W1", ECCurve_X9_62_CHAR2_PNB368W1); ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB431R1", ECCurve_X9_62_CHAR2_TNB431R1); ECTEST_NAMED_GF2M("SECT-113R1", ECCurve_SECG_CHAR2_113R1); ECTEST_NAMED_GF2M("SECT-113R2", ECCurve_SECG_CHAR2_113R2); ECTEST_NAMED_GF2M("SECT-131R1", ECCurve_SECG_CHAR2_131R1); ECTEST_NAMED_GF2M("SECT-131R2", ECCurve_SECG_CHAR2_131R2); ECTEST_NAMED_GF2M("SECT-163K1", ECCurve_SECG_CHAR2_163K1); ECTEST_NAMED_GF2M("SECT-163R1", ECCurve_SECG_CHAR2_163R1); ECTEST_NAMED_GF2M("SECT-163R2", ECCurve_SECG_CHAR2_163R2); ECTEST_NAMED_GF2M("SECT-193R1", ECCurve_SECG_CHAR2_193R1); ECTEST_NAMED_GF2M("SECT-193R2", ECCurve_SECG_CHAR2_193R2); ECTEST_NAMED_GF2M("SECT-233K1", ECCurve_SECG_CHAR2_233K1); ECTEST_NAMED_GF2M("SECT-233R1", ECCurve_SECG_CHAR2_233R1); ECTEST_NAMED_GF2M("SECT-239K1", ECCurve_SECG_CHAR2_239K1); ECTEST_NAMED_GF2M("SECT-283K1", ECCurve_SECG_CHAR2_283K1); ECTEST_NAMED_GF2M("SECT-283R1", ECCurve_SECG_CHAR2_283R1); ECTEST_NAMED_GF2M("SECT-409K1", ECCurve_SECG_CHAR2_409K1); ECTEST_NAMED_GF2M("SECT-409R1", ECCurve_SECG_CHAR2_409R1); ECTEST_NAMED_GF2M("SECT-571K1", ECCurve_SECG_CHAR2_571K1); ECTEST_NAMED_GF2M("SECT-571R1", ECCurve_SECG_CHAR2_571R1); ECTEST_NAMED_GF2M("WTLS-1 (113)", ECCurve_WTLS_1); ECTEST_NAMED_GF2M("WTLS-3 (163)", ECCurve_WTLS_3); ECTEST_NAMED_GF2M("WTLS-4 (113)", ECCurve_WTLS_4); ECTEST_NAMED_GF2M("WTLS-5 (163)", ECCurve_WTLS_5); ECTEST_NAMED_GF2M("WTLS-10 (233)", ECCurve_WTLS_10); ECTEST_NAMED_GF2M("WTLS-11 (233)", ECCurve_WTLS_11); CLEANUP: EC_FreeCurveParams(params); ECGroup_free(group); if (res != MP_OKAY) { printf("Error: exiting with error value %i\n", res); } return res; }