Coverage for aiocoap/util/cryptography_additions.py: 90%

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

29 statements  

1# This file is part of the Python aiocoap library project. 

2# 

3# Copyright (c) 2012-2014 Maciej Wasilak <http://sixpinetrees.blogspot.com/>, 

4# 2013-2014 Christian Amsüss <c.amsuess@energyharvesting.at> 

5# 

6# aiocoap is free software, this file is published under the MIT license as 

7# described in the accompanying LICENSE file. 

8 

9""" 

10Workaround for https://github.com/pyca/cryptography/issues/5557 

11 

12These functions could be methods to 

13`cryptography.hazmat.primitives.asymmetric.ed25519.{Ed25519PrivateKey, 

14Ed25519PublicKey}`, respectively, and are currently implemented manually or 

15using ge25519. 

16 

17These conversions are not too critical in that they do not run on data an 

18attacker can send arbitrarily (in the most dynamic situation, the keys are 

19distributed through a KDC aka. group manager). 

20""" 

21 

22from cryptography.hazmat.primitives.asymmetric import ed25519, x25519 

23from cryptography.hazmat.primitives import serialization 

24 

25def sk_to_curve25519(ed: ed25519.Ed25519PrivateKey) -> x25519.X25519PrivateKey: 

26 raw = ed.private_bytes( 

27 encoding=serialization.Encoding.Raw, 

28 format=serialization.PrivateFormat.Raw, 

29 encryption_algorithm=serialization.NoEncryption(), 

30 ) 

31 

32 # as proposed in https://github.com/pyca/cryptography/issues/5557#issuecomment-739339132 

33 

34 from cryptography.hazmat.primitives import hashes 

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

36 

37 hasher = hashes.Hash(hashes.SHA512()) 

38 hasher.update(raw) 

39 h = bytearray(hasher.finalize()) 

40 # curve25519 clamping 

41 h[0] &= 248 

42 h[31] &= 127 

43 h[31] |= 64 

44 

45 return backend.x25519_load_private_bytes(h[0:32]) 

46 

47def pk_to_curve25519(ed: ed25519.Ed25519PublicKey) -> x25519.X25519PublicKey: 

48 raw = ed.public_bytes( 

49 encoding=serialization.Encoding.Raw, 

50 format=serialization.PublicFormat.Raw, 

51 ) 

52 

53 # This is libsodium's crypto_sign_ed25519_pk_to_curve25519 translated into 

54 # the Pyton module ge25519. 

55 

56 from ge25519 import ge25519, ge25519_p3 

57 from fe25519 import fe25519 

58 

59 if ge25519.has_small_order(raw) != 0: 

60 raise RuntimeError("Doesn' thave small order") 

61 

62 # frombytes in libsodium appears to be the same as 

63 # frombytes_negate_vartime; as ge25519 only implements the from_bytes 

64 # version, we have to do the root check manually. 

65 A = ge25519_p3.from_bytes(raw) 

66 if A.root_check: 

67 raise RuntimeError("Root check failed") 

68 

69 if not A.is_on_main_subgroup(): 

70 raise RuntimeError("It's on the main subgroup") 

71 

72 one_minus_y = fe25519.one() - A.Y 

73 x = A.Y + fe25519.one() 

74 x = x * one_minus_y.invert() 

75 

76 return x25519.X25519PublicKey.from_public_bytes(bytes(x.to_bytes()))