[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$api-II43X7XnidFD7Cxeaz2bQvZwmi0_GxuUqNMOzDGfTRs":3,"task-description-even-better-aes":4,"task-even-better-aes":5,"task-solution-even-better-aes":12,"MarkdownContent_FYSQX4FlAuvoIRVOHmEcwP8z61Hi954XerV1eyTxvo":13},"Jeszcze lepszy AES++","Niektóre wiadomości muszą być przesyłane w sposób bezpieczny, tak aby nikt niepowołany nie mógł ich odczytać. W tym celu stosuje się szyfrowanie.\n\nIstnieje wiele znanych szyfrów – od prostych, takich jak szyfr Cezara, po zaawansowane, jak AES.\n\nAle my stworzyliśmy własny, jeszcze lepszy algorytm szyfrowania – nazywa się **AES++**!\n\n## Użycie\n\nW załącznikach znajdziesz dwa pliki `decoder.py` i `encoder.py`, które implementują szyfrowanie AES++.\n\nMożesz ich używać w następujący sposób:\n\n```shell\n# Zaszyfruj wiadomość\npython encoder.py \u003Ctajne hasło> \u003Cwiadomość>\n\n# Odszyfruj\npython decoder.py \u003Ctajne hasło> \u003Czaszyfrowana wiadomość>\n```\n\n## Zadanie\n\nSpróbuj odszyfrować poniższą wiadomość:\n\n```\nLWyhq985w3glL3/ZIZPJ3C777etYn4yLDdh8owJM+QwJpSzPTZR95C2kBohXLZ/kC7/BKyL9pwgAAAAAFB+4Nw==\n```\n\nMoże zawiera ona coś, co Cię interesuje!\n\n\n*Uwaga: Wiadomość zawiera wyłącznie znaki z [ASCII](https://en.wikipedia.org/wiki/ASCII), czyli podstawowe symbole, litery (bez polskich znaków) oraz cyfry.*",[6,9],{"description":7,"path":8},"Program do odszyfrowania wiadomości AES++ w Python","decoder.py",{"description":10,"path":11},"Program do zaszyfrowania wiadomości AES++ w Python","encoder.py","## Opis\n\nAES++ oczywiście **nie jest bezpieczny**. Zawsze lepiej używać sprawdzonych i szeroko analizowanych algorytmów szyfrowania, takich jak AES.\n\nTeoretycznie można rozwiązać to zadanie brute-forcem. Zakładając, że hasło składa się z 8 znaków, a każdy może być jednym z 95 symboli, mamy `95^8 = 6634204312890625` możliwych kombinacji.\n\nNawet mając superkomputer sprawdzający miliard haseł na sekundę, zajęłoby to około **76 dni**. A to znacznie dłużej niż czas trwania CTF-a.\n\n## Rozwiązanie\n\nNa szczęście algorytm zawiera poważną **lukę bezpieczeństwa**. Każda część wiadomości jest szyfrowana kolejną literą hasła (czyli np. pierwszy blok – pierwszą literą, drugi – drugą itd.).\n\nDzięki temu można zgadywać hasło znak po znaku:\n1. Zgadujemy pierwszy znak hasła.\n2. Sprawdzamy, czy rozszyfrowany pierwszy blok ma sens.\n3. Jeśli tak, zgadujemy drugi znak, i tak dalej.\n\nPoniżej znajduje się przykład implementacji w Pythonie, która automatyzuje ten atak. Kod nie jest idealny, ale pokazuje zasadę działania i skutecznie łamie szyfrowanie.\n\n```python\nimport base64\nimport random\nfrom io import BytesIO\n\n\ndef decode_start(passphrase: str, code_base64: str, seed: int, n=1):\n    pass_bytes = passphrase.encode('ascii')\n    code = BytesIO(base64.b64decode(code_base64.encode('ascii')))\n\n    out = BytesIO()\n    random.seed(seed)\n\n    for i in range(n):\n        bts = code.read(8)\n        r = random.randint(0, 2 ** 8 - 1)\n        decoded_bytes = int.from_bytes(bts, 'big') // r // pass_bytes[i % len(pass_bytes)]\n        out.write(decoded_bytes.to_bytes(6, 'big'))\n\n    out.seek(0)\n    return out.read()\n\n\ndef decode_bigger(passphrase: str, code_base64: str, seed: int, n: int):\n    pass_bytes = passphrase.encode('ascii')\n    code = BytesIO(base64.b64decode(code_base64.encode('ascii')))\n\n    out = BytesIO()\n    random.seed(seed)\n\n    bts = code.read(8)\n    r = random.randint(0, 2 ** 8 - 1)\n    decoded_bytes = int.from_bytes(bts, 'big') // r // pass_bytes[0 % len(pass_bytes)]\n    out.write(decoded_bytes.to_bytes(6, 'big'))\n\n    for combination in possible_values:\n        try:\n            combined_str = ''.join(combination)\n\n            value = decode_start(passphrase + combined_str, code_base64, seed, n + 1)\n            encoded = encode_start(passphrase + combined_str, value.decode('ascii'), seed, n + 1)\n\n            if msg_bytes.startswith(encoded):\n                print(\n                    f\"{n} {bytes(b for b in value if b != 0)} Seed: {seed} Passphrase: {passphrase + combined_str}\")\n                decode_bigger(passphrase + combined_str, code_base64, seed, n + 1)\n        except:\n            pass\n    out.seek(0)\n    return out.read()\n\n\ndef encode_start(passphrase: str, msg: str, seed: int, n=1):\n    msg_bytes = BytesIO(bytes(msg, 'utf-8'))\n    pass_bytes = passphrase.encode('ascii')\n\n    out = BytesIO()\n    random.seed(seed)\n\n    for i in range(n):\n        bts = msg_bytes.read(6)\n\n        num = int.from_bytes(bts, 'big') * random.randint(0, 2 ** 8 - 1) * pass_bytes[i % len(pass_bytes)]\n\n        out.write(num.to_bytes(8, 'big'))\n\n    out.seek(0)\n    return out.read()\n\n\npossible_values = [chr(i) for i in range(32, 127)]\n\nmsg = 'LWyhq985w3glL3/ZIZPJ3C777etYn4yLDdh8owJM+QwJpSzPTZR95C2kBohXLZ/kC7/BKyL9pwgAAAAAFB+4Nw=='\nmsg_bytes = base64.b64decode(msg)\n\nprint(\"Message as bytes\", msg_bytes)\nprint(\"Amount of different characters\", len(possible_values))\n\n# Pick number relatively high to make sure we get the right seed\nfor seed in range(10000):\n    for val in possible_values:\n        try:\n            decoded = decode_start(val, msg, seed)\n\n            decoded = decoded.decode('utf-8')\n            decoded.encode('ascii')\n            encoded = encode_start(val, decoded, seed)\n\n            if msg_bytes.startswith(encoded):\n                decode_bigger(val, msg, seed, 1)\n        except:\n            pass\n```\n\nDla tego konkretnego przykładu łamanie szyfrowania zajmuje około 3 sekund – więc spokojnie zdążysz podczas CTF-a.",["Island",14],{"key":15,"params":16,"result":18},"MarkdownContent_FYSQX4FlAuvoIRVOHmEcwP8z61Hi954XerV1eyTxvo",{"props":17},"{\"text\":\"Niektóre wiadomości muszą być przesyłane w sposób bezpieczny, tak aby nikt niepowołany nie mógł ich odczytać. W tym celu stosuje się szyfrowanie.\\n\\nIstnieje wiele znanych szyfrów – od prostych, takich jak szyfr Cezara, po zaawansowane, jak AES.\\n\\nAle my stworzyliśmy własny, jeszcze lepszy algorytm szyfrowania – nazywa się **AES++**!\\n\\n## Użycie\\n\\nW załącznikach znajdziesz dwa pliki `decoder.py` i `encoder.py`, które implementują szyfrowanie AES++.\\n\\nMożesz ich używać w następujący sposób:\\n\\n```shell\\n# Zaszyfruj wiadomość\\npython encoder.py \u003Ctajne hasło> \u003Cwiadomość>\\n\\n# Odszyfruj\\npython decoder.py \u003Ctajne hasło> \u003Czaszyfrowana wiadomość>\\n```\\n\\n## Zadanie\\n\\nSpróbuj odszyfrować poniższą wiadomość:\\n\\n```\\nLWyhq985w3glL3/ZIZPJ3C777etYn4yLDdh8owJM+QwJpSzPTZR95C2kBohXLZ/kC7/BKyL9pwgAAAAAFB+4Nw==\\n```\\n\\nMoże zawiera ona coś, co Cię interesuje!\\n\\n\\n*Uwaga: Wiadomość zawiera wyłącznie znaki z [ASCII](https://en.wikipedia.org/wiki/ASCII), czyli podstawowe symbole, litery (bez polskich znaków) oraz cyfry.*\"}",{"head":19},{"style":20},[21,23],{"innerHTML":22},"@layer base {:where(.i-lucide\\:copy){display:inline-block;width:1em;height:1em;background-color:currentColor;-webkit-mask-image:var(--svg);mask-image:var(--svg);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;--svg:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E\")}:where(.i-lucide\\:hash){display:inline-block;width:1em;height:1em;background-color:currentColor;-webkit-mask-image:var(--svg);mask-image:var(--svg);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;--svg:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 9h16M4 15h16M10 3L8 21m8-18l-2 18'/%3E%3C/svg%3E\")}}",{"innerHTML":24},".shiki span.line{display:block}.shiki span.line.highlight{background-color:var(--ui-bg-accented);margin:0 -16px;padding:0 16px}@supports (color:color-mix(in lab,red,red)){.shiki span.line.highlight{background-color:color-mix(in oklab,var(--ui-bg-accented) 50%,transparent)}}"]