От : Encryption Co.
К : x $ * sj4 (это вы)
Ваша миссия, если вы решите принять он состоит в том, чтобы создать программу за кратчайшее количество нажатий клавиш, которая
принимает два параметра имени файла (либо командную строку, либо стандартный ввод), первый - это файл, содержащий ключ, а второй - какое-то сообщение. Оба файла будут в виде простого текста.
Применяет ключ к сообщению, используя шифрование XOR , перезаписывая файл.
Пример:
Входной файл:
StackOverflow is Cool
Ключ:
Code Golf
Шестнадцатеричный дамп зашифрованного выходного файла:
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 невозможно взломать, если размер ключа больше или равен размеру сообщения, и ключ генерируется беспристрастным случайным процессом. См .: Одноразовый блокнот . Так что никакого "плохого шифрования" здесь нет.
n.+/~:k;.,.)k.,@\/)*<{\(@^}%
Чтобы использовать, передайте файл сообщения, а затем новую строку, а затем файл ключа в стандартный ввод сценария:
$ (cat message-file ; echo ; cat key-file) | ruby golfscript.rb poorencrypt.gs
$ (echo StackOverflow is Cool;echo;echo Code Golf) | \ ruby golfscript.rb poorencrypt.gs > encoded-file $ (cat encoded-file;echo;echo Code Golf) | ruby golfscript.rb poorencrypt.gs StackOverflow is Cool
Это немного хрупко.
print$/=!1,($_=<>)^substr<>x 1E4,0,y///c
Perl имеет встроенный строковый оператор xor. Чтобы решить эту проблему, сложнее всего добиться, чтобы две строки имели одинаковую длину.
$/=!1
Устанавливает «разделитель записей» на неопределенное значение и ничего не выводит на печать. С этой настройкой оператор строки чтения файла будет пролистывать весь файл.
$_=<>
Загружает весь первый файл (содержащий сообщение) в переменную $ _
.
substr <> x 1E4, 0, y///c
Создает другую строку из второго файла (ключа) и добавляет ее к себе 10 000 раз. Надеюсь, (1) эта действительно длинная строка будет длиннее, чем строка сообщения, и (2) она не будет настолько длинной, чтобы из-за нее программе не хватало памяти (вот почему это решение хрупкое). y /// c
- это операция для подсчета количества символов в $ _
, и она на один символ короче, чем указанная длина
. Это сокращает строку ключа до того же размера, что и строка сообщения.
Обновление 1: заменено char [] c = r (a [0]) ; char [] k = r (a [1]);
по char [] c = r (a [0]), k = r (a [1]);
, сохранено 6 символы.
Обновление 2: заменено на (int i = 0; i
int i = 0; для (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 символов.
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))))
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);}}
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" "StackOverflow 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↔⇄¦*⊕;▼
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
Примечание: в основном ввод-вывод, ключ - Array.mapi. Кроме того, какой-нибудь гуру F # наверняка выбьет из него черту это решение - я по профессии программист на C # и никогда не использовал F # ни для чего другого, кроме обучения для развлечения.
Ruby 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 ^ (rkslice! 0)
XOR 'b' с первым символом в ключе (который он отсекает и сохраняет в 'r '
.chr;
преобразует целое число обратно в ascii
k << r
поворачивает первый символ ключа до конца.
}}
Блок возвращает обновленный k, который будет использоваться в качестве первого аргумента в следующем проходе для инъекции; второй аргумент будет следующей строкой ввода.
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
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)
}
}
Это решение использует следующий аспект проблемы:
Ваша миссия, если вы решите принять это, значит создать программу в кратчайшее количество нажатий клавиш что ...
Это решение было написано на моем планшете с использованием распознавания рукописного ввода для ввода. При создании этого кода клавиши не нажимались. Таким образом, эта программа была разработана без нажатия клавиш. Игра окончена, я выигрываю!
Реализовано с использованием 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)}.
Сформируйте ключ такой же длины, как и сообщение. Ключ обрезается, если он слишком длинный, и повторяется, если он слишком короткий. Список теперь хорошо отформатирован, 2x22.
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
Другое
(соответствует однострочному тексту, который пока работает :)
Программа (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
Этот перепишет сообщение на свое xor-ed и обратно в текстовую форму:
$> cat keyfile ; cat messagefile
Code Golf
StackOverflow 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
StackOverflow is Cool
С уважением
rbo
принимает параметры из stdin
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)))
На данный момент это самый короткий ответ на основе .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
.
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)))
Редактировать 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)});
Это в значительной степени основано на решении driis'а. Все, что я сделал, это добавил необходимые отступы для компиляции, изменил порядок параметров командной строки и подтянул все. Я не удивлюсь, если его можно еще немного сократить. Примечание: Вы получите предупреждение о неполном совпадении шаблонов. Обычно я бы первым пожаловался на это, но я думаю, что кодовый гольф заслуживает исключения из обычной лучшей практики. :)
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
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
РЕДАКТИРОВАТЬ: Забыл, что нужно было читать из файла. * вздох
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 здесь лучший язык ...
использует параметры командной строки для ключевого файла, а файл данных
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))
Ввод-вывод - это сука при игре в гольф на Haskell, а двоичный ввод-вывод - вдвойне. Это решение, вероятно, можно значительно улучшить. Не стесняйтесь!
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 'StackOverflow is Cool' > message
$ echo 'key message' | ./encrypt
$ od -tx1 message
Java - 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();
}
}
Я фактически не тестировал код, но и не изменил ничего радикального.