def test_bad_exchange(self, backend, vector): if ( backend._fips_enabled and int(vector["p1"]) < backend._fips_dh_min_modulus ): pytest.skip("modulus too small for FIPS mode") parameters1 = dh.DHParameterNumbers( int(vector["p1"]), int(vector["g"]) ) public1 = dh.DHPublicNumbers(int(vector["y1"]), parameters1) private1 = dh.DHPrivateNumbers(int(vector["x1"]), public1) key1 = private1.private_key(backend) pub_key1 = key1.public_key() parameters2 = dh.DHParameterNumbers( int(vector["p2"]), int(vector["g"]) ) public2 = dh.DHPublicNumbers(int(vector["y2"]), parameters2) private2 = dh.DHPrivateNumbers(int(vector["x2"]), public2) key2 = private2.private_key(backend) pub_key2 = key2.public_key() if pub_key2.public_numbers().y >= parameters1.p: with pytest.raises(ValueError): key1.exchange(pub_key2) else: symkey1 = key1.exchange(pub_key2) assert symkey1 symkey2 = key2.exchange(pub_key1) assert symkey1 != symkey2
def test_bad_exchange(self, backend, vector): parameters1 = dh.DHParameterNumbers(int(vector["p1"]), int(vector["g"])) public1 = dh.DHPublicNumbers(int(vector["y1"]), parameters1) private1 = dh.DHPrivateNumbers(int(vector["x1"]), public1) key1 = private1.private_key(backend) pub_key1 = key1.public_key() parameters2 = dh.DHParameterNumbers(int(vector["p2"]), int(vector["g"])) public2 = dh.DHPublicNumbers(int(vector["y2"]), parameters2) private2 = dh.DHPrivateNumbers(int(vector["x2"]), public2) key2 = private2.private_key(backend) pub_key2 = key2.public_key() if pub_key2.public_numbers().y >= parameters1.p: with pytest.raises(ValueError): key1.exchange(pub_key2) else: symkey1 = key1.exchange(pub_key2) assert symkey1 symkey2 = key2.exchange(pub_key1) assert symkey1 != symkey2
def test_dh_private_numbers_equality(): params = dh.DHParameterNumbers(P_1536, 2) public = dh.DHPublicNumbers(1, params) private = dh.DHPrivateNumbers(2, public) assert private == dh.DHPrivateNumbers(2, public) assert private != dh.DHPrivateNumbers(0, public) assert private != dh.DHPrivateNumbers(2, dh.DHPublicNumbers(0, params)) assert private != dh.DHPrivateNumbers( 2, dh.DHPublicNumbers(1, dh.DHParameterNumbers(P_1536, 5))) assert private != object()
def test_dh_vectors_with_q(self, backend, vector): parameters = dh.DHParameterNumbers( int(vector["p"], 16), int(vector["g"], 16), int(vector["q"], 16) ) public1 = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters) private1 = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public1) public2 = dh.DHPublicNumbers(int(vector["ystatiut"], 16), parameters) private2 = dh.DHPrivateNumbers(int(vector["xstatiut"], 16), public2) key1 = private1.private_key(backend) key2 = private2.private_key(backend) symkey1 = key1.exchange(public2.public_key(backend)) symkey2 = key2.exchange(public1.public_key(backend)) assert int_from_bytes(symkey1, "big") == int(vector["z"], 16) assert int_from_bytes(symkey2, "big") == int(vector["z"], 16)
def test_convert_to_numbers(self, backend, with_q): if with_q: vector = load_vectors_from_file( os.path.join("asymmetric", "DH", "RFC5114.txt"), load_nist_vectors, )[0] p = int(vector["p"], 16) g = int(vector["g"], 16) q = int(vector["q"], 16) else: parameters = backend.generate_dh_private_key_and_parameters(2, 512) private = parameters.private_numbers() p = private.public_numbers.parameter_numbers.p g = private.public_numbers.parameter_numbers.g q = None params = dh.DHParameterNumbers(p, g, q) public = dh.DHPublicNumbers(1, params) private = dh.DHPrivateNumbers(2, public) deserialized_params = params.parameters(backend) deserialized_public = public.public_key(backend) deserialized_private = private.private_key(backend) assert isinstance( deserialized_params, dh.DHParametersWithSerialization ) assert isinstance(deserialized_public, dh.DHPublicKeyWithSerialization) assert isinstance( deserialized_private, dh.DHPrivateKeyWithSerialization )
def test_numbers_unsupported_parameters(self, backend): params = dh.DHParameterNumbers(23, 2) public = dh.DHPublicNumbers(1, params) private = dh.DHPrivateNumbers(2, public) with pytest.raises(ValueError): private.private_key(backend)
def test_symmetric_key_padding(self, backend): """ This test has specific parameters that produce a symmetric key In length 63 bytes instead 64. We make sure here that we add padding to the key. """ p = int( "11859949538425015739337467917303613431031019140213666" "129025407300654026585086345323066284800963463204246390" "256567934582260424238844463330887962689642467123" ) g = 2 y = int( "32155788395534640648739966373159697798396966919821525" "72238852825117261342483718574508213761865276905503199" "969908098203345481366464874759377454476688391248" ) x = int( "409364065449673443397833358558926598469347813468816037" "268451847116982490733450463194921405069999008617231539" "7147035896687401350877308899732826446337707128" ) parameters = dh.DHParameterNumbers(p, g) public = dh.DHPublicNumbers(y, parameters) private = dh.DHPrivateNumbers(x, public) key = private.private_key(backend) symkey = key.exchange(public.public_key(backend)) assert len(symkey) == 512 // 8 assert symkey[:1] == b"\x00"
def private_numbers(self): p = self._backend._ffi.new("BIGNUM **") g = self._backend._ffi.new("BIGNUM **") q = self._backend._ffi.new("BIGNUM **") self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) if q[0] == self._backend._ffi.NULL: q_val = None else: q_val = self._backend._bn_to_int(q[0]) pub_key = self._backend._ffi.new("BIGNUM **") priv_key = self._backend._ffi.new("BIGNUM **") self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key) self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) return dh.DHPrivateNumbers( public_numbers=dh.DHPublicNumbers( parameter_numbers=dh.DHParameterNumbers( p=self._backend._bn_to_int(p[0]), g=self._backend._bn_to_int(g[0]), q=q_val ), y=self._backend._bn_to_int(pub_key[0]) ), x=self._backend._bn_to_int(priv_key[0]) )
def test_dh_vectors(self, backend, vector): parameters = dh.DHParameterNumbers(int(vector["p"]), int(vector["g"])) public = dh.DHPublicNumbers(int(vector["y"]), parameters) private = dh.DHPrivateNumbers(int(vector["x"]), public) key = private.private_key(backend) symkey = key.exchange(public.public_key(backend)) assert int_from_bytes(symkey, 'big') == int(vector["k"], 16)
def dh_shared_secret( message: bytes, private_secret: dh.DHPublicNumbers) -> dh.DHPrivateNumbers: """ Compute the shared secret from private secret and the other party's message. """ gx = utils.int_from_bytes(message, 'big') gxy = pow(gx, private_secret.y, private_secret.parameter_numbers.p) return dh.DHPrivateNumbers(gxy, private_secret)
def test_numbers_unsupported_parameters(self, backend): # p is set to P_1536 + 1 because when calling private_key we want it to # fail the DH_check call OpenSSL does, but we specifically want it to # fail such that we don't get a DH_NOT_SUITABLE_GENERATOR. We can cause # this by making sure p is not prime. params = dh.DHParameterNumbers(P_1536 + 1, 2) public = dh.DHPublicNumbers(1, params) private = dh.DHPrivateNumbers(2, public) with pytest.raises(ValueError): private.private_key(backend)
def test_dh_vectors(self, backend, vector): if (backend._fips_enabled and int(vector["p"]) < backend._fips_dh_min_modulus): pytest.skip("modulus too small for FIPS mode") parameters = dh.DHParameterNumbers(int(vector["p"]), int(vector["g"])) public = dh.DHPublicNumbers(int(vector["y"]), parameters) private = dh.DHPrivateNumbers(int(vector["x"]), public) key = private.private_key(backend) symkey = key.exchange(public.public_key(backend)) assert int_from_bytes(symkey, "big") == int(vector["k"], 16)
def test_numbers_unsupported_parameters(self, backend): # p is set to 21 because when calling private_key we want it to # fail the DH_check call OpenSSL does. Originally this was 23, but # we are allowing p % 24 to == 23 with this PR (see #3768 for more) # By setting it to 21 it fails later in DH_check in a primality check # which triggers the code path we want to test params = dh.DHParameterNumbers(21, 2) public = dh.DHPublicNumbers(1, params) private = dh.DHPrivateNumbers(2, public) with pytest.raises(ValueError): private.private_key(backend)
def test_dh_numbers(): params = dh.DHParameterNumbers( 65537, 2 ) public = dh.DHPublicNumbers( 1, params ) assert public.parameter_numbers is params assert public.y == 1 with pytest.raises(TypeError): dh.DHPublicNumbers( 1, None ) with pytest.raises(TypeError): dh.DHPublicNumbers( None, params ) private = dh.DHPrivateNumbers( 1, public ) assert private.public_numbers is public assert private.x == 1 with pytest.raises(TypeError): dh.DHPrivateNumbers( 1, None ) with pytest.raises(TypeError): dh.DHPrivateNumbers( None, public )
def test_dh(): # noqa: E501 bend = default_backend() p = 179769313486231590770839156793787453197860296048756011706444423684197180216158519368947833795864925541502180565485980503646440548199239100050792877003355816639229553136239076508735759914822574862575007425302077447712589550957937778424442426617334727629299387668709205606050270810842907692932019128194467627007 g = 2 mini_tor_p_bytes = b'\xff\xff\xff\xff\xff\xff\xff\xff\xc9\x0f\xda\xa2\x21\x68\xc2\x34\xc4\xc6\x62\x8b\x80\xdc\x1c\xd1\x29\x02\x4e\x08\x8a\x67\xcc\x74\x02\x0b\xbe\xa6\x3b\x13\x9b\x22\x51\x4a\x08\x79\x8e\x34\x04\xdd\xef\x95\x19\xb3\xcd\x3a\x43\x1b\x30\x2b\x0a\x6d\xf2\x5f\x14\x37\x4f\xe1\x35\x6d\x6d\x51\xc2\x45\xe4\x85\xb5\x76\x62\x5e\x7e\xc6\xf4\x4c\x42\xe9\xa6\x37\xed\x6b\x0b\xff\x5c\xb6\xf4\x06\xb7\xed\xee\x38\x6b\xfb\x5a\x89\x9f\xa5\xae\x9f\x24\x11\x7c\x4b\x1f\xe6\x49\x28\x66\x51\xec\xe6\x53\x81\xff\xff\xff\xff\xff\xff\xff\xff' assert p.to_bytes(128, 'big') == mini_tor_p_bytes dh_parameters_numbers = dh.DHParameterNumbers(p, g) dh_private_bytes = to_bytes( '81 2A 69 3A CD 75 6B 3F 3E 9A 8C 64 A4 ED 8C B5 2A 43 8B E7 6B 0D FB F5 CB 0D 70 E1 DB 2A 5F 57 4F 36 7D F1 B0 D1 E5 57 32 57 92 03 E4 0C 08 EF BA 7B 82 25 10 00 94 F0 3A E9 3F 2C AF 24 D6 FB A7 E0 DE 97 18 B5 DB E9 15 44 69 F8 CA 42 E8 87 18 16 BB F6 F8 8E D0 C9 B1 41 D4 02 02 E8 1A EC B3 E2 EB 06 04 86 EB 3D 6E A4 5E D7 4C ED EB B5 C6 7A A7 4F 13 99 D4 50 C8 BA 1E 9B 79 66 36 1D' ) dh_private_x = int.from_bytes(dh_private_bytes, 'big') dh_public_bytes = to_bytes( '8F 61 59 22 DC 09 BF AB EF 79 3B 2F 3C 6D D3 51 2D FB 29 41 B2 45 59 B7 BF 64 17 41 9B 17 5F F3 7C 5E C8 A8 A9 87 19 72 4D 94 8A 7F 3A 7B D8 30 8C F3 79 88 4F 72 55 DA 7F A7 DC 93 26 C4 16 92 DB 14 C5 34 94 5C 48 4A 0F 54 39 EF 77 8F D1 64 EF BE 0F B4 55 B8 C1 DF DA 9F D5 60 03 B2 C5 34 4C 46 23 00 A8 89 47 F0 2F 5A 26 FC 5E 1A BB 63 49 25 19 BB BD 5F 69 6E 7D A0 00 50 28 06 21 CC' ) dh_public_y = int.from_bytes(dh_public_bytes, 'big') dh_public_num = dh.DHPublicNumbers(dh_public_y, dh_parameters_numbers) dh_public = dh_public_num.public_key(bend) # Check public serialization assert dh_public_to_bytes(dh_public) == dh_public_bytes dh_private_num = dh.DHPrivateNumbers(dh_private_x, dh_public_num) dh_private = dh_private_num.private_key(bend) other_public_bytes = to_bytes( '69 47 FC C9 54 60 AE F6 F6 99 C1 E2 FA 9A 6F FA A2 76 FD 0B 89 6C CD 6F 0C 73 99 20 F6 38 64 83 54 09 61 F4 48 F4 90 9D 41 BB D7 72 E5 B0 C1 B7 9D B2 DD ED E2 C8 50 D8 49 EE 61 DA D0 6E 73 02 4B B4 A9 66 CE 83 AF 97 01 2D 08 9C 83 63 9A AB 33 D9 0C 80 2B 26 E9 6B D0 C9 9D 53 FF 53 C0 24 8F 73 5A 71 15 CC 6D 20 92 80 00 4E EA FD 11 25 C9 74 44 8A 86 3F 27 BC 5F 4C B3 D7 98 DB 7A 7F' ) dh_other_public_y = int.from_bytes(other_public_bytes, 'big') dh_other_public_num = dh.DHPublicNumbers(dh_other_public_y, dh_parameters_numbers) dh_other_public = dh_other_public_num.public_key(bend) # Check shared shared = dh_shared(dh_private, dh_other_public) expected_shared = to_bytes( 'CF 67 62 D4 65 96 A0 B0 E0 A9 C2 32 7E 09 E5 B4 81 6B 30 6B 9B 7B 75 65 BE 91 0E 59 F0 96 D8 95 AA 51 89 AE CB 07 50 DE E7 9B 53 A9 29 06 16 65 6C F1 F1 4D F8 B9 94 23 5E FE C5 64 83 F2 40 AD 92 7D 63 76 47 37 6F DE 67 16 CE 38 B7 5C BD 36 C6 99 00 00 09 DE 6E E2 5A 9D 9B BB EC 71 43 1C 41 1A 39 C0 C5 21 88 A0 BB 0E C4 BF 46 F3 30 FC 47 5B 05 45 F9 49 59 3B 63 1C ED C0 EF 21 F0 44' ) assert shared == expected_shared # Check derived computed_auth, key_material = kdf_tor(shared) expected_derived = to_bytes( '01 41 3D 3A 4A 06 55 4E 27 76 42 EA D4 44 F5 D8 A3 50 CD DD 60 2B 4D BD 97 76 7C CE DF E9 05 29 40 C6 14 EA E0 05 40 2D 08 8C B9 34 BD 24 16 E9 97 E6 8A 76 C1 FB C9 25 EA 77 D5 F6 19 9C 0E 65 A1 C2 D9 9E 70 B4 39 7F 60 C2 9D 8C A8 BE C0 E3 77 7D 05 FC A8 5A 6C F2 BD 46 05 CB 83 37 B4 96 4A 6C 2F 8F' ) assert computed_auth + key_material == expected_derived
def test_dh_numbers(): params = dh.DHParameterNumbers(P_1536, 2) public = dh.DHPublicNumbers(1, params) assert public.parameter_numbers is params assert public.y == 1 with pytest.raises(TypeError): dh.DHPublicNumbers(1, None) # type: ignore[arg-type] with pytest.raises(TypeError): dh.DHPublicNumbers(None, params) # type:ignore[arg-type] private = dh.DHPrivateNumbers(1, public) assert private.public_numbers is public assert private.x == 1 with pytest.raises(TypeError): dh.DHPrivateNumbers(1, None) # type: ignore[arg-type] with pytest.raises(TypeError): dh.DHPrivateNumbers(None, public) # type:ignore[arg-type]
def test_dh_serialization_with_q_unsupported(self, backend, vector): parameters = dh.DHParameterNumbers(int(vector["p"], 16), int(vector["g"], 16), int(vector["q"], 16)) public = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters) private = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public) private_key = private.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): private_key.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): public_key.public_bytes( serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo)
def test_convert_to_numbers(self, backend): parameters = backend.generate_dh_private_key_and_parameters(2, 512) private = parameters.private_numbers() p = private.public_numbers.parameter_numbers.p g = private.public_numbers.parameter_numbers.g params = dh.DHParameterNumbers(p, g) public = dh.DHPublicNumbers(1, params) private = dh.DHPrivateNumbers(2, public) deserialized_params = params.parameters(backend) deserialized_public = public.public_key(backend) deserialized_private = private.private_key(backend) assert isinstance(deserialized_params, dh.DHParametersWithSerialization) assert isinstance(deserialized_public, dh.DHPublicKeyWithSerialization) assert isinstance(deserialized_private, dh.DHPrivateKeyWithSerialization)
from cryptography.hazmat.primitives.asymmetric import dh from cryptography.utils import int_from_bytes backend = default_backend() p = int("11859949538425015739337467917303613431031019140213666" "12902540730065402658508634532306628480096346320424639" "0256567934582260424238844463330887962689642467123") g = 2 y = int("32155788395534640648739966373159697798396966919821525" "72238852825117261342483718574508213761865276905503199" "969908098203345481366464874759377454476688391248") x = int("409364065449673443397833358558926598469347813468816037" "268451847116982490733450463194921405069999008617231539" "7147035896687401350877308899732826446337707128") params = dh.DHParameterNumbers(p, g) public = dh.DHPublicNumbers(y, params) private = dh.DHPrivateNumbers(x, public) key = private.private_key(backend) shared_key = key.exchange(public.public_key(backend)) # check shared key shared_key = int_from_bytes(shared_key, 'big') shared_key_manual = pow(y, x, p) # y^x mod p assert shared_key == shared_key_manual