|
14 | 14 |
|
15 | 15 | Reference: https://github.com/gungunfebrianza/Mastering-Cryptography/blob/master/ATOM-128/ATOM-128.js |
16 | 16 | """ |
17 | | -import re |
18 | | -from base64 import b64decode, b64encode |
19 | | -from binascii import Error as B64Error |
20 | | -from string import ascii_letters, ascii_lowercase as LC, ascii_uppercase as UC, digits |
21 | | - |
22 | | -from ..__common__ import * |
| 17 | +from ._jsbase64 import js_base64 |
| 18 | +from ..__common__ import add |
23 | 19 |
|
24 | 20 |
|
25 | 21 | __examples__ = { |
|
30 | 26 | __guess__ = ["atom128"] |
31 | 27 |
|
32 | 28 |
|
33 | | -B64 = UC + LC + digits + "+/=" |
34 | | -ATOM128 = "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC" |
35 | | -# characters left as is by JavaScript's escape() |
36 | | -_SAFE = set(ascii_letters + digits + "@*_+-./") |
37 | | - |
38 | | - |
39 | | -def js_escape(text): |
40 | | - """ Escape a string like JavaScript's escape() (characters beyond the BMP being escaped as surrogate pairs). """ |
41 | | - r = "" |
42 | | - for c in text: |
43 | | - if c in _SAFE: |
44 | | - r += c |
45 | | - elif ord(c) < 256: |
46 | | - r += f"%{ord(c):02X}" |
47 | | - else: |
48 | | - u = c.encode("utf-16-be", "surrogatepass") |
49 | | - r += "".join(f"%u{u[i:i+2].hex().upper()}" for i in range(0, len(u), 2)) |
50 | | - return r |
51 | | - |
52 | | - |
53 | | -def js_unescape(text): |
54 | | - """ Unescape a string like JavaScript's unescape() (surrogate pairs being joined). """ |
55 | | - s = re.sub(r"%u([0-9a-fA-F]{4})|%([0-9a-fA-F]{2})", lambda m: chr(int(m.group(1) or m.group(2), 16)), text) |
56 | | - return s.encode("utf-16-be", "surrogatepass").decode("utf-16-be", "replace") |
57 | | - |
58 | | - |
59 | | -def atom128_encode(text, errors="strict"): |
60 | | - r = b64encode(js_escape(ensure_str(text)).encode()).decode() |
61 | | - return r.translate(str.maketrans(B64, ATOM128)), len(text) |
62 | | - |
63 | | - |
64 | | -def atom128_decode(text, errors="strict"): |
65 | | - _h, t, r = handle_error("atom128", errors, decode=True), re.sub(r"\s", "", ensure_str(text)), "" |
66 | | - for i, c in enumerate(t): |
67 | | - if c in ATOM128: |
68 | | - r += B64[ATOM128.index(c)] |
69 | | - else: |
70 | | - # invalid characters are dropped (as the original JavaScript does) when not in strict mode |
71 | | - _h(c, i) |
72 | | - try: |
73 | | - r = b64decode(r, validate=True) |
74 | | - except B64Error: |
75 | | - if errors == "strict": |
76 | | - raise Atom128DecodeError("'atom128' codec can't decode: incorrect padding") # noqa: F821 |
77 | | - # otherwise, the padding is fixed, dropping an incomplete last character |
78 | | - r = r.replace("=", "") |
79 | | - r = r[:len(r) - (len(r) % 4 == 1)] |
80 | | - r = b64decode(r + "=" * (-len(r) % 4)) |
81 | | - return js_unescape(r.decode("latin-1")), len(text) |
82 | | - |
83 | | - |
84 | | -add("atom128", atom128_encode, atom128_decode, r"^atom[-_]?128$", printables_rate=1., expansion_factor=(1.6, .3)) |
| 29 | +add("atom128", *js_base64("atom128", "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC"), |
| 30 | + r"^atom[-_]?128$", printables_rate=1., expansion_factor=(1.6, .3)) |
0 commit comments