Gambaran
Tujuan Anda adalah mengimplementasikan enkripsi RC4. Enkripsi RC4, ditemukan oleh Ron Rivest (dari ketenaran RSA), dirancang untuk aman, namun cukup sederhana untuk diimplementasikan dari memori oleh tentara militer di medan perang. Saat ini, ada beberapa serangan pada RC4, tetapi masih digunakan di banyak tempat saat ini.
Program Anda harus menerima string tunggal dengan kunci dan beberapa data. Ini akan disajikan dalam format ini.
\x0Dthis is a keythis is some data to encrypt
Byte pertama menunjukkan berapa lama kuncinya. Dapat diasumsikan kunci tidak lebih dari 255 byte, dan tidak lebih pendek dari 1 byte. Data bisa panjang sewenang-wenang.
Program Anda harus memproses kunci, lalu mengembalikan data yang dienkripsi. Enkripsi dan dekripsi RC4 identik, jadi menggunakan kunci yang sama untuk "mengenkripsi" ciphertext harus mengembalikan plaintext asli.
Bagaimana RC4 Bekerja
Inisialisasi
Inisialisasi RC4 cukup sederhana. Status array 256 byte diinisialisasi ke semua byte dari 0 hingga 255.
S = [0, 1, 2, 3, ..., 253, 254, 255]
Pemrosesan kunci
Nilai-nilai di negara bagian ditukar berdasarkan kunci.
j = 0
for i from 0 to 255
j = (j + S[i] + key[i mod keylength]) mod 256
swap S[i] and S[j]
Enkripsi
Enkripsi dilakukan dengan menggunakan negara untuk menghasilkan byte pseudo-acak, yang kemudian XOR'd ke data. Nilai-nilai di negara bagian terus-menerus ditukar.
i = j = 0
for each byte B in data
i = (i + 1) mod 256
j = (j + S[i]) mod 256
swap S[i] and S[j]
K = S[(S[i] + S[j]) mod 256]
output K XOR B
Input dan output yang diharapkan
Karakter yang tidak dapat dicetak akan ditampilkan dalam \xAB
format.
Input: \x01\x00\x00\x00\x00\x00\x00
Output: \xde\x18\x89A\xa3
Output (hex):de188941a3
Input: \x0Dthis is a keythis is some data to encrypt
Output: \xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Output (hex):b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Input: \x0dthis is a key\xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Input (hex): 0d746869732069732061206b6579b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Output:this is some data to encrypt
Input: Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted
Output: \x96\x1f,\x8f\xa3%\x9b\xa3f[mk\xdf\xbc\xac\x8b\x8e\xfa\xfe\x96B=!\xfc;\x13`c\x16q\x04\x11\xd8\x86\xee\x07
Output (hex):961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07
sumber
\xde
, maka panjangnya harus 1 byte, dan mengonversinya menjadi angka (melalui pythonord()
atau javascript.charCodeAt(0)
) harus mengembalikan 222 (0xDE).Jawaban:
JavaScript (ES6),
169168 byteMengambil input sebagai array byte. Mengembalikan array byte lainnya.
Bagaimana?
Ini pada dasarnya adalah implementasi spesifikasi secara literal.
Kami pertama-tama membagi array input menjadi l (panjang kunci) dan s (data payload: kunci + pesan). Kemudian, dalam urutan eksekusi:
Kami menginisialisasi array status S dan mendefinisikan m = 255 yang berulang kali digunakan kemudian sebagai bit mask.
Kami mengocok susunan status. Indeks I dan J yang diinisialisasi di sini sebenarnya digunakan pada langkah berikutnya.
Kami menerapkan enkripsi.
Uji kasus
Tampilkan cuplikan kode
sumber
138 byte, kode mesin (16-bit x86)
Berjalan: simpan ke codegolf.com, dosbox:
codegolf.com < input.bin
Saya tidak tahu apakah ini akan dihitung sebagai entri, tetapi saya telah memutuskan untuk melakukannya secara manual menggunakan hex editor. Tidak ada kompiler yang digunakan untuk melakukan ini.
Editor ht sebenarnya memiliki assembler, tetapi jujur saya tidak tahu tentang ini sampai saya selesai ¯ \ _ (ツ) _ / ¯
Mengapa bagaimana
Mengapa: kebanyakan karena saya ingin memeriksa apakah saya dapat melakukan ini.
Bagaimana: Saya sudah mulai dengan membuat byte yang diisi dengan
NOP
s dan mengikuti dengan bagian yang sederhana: mencoba menulis loop pertama yang mengisiS
nilai 0..255. Saya beralih ke python dan dengan cepat menulis versi python, hanya untuk menguji sesuatu. Selanjutnya saya menyederhanakan kode python menjadi pseudo code / pseudo assembly. Kemudian saya mencoba menulis potongan-potongan kecil. Saya memutuskan akan lebih mudah untuk membaca dari stdin, jadi saya mulai dengan sesuatu yang kecil yang akan membaca satu byte, kemudian saya menambahkan pembacaan kata sandi dan inisialisasi kunci. Mencari tahu register apa yang perlu diambil, butuh waktu.Meskipun saya menambahkan de / enkripsi loop akan mudah, tetapi pertama-tama saya benar-benar mendapat decode byte tunggal dan menambahkan seluruh loop setelahnya.
Langkah terakhir adalah menyingkirkan tambahan
nops
yang saya tinggalkan di antara instruksi ketika menulisnya (ofc yang juga perlu memperbaiki lompatan).Anda dapat melihat galeri kecil yang saya coba buat sambil mengalami kemajuan di sini .
Pembedahan
Program ini bergantung pada beberapa nilai awal setelah startup (lihat sumber di bawah).
isi Negara (pada 0x200)
panjang baca, baca kata sandi, simpan kata sandi di ds: 0x300
menginisialisasi Negara dengan kunci (
BP
digunakan untuk melintasi kunci,SI
digunakan untuk melintasi Negara)menghasilkan nilai acak semu (dalam
DL
,DH
adalah 0 thx ke xor pada 0x140)SI
- ints tidak akan menyentuhnya,BX
)DX
)PS Ini mungkin bisa lebih pendek, tapi ini butuh 4 malam, jadi tidak yakin apakah saya ingin menghabiskan yang lain ...
Alat dan sumber daya
sumber
C (gcc) ,
193 188 182 178 171172 byteCobalah online!
Sunting: Sekarang berfungsi dengan kunci yang lebih panjang dari 127 byte.
Sunting2: Menambahkan testcase dengan kunci 129 byte ke tautan TIO.
Versi sedikit kurang golf
sumber
Kumpulan instruksi CPU x86, 133 byte
A7D-9F8 = 85j = 133 byte tetapi saya tidak tahu apakah perhitungannya ok karena jumlah byte sebelumnya dari fungsi yang sama menghasilkan 130 byte ... Argumen pertama dari fungsi yang saya beri nama "cript" adalah string, argumeni kedua adalah panjang string (byte pertama + panjang kunci + panjang pesan). Di bawah ini ada file bahasa assembly untuk mendapatkan rutinitas yang tidak jelas:
di bawah file C untuk hasil pemeriksaan:
hasil:
sumber
JavaScript (ES6), 262 byte
Saya mempertimbangkan hanya menggunakan fungsi berantai, tetapi memilih untuk menambahkan algoritma yang diberikan di sini: https://gist.github.com/farhadi/2185197 .
Kurang Golf
Tampilkan cuplikan kode
sumber
Python 2 , 203 byte
Cobalah online!
f
adalah generator (iterable) dari string.Tidak Disatukan:
sumber
Ruby, 234 byte
Belum dicoba.
sumber
C, 181 byte
terima kasih kepada ceilingcat untuk beberapa byte lebih sedikit:
f (a, n) dalam "a" akan ada array karakter 1Byte len + key + message; di n ada ukuran semua array "a" tidak termasuk yang terakhir '\ 0'. kode untuk pengujian dan hasil akan seperti yang digunakan untuk fungsi perakitan.
sumber
APL (NARS), 329 karakter, 658 byte
seperti biasa pemeriksaan kesalahan akan diminta ke orang lain ... Ini tampaknya ok pada input dan output, tes:
Ya semua dapat dikurangi ... tetapi misalnya membuat lebih sedikit fungsi xor bisa berarti membuatnya kurang umum ...
sumber
Karat 348
Ini sangat besar, saya berharap mungkin seseorang dapat memberikan beberapa saran.
ungolfed: di play.rust-lang.org playground
sumber
k
bukannyakey
danm
bukannyamsg
danfoo&255
bukannya(foo)%256