Код Гольф: Шифрование XOR
От: Шифрование Ко
To: x $ * sj4 (это ты)
Ваша миссия, если вы решите принять ее, - создать программу с минимальным количеством нажатий клавиш,
Принимает два имени файла параметров (либо командной строки или стандартного ввода), первый файл, содержащий ключ, а второй некоторые сообщения. Оба файла будут в текстовом формате.
Применяет ключ к сообщению с использованием шифрования XOR, перезаписывая файл.
Пример:
Входной файл:
Stackru это круто
Ключ:
Код Гольф
Шестнадцатеричный дамп зашифрованного выходного файла:
0000000: 101b 0506 4b08 1909 1425 030b 1200 2e1c ....K....%......
0000010: 4c25 2c00 080d 0a L%,....
Для простоты предположим, что файлы могут поместиться в памяти
Это сообщение будет самошифроваться через 5... 4... 3... 2... 1...
#####
#### _\_ ________
##=-[.].]| \ \
#( _\ | |------|
# __| | ||||||||
\ _/ | ||||||||
.--'--'-. | | ____ |
/ __ `|__|[o__o]|
_(____nm_______ /____\____
Шифрование XOR невозможно взломать, если размер ключа больше или равен размеру сообщения и ключ генерируется непредвзятым случайным процессом. Смотрите: Одноразовый блокнот. Так что никакого "плохого шифрования" здесь нет.
23 ответа
Покайтесь, 13 7 символов (без поддержки файлов), 14 символов (с поддержкой файлов)
Repent - мой собственный эзотерический игрушечный язык, основанный на стеке, вдохновленный J, APL, Golfscript и Python. Вот краткое решение. Я объясню это, но уже очень поздно, и это очень волнует меня, поэтому я объясню это и выпущу переводчика Silverlight утром.
↓↷¦*⊕;€
Объяснение:
↓ Copies the message string back onto the stack
↷ Puts the extra message string to the bottom of stack
¦ Find length of message string
* Multiply key array by last number - repeats key for at least as long as message
⊕; Apply XOR between each element corresponding of message array and repeated
key array, pushing XOR encoded message to stack
€ Print encoded message string/(char array) as string.
Используйте как:
Repent "↓↷¦*⊕;€" "Code Golf" "Stackru is Cool" > output.txt
Вывод (большинство символов не отображаются):
Ascii: K % .L%,
Hex: 10 1B 05 06 4B 08 19 09 14 25 03 0B 12 00 2E 1C 4C 25 2C 00 08 0D 0A
Используя файлы это:
↓↶▲⇄▲↓3↔⇄¦*⊕;▼
Perl, 40 символов
Это немного хрупко.
print$/=!1,($_=<>)^substr<>x 1E4,0,y///c
Perl имеет встроенный оператор xor строки. Чтобы решить эту проблему, сложная часть состоит в том, чтобы две строки имели одинаковую длину.
$/=!1
Устанавливает "разделитель записей" на неопределенное значение и не приводит к печати чего-либо. С этим параметром оператор чтения строки файла будет хлестать весь файл.
$_=<>
Загружает весь первый файл (содержащий сообщение) в переменную $_
,
substr <> x 1E4, 0, y///c
Создает другую строку из второго файла (ключ) и добавляет ее к себе 10000 раз. Надеемся, что (1) эта действительно длинная строка будет длиннее строки сообщения, и (2) она не будет такой длинной, что приведет к нехватке памяти в программе (вот почему это решение хрупкое). y///c
это операция для подсчета количества символов в $_
и это на один символ короче, чем сказать length
, Это сокращает строку ключа до того же размера, что и строка сообщения.
Символы C# 190
using System.IO;class a{static void Main(string[] b){var c=File.ReadAllBytes(b[0]);var d=File.ReadAllBytes(b[1]);for(int e=0;e<c.Length;e++) c[e]^=d[e%d.Length];File.WriteAllBytes(b[0],c);}}
Python, 162 символа
m,r,o=map,raw_input,open
a,b=r(),r()
t,k=m(lambda x:list(o(x).read()[:-1]),[a,b])
o(a,'w').write(''.join(m(chr,m(lambda c:ord(c[0])^ord(c[1]),zip(t,len(t)*k)))))
Python 3, 143 символа
i,o=input,open
a,b=i(),i()
t,k=map(lambda x:list(o(x,'rb').read()[:-1]),[a,b])
o(a,'wb').write(bytes(map(lambda c:c[0]^c[1],zip(t,len(t)*k))))
GolfScript, 28 символов
n.+/~:k;.,.)k.,@\/)*<{\(@^}%
Чтобы использовать, передайте файл сообщения, затем новую строку и файл ключа в стандартный ввод скрипта:
$ (cat message-file ; echo ; cat key-file) | ruby golfscript.rb poorencrypt.gs
$ (echo Stackru - Круто;echo;echo Code Golf) | \ ruby golfscript.rb poorencrypt.gs > кодированный файл $ (кодированный файл cat;echo;echo Code Golf) | ruby golfscript.rb poorencrypt.gs Stackru это круто
Ява, 319 313 310 символов
Обновление 1: заменено
char[]c=r(a[0]);char[]k=r(a[1]);
отchar[]c=r(a[0]),k=r(a[1]);
, сохранил 6 символов.Обновление 2: заменено
for(int i=0;i<c.length;c[i]^=k[i++%k.length]);
отint i=0;for(char p:c)c[i]^=k[i++%k.length];
, сохранил 3 символа.
import java.io.*;class X{public static void main(String[]a)throws Exception{char[]c=r(a[0]),k=r(a[1]);int i=0;for(char p:c)c[i]^=k[i++%k.length];Writer w=new FileWriter(a[0]);w.write(c);w.close();}static char[]r(String a)throws Exception{return new BufferedReader(new FileReader(a)).readLine().toCharArray();}}
Более читаемая версия:
import java.io.*;
class X{
public static void main(String[]a)throws Exception{
char[]c=r(a[0]),k=r(a[1]);int i=0;for(char p:c)c[i]^=k[i++%k.length];
Writer w=new FileWriter(a[0]);w.write(c);w.close();
}
static char[]r(String a)throws Exception{
return new BufferedReader(new FileReader(a)).readLine().toCharArray();
}
}
Java IO довольно многословен. Рефакторинг двух операций file-to-char[] приводит к сохранению 4 символов в методе. Да, закрытие (промывка) писателя абсолютно необходимо. В противном случае файл остается пустым. В противном случае было бы 298 292 289 символов.
Python3 - 114 символов
принимает параметры из стандартного ввода
a=input().split()
k,t=[open(x,"rb").read()for x in a]
open(a[1],"wb").write(bytes(x^y for x,y in zip(k*len(t),t)))
F#, 168 символов
open System.IO
[<EntryPoint>]
let main a=
let k=File.ReadAllBytes a.[1]
let z i v=v^^^k.[i%k.Length]
File.WriteAllBytes(a.[0], Array.mapi z (File.ReadAllBytes a.[0]))
0
Примечание: в основном IO, ключ Array.mapi. Кроме того, некоторые F# Guru, вероятно, будут чертовски удачны из этого решения - я программист на C# по профессии и никогда не использовал F# для чего-то еще, кроме обучения для развлечения.
Руби 72 62 символа
$<.inject{|k,l|l.each_byte{|b|$><<(b^(r=k.slice!0)).chr;k<<r}}
Я мог бы сэкономить 10 символов, если бы мне не пришлось раздеть \n
от клавиши ввода с k=a.chomp;
Ушел вперед и сделал это
Ограничения: обрабатывает только однострочные ключи.
Как это устроено:
$<
действует как массив, содержащий все строки всех входных файлов.
.inject
перебирает массив,
{|k,l|
: на первом проходе аргументы являются ключевой строкой и первой строкой ввода.
l.each_byte{|b|
берет каждый символ из строк ввода как int.
$><<
означает "печать"
(b^(r.k.slice!0)
XOR 'b' с первым символом в ключе (который он вырезает и сохраняет в 'r'
.chr;
преобразует целое число обратно в ascii
k<<r
вращает первый символ клавиши до конца.
}}
Блок выдает обновленный k, который будет использоваться в качестве первого аргумента в следующем проходе для внедрения; 2-й аргумент будет следующей строкой ввода.
Другая
Perl решение, 59 (42) символов
(соответствует одной линии, которая, кажется, работает до сих пор:)
Программа (59 символов) с вычисленной длиной ключа:
$.-1?$_^=substr($k x((length)/length($k)+1),0,length):$k=$_
будет 42 символа, если использовать "хрупкий" подход mobrule к длине ключа:
$.-1?$_^=substr($k x 1e4,0,(length)):$k=$_
Командная строка:
$> perl -i -0777 -pe'<insert above>' keyfile messagefile
Это перезапишет сообщение в его отредактированную форму и вернется в текстовую форму:
$> cat keyfile ; cat messagefile
Code Golf
Stackru is Cool
Применить команду:
$> perl -i.bak -0777 -pe'<insert above>' keyfile messagefile
$> cat keyfile ; cat messagefile
Code Golf
^P^[^E^FK^H^Y ^Tl/^@^SEI4O/ e/e
Применить снова:
$> perl -i.bak -0777 -pe'<insert above>' keyfile messagefile
$> cat keyfile ; cat messagefile
Code Golf
Stackru is Cool
С уважением
БВ
Haskell, 181 символ
I/O - сука при игре в гольф на Haskell, а бинарный I/O - вдвойне. Это решение может быть значительно улучшено. Не стесняйтесь!
import Data.Bits
import Data.ByteString as B
u=unpack
g o[l,n]=o$pack$Prelude.zipWith xor(u n)(cycle$u l)
f x=mapM B.readFile x>>=g(B.writeFile$x!!1)
main=Prelude.getLine>>=f.words
Использование:
$ ghc --make encrypt.hs
$ echo -n 'Code Golf' > key
$ echo -n 'Stackru is Cool' > message
$ echo 'key message' | ./encrypt
$ od -tx1 message
PowerShell, 125 115 символов
Пока что это самый короткий ответ на основе.net:
$k=[char[]](gc $args[1]);$i=0;sc $args[0] ([byte[]]([char[]](gc $args[0])|%{$_ -bXor $k[$i++%$k.Length]})) -en byte
Симпатичная версия с прописанными сокращениями команд:
$k=[char[]](get-content $args[1])
$i=0
set-content `
$args[0] `
([byte[]] ([char[]] (get-content $args[0]) `
| foreach {$_ -bXor $k[$i++ % $k.Length]})) `
-encoding byte
Использование: powershell codegolf.ps1 message.txt key.txt
, По запросу перезаписывает message.txt
,
q, 88 знаков
Реализовано с использованием q из http://kx.com/ который написан Артуром Уитни и вдохновлен APL и lisp.
a[0]1:"x"$2 sv'{(x|y)¬ x&y}.'0b vs''flip{y:count[x]#y;(x;y)}.(read1')a:(hsym')`$'.z.x
Итак, небольшое объяснение того, что происходит: (читайте справа налево)
a:(hsym')`$'.z.x
Создает список из двух файловых дескрипторов из списка аргументов времени выполнения и сохраняет его для последующего использования в переменной "a".
(read1')
Зациклите два файла, прочитайте их и верните список байтов, где byte=0x00..0xFF ((22 байта),(10 байтов))
{y:count[x]#y;(x;y)}.
Сформируйте ключ такой же длины, что и сообщение. Ключ усекается, если он слишком длинный, и повторяется, если он слишком короткий. Список теперь хорошо отформатирован, 2х22.
flip
Переместите список, и теперь он 22x2.
0b vs''
Конвертировать каждый элемент списка в двоичный тип
{(x|y)¬ x&y}.'
Пара XOR, подходящая для всех 22 элементов, возвращает список из 8 логических значений
"x"$2 sv'
Преобразовать 8 логических битов в байт.
a[0]1:
Записать файл, переопределяя исходный файл сообщения.
Образец прогона:
$ cp message.txt message.txt.bk
$ q g.q message.txt key.txt
$ diff -s message.txt message.txt.bk0
Binary files message.txt and message.txt.bk0 differ
$ q g.q message.txt key.txt
$ diff -s message.txt message.txt.bk0
Files message.txt and message.txt.bk0 are identical
Питон - 127 символов
использует параметры командной строки для ключевого файла и файла данных
import sys
a=sys.argv
_,k,t=[open(x).read()for x in a]
s=open(a[2],"w").write
[s(chr(ord(x)^ord(y)))for x,y in zip(k*len(t),t)]
запись на стандартный вывод - 109 символов
import sys
_,k,t=[open(x).read()for x in sys.argv]
print"".join(chr(ord(x)^ord(y))for x,y in zip(k*len(t),t))
Рубин - 158 символов
def a(b);File.readlines(b).join("\n").chomp;end;t=a($*[0]);k=a($*[1]);File.open($*[0],"w"){|f|0.upto(t.length-1){|i|f.putc((t[i]^k[i.modulo(k.length)]).chr)}}
Более красивая версия:
def a(b)
File.readlines(b).join("\n").chomp
end
t = a($*[0])
k = a($*[1])
File.open($*[0],"w") {|f|
0.upto(t.length - 1) {|i|
f.putc((t[i] ^ k[i.modulo(k.length)]).chr)
}
}
Это решение использует следующие аспекты проблемы:
Ваша миссия, если вы решите принять ее, - создать программу с минимальным количеством нажатий клавиш, которая...
Это решение было написано на моем планшете с использованием распознавания рукописного ввода для ввода. При создании этого кода не было нажатий клавиш. Поэтому эта программа была разработана с нуля нажатий клавиш. Игра окончена, я выиграл!
Ява, 336 316 405 символов
РЕДАКТИРОВАТЬ: забыл, что он должен был прочитать из файла. *вздох
public class A {
public static void main(String[] a) throws Throwable {
char[] p = new BufferedReader(new FileReader(a[1])).readLine().toCharArray();
char[] t = new BufferedReader(new FileReader(a[0])).readLine().toCharArray();
int u = t.length;
int k = 0;
for (int i = 0; i < u; i++) {
new FileOutputStream (a[0]).write((char) ((int) t[i] ^ (int) p[k]));
k = k = ++k % p.length;
}
}
}
Это стоило попробовать. Однако я не думаю, что Java - лучший язык здесь...
F#, 147 146 символов
Это в значительной степени основано на решении Дрис. Все, что я сделал, это добавил необходимые отступы, чтобы они компилировались, меняли порядок параметров командной строки и затягивали. Я не был бы удивлен, если это все еще может быть сокращено немного, все же. Примечание. Вы получите предупреждение о неполном совпадении с образцом. Обычно я был бы первым, кто пожаловался на это, но я думаю, что Code Golf заслуживает исключения из обычных лучших практик.:)
open System.IO[<EntryPoint>]let m[|a;b|]=File.ReadAllBytes|>fun r->r a|>fun k->File.WriteAllBytes(b,Array.mapi(fun i->(^^^)k.[i%k.Length])(r b));0
F#, 147 символов, более читабельный
open System.IO
let r=File.ReadAllBytes
[<EntryPoint>]
let m[|a;b|]=
let k=r a
File.WriteAllBytes(b,Array.mapi(fun i->(^^^)k.[i%k.Length])(r b));0
C - 163 161 символ
Добавлен сброс и удален ненужный поиск.
golfed:
#include <stdio.h>
int*p,l;char*k;main(int c,char**v){FILE*f=fopen(*++v,"rb+");k=p=*++v;while(fgets(&l,2,f)){fseek(f,-1,1);putc(l^*k++,f);fflush(f);if(!*k)k=p;}}
ungolfed:
#include <stdio.h>
int*p,l;
char*k;
main(int c,char**v){
FILE*f=fopen(*++v,"rb+");
k=p=*++v;
while(fgets(&l,2,f)){
fseek(f,-1,1);
putc(l^*k++,f);
fflush(f);
if(!*k)k=p;
}
}
Ява - 306 символов
Использование Java -решения BalusC в качестве основы:
import java.io.*;class X{public static void main(String[]a)throws Exception{final char[]c=r(a[0]),k=r(a[1]);int i=0;for(int p:c)c[i]^=k[i++%k.length];new FileWriter(a[0]){{write(c);}}.close();}static char[]r(String a)throws Exception{return new BufferedReader(new FileReader(a)).readLine().toCharArray();}}
Более читабельно:
import java.io.*;
class X{
public static void main(String[]a)throws Exception{
final char[]c=r(a[0]),k=r(a[1]);int i=0;for(int p:c)c[i]^=k[i++%k.length];
new FileWriter(a[0]){{write(c);}}.close();
}
static char[]r(String a)throws Exception{
return new BufferedReader(new FileReader(a)).readLine().toCharArray();
}
}
Я на самом деле не тестировал код, но я также ничего не изменил.
С # 168:
using System.IO;class a{static void Main(string[] b){File.WriteAllBytes(b[0],File.ReadAllBytes(b[0]).Select((x,i)=>x^File.ReadAllBytes(b[1])[i%d.Length]).ToArray());}}
Функциональное решение. Я сохранил переменные, вставив операцию чтения, которая заставляет ее выполняться снова и снова.
PHP, 142 141 символов
Изменить 1: fputs()
вместо fwrite()
,
$t=fopen($argv[1],'r+');$s=fgets($t);rewind($t);$k=fgets(fopen($argv[2],'r'));for($i=0;$i<strlen($s);$i++)fputs($t,$s{$i}^$k{$i%strlen($k)});
Красивая печать:
$t = fopen($argv[1],'r+');
$s = fgets($t);
rewind($t);
$k = fgets(fopen($argv[2],'r'));
for($i=0; $i<strlen($s); $i++)
fputs($t, $s{$i} ^ $k{$i % strlen($k)});
Python, 154 символа
import sys,struct;_,f,k=sys.argv
open(f,'r+b').write(''.join(struct.pack('B',ord(a)^ord(b))for a,b in zip(open(f,'r+b').read(),open(k,'rb').read()*1000)))
KSH93 - 152 символа
m=$(<$1)
k=$(<$2)
for ((e=0;e<${#m};e++))
do
out="$out$(printf "%02X" $(("'${m:$e:1}"^"'${k:${e}%${#k}:1}")))"
done
echo "${out}0d0a" | xxd -p -r >$1