Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py: 69%

227 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1# This file is dual licensed under the terms of the Apache License, Version 

2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 

3# for complete details. 

4 

5 

6import abc 

7import typing 

8import warnings 

9 

10from cryptography import utils 

11from cryptography.hazmat._oid import ObjectIdentifier 

12from cryptography.hazmat.primitives import _serialization, hashes 

13from cryptography.hazmat.primitives.asymmetric import ( 

14 utils as asym_utils, 

15) 

16 

17 

18class EllipticCurveOID: 

19 SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1") 

20 SECP224R1 = ObjectIdentifier("1.3.132.0.33") 

21 SECP256K1 = ObjectIdentifier("1.3.132.0.10") 

22 SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7") 

23 SECP384R1 = ObjectIdentifier("1.3.132.0.34") 

24 SECP521R1 = ObjectIdentifier("1.3.132.0.35") 

25 BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7") 

26 BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11") 

27 BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13") 

28 SECT163K1 = ObjectIdentifier("1.3.132.0.1") 

29 SECT163R2 = ObjectIdentifier("1.3.132.0.15") 

30 SECT233K1 = ObjectIdentifier("1.3.132.0.26") 

31 SECT233R1 = ObjectIdentifier("1.3.132.0.27") 

32 SECT283K1 = ObjectIdentifier("1.3.132.0.16") 

33 SECT283R1 = ObjectIdentifier("1.3.132.0.17") 

34 SECT409K1 = ObjectIdentifier("1.3.132.0.36") 

35 SECT409R1 = ObjectIdentifier("1.3.132.0.37") 

36 SECT571K1 = ObjectIdentifier("1.3.132.0.38") 

37 SECT571R1 = ObjectIdentifier("1.3.132.0.39") 

38 

39 

40class EllipticCurve(metaclass=abc.ABCMeta): 

41 @abc.abstractproperty 

42 def name(self) -> str: 

43 """ 

44 The name of the curve. e.g. secp256r1. 

45 """ 

46 

47 @abc.abstractproperty 

48 def key_size(self) -> int: 

49 """ 

50 Bit size of a secret scalar for the curve. 

51 """ 

52 

53 

54class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta): 

55 @abc.abstractproperty 

56 def algorithm( 

57 self, 

58 ) -> typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm]: 

59 """ 

60 The digest algorithm used with this signature. 

61 """ 

62 

63 

64class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): 

65 @abc.abstractmethod 

66 def exchange( 

67 self, algorithm: "ECDH", peer_public_key: "EllipticCurvePublicKey" 

68 ) -> bytes: 

69 """ 

70 Performs a key exchange operation using the provided algorithm with the 

71 provided peer's public key. 

72 """ 

73 

74 @abc.abstractmethod 

75 def public_key(self) -> "EllipticCurvePublicKey": 

76 """ 

77 The EllipticCurvePublicKey for this private key. 

78 """ 

79 

80 @abc.abstractproperty 

81 def curve(self) -> EllipticCurve: 

82 """ 

83 The EllipticCurve that this key is on. 

84 """ 

85 

86 @abc.abstractproperty 

87 def key_size(self) -> int: 

88 """ 

89 Bit size of a secret scalar for the curve. 

90 """ 

91 

92 @abc.abstractmethod 

93 def sign( 

94 self, 

95 data: bytes, 

96 signature_algorithm: EllipticCurveSignatureAlgorithm, 

97 ) -> bytes: 

98 """ 

99 Signs the data 

100 """ 

101 

102 @abc.abstractmethod 

103 def private_numbers(self) -> "EllipticCurvePrivateNumbers": 

104 """ 

105 Returns an EllipticCurvePrivateNumbers. 

106 """ 

107 

108 @abc.abstractmethod 

109 def private_bytes( 

110 self, 

111 encoding: _serialization.Encoding, 

112 format: _serialization.PrivateFormat, 

113 encryption_algorithm: _serialization.KeySerializationEncryption, 

114 ) -> bytes: 

115 """ 

116 Returns the key serialized as bytes. 

117 """ 

118 

119 

120EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey 

121 

122 

123class EllipticCurvePublicKey(metaclass=abc.ABCMeta): 

124 @abc.abstractproperty 

125 def curve(self) -> EllipticCurve: 

126 """ 

127 The EllipticCurve that this key is on. 

128 """ 

129 

130 @abc.abstractproperty 

131 def key_size(self) -> int: 

132 """ 

133 Bit size of a secret scalar for the curve. 

134 """ 

135 

136 @abc.abstractmethod 

137 def public_numbers(self) -> "EllipticCurvePublicNumbers": 

138 """ 

139 Returns an EllipticCurvePublicNumbers. 

140 """ 

141 

142 @abc.abstractmethod 

143 def public_bytes( 

144 self, 

145 encoding: _serialization.Encoding, 

146 format: _serialization.PublicFormat, 

147 ) -> bytes: 

148 """ 

149 Returns the key serialized as bytes. 

150 """ 

151 

152 @abc.abstractmethod 

153 def verify( 

154 self, 

155 signature: bytes, 

156 data: bytes, 

157 signature_algorithm: EllipticCurveSignatureAlgorithm, 

158 ) -> None: 

159 """ 

160 Verifies the signature of the data. 

161 """ 

162 

163 @classmethod 

164 def from_encoded_point( 

165 cls, curve: EllipticCurve, data: bytes 

166 ) -> "EllipticCurvePublicKey": 

167 utils._check_bytes("data", data) 

168 

169 if not isinstance(curve, EllipticCurve): 

170 raise TypeError("curve must be an EllipticCurve instance") 

171 

172 if len(data) == 0: 

173 raise ValueError("data must not be an empty byte string") 

174 

175 if data[0] not in [0x02, 0x03, 0x04]: 

176 raise ValueError("Unsupported elliptic curve point type") 

177 

178 from cryptography.hazmat.backends.openssl.backend import backend 

179 

180 return backend.load_elliptic_curve_public_bytes(curve, data) 

181 

182 

183EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey 

184 

185 

186class SECT571R1(EllipticCurve): 

187 name = "sect571r1" 

188 key_size = 570 

189 

190 

191class SECT409R1(EllipticCurve): 

192 name = "sect409r1" 

193 key_size = 409 

194 

195 

196class SECT283R1(EllipticCurve): 

197 name = "sect283r1" 

198 key_size = 283 

199 

200 

201class SECT233R1(EllipticCurve): 

202 name = "sect233r1" 

203 key_size = 233 

204 

205 

206class SECT163R2(EllipticCurve): 

207 name = "sect163r2" 

208 key_size = 163 

209 

210 

211class SECT571K1(EllipticCurve): 

212 name = "sect571k1" 

213 key_size = 571 

214 

215 

216class SECT409K1(EllipticCurve): 

217 name = "sect409k1" 

218 key_size = 409 

219 

220 

221class SECT283K1(EllipticCurve): 

222 name = "sect283k1" 

223 key_size = 283 

224 

225 

226class SECT233K1(EllipticCurve): 

227 name = "sect233k1" 

228 key_size = 233 

229 

230 

231class SECT163K1(EllipticCurve): 

232 name = "sect163k1" 

233 key_size = 163 

234 

235 

236class SECP521R1(EllipticCurve): 

237 name = "secp521r1" 

238 key_size = 521 

239 

240 

241class SECP384R1(EllipticCurve): 

242 name = "secp384r1" 

243 key_size = 384 

244 

245 

246class SECP256R1(EllipticCurve): 

247 name = "secp256r1" 

248 key_size = 256 

249 

250 

251class SECP256K1(EllipticCurve): 

252 name = "secp256k1" 

253 key_size = 256 

254 

255 

256class SECP224R1(EllipticCurve): 

257 name = "secp224r1" 

258 key_size = 224 

259 

260 

261class SECP192R1(EllipticCurve): 

262 name = "secp192r1" 

263 key_size = 192 

264 

265 

266class BrainpoolP256R1(EllipticCurve): 

267 name = "brainpoolP256r1" 

268 key_size = 256 

269 

270 

271class BrainpoolP384R1(EllipticCurve): 

272 name = "brainpoolP384r1" 

273 key_size = 384 

274 

275 

276class BrainpoolP512R1(EllipticCurve): 

277 name = "brainpoolP512r1" 

278 key_size = 512 

279 

280 

281_CURVE_TYPES: typing.Dict[str, typing.Type[EllipticCurve]] = { 

282 "prime192v1": SECP192R1, 

283 "prime256v1": SECP256R1, 

284 "secp192r1": SECP192R1, 

285 "secp224r1": SECP224R1, 

286 "secp256r1": SECP256R1, 

287 "secp384r1": SECP384R1, 

288 "secp521r1": SECP521R1, 

289 "secp256k1": SECP256K1, 

290 "sect163k1": SECT163K1, 

291 "sect233k1": SECT233K1, 

292 "sect283k1": SECT283K1, 

293 "sect409k1": SECT409K1, 

294 "sect571k1": SECT571K1, 

295 "sect163r2": SECT163R2, 

296 "sect233r1": SECT233R1, 

297 "sect283r1": SECT283R1, 

298 "sect409r1": SECT409R1, 

299 "sect571r1": SECT571R1, 

300 "brainpoolP256r1": BrainpoolP256R1, 

301 "brainpoolP384r1": BrainpoolP384R1, 

302 "brainpoolP512r1": BrainpoolP512R1, 

303} 

304 

305 

306class ECDSA(EllipticCurveSignatureAlgorithm): 

307 def __init__( 

308 self, 

309 algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], 

310 ): 

311 self._algorithm = algorithm 

312 

313 @property 

314 def algorithm( 

315 self, 

316 ) -> typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm]: 

317 return self._algorithm 

318 

319 

320def generate_private_key( 

321 curve: EllipticCurve, backend: typing.Any = None 

322) -> EllipticCurvePrivateKey: 

323 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

324 

325 return ossl.generate_elliptic_curve_private_key(curve) 

326 

327 

328def derive_private_key( 

329 private_value: int, 

330 curve: EllipticCurve, 

331 backend: typing.Any = None, 

332) -> EllipticCurvePrivateKey: 

333 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

334 

335 if not isinstance(private_value, int): 

336 raise TypeError("private_value must be an integer type.") 

337 

338 if private_value <= 0: 

339 raise ValueError("private_value must be a positive integer.") 

340 

341 if not isinstance(curve, EllipticCurve): 

342 raise TypeError("curve must provide the EllipticCurve interface.") 

343 

344 return ossl.derive_elliptic_curve_private_key(private_value, curve) 

345 

346 

347class EllipticCurvePublicNumbers: 

348 def __init__(self, x: int, y: int, curve: EllipticCurve): 

349 if not isinstance(x, int) or not isinstance(y, int): 

350 raise TypeError("x and y must be integers.") 

351 

352 if not isinstance(curve, EllipticCurve): 

353 raise TypeError("curve must provide the EllipticCurve interface.") 

354 

355 self._y = y 

356 self._x = x 

357 self._curve = curve 

358 

359 def public_key(self, backend: typing.Any = None) -> EllipticCurvePublicKey: 

360 from cryptography.hazmat.backends.openssl.backend import ( 

361 backend as ossl, 

362 ) 

363 

364 return ossl.load_elliptic_curve_public_numbers(self) 

365 

366 def encode_point(self) -> bytes: 

367 warnings.warn( 

368 "encode_point has been deprecated on EllipticCurvePublicNumbers" 

369 " and will be removed in a future version. Please use " 

370 "EllipticCurvePublicKey.public_bytes to obtain both " 

371 "compressed and uncompressed point encoding.", 

372 utils.PersistentlyDeprecated2019, 

373 stacklevel=2, 

374 ) 

375 # key_size is in bits. Convert to bytes and round up 

376 byte_length = (self.curve.key_size + 7) // 8 

377 return ( 

378 b"\x04" 

379 + utils.int_to_bytes(self.x, byte_length) 

380 + utils.int_to_bytes(self.y, byte_length) 

381 ) 

382 

383 @classmethod 

384 def from_encoded_point( 

385 cls, curve: EllipticCurve, data: bytes 

386 ) -> "EllipticCurvePublicNumbers": 

387 if not isinstance(curve, EllipticCurve): 

388 raise TypeError("curve must be an EllipticCurve instance") 

389 

390 warnings.warn( 

391 "Support for unsafe construction of public numbers from " 

392 "encoded data will be removed in a future version. " 

393 "Please use EllipticCurvePublicKey.from_encoded_point", 

394 utils.PersistentlyDeprecated2019, 

395 stacklevel=2, 

396 ) 

397 

398 if data.startswith(b"\x04"): 

399 # key_size is in bits. Convert to bytes and round up 

400 byte_length = (curve.key_size + 7) // 8 

401 if len(data) == 2 * byte_length + 1: 

402 x = int.from_bytes(data[1 : byte_length + 1], "big") 

403 y = int.from_bytes(data[byte_length + 1 :], "big") 

404 return cls(x, y, curve) 

405 else: 

406 raise ValueError("Invalid elliptic curve point data length") 

407 else: 

408 raise ValueError("Unsupported elliptic curve point type") 

409 

410 @property 

411 def curve(self) -> EllipticCurve: 

412 return self._curve 

413 

414 @property 

415 def x(self) -> int: 

416 return self._x 

417 

418 @property 

419 def y(self) -> int: 

420 return self._y 

421 

422 def __eq__(self, other: object) -> bool: 

423 if not isinstance(other, EllipticCurvePublicNumbers): 

424 return NotImplemented 

425 

426 return ( 

427 self.x == other.x 

428 and self.y == other.y 

429 and self.curve.name == other.curve.name 

430 and self.curve.key_size == other.curve.key_size 

431 ) 

432 

433 def __hash__(self) -> int: 

434 return hash((self.x, self.y, self.curve.name, self.curve.key_size)) 

435 

436 def __repr__(self) -> str: 

437 return ( 

438 "<EllipticCurvePublicNumbers(curve={0.curve.name}, x={0.x}, " 

439 "y={0.y}>".format(self) 

440 ) 

441 

442 

443class EllipticCurvePrivateNumbers: 

444 def __init__( 

445 self, private_value: int, public_numbers: EllipticCurvePublicNumbers 

446 ): 

447 if not isinstance(private_value, int): 

448 raise TypeError("private_value must be an integer.") 

449 

450 if not isinstance(public_numbers, EllipticCurvePublicNumbers): 

451 raise TypeError( 

452 "public_numbers must be an EllipticCurvePublicNumbers " 

453 "instance." 

454 ) 

455 

456 self._private_value = private_value 

457 self._public_numbers = public_numbers 

458 

459 def private_key( 

460 self, backend: typing.Any = None 

461 ) -> EllipticCurvePrivateKey: 

462 from cryptography.hazmat.backends.openssl.backend import ( 

463 backend as ossl, 

464 ) 

465 

466 return ossl.load_elliptic_curve_private_numbers(self) 

467 

468 @property 

469 def private_value(self) -> int: 

470 return self._private_value 

471 

472 @property 

473 def public_numbers(self) -> EllipticCurvePublicNumbers: 

474 return self._public_numbers 

475 

476 def __eq__(self, other: object) -> bool: 

477 if not isinstance(other, EllipticCurvePrivateNumbers): 

478 return NotImplemented 

479 

480 return ( 

481 self.private_value == other.private_value 

482 and self.public_numbers == other.public_numbers 

483 ) 

484 

485 def __hash__(self) -> int: 

486 return hash((self.private_value, self.public_numbers)) 

487 

488 

489class ECDH: 

490 pass 

491 

492 

493_OID_TO_CURVE = { 

494 EllipticCurveOID.SECP192R1: SECP192R1, 

495 EllipticCurveOID.SECP224R1: SECP224R1, 

496 EllipticCurveOID.SECP256K1: SECP256K1, 

497 EllipticCurveOID.SECP256R1: SECP256R1, 

498 EllipticCurveOID.SECP384R1: SECP384R1, 

499 EllipticCurveOID.SECP521R1: SECP521R1, 

500 EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, 

501 EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, 

502 EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, 

503 EllipticCurveOID.SECT163K1: SECT163K1, 

504 EllipticCurveOID.SECT163R2: SECT163R2, 

505 EllipticCurveOID.SECT233K1: SECT233K1, 

506 EllipticCurveOID.SECT233R1: SECT233R1, 

507 EllipticCurveOID.SECT283K1: SECT283K1, 

508 EllipticCurveOID.SECT283R1: SECT283R1, 

509 EllipticCurveOID.SECT409K1: SECT409K1, 

510 EllipticCurveOID.SECT409R1: SECT409R1, 

511 EllipticCurveOID.SECT571K1: SECT571K1, 

512 EllipticCurveOID.SECT571R1: SECT571R1, 

513} 

514 

515 

516def get_curve_for_oid(oid: ObjectIdentifier) -> typing.Type[EllipticCurve]: 

517 try: 

518 return _OID_TO_CURVE[oid] 

519 except KeyError: 

520 raise LookupError( 

521 "The provided object identifier has no matching elliptic " 

522 "curve class" 

523 )