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 5from __future__ import absolute_import, division, print_function 6 7import binascii 8import os 9 10import pytest 11 12from cryptography.exceptions import InvalidSignature, _Reasons 13from cryptography.hazmat.primitives import serialization 14from cryptography.hazmat.primitives.asymmetric.ed448 import ( 15 Ed448PrivateKey, 16 Ed448PublicKey, 17) 18 19from ...utils import ( 20 load_nist_vectors, 21 load_vectors_from_file, 22 raises_unsupported_algorithm, 23) 24 25 26@pytest.mark.supported( 27 only_if=lambda backend: not backend.ed448_supported(), 28 skip_message="Requires OpenSSL without Ed448 support", 29) 30def test_ed448_unsupported(backend): 31 with raises_unsupported_algorithm( 32 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM 33 ): 34 Ed448PublicKey.from_public_bytes(b"0" * 57) 35 36 with raises_unsupported_algorithm( 37 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM 38 ): 39 Ed448PrivateKey.from_private_bytes(b"0" * 57) 40 41 with raises_unsupported_algorithm( 42 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM 43 ): 44 Ed448PrivateKey.generate() 45 46 47@pytest.mark.supported( 48 only_if=lambda backend: backend.ed448_supported(), 49 skip_message="Requires OpenSSL with Ed448 support", 50) 51class TestEd448Signing(object): 52 @pytest.mark.parametrize( 53 "vector", 54 load_vectors_from_file( 55 os.path.join("asymmetric", "Ed448", "rfc8032.txt"), 56 load_nist_vectors, 57 ), 58 ) 59 def test_sign_input(self, vector, backend): 60 if vector.get("context") is not None: 61 pytest.skip("ed448 contexts are not currently supported") 62 63 sk = binascii.unhexlify(vector["secret"]) 64 pk = binascii.unhexlify(vector["public"]) 65 message = binascii.unhexlify(vector["message"]) 66 signature = binascii.unhexlify(vector["signature"]) 67 private_key = Ed448PrivateKey.from_private_bytes(sk) 68 computed_sig = private_key.sign(message) 69 assert computed_sig == signature 70 public_key = private_key.public_key() 71 assert ( 72 public_key.public_bytes( 73 serialization.Encoding.Raw, serialization.PublicFormat.Raw 74 ) 75 == pk 76 ) 77 public_key.verify(signature, message) 78 79 def test_invalid_signature(self, backend): 80 key = Ed448PrivateKey.generate() 81 signature = key.sign(b"test data") 82 with pytest.raises(InvalidSignature): 83 key.public_key().verify(signature, b"wrong data") 84 85 with pytest.raises(InvalidSignature): 86 key.public_key().verify(b"0" * 64, b"test data") 87 88 def test_generate(self, backend): 89 key = Ed448PrivateKey.generate() 90 assert key 91 assert key.public_key() 92 93 @pytest.mark.parametrize( 94 "vector", 95 load_vectors_from_file( 96 os.path.join("asymmetric", "Ed448", "rfc8032.txt"), 97 load_nist_vectors, 98 ), 99 ) 100 def test_pub_priv_bytes_raw(self, vector, backend): 101 sk = binascii.unhexlify(vector["secret"]) 102 pk = binascii.unhexlify(vector["public"]) 103 private_key = Ed448PrivateKey.from_private_bytes(sk) 104 assert ( 105 private_key.private_bytes( 106 serialization.Encoding.Raw, 107 serialization.PrivateFormat.Raw, 108 serialization.NoEncryption(), 109 ) 110 == sk 111 ) 112 assert ( 113 private_key.public_key().public_bytes( 114 serialization.Encoding.Raw, serialization.PublicFormat.Raw 115 ) 116 == pk 117 ) 118 public_key = Ed448PublicKey.from_public_bytes(pk) 119 assert ( 120 public_key.public_bytes( 121 serialization.Encoding.Raw, serialization.PublicFormat.Raw 122 ) 123 == pk 124 ) 125 126 @pytest.mark.parametrize( 127 ("encoding", "fmt", "encryption", "passwd", "load_func"), 128 [ 129 ( 130 serialization.Encoding.PEM, 131 serialization.PrivateFormat.PKCS8, 132 serialization.BestAvailableEncryption(b"password"), 133 b"password", 134 serialization.load_pem_private_key, 135 ), 136 ( 137 serialization.Encoding.DER, 138 serialization.PrivateFormat.PKCS8, 139 serialization.BestAvailableEncryption(b"password"), 140 b"password", 141 serialization.load_der_private_key, 142 ), 143 ( 144 serialization.Encoding.PEM, 145 serialization.PrivateFormat.PKCS8, 146 serialization.NoEncryption(), 147 None, 148 serialization.load_pem_private_key, 149 ), 150 ( 151 serialization.Encoding.DER, 152 serialization.PrivateFormat.PKCS8, 153 serialization.NoEncryption(), 154 None, 155 serialization.load_der_private_key, 156 ), 157 ], 158 ) 159 def test_round_trip_private_serialization( 160 self, encoding, fmt, encryption, passwd, load_func, backend 161 ): 162 key = Ed448PrivateKey.generate() 163 serialized = key.private_bytes(encoding, fmt, encryption) 164 loaded_key = load_func(serialized, passwd, backend) 165 assert isinstance(loaded_key, Ed448PrivateKey) 166 167 def test_invalid_type_public_bytes(self, backend): 168 with pytest.raises(TypeError): 169 Ed448PublicKey.from_public_bytes(object()) 170 171 def test_invalid_type_private_bytes(self, backend): 172 with pytest.raises(TypeError): 173 Ed448PrivateKey.from_private_bytes(object()) 174 175 def test_invalid_length_from_public_bytes(self, backend): 176 with pytest.raises(ValueError): 177 Ed448PublicKey.from_public_bytes(b"a" * 56) 178 with pytest.raises(ValueError): 179 Ed448PublicKey.from_public_bytes(b"a" * 58) 180 181 def test_invalid_length_from_private_bytes(self, backend): 182 with pytest.raises(ValueError): 183 Ed448PrivateKey.from_private_bytes(b"a" * 56) 184 with pytest.raises(ValueError): 185 Ed448PrivateKey.from_private_bytes(b"a" * 58) 186 187 def test_invalid_private_bytes(self, backend): 188 key = Ed448PrivateKey.generate() 189 with pytest.raises(ValueError): 190 key.private_bytes( 191 serialization.Encoding.Raw, 192 serialization.PrivateFormat.Raw, 193 None, 194 ) 195 196 with pytest.raises(ValueError): 197 key.private_bytes( 198 serialization.Encoding.Raw, 199 serialization.PrivateFormat.PKCS8, 200 None, 201 ) 202 203 with pytest.raises(ValueError): 204 key.private_bytes( 205 serialization.Encoding.PEM, 206 serialization.PrivateFormat.Raw, 207 serialization.NoEncryption(), 208 ) 209 210 def test_invalid_public_bytes(self, backend): 211 key = Ed448PrivateKey.generate().public_key() 212 with pytest.raises(ValueError): 213 key.public_bytes( 214 serialization.Encoding.Raw, 215 serialization.PublicFormat.SubjectPublicKeyInfo, 216 ) 217 218 with pytest.raises(ValueError): 219 key.public_bytes( 220 serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 221 ) 222 223 with pytest.raises(ValueError): 224 key.public_bytes( 225 serialization.Encoding.PEM, serialization.PublicFormat.Raw 226 ) 227 228 def test_buffer_protocol(self, backend): 229 private_bytes = os.urandom(57) 230 key = Ed448PrivateKey.from_private_bytes(bytearray(private_bytes)) 231 assert ( 232 key.private_bytes( 233 serialization.Encoding.Raw, 234 serialization.PrivateFormat.Raw, 235 serialization.NoEncryption(), 236 ) 237 == private_bytes 238 ) 239 240 def test_malleability(self, backend): 241 # This is a signature where r > the group order. It should be 242 # rejected to prevent signature malleability issues. This test can 243 # be removed when wycheproof grows ed448 vectors 244 public_bytes = binascii.unhexlify( 245 "fedb02a658d74990244d9d10cf338e977565cbbda6b24c716829ed6ee1e4f28cf" 246 "2620c052db8d878f6243bffc22242816c1aaa67d2f3603600" 247 ) 248 signature = binascii.unhexlify( 249 "0cc16ba24d69277f927c1554b0f08a2a711bbdd20b058ccc660d00ca13542a3ce" 250 "f9e5c44c54ab23a2eb14f947e167b990b080863e28b399380f30db6e54d5d1406" 251 "d23378ffde11b1fb81b2b438a3b8e8aa7f7f4e1befcc905023fab5a5465053844" 252 "f04cf0c1b51d84760f869588687f57500" 253 ) 254 key = Ed448PublicKey.from_public_bytes(public_bytes) 255 with pytest.raises(InvalidSignature): 256 key.verify(signature, b"8") 257