A Python port of the Invisible Internet Project (I2P)
at main 177 lines 6.8 kB view raw
1"""Tests for RouterIdentity, RouterAddress, RouterInfo.""" 2 3import os 4import struct 5 6 7class TestRouterAddress: 8 def test_construct(self): 9 from i2p_data.router import RouterAddress 10 addr = RouterAddress(10, 0, "NTCP2", {"host": "1.2.3.4", "port": "15555"}) 11 assert addr.cost == 10 12 assert addr.expiration == 0 13 assert addr.transport == "NTCP2" 14 assert addr.get_host() == "1.2.3.4" 15 assert addr.get_port() == 15555 16 17 def test_roundtrip(self): 18 from i2p_data.router import RouterAddress 19 addr = RouterAddress(5, 0, "SSU2", {"host": "::1", "port": "9999", "key": "abc123"}) 20 data = addr.to_bytes() 21 addr2, consumed = RouterAddress.from_bytes(data) 22 assert consumed == len(data) 23 assert addr2.cost == 5 24 assert addr2.transport == "SSU2" 25 assert addr2.get_host() == "::1" 26 assert addr2.get_port() == 9999 27 assert addr2.options["key"] == "abc123" 28 29 def test_no_options(self): 30 from i2p_data.router import RouterAddress 31 addr = RouterAddress(20, 0, "NTCP2") 32 data = addr.to_bytes() 33 addr2, _ = RouterAddress.from_bytes(data) 34 assert addr2.transport == "NTCP2" 35 assert addr2.options == {} 36 assert addr2.get_host() is None 37 assert addr2.get_port() is None 38 39 def test_equality(self): 40 from i2p_data.router import RouterAddress 41 a1 = RouterAddress(10, 0, "NTCP2", {"host": "1.2.3.4"}) 42 a2 = RouterAddress(10, 0, "NTCP2", {"host": "1.2.3.4"}) 43 a3 = RouterAddress(20, 0, "NTCP2", {"host": "1.2.3.4"}) 44 assert a1 == a2 45 assert a1 != a3 46 47 def test_multiple_addresses_roundtrip(self): 48 from i2p_data.router import RouterAddress 49 import io 50 addrs = [ 51 RouterAddress(5, 0, "NTCP2", {"host": "10.0.0.1", "port": "443"}), 52 RouterAddress(10, 0, "SSU2", {"host": "10.0.0.1", "port": "9999"}), 53 ] 54 buf = io.BytesIO() 55 for a in addrs: 56 buf.write(a.to_bytes()) 57 58 buf.seek(0) 59 recovered = [] 60 for _ in range(2): 61 a, _ = RouterAddress.from_stream(buf) 62 recovered.append(a) 63 64 assert recovered[0].transport == "NTCP2" 65 assert recovered[1].transport == "SSU2" 66 67 68class TestRouterIdentity: 69 def _make_router_identity(self): 70 from i2p_data.router import RouterIdentity 71 from i2p_data.key_types import PublicKey, SigningPublicKey, EncType 72 from i2p_data.certificate import Certificate 73 from i2p_crypto.dsa import SigType 74 75 pub = PublicKey(os.urandom(256), EncType.ELGAMAL) 76 sig = SigningPublicKey(os.urandom(128), SigType.DSA_SHA1) 77 cert = Certificate.NULL 78 return RouterIdentity(pub, sig, cert) 79 80 def test_construct(self): 81 from i2p_data.keys_and_cert import KeysAndCert 82 ri = self._make_router_identity() 83 assert isinstance(ri, KeysAndCert) 84 assert len(ri.to_bytes()) == 387 85 86 def test_roundtrip(self): 87 from i2p_data.router import RouterIdentity 88 ri = self._make_router_identity() 89 data = ri.to_bytes() 90 ri2 = RouterIdentity.from_bytes(data) 91 assert ri2.to_bytes() == data 92 assert ri2.public_key == ri.public_key 93 94 95class TestRouterInfo: 96 def _make_signed_router_info(self): 97 """Create a RouterInfo with real EdDSA signature.""" 98 from i2p_data.router import RouterIdentity, RouterAddress, RouterInfo 99 from i2p_data.key_types import PublicKey, SigningPublicKey, EncType 100 from i2p_data.certificate import KeyCertificate 101 from i2p_crypto.dsa import SigType, KeyGenerator 102 103 # Generate EdDSA keypair 104 pub_sig, priv_sig = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519) 105 106 # Create identity with KEY cert 107 pub_enc = PublicKey(os.urandom(32), EncType.ECIES_X25519) 108 sig_key = SigningPublicKey(pub_sig, SigType.EdDSA_SHA512_Ed25519) 109 cert = KeyCertificate(struct.pack("!HH", 7, 4)) # EdDSA + X25519 110 identity = RouterIdentity(pub_enc, sig_key, cert) 111 112 addresses = [ 113 RouterAddress(10, 0, "NTCP2", {"host": "192.168.1.1", "port": "15555"}), 114 ] 115 options = {"router.version": "0.9.62", "caps": "XfR"} 116 117 info = RouterInfo(identity, 1710000000000, addresses, options) 118 info.sign(priv_sig) 119 return info, priv_sig 120 121 def test_sign_and_verify(self): 122 info, _ = self._make_signed_router_info() 123 assert info.verify() 124 125 def test_verify_fails_with_modified_data(self): 126 from i2p_data.router import RouterInfo 127 info, _ = self._make_signed_router_info() 128 # Modify options after signing 129 data = info.to_bytes() 130 # Tamper with a byte in the middle 131 tampered = bytearray(data) 132 tampered[200] ^= 0xFF 133 info2 = RouterInfo.from_bytes(bytes(tampered)) 134 assert not info2.verify() 135 136 def test_roundtrip(self): 137 from i2p_data.router import RouterInfo 138 info, _ = self._make_signed_router_info() 139 data = info.to_bytes() 140 info2 = RouterInfo.from_bytes(data) 141 assert info2.identity.to_bytes() == info.identity.to_bytes() 142 assert info2.published == info.published 143 assert len(info2.addresses) == 1 144 assert info2.addresses[0].get_host() == "192.168.1.1" 145 assert info2.options["router.version"] == "0.9.62" 146 assert info2.verify() 147 148 def test_no_addresses(self): 149 from i2p_data.router import RouterIdentity, RouterInfo 150 from i2p_data.key_types import PublicKey, SigningPublicKey, EncType 151 from i2p_data.certificate import KeyCertificate 152 from i2p_crypto.dsa import SigType, KeyGenerator 153 154 pub_sig, priv_sig = KeyGenerator.generate(SigType.EdDSA_SHA512_Ed25519) 155 identity = RouterIdentity( 156 PublicKey(os.urandom(32), EncType.ECIES_X25519), 157 SigningPublicKey(pub_sig, SigType.EdDSA_SHA512_Ed25519), 158 KeyCertificate(struct.pack("!HH", 7, 4)) 159 ) 160 info = RouterInfo(identity, 1710000000000) 161 info.sign(priv_sig) 162 assert info.verify() 163 assert len(info.addresses) == 0 164 165 def test_unsigned_verify_fails(self): 166 from i2p_data.router import RouterIdentity, RouterInfo 167 from i2p_data.key_types import PublicKey, SigningPublicKey, EncType 168 from i2p_data.certificate import Certificate 169 from i2p_crypto.dsa import SigType 170 171 identity = RouterIdentity( 172 PublicKey(os.urandom(256), EncType.ELGAMAL), 173 SigningPublicKey(os.urandom(128), SigType.DSA_SHA1), 174 Certificate.NULL 175 ) 176 info = RouterInfo(identity, 1710000000000) 177 assert not info.verify()