Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/ecdsa/curves.py: 56%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

154 statements  

1from __future__ import division 

2 

3from six import PY2 

4from . import der, ecdsa, ellipticcurve, eddsa 

5from .util import orderlen, number_to_string, string_to_number 

6from ._compat import normalise_bytes, bit_length 

7 

8 

9# orderlen was defined in this module previously, so keep it in __all__, 

10# will need to mark it as deprecated later 

11__all__ = [ 

12 "UnknownCurveError", 

13 "orderlen", 

14 "Curve", 

15 "SECP112r1", 

16 "SECP112r2", 

17 "SECP128r1", 

18 "SECP160r1", 

19 "NIST192p", 

20 "NIST224p", 

21 "NIST256p", 

22 "NIST384p", 

23 "NIST521p", 

24 "curves", 

25 "find_curve", 

26 "curve_by_name", 

27 "SECP256k1", 

28 "BRAINPOOLP160r1", 

29 "BRAINPOOLP160t1", 

30 "BRAINPOOLP192r1", 

31 "BRAINPOOLP192t1", 

32 "BRAINPOOLP224r1", 

33 "BRAINPOOLP224t1", 

34 "BRAINPOOLP256r1", 

35 "BRAINPOOLP256t1", 

36 "BRAINPOOLP320r1", 

37 "BRAINPOOLP320t1", 

38 "BRAINPOOLP384r1", 

39 "BRAINPOOLP384t1", 

40 "BRAINPOOLP512r1", 

41 "BRAINPOOLP512t1", 

42 "PRIME_FIELD_OID", 

43 "CHARACTERISTIC_TWO_FIELD_OID", 

44 "Ed25519", 

45 "Ed448", 

46] 

47 

48 

49PRIME_FIELD_OID = (1, 2, 840, 10045, 1, 1) 

50CHARACTERISTIC_TWO_FIELD_OID = (1, 2, 840, 10045, 1, 2) 

51 

52 

53class UnknownCurveError(Exception): 

54 pass 

55 

56 

57class Curve: 

58 def __init__(self, name, curve, generator, oid, openssl_name=None): 

59 self.name = name 

60 self.openssl_name = openssl_name # maybe None 

61 self.curve = curve 

62 self.generator = generator 

63 self.order = generator.order() 

64 if isinstance(curve, ellipticcurve.CurveEdTw): 

65 # EdDSA keys are special in that both private and public 

66 # are the same size (as it's defined only with compressed points) 

67 

68 # +1 for the sign bit and then round up 

69 self.baselen = (bit_length(curve.p()) + 1 + 7) // 8 

70 self.verifying_key_length = self.baselen 

71 else: 

72 self.baselen = orderlen(self.order) 

73 self.verifying_key_length = 2 * orderlen(curve.p()) 

74 self.signature_length = 2 * self.baselen 

75 self.oid = oid 

76 if oid: 

77 self.encoded_oid = der.encode_oid(*oid) 

78 

79 def __eq__(self, other): 

80 if isinstance(other, Curve): 

81 return ( 

82 self.curve == other.curve and self.generator == other.generator 

83 ) 

84 return NotImplemented 

85 

86 def __ne__(self, other): 

87 return not self == other 

88 

89 def __repr__(self): 

90 return self.name 

91 

92 def to_der(self, encoding=None, point_encoding="uncompressed"): 

93 """Serialise the curve parameters to binary string. 

94 

95 :param str encoding: the format to save the curve parameters in. 

96 Default is ``named_curve``, with fallback being the ``explicit`` 

97 if the OID is not set for the curve. 

98 :param str point_encoding: the point encoding of the generator when 

99 explicit curve encoding is used. Ignored for ``named_curve`` 

100 format. 

101 

102 :return: DER encoded ECParameters structure 

103 :rtype: bytes 

104 """ 

105 if encoding is None: 

106 if self.oid: 

107 encoding = "named_curve" 

108 else: 

109 encoding = "explicit" 

110 

111 if encoding not in ("named_curve", "explicit"): 

112 raise ValueError( 

113 "Only 'named_curve' and 'explicit' encodings supported" 

114 ) 

115 

116 if encoding == "named_curve": 

117 if not self.oid: 

118 raise UnknownCurveError( 

119 "Can't encode curve using named_curve encoding without " 

120 "associated curve OID" 

121 ) 

122 return der.encode_oid(*self.oid) 

123 elif isinstance(self.curve, ellipticcurve.CurveEdTw): 

124 assert encoding == "explicit" 

125 raise UnknownCurveError( 

126 "Twisted Edwards curves don't support explicit encoding" 

127 ) 

128 

129 # encode the ECParameters sequence 

130 curve_p = self.curve.p() 

131 version = der.encode_integer(1) 

132 field_id = der.encode_sequence( 

133 der.encode_oid(*PRIME_FIELD_OID), der.encode_integer(curve_p) 

134 ) 

135 curve = der.encode_sequence( 

136 der.encode_octet_string( 

137 number_to_string(self.curve.a() % curve_p, curve_p) 

138 ), 

139 der.encode_octet_string( 

140 number_to_string(self.curve.b() % curve_p, curve_p) 

141 ), 

142 ) 

143 base = der.encode_octet_string(self.generator.to_bytes(point_encoding)) 

144 order = der.encode_integer(self.generator.order()) 

145 seq_elements = [version, field_id, curve, base, order] 

146 if self.curve.cofactor(): 

147 cofactor = der.encode_integer(self.curve.cofactor()) 

148 seq_elements.append(cofactor) 

149 

150 return der.encode_sequence(*seq_elements) 

151 

152 def to_pem(self, encoding=None, point_encoding="uncompressed"): 

153 """ 

154 Serialise the curve parameters to the :term:`PEM` format. 

155 

156 :param str encoding: the format to save the curve parameters in. 

157 Default is ``named_curve``, with fallback being the ``explicit`` 

158 if the OID is not set for the curve. 

159 :param str point_encoding: the point encoding of the generator when 

160 explicit curve encoding is used. Ignored for ``named_curve`` 

161 format. 

162 

163 :return: PEM encoded ECParameters structure 

164 :rtype: str 

165 """ 

166 return der.topem( 

167 self.to_der(encoding, point_encoding), "EC PARAMETERS" 

168 ) 

169 

170 @staticmethod 

171 def from_der(data, valid_encodings=None): 

172 """Decode the curve parameters from DER file. 

173 

174 :param data: the binary string to decode the parameters from 

175 :type data: :term:`bytes-like object` 

176 :param valid_encodings: set of names of allowed encodings, by default 

177 all (set by passing ``None``), supported ones are ``named_curve`` 

178 and ``explicit`` 

179 :type valid_encodings: :term:`set-like object` 

180 """ 

181 if not valid_encodings: 

182 valid_encodings = set(("named_curve", "explicit")) 

183 if not all(i in ["named_curve", "explicit"] for i in valid_encodings): 

184 raise ValueError( 

185 "Only named_curve and explicit encodings supported" 

186 ) 

187 data = normalise_bytes(data) 

188 if not der.is_sequence(data): 

189 if "named_curve" not in valid_encodings: 

190 raise der.UnexpectedDER( 

191 "named_curve curve parameters not allowed" 

192 ) 

193 oid, empty = der.remove_object(data) 

194 if empty: 

195 raise der.UnexpectedDER("Unexpected data after OID") 

196 return find_curve(oid) 

197 

198 if "explicit" not in valid_encodings: 

199 raise der.UnexpectedDER("explicit curve parameters not allowed") 

200 

201 seq, empty = der.remove_sequence(data) 

202 if empty: 

203 raise der.UnexpectedDER( 

204 "Unexpected data after ECParameters structure" 

205 ) 

206 # decode the ECParameters sequence 

207 version, rest = der.remove_integer(seq) 

208 if version != 1: 

209 raise der.UnexpectedDER("Unknown parameter encoding format") 

210 field_id, rest = der.remove_sequence(rest) 

211 curve, rest = der.remove_sequence(rest) 

212 base_bytes, rest = der.remove_octet_string(rest) 

213 order, rest = der.remove_integer(rest) 

214 cofactor = None 

215 if rest: 

216 # the ASN.1 specification of ECParameters allows for future 

217 # extensions of the sequence, so ignore the remaining bytes 

218 cofactor, _ = der.remove_integer(rest) 

219 

220 # decode the ECParameters.fieldID sequence 

221 field_type, rest = der.remove_object(field_id) 

222 if field_type == CHARACTERISTIC_TWO_FIELD_OID: 

223 raise UnknownCurveError("Characteristic 2 curves unsupported") 

224 if field_type != PRIME_FIELD_OID: 

225 raise UnknownCurveError( 

226 "Unknown field type: {0}".format(field_type) 

227 ) 

228 prime, empty = der.remove_integer(rest) 

229 if empty: 

230 raise der.UnexpectedDER( 

231 "Unexpected data after ECParameters.fieldID.Prime-p element" 

232 ) 

233 

234 # decode the ECParameters.curve sequence 

235 curve_a_bytes, rest = der.remove_octet_string(curve) 

236 curve_b_bytes, rest = der.remove_octet_string(rest) 

237 # seed can be defined here, but we don't parse it, so ignore `rest` 

238 

239 curve_a = string_to_number(curve_a_bytes) 

240 curve_b = string_to_number(curve_b_bytes) 

241 

242 curve_fp = ellipticcurve.CurveFp(prime, curve_a, curve_b, cofactor) 

243 

244 # decode the ECParameters.base point 

245 

246 base = ellipticcurve.PointJacobi.from_bytes( 

247 curve_fp, 

248 base_bytes, 

249 valid_encodings=("uncompressed", "compressed", "hybrid"), 

250 order=order, 

251 generator=True, 

252 ) 

253 tmp_curve = Curve("unknown", curve_fp, base, None) 

254 

255 # if the curve matches one of the well-known ones, use the well-known 

256 # one in preference, as it will have the OID and name associated 

257 for i in curves: 

258 if tmp_curve == i: 

259 return i 

260 return tmp_curve 

261 

262 @classmethod 

263 def from_pem(cls, string, valid_encodings=None): 

264 """Decode the curve parameters from PEM file. 

265 

266 :param str string: the text string to decode the parameters from 

267 :param valid_encodings: set of names of allowed encodings, by default 

268 all (set by passing ``None``), supported ones are ``named_curve`` 

269 and ``explicit`` 

270 :type valid_encodings: :term:`set-like object` 

271 """ 

272 if not PY2 and isinstance(string, str): # pragma: no branch 

273 string = string.encode() 

274 

275 ec_param_index = string.find(b"-----BEGIN EC PARAMETERS-----") 

276 if ec_param_index == -1: 

277 raise der.UnexpectedDER("EC PARAMETERS PEM header not found") 

278 

279 return cls.from_der( 

280 der.unpem(string[ec_param_index:]), valid_encodings 

281 ) 

282 

283 

284# the SEC curves 

285SECP112r1 = Curve( 

286 "SECP112r1", 

287 ecdsa.curve_112r1, 

288 ecdsa.generator_112r1, 

289 (1, 3, 132, 0, 6), 

290 "secp112r1", 

291) 

292 

293 

294SECP112r2 = Curve( 

295 "SECP112r2", 

296 ecdsa.curve_112r2, 

297 ecdsa.generator_112r2, 

298 (1, 3, 132, 0, 7), 

299 "secp112r2", 

300) 

301 

302 

303SECP128r1 = Curve( 

304 "SECP128r1", 

305 ecdsa.curve_128r1, 

306 ecdsa.generator_128r1, 

307 (1, 3, 132, 0, 28), 

308 "secp128r1", 

309) 

310 

311 

312SECP160r1 = Curve( 

313 "SECP160r1", 

314 ecdsa.curve_160r1, 

315 ecdsa.generator_160r1, 

316 (1, 3, 132, 0, 8), 

317 "secp160r1", 

318) 

319 

320 

321# the NIST curves 

322NIST192p = Curve( 

323 "NIST192p", 

324 ecdsa.curve_192, 

325 ecdsa.generator_192, 

326 (1, 2, 840, 10045, 3, 1, 1), 

327 "prime192v1", 

328) 

329 

330 

331NIST224p = Curve( 

332 "NIST224p", 

333 ecdsa.curve_224, 

334 ecdsa.generator_224, 

335 (1, 3, 132, 0, 33), 

336 "secp224r1", 

337) 

338 

339 

340NIST256p = Curve( 

341 "NIST256p", 

342 ecdsa.curve_256, 

343 ecdsa.generator_256, 

344 (1, 2, 840, 10045, 3, 1, 7), 

345 "prime256v1", 

346) 

347 

348 

349NIST384p = Curve( 

350 "NIST384p", 

351 ecdsa.curve_384, 

352 ecdsa.generator_384, 

353 (1, 3, 132, 0, 34), 

354 "secp384r1", 

355) 

356 

357 

358NIST521p = Curve( 

359 "NIST521p", 

360 ecdsa.curve_521, 

361 ecdsa.generator_521, 

362 (1, 3, 132, 0, 35), 

363 "secp521r1", 

364) 

365 

366 

367SECP256k1 = Curve( 

368 "SECP256k1", 

369 ecdsa.curve_secp256k1, 

370 ecdsa.generator_secp256k1, 

371 (1, 3, 132, 0, 10), 

372 "secp256k1", 

373) 

374 

375 

376BRAINPOOLP160r1 = Curve( 

377 "BRAINPOOLP160r1", 

378 ecdsa.curve_brainpoolp160r1, 

379 ecdsa.generator_brainpoolp160r1, 

380 (1, 3, 36, 3, 3, 2, 8, 1, 1, 1), 

381 "brainpoolP160r1", 

382) 

383 

384 

385BRAINPOOLP160t1 = Curve( 

386 "BRAINPOOLP160t1", 

387 ecdsa.curve_brainpoolp160t1, 

388 ecdsa.generator_brainpoolp160t1, 

389 (1, 3, 36, 3, 3, 2, 8, 1, 1, 2), 

390 "brainpoolP160t1", 

391) 

392 

393 

394BRAINPOOLP192r1 = Curve( 

395 "BRAINPOOLP192r1", 

396 ecdsa.curve_brainpoolp192r1, 

397 ecdsa.generator_brainpoolp192r1, 

398 (1, 3, 36, 3, 3, 2, 8, 1, 1, 3), 

399 "brainpoolP192r1", 

400) 

401 

402 

403BRAINPOOLP192t1 = Curve( 

404 "BRAINPOOLP192t1", 

405 ecdsa.curve_brainpoolp192t1, 

406 ecdsa.generator_brainpoolp192t1, 

407 (1, 3, 36, 3, 3, 2, 8, 1, 1, 4), 

408 "brainpoolP192t1", 

409) 

410 

411 

412BRAINPOOLP224r1 = Curve( 

413 "BRAINPOOLP224r1", 

414 ecdsa.curve_brainpoolp224r1, 

415 ecdsa.generator_brainpoolp224r1, 

416 (1, 3, 36, 3, 3, 2, 8, 1, 1, 5), 

417 "brainpoolP224r1", 

418) 

419 

420 

421BRAINPOOLP224t1 = Curve( 

422 "BRAINPOOLP224t1", 

423 ecdsa.curve_brainpoolp224t1, 

424 ecdsa.generator_brainpoolp224t1, 

425 (1, 3, 36, 3, 3, 2, 8, 1, 1, 6), 

426 "brainpoolP224t1", 

427) 

428 

429 

430BRAINPOOLP256r1 = Curve( 

431 "BRAINPOOLP256r1", 

432 ecdsa.curve_brainpoolp256r1, 

433 ecdsa.generator_brainpoolp256r1, 

434 (1, 3, 36, 3, 3, 2, 8, 1, 1, 7), 

435 "brainpoolP256r1", 

436) 

437 

438 

439BRAINPOOLP256t1 = Curve( 

440 "BRAINPOOLP256t1", 

441 ecdsa.curve_brainpoolp256t1, 

442 ecdsa.generator_brainpoolp256t1, 

443 (1, 3, 36, 3, 3, 2, 8, 1, 1, 8), 

444 "brainpoolP256t1", 

445) 

446 

447 

448BRAINPOOLP320r1 = Curve( 

449 "BRAINPOOLP320r1", 

450 ecdsa.curve_brainpoolp320r1, 

451 ecdsa.generator_brainpoolp320r1, 

452 (1, 3, 36, 3, 3, 2, 8, 1, 1, 9), 

453 "brainpoolP320r1", 

454) 

455 

456 

457BRAINPOOLP320t1 = Curve( 

458 "BRAINPOOLP320t1", 

459 ecdsa.curve_brainpoolp320t1, 

460 ecdsa.generator_brainpoolp320t1, 

461 (1, 3, 36, 3, 3, 2, 8, 1, 1, 10), 

462 "brainpoolP320t1", 

463) 

464 

465 

466BRAINPOOLP384r1 = Curve( 

467 "BRAINPOOLP384r1", 

468 ecdsa.curve_brainpoolp384r1, 

469 ecdsa.generator_brainpoolp384r1, 

470 (1, 3, 36, 3, 3, 2, 8, 1, 1, 11), 

471 "brainpoolP384r1", 

472) 

473 

474 

475BRAINPOOLP384t1 = Curve( 

476 "BRAINPOOLP384t1", 

477 ecdsa.curve_brainpoolp384t1, 

478 ecdsa.generator_brainpoolp384t1, 

479 (1, 3, 36, 3, 3, 2, 8, 1, 1, 12), 

480 "brainpoolP384t1", 

481) 

482 

483 

484BRAINPOOLP512r1 = Curve( 

485 "BRAINPOOLP512r1", 

486 ecdsa.curve_brainpoolp512r1, 

487 ecdsa.generator_brainpoolp512r1, 

488 (1, 3, 36, 3, 3, 2, 8, 1, 1, 13), 

489 "brainpoolP512r1", 

490) 

491 

492 

493BRAINPOOLP512t1 = Curve( 

494 "BRAINPOOLP512t1", 

495 ecdsa.curve_brainpoolp512t1, 

496 ecdsa.generator_brainpoolp512t1, 

497 (1, 3, 36, 3, 3, 2, 8, 1, 1, 14), 

498 "brainpoolP512t1", 

499) 

500 

501 

502Ed25519 = Curve( 

503 "Ed25519", 

504 eddsa.curve_ed25519, 

505 eddsa.generator_ed25519, 

506 (1, 3, 101, 112), 

507) 

508 

509 

510Ed448 = Curve( 

511 "Ed448", 

512 eddsa.curve_ed448, 

513 eddsa.generator_ed448, 

514 (1, 3, 101, 113), 

515) 

516 

517 

518# no order in particular, but keep previously added curves first 

519curves = [ 

520 NIST192p, 

521 NIST224p, 

522 NIST256p, 

523 NIST384p, 

524 NIST521p, 

525 SECP256k1, 

526 BRAINPOOLP160r1, 

527 BRAINPOOLP192r1, 

528 BRAINPOOLP224r1, 

529 BRAINPOOLP256r1, 

530 BRAINPOOLP320r1, 

531 BRAINPOOLP384r1, 

532 BRAINPOOLP512r1, 

533 SECP112r1, 

534 SECP112r2, 

535 SECP128r1, 

536 SECP160r1, 

537 Ed25519, 

538 Ed448, 

539 BRAINPOOLP160t1, 

540 BRAINPOOLP192t1, 

541 BRAINPOOLP224t1, 

542 BRAINPOOLP256t1, 

543 BRAINPOOLP320t1, 

544 BRAINPOOLP384t1, 

545 BRAINPOOLP512t1, 

546] 

547 

548 

549def find_curve(oid_curve): 

550 """Select a curve based on its OID 

551 

552 :param tuple[int,...] oid_curve: ASN.1 Object Identifier of the 

553 curve to return, like ``(1, 2, 840, 10045, 3, 1, 7)`` for ``NIST256p``. 

554 

555 :raises UnknownCurveError: When the oid doesn't match any of the supported 

556 curves 

557 

558 :rtype: ~ecdsa.curves.Curve 

559 """ 

560 for c in curves: 

561 if c.oid == oid_curve: 

562 return c 

563 raise UnknownCurveError( 

564 "I don't know about the curve with oid %s." 

565 "I only know about these: %s" % (oid_curve, [c.name for c in curves]) 

566 ) 

567 

568 

569def curve_by_name(name): 

570 """Select a curve based on its name. 

571 

572 Returns a :py:class:`~ecdsa.curves.Curve` object with a ``name`` name. 

573 Note that ``name`` is case-sensitve. 

574 

575 :param str name: Name of the curve to return, like ``NIST256p`` or 

576 ``prime256v1`` 

577 

578 :raises UnknownCurveError: When the name doesn't match any of the supported 

579 curves 

580 

581 :rtype: ~ecdsa.curves.Curve 

582 """ 

583 for c in curves: 

584 if name == c.name or (c.openssl_name and name == c.openssl_name): 

585 return c 

586 raise UnknownCurveError( 

587 "Curve with name {0!r} unknown, only curves supported: {1}".format( 

588 name, [c.name for c in curves] 

589 ) 

590 )