| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 | |
| 5 #include "mpi.h" | |
| 6 #include "mplogic.h" | |
| 7 #include "ecl.h" | |
| 8 #include "ecl-priv.h" | |
| 9 #include "ec2.h" | |
| 10 #include "ecp.h" | |
| 11 #include <stdlib.h> | |
| 12 #include <string.h> | |
| 13 | |
| 14 /* Allocate memory for a new ECGroup object. */ | |
| 15 ECGroup * | |
| 16 ECGroup_new() | |
| 17 { | |
| 18 mp_err res = MP_OKAY; | |
| 19 ECGroup *group; | |
| 20 group = (ECGroup *) malloc(sizeof(ECGroup)); | |
| 21 if (group == NULL) | |
| 22 return NULL; | |
| 23 group->constructed = MP_YES; | |
| 24 group->meth = NULL; | |
| 25 group->text = NULL; | |
| 26 MP_DIGITS(&group->curvea) = 0; | |
| 27 MP_DIGITS(&group->curveb) = 0; | |
| 28 MP_DIGITS(&group->genx) = 0; | |
| 29 MP_DIGITS(&group->geny) = 0; | |
| 30 MP_DIGITS(&group->order) = 0; | |
| 31 group->base_point_mul = NULL; | |
| 32 group->points_mul = NULL; | |
| 33 group->validate_point = NULL; | |
| 34 group->extra1 = NULL; | |
| 35 group->extra2 = NULL; | |
| 36 group->extra_free = NULL; | |
| 37 MP_CHECKOK(mp_init(&group->curvea)); | |
| 38 MP_CHECKOK(mp_init(&group->curveb)); | |
| 39 MP_CHECKOK(mp_init(&group->genx)); | |
| 40 MP_CHECKOK(mp_init(&group->geny)); | |
| 41 MP_CHECKOK(mp_init(&group->order)); | |
| 42 | |
| 43 CLEANUP: | |
| 44 if (res != MP_OKAY) { | |
| 45 ECGroup_free(group); | |
| 46 return NULL; | |
| 47 } | |
| 48 return group; | |
| 49 } | |
| 50 | |
| 51 /* Construct a generic ECGroup for elliptic curves over prime fields. */ | |
| 52 ECGroup * | |
| 53 ECGroup_consGFp(const mp_int *irr, const mp_int *curvea, | |
| 54 const mp_int *curveb, const mp_int *genx, | |
| 55 const mp_int *geny, const mp_int *order, int cof
actor) | |
| 56 { | |
| 57 mp_err res = MP_OKAY; | |
| 58 ECGroup *group = NULL; | |
| 59 | |
| 60 group = ECGroup_new(); | |
| 61 if (group == NULL) | |
| 62 return NULL; | |
| 63 | |
| 64 group->meth = GFMethod_consGFp(irr); | |
| 65 if (group->meth == NULL) { | |
| 66 res = MP_MEM; | |
| 67 goto CLEANUP; | |
| 68 } | |
| 69 MP_CHECKOK(mp_copy(curvea, &group->curvea)); | |
| 70 MP_CHECKOK(mp_copy(curveb, &group->curveb)); | |
| 71 MP_CHECKOK(mp_copy(genx, &group->genx)); | |
| 72 MP_CHECKOK(mp_copy(geny, &group->geny)); | |
| 73 MP_CHECKOK(mp_copy(order, &group->order)); | |
| 74 group->cofactor = cofactor; | |
| 75 group->point_add = &ec_GFp_pt_add_aff; | |
| 76 group->point_sub = &ec_GFp_pt_sub_aff; | |
| 77 group->point_dbl = &ec_GFp_pt_dbl_aff; | |
| 78 group->point_mul = &ec_GFp_pt_mul_jm_wNAF; | |
| 79 group->base_point_mul = NULL; | |
| 80 group->points_mul = &ec_GFp_pts_mul_jac; | |
| 81 group->validate_point = &ec_GFp_validate_point; | |
| 82 | |
| 83 CLEANUP: | |
| 84 if (res != MP_OKAY) { | |
| 85 ECGroup_free(group); | |
| 86 return NULL; | |
| 87 } | |
| 88 return group; | |
| 89 } | |
| 90 | |
| 91 /* Construct a generic ECGroup for elliptic curves over prime fields with | |
| 92 * field arithmetic implemented in Montgomery coordinates. */ | |
| 93 ECGroup * | |
| 94 ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea, | |
| 95 const mp_int *curveb, const mp_int *gen
x, | |
| 96 const mp_int *geny, const mp_int *order
, int cofactor) | |
| 97 { | |
| 98 mp_err res = MP_OKAY; | |
| 99 ECGroup *group = NULL; | |
| 100 | |
| 101 group = ECGroup_new(); | |
| 102 if (group == NULL) | |
| 103 return NULL; | |
| 104 | |
| 105 group->meth = GFMethod_consGFp_mont(irr); | |
| 106 if (group->meth == NULL) { | |
| 107 res = MP_MEM; | |
| 108 goto CLEANUP; | |
| 109 } | |
| 110 MP_CHECKOK(group->meth-> | |
| 111 field_enc(curvea, &group->curvea, group->meth)); | |
| 112 MP_CHECKOK(group->meth-> | |
| 113 field_enc(curveb, &group->curveb, group->meth)); | |
| 114 MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth)); | |
| 115 MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth)); | |
| 116 MP_CHECKOK(mp_copy(order, &group->order)); | |
| 117 group->cofactor = cofactor; | |
| 118 group->point_add = &ec_GFp_pt_add_aff; | |
| 119 group->point_sub = &ec_GFp_pt_sub_aff; | |
| 120 group->point_dbl = &ec_GFp_pt_dbl_aff; | |
| 121 group->point_mul = &ec_GFp_pt_mul_jm_wNAF; | |
| 122 group->base_point_mul = NULL; | |
| 123 group->points_mul = &ec_GFp_pts_mul_jac; | |
| 124 group->validate_point = &ec_GFp_validate_point; | |
| 125 | |
| 126 CLEANUP: | |
| 127 if (res != MP_OKAY) { | |
| 128 ECGroup_free(group); | |
| 129 return NULL; | |
| 130 } | |
| 131 return group; | |
| 132 } | |
| 133 | |
| 134 #ifdef NSS_ECC_MORE_THAN_SUITE_B | |
| 135 /* Construct a generic ECGroup for elliptic curves over binary polynomial | |
| 136 * fields. */ | |
| 137 ECGroup * | |
| 138 ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5], | |
| 139 const mp_int *curvea, const mp_int *curveb, | |
| 140 const mp_int *genx, const mp_int *geny, | |
| 141 const mp_int *order, int cofactor) | |
| 142 { | |
| 143 mp_err res = MP_OKAY; | |
| 144 ECGroup *group = NULL; | |
| 145 | |
| 146 group = ECGroup_new(); | |
| 147 if (group == NULL) | |
| 148 return NULL; | |
| 149 | |
| 150 group->meth = GFMethod_consGF2m(irr, irr_arr); | |
| 151 if (group->meth == NULL) { | |
| 152 res = MP_MEM; | |
| 153 goto CLEANUP; | |
| 154 } | |
| 155 MP_CHECKOK(mp_copy(curvea, &group->curvea)); | |
| 156 MP_CHECKOK(mp_copy(curveb, &group->curveb)); | |
| 157 MP_CHECKOK(mp_copy(genx, &group->genx)); | |
| 158 MP_CHECKOK(mp_copy(geny, &group->geny)); | |
| 159 MP_CHECKOK(mp_copy(order, &group->order)); | |
| 160 group->cofactor = cofactor; | |
| 161 group->point_add = &ec_GF2m_pt_add_aff; | |
| 162 group->point_sub = &ec_GF2m_pt_sub_aff; | |
| 163 group->point_dbl = &ec_GF2m_pt_dbl_aff; | |
| 164 group->point_mul = &ec_GF2m_pt_mul_mont; | |
| 165 group->base_point_mul = NULL; | |
| 166 group->points_mul = &ec_pts_mul_basic; | |
| 167 group->validate_point = &ec_GF2m_validate_point; | |
| 168 | |
| 169 CLEANUP: | |
| 170 if (res != MP_OKAY) { | |
| 171 ECGroup_free(group); | |
| 172 return NULL; | |
| 173 } | |
| 174 return group; | |
| 175 } | |
| 176 #endif | |
| 177 | |
| 178 /* Construct ECGroup from hex parameters and name, if any. Called by | |
| 179 * ECGroup_fromHex and ECGroup_fromName. */ | |
| 180 ECGroup * | |
| 181 ecgroup_fromNameAndHex(const ECCurveName name, | |
| 182 const ECCurveParams * params) | |
| 183 { | |
| 184 mp_int irr, curvea, curveb, genx, geny, order; | |
| 185 int bits; | |
| 186 ECGroup *group = NULL; | |
| 187 mp_err res = MP_OKAY; | |
| 188 | |
| 189 /* initialize values */ | |
| 190 MP_DIGITS(&irr) = 0; | |
| 191 MP_DIGITS(&curvea) = 0; | |
| 192 MP_DIGITS(&curveb) = 0; | |
| 193 MP_DIGITS(&genx) = 0; | |
| 194 MP_DIGITS(&geny) = 0; | |
| 195 MP_DIGITS(&order) = 0; | |
| 196 MP_CHECKOK(mp_init(&irr)); | |
| 197 MP_CHECKOK(mp_init(&curvea)); | |
| 198 MP_CHECKOK(mp_init(&curveb)); | |
| 199 MP_CHECKOK(mp_init(&genx)); | |
| 200 MP_CHECKOK(mp_init(&geny)); | |
| 201 MP_CHECKOK(mp_init(&order)); | |
| 202 MP_CHECKOK(mp_read_radix(&irr, params->irr, 16)); | |
| 203 MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16)); | |
| 204 MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16)); | |
| 205 MP_CHECKOK(mp_read_radix(&genx, params->genx, 16)); | |
| 206 MP_CHECKOK(mp_read_radix(&geny, params->geny, 16)); | |
| 207 MP_CHECKOK(mp_read_radix(&order, params->order, 16)); | |
| 208 | |
| 209 /* determine number of bits */ | |
| 210 bits = mpl_significant_bits(&irr) - 1; | |
| 211 if (bits < MP_OKAY) { | |
| 212 res = bits; | |
| 213 goto CLEANUP; | |
| 214 } | |
| 215 | |
| 216 /* determine which optimizations (if any) to use */ | |
| 217 if (params->field == ECField_GFp) { | |
| 218 switch (name) { | |
| 219 #ifdef NSS_ECC_MORE_THAN_SUITE_B | |
| 220 #ifdef ECL_USE_FP | |
| 221 case ECCurve_SECG_PRIME_160R1: | |
| 222 group = | |
| 223 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 224 &order, params->
cofactor); | |
| 225 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 226 MP_CHECKOK(ec_group_set_secp160r1_fp(group)); | |
| 227 break; | |
| 228 #endif | |
| 229 case ECCurve_SECG_PRIME_192R1: | |
| 230 #ifdef ECL_USE_FP | |
| 231 group = | |
| 232 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 233 &order, params->
cofactor); | |
| 234 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 235 MP_CHECKOK(ec_group_set_nistp192_fp(group)); | |
| 236 #else | |
| 237 group = | |
| 238 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 239 &order, params->
cofactor); | |
| 240 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 241 MP_CHECKOK(ec_group_set_gfp192(group, name)); | |
| 242 #endif | |
| 243 break; | |
| 244 case ECCurve_SECG_PRIME_224R1: | |
| 245 #ifdef ECL_USE_FP | |
| 246 group = | |
| 247 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 248 &order, params->
cofactor); | |
| 249 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 250 MP_CHECKOK(ec_group_set_nistp224_fp(group)); | |
| 251 #else | |
| 252 group = | |
| 253 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 254 &order, params->
cofactor); | |
| 255 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 256 MP_CHECKOK(ec_group_set_gfp224(group, name)); | |
| 257 #endif | |
| 258 break; | |
| 259 case ECCurve_SECG_PRIME_521R1: | |
| 260 group = | |
| 261 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 262 &order, params->
cofactor); | |
| 263 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 264 MP_CHECKOK(ec_group_set_gfp521(group, name)); | |
| 265 break; | |
| 266 #endif /* NSS_ECC_MORE_THAN_SUITE_B */ | |
| 267 case ECCurve_SECG_PRIME_256R1: | |
| 268 group = | |
| 269 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &
geny, | |
| 270 &order, params->
cofactor); | |
| 271 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 272 #ifdef NSS_ECC_MORE_THAN_SUITE_B | |
| 273 MP_CHECKOK(ec_group_set_gfp256(group, name)); | |
| 274 #endif | |
| 275 MP_CHECKOK(ec_group_set_gfp256_32(group, name)); | |
| 276 break; | |
| 277 default: | |
| 278 /* use generic arithmetic */ | |
| 279 group = | |
| 280 ECGroup_consGFp_mont(&irr, &curvea, &curveb, &ge
nx, &geny, | |
| 281 &order,
params->cofactor); | |
| 282 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 283 } | |
| 284 #ifdef NSS_ECC_MORE_THAN_SUITE_B | |
| 285 } else if (params->field == ECField_GF2m) { | |
| 286 group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &g
eny, &order, params->cofactor); | |
| 287 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } | |
| 288 if ((name == ECCurve_NIST_K163) || | |
| 289 (name == ECCurve_NIST_B163) || | |
| 290 (name == ECCurve_SECG_CHAR2_163R1)) { | |
| 291 MP_CHECKOK(ec_group_set_gf2m163(group, name)); | |
| 292 } else if ((name == ECCurve_SECG_CHAR2_193R1) || | |
| 293 (name == ECCurve_SECG_CHAR2_193R2)) { | |
| 294 MP_CHECKOK(ec_group_set_gf2m193(group, name)); | |
| 295 } else if ((name == ECCurve_NIST_K233) || | |
| 296 (name == ECCurve_NIST_B233)) { | |
| 297 MP_CHECKOK(ec_group_set_gf2m233(group, name)); | |
| 298 } | |
| 299 #endif | |
| 300 } else { | |
| 301 res = MP_UNDEF; | |
| 302 goto CLEANUP; | |
| 303 } | |
| 304 | |
| 305 /* set name, if any */ | |
| 306 if ((group != NULL) && (params->text != NULL)) { | |
| 307 group->text = strdup(params->text); | |
| 308 if (group->text == NULL) { | |
| 309 res = MP_MEM; | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 CLEANUP: | |
| 314 mp_clear(&irr); | |
| 315 mp_clear(&curvea); | |
| 316 mp_clear(&curveb); | |
| 317 mp_clear(&genx); | |
| 318 mp_clear(&geny); | |
| 319 mp_clear(&order); | |
| 320 if (res != MP_OKAY) { | |
| 321 ECGroup_free(group); | |
| 322 return NULL; | |
| 323 } | |
| 324 return group; | |
| 325 } | |
| 326 | |
| 327 /* Construct ECGroup from hexadecimal representations of parameters. */ | |
| 328 ECGroup * | |
| 329 ECGroup_fromHex(const ECCurveParams * params) | |
| 330 { | |
| 331 return ecgroup_fromNameAndHex(ECCurve_noName, params); | |
| 332 } | |
| 333 | |
| 334 /* Construct ECGroup from named parameters. */ | |
| 335 ECGroup * | |
| 336 ECGroup_fromName(const ECCurveName name) | |
| 337 { | |
| 338 ECGroup *group = NULL; | |
| 339 ECCurveParams *params = NULL; | |
| 340 mp_err res = MP_OKAY; | |
| 341 | |
| 342 params = EC_GetNamedCurveParams(name); | |
| 343 if (params == NULL) { | |
| 344 res = MP_UNDEF; | |
| 345 goto CLEANUP; | |
| 346 } | |
| 347 | |
| 348 /* construct actual group */ | |
| 349 group = ecgroup_fromNameAndHex(name, params); | |
| 350 if (group == NULL) { | |
| 351 res = MP_UNDEF; | |
| 352 goto CLEANUP; | |
| 353 } | |
| 354 | |
| 355 CLEANUP: | |
| 356 EC_FreeCurveParams(params); | |
| 357 if (res != MP_OKAY) { | |
| 358 ECGroup_free(group); | |
| 359 return NULL; | |
| 360 } | |
| 361 return group; | |
| 362 } | |
| 363 | |
| 364 /* Validates an EC public key as described in Section 5.2.2 of X9.62. */ | |
| 365 mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const | |
| 366 mp_int *py) | |
| 367 { | |
| 368 /* 1: Verify that publicValue is not the point at infinity */ | |
| 369 /* 2: Verify that the coordinates of publicValue are elements | |
| 370 * of the field. | |
| 371 */ | |
| 372 /* 3: Verify that publicValue is on the curve. */ | |
| 373 /* 4: Verify that the order of the curve times the publicValue | |
| 374 * is the point at infinity. | |
| 375 */ | |
| 376 return group->validate_point(px, py, group); | |
| 377 } | |
| 378 | |
| 379 /* Free the memory allocated (if any) to an ECGroup object. */ | |
| 380 void | |
| 381 ECGroup_free(ECGroup *group) | |
| 382 { | |
| 383 if (group == NULL) | |
| 384 return; | |
| 385 GFMethod_free(group->meth); | |
| 386 if (group->constructed == MP_NO) | |
| 387 return; | |
| 388 mp_clear(&group->curvea); | |
| 389 mp_clear(&group->curveb); | |
| 390 mp_clear(&group->genx); | |
| 391 mp_clear(&group->geny); | |
| 392 mp_clear(&group->order); | |
| 393 if (group->text != NULL) | |
| 394 free(group->text); | |
| 395 if (group->extra_free != NULL) | |
| 396 group->extra_free(group); | |
| 397 free(group); | |
| 398 } | |
| OLD | NEW |