A Python port of the Invisible Internet Project (I2P)
1"""Convert various I2P address formats to a 32-byte hash.
2
3Ported from net.i2p.util.ConvertToHash.
4"""
5
6from __future__ import annotations
7
8import base64
9
10
11def convert_to_hash(input_str: str) -> bytes | None:
12 """Convert a Base64 hash, .b32.i2p address, or full destination to a 32-byte hash.
13
14 Returns None if the input is not a recognized format.
15 """
16 if not input_str:
17 return None
18
19 # 43 or 44-char Base64 → raw 32-byte hash
20 # I2P uses modified Base64: -~ instead of +/
21 # 32 bytes = 43 Base64 chars + 1 padding, or 44 chars if padding included
22 if len(input_str) in (43, 44) and not input_str.endswith(".i2p"):
23 try:
24 std = input_str.replace("-", "+").replace("~", "/")
25 # Pad to multiple of 4
26 pad = (4 - len(std) % 4) % 4
27 decoded = base64.b64decode(std + "=" * pad)
28 if len(decoded) == 32:
29 return decoded
30 except Exception:
31 pass
32 return None
33
34 # 52-char-prefix.b32.i2p → Base32 decode to 32 bytes
35 if input_str.endswith(".b32.i2p"):
36 b32_part = input_str[: -len(".b32.i2p")]
37 if len(b32_part) == 52:
38 try:
39 decoded = base64.b32decode(b32_part.upper() + "====")
40 if len(decoded) == 32:
41 return decoded
42 except Exception:
43 pass
44 return None
45
46 return None