Код Гольф: Шифрование 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)&not 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)&not 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
Другие вопросы по тегам