|
| 1 | +# -*- coding: UTF-8 -*- |
| 2 | +"""ARABICA-2RS Codec - ARABICA-2RS content encryption. |
| 3 | +
|
| 4 | +ARABICA-2RS is a toy cipher found on online JavaScript encryption tools. The text is encoded like JavaScript's |
| 5 | + encodeURIComponent() does, then each of its characters (written as 5 digits in base 3 by the original JavaScript) is |
| 6 | + substituted by an Arabic letter (or a similar character), the ciphertext ending with "ش". The original JavaScript |
| 7 | + reverses the text before and after the substitution (which cancel each other) and inserts random spaces, which are |
| 8 | + ignored when decoding ; this codec gives a ciphertext without spaces, and encodes a text holding "ش" (that the |
| 9 | + original JavaScript leaves as is). When decoding, the left-to-right marks around "ݣ" (easily lost) are optional. |
| 10 | +
|
| 11 | +This codec: |
| 12 | +- en/decodes strings from str to str |
| 13 | +- en/decodes strings from bytes to bytes |
| 14 | +- decodes file content to str (read) |
| 15 | +- encodes file content from str to bytes (write) |
| 16 | +
|
| 17 | +Reference: https://github.com/gungunfebrianza/Mastering-Cryptography/blob/master/ARABICA2RS/arabperkasaahaha.js |
| 18 | +""" |
| 19 | +import re |
| 20 | + |
| 21 | +from ._jsuri import substitution |
| 22 | +from ..__common__ import * |
| 23 | + |
| 24 | + |
| 25 | +__examples__ = { |
| 26 | + 'enc(arabica-2rs|arabica2rs|arabica_2rs)': { |
| 27 | + 'test': '\u062d\u0628\u0637\u062d\u0634', |
| 28 | + 'Hello, World!': |
| 29 | + '\u06f1\u0628\u0639\u0639\u0645\ufebf\u0623\u06cc\ufebf\u0623\ufeb9\ufe9b\u0645\u064a\u0639\u062e\ufb90' |
| 30 | + '\u0634', |
| 31 | + '5': '\u200e\u0763\u200e\u0634', |
| 32 | + '': '', |
| 33 | + }, |
| 34 | + 'dec(arabica-2rs)': { |
| 35 | + '\u062d\u0628\u0637\u062d\u0634': 'test', |
| 36 | + '\u06f1\u0628 \u0639 \u0639\u0645 \ufebf\u0623 \u06cc\ufebf\u0623 \ufeb9 \ufe9b\u0645\u064a\u0639\u062e\ufb90' |
| 37 | + '\u0634': |
| 38 | + 'Hello, World!', |
| 39 | + '\u0763\u0634': '5', |
| 40 | + '\u062d\u0628X\u0634': None, |
| 41 | + '\ufebf\u0634': None, |
| 42 | + }, |
| 43 | + 'enc-dec(arabica-2rs)': ['', 'test', 'Hello, World!', 'caf\xe9 \u20ac \U0001f600 \u0634', "0123456789-_.!~*'()%"], |
| 44 | +} |
| 45 | +__guess__ = ["arabica-2rs"] |
| 46 | + |
| 47 | + |
| 48 | +# substitutes of the characters of the URI-encoded text, given by their codes in base 3 (as in the original JavaScript) |
| 49 | +ARABICA = [ |
| 50 | + ("10121", "غ"), ("10122", "ظ"), ("10200", "ذ"), ("10201", "خ"), ("10202", "ب"), ("10210", "ت"), |
| 51 | + ("10211", "س"), ("10212", "ر"), ("10220", "ق"), ("10221", "ض"), ("10222", "ف"), ("11000", "ع"), |
| 52 | + ("11001", "ص"), ("11002", "ن"), ("11010", "م"), ("11011", "ل"), ("11012", "ك"), ("11020", "ي"), |
| 53 | + ("11021", "ط"), ("11022", "ح"), ("11100", "ز"), ("11101", "و"), ("11102", "ه"), ("11110", "د"), |
| 54 | + ("11111", "ج"), ("11112", "ﺵ"), ("01210", "ﺹ"), ("01211", "ﻃ"), ("01212", "أ"), ("01220", "ا"), |
| 55 | + ("01221", "ـ"), ("01222", "\u200eݣ\u200e"), ("02000", "چ"), ("02001", "گ"), ("02002", "آ"), ("02010", "ة"), |
| 56 | + ("02102", "ى"), ("02110", "ک"), ("02111", "ی"), ("02112", "پ"), ("02120", "۴"), ("02121", "۸"), |
| 57 | + ("02122", "۶"), ("02200", "۱"), ("02201", "ﭻ"), ("02202", "ئ"), ("02210", "ە"), ("02211", "ﻼ"), |
| 58 | + ("02212", "ﻻ"), ("02220", "\u0651"), ("02221", "\u0650"), ("02222", "ژ"), ("10000", "ڨ"), ("10001", "ڜ"), |
| 59 | + ("10002", "ﷲ"), ("10010", "ﺑ"), ("10011", "ﭘ"), ("10012", "ﺗ"), ("10020", "ﺛ"), ("10021", "ﺟ"), |
| 60 | + ("10022", "ﺣ"), ("10100", "ﺡ"), ("01101", "ﺿ"), ("01111", "ﻏ"), ("01112", "ﻓ"), ("01200", "ﻑ"), |
| 61 | + ("01120", "ﻕ"), ("01020", "ﮐ"), ("10112", "ﻝ"), ("01201", "ﻡ"), ("01110", "ﻥ"), ("11200", "ﻳ"), |
| 62 | +] |
| 63 | +_TABLE = {chr(int(code, 3)): s for code, s in ARABICA} |
| 64 | +_encode, _decode = substitution("arabica-2rs", _TABLE, {s.strip("\u200e"): c for c, s in _TABLE.items()}) |
| 65 | + |
| 66 | + |
| 67 | +def arabica_encode(text, errors="strict"): |
| 68 | + t = ensure_str(text) |
| 69 | + return "".join(_encode(t)) + "\u0634" if t else "", len(text) |
| 70 | + |
| 71 | + |
| 72 | +def arabica_decode(text, errors="strict"): |
| 73 | + t = re.sub(r"[\s\u200e]+", "", ensure_str(text)).replace("\u0634", "") |
| 74 | + return _decode(t, errors), len(text) |
| 75 | + |
| 76 | + |
| 77 | +add("arabica-2rs", arabica_encode, arabica_decode, r"^arabica[-_]?2rs$", examples=__examples__, guess=__guess__) |
0 commit comments