Shifty XORyption

15

Напишите программу или функцию (или набор программ / функций) для шифрования и дешифрования данных с учетом следующей спецификации:

шифрование

  1. Вычислить XOR-хэш-данные ввода, XOR-каждый байт друг с другом.

  2. XOR каждый байт ввода этого хэша.

  3. Сдвиньте результат на четыре бита влево.

  4. Дополните левую сторону первыми четырьмя битами хэша XOR.

  5. Дополните правую сторону последними четырьмя битами хэша XOR.

пример

  • Учитывая вход: "G0lf"( 0x47306C66)

  • Рассчитать XOR хеш: 0x47 ^ 0x30 ^ 0x6C ^ 0x66 = 0x7D

  • XOR каждый байт по хешу: 0x3A4D111B

  • Ожидаемый результат (после смены и заполнения): "s¤Ñ\x11½"( 0x73A4D111BD)

правила

  • Ваша программа / функция может выполнять ввод / вывод любого типа, который имеет смысл на выбранном вами языке игры в гольф (String, Byte Array и т. Д.), Если входные / выходные данные являются действительными байтами. Например, вы не можете выводить шестнадцатеричную строку.

  • Шифрование и дешифрование могут быть разделены на отдельные программы (оценка будет соответствовать их объединенному размеру) или одну. Одиночные методы могут принимать аргумент о том, должен ли он шифроваться или расшифровываться.

  • Ожидается, что ввод для шифрования будет иметь размер не менее 1 байта.

  • Ожидается, что вход для дешифрования будет не менее 2 байтов.

  • Непечатные байты не должны быть экранированы в выводе.

nderscore
источник
1
Может ли десятичный массив использоваться в качестве выходной формы?
Aprıʇǝɥʇuʎs
@ ɐɔıʇɥʇuʎs Было бы приемлемо принимать входные и выходные данные как массив целых чисел для представления байтов.
nderscore
Существует ли максимальная входная длина (например, 14 байтов (56 бит), чтобы конечный результат соответствовал 64-битному целому числу)?
Ручка двери
1
Просто примечание: с точки зрения криптографии это не шифрование, так как оно не имеет ключа (или 0-битного ключа).
Паŭло Эберманн
1
Я просто жду, когда кто-нибудь
напишет

Ответы:

9

CJam, 28 + 27 = 55 байт

Для каждой части я представляю одну программу, которая ожидает ввод / вывод в виде целочисленного массива, и одну, которая использует строку. Приведенный выше счетчик байтов предназначен для версии целочисленного массива, но связанный скрипт и объяснение предназначены для строковой версии (которую можно использовать для проверки примера, приведенного в вопросе).

шифрование

q~_:^_GbYUe[\@f^Gfbe_*2/Gfbp
q:i_:^_GbYUe[\@f^Gfbe_*2/Gfb:c

Дешифрирование

q~{_G/\G%}%)\(G*@+\2/Gfbf^p
q:i{_G/\G%}%)\(G*@+\2/Gfbf^:c

Вот тестовый скрипт, который выполняет полный обход и печатает зашифрованный код перед повторной расшифровкой.

объяснение

q:i_:^_GbYUe[\@f^Gfbe_*2/Gfb:c
q:i                            e# Read the input and convert characters to byte values.
   _:^                         e# Duplicate and fold XOR onto the characters to get 
                               e# the hash.
      _Gb                      e# Duplicate and convert to base 16 to get nibbles.
         YUe[                  e# Pad to width 2 with zeroes.
             \@                e# Pull up other copy and integer array.
               f^              e# XOR each integer with the hash.
                 Gfbe_         e# Convert each result to base 16 and flatten that.
                      *        e# Join the hash nibbles with this array.
                       2/      e# Split into pairs.
                         Gfb   e# Interpret each pair as base 16.
                            :c e# Convert each integer to a character.

q:i{_G/\G%}%)\(G*@+\2/Gfbf^:c
q:i                            e# Read the input and convert characters to byte values.
   {      }%                   e# Map this block onto each byte.
    _G/\G%                     e# Get the two base 16 digits individually.
            )\(                e# Slice off the last and first nibble.
               G*@+\           e# Combine into byte (the hash) and swap with array.
                    2/Gfb      e# Split array into pairs and interpret each as base 16.
                         f^    e# XOR each with the hash.
                           :c  e# Convert each integer to a character.
Мартин Эндер
источник
6

CJam, 36 + 34 = 70 байт

Немного другой подход с использованием бинарных форм

Шифратор :

q_:^:Hf^H+{i2b8Ue[}%)4/~@\]e_8/2fb:c

Как это устроено:

q_:^                                  e# Read input as string, copy and XOR all the chars
    :Hf^                              e# Store the XOR in H and XOR each char with H
        H+                            e# Append H to the char array
          {       }%                  e# On each of the elements in the array
           i2b                        e# Convert the ASCII value to binary
              8Ue[                    e# Pad with 0 so that the length is 8
                    )                 e# Pop out the last array element, which is H
                     4/~@\            e# Put first 4 bits of H before the input array
                                      e# And rest 4 after it
                          ]e_8/       e# Flatten everything into a single array and group
                                      e# into pieces of 8 bits
                               2fb:c  e# Convert each 8 bit part to integer and then to
                                      e# its character form

Дешифровщик :

q{i2b8Ue[4/~}%)\(@+2b\:+8/2fb\f^:c

Как это устроено:

q{          }%                      e# For each character of the input string
  i2b                               e# Convert to ASCII code and then to its binary form
     8Ue[                           e# Pad with enough 0 so that length is 8 bit
         4/~                        e# Split into parts of 4 and unwrap
              )\(@+                 e# Take out the first and last 4 bit group and join
                                    e# them together to get the XOR Hash H
                   2b\              e# Convert H to decimal form and swap to put the
                                    e# remaining converted input array on top
                      :+8/          e# Join all bits together and split into groups of 8
                          2fb       e# Convert each 8 but group to decimal form
                             \f^    e# Swap to put H on top and XOR each number with H
                                :c  e# Get character from each of the ASCII value

Попробуйте шифратор и дешифратор онлайн

оптимизатор
источник
6

Pyth, 69 байт

Ksm>+0jCd16_2zJ?,hKeKQmxFdCcK2=KsmmxFkC,dJc?tPKQK2smCid16c?KQ++hJKeJ2

Это объединяет шифрование и дешифрование, просто добавьте 0аргумент as для шифрования или a 1для расшифровки. Причина этого проста. Преобразование строк в биты (или 4-х битное целое число) или наоборот очень долго в Pyth. Объединяя обе функции в одну программу, я могу сэкономить много байтов.

Онлайн демонстрации: шифрование и дешифрование .

Объяснение:

Первая часть преобразует входные данные в список 4-разрядного целого числа (каждый символ преобразуется в 2 4-разрядное целое число) и сохраняет его в K.

  m          z   map each character d of input (=z) to:
       Cd            the ascii-value of d
      j  16          convert the result into base 16
   >+0     _2        insert a zero to the front and take the last 2 values
                     (so that each char gets mapped to exactly 2 numbers)
Ks               chain all these tuples and assign them to K

Вторая часть определяет значения хешей и сохраняет их в J. Если Q==0он вычисляет их по xor, в противном случае он принимает первое и последнее значение K.

 ?     Q           ... if Q (=second input) else ...
  ,hKeK            [K[0], K[-1]]
        m   CcK2   map each d of zipped(K chopped into pairs) to:
                   [zipped(...) gives me 2 lists, one with the values of the even indices, and one with the odd indices]
         xFd           fold the list d by xor
J                  store the result in J (this is the hash value)

Следующая часть выполняет xor, используя значения хеша. Когда Q == 0это выполняется в полном списке K, в противном случае только в спискеK без первого и последнего значения.

=KsmmxFkC,dJc?tPKQK2
             ?tPKQK    K[1:-1] if Q else K 
   m        c      2   map each d of [... chopped into pairs] to:
    m   C,dJ              map each pair k of zip(d,J) to:
     xFk                     apply xor to the 2 values in k
=Ks                    chain all these tuples and assign them to K

И последняя часть преобразует Kобратно в символы:

smCid16c?KQ++hJKeJ2
        ?KQ++hJKeJ    K if Q else J[0] + K + J[1]
 m     c          2   map each pair of [... chopped into pairs] to:
   id16                  convert d into a single integer
  C                      convert to char
s                     join all chars and print
Jakube
источник
0

Javascript ( ES6 ) 83 + 73 = 156

Обе функции принимают входные данные как и выводят массив чисел для представления байтов.

Шифровать 85 84 83

E=s=>s.concat((h=s.reduce((x,y)=>x^y))<<4&240^h).map(x=>a<<4&240|(a=x^h)>>4,a=h>>4)

Расшифровывать 75 73

D=s=>s.map(x=>(a<<4&240|(a=x)>>4)^h,h=(a=s.shift())&240|s[~-s.length]&15)

Демонстрация (только Firefox)

E=s=>s.concat((h=s.reduce((x,y)=>x^y))<<4&240^h).map(x=>a<<4&240|(a=x^h)>>4,a=h>>4)
D=s=>s.map(x=>(a<<4&240|(a=x)>>4)^h,h=(a=s.shift())&240|s[~-s.length]&15)

toHexString = x=>'0x'+x.map(y=>y.toString(16)).join('')

input = [...'G0lf'].map(x=>x.charCodeAt());
document.write('Input: ' + toHexString(input) + '<br />');

encrypted = E(input);
document.write('Encrypted: ' + toHexString(encrypted) + '<br />');

decrypted = D(encrypted);
document.write('Decrypted: ' + toHexString(decrypted) + '<br />');


Использование строк 131 + 129 = 260

И просто для удовольствия ... вот некоторые версии, которые вместо этого используют строки для ввода / вывода.

E=(s,h=0)=>[for(x of s)(h^=y=x.charCodeAt(),y)].concat(h<<4&240^h).map(x=>String.fromCharCode(a<<4&240|(a=x^h)>>4),a=h>>4).join('')

D=s=>(s=[s.charCodeAt(j=i)for(i in s)]).map(x=>String.fromCharCode((a<<4&240|(a=x)>>4)^h),h=(a=s.shift())&240|s[~-j]&15).join('')

E('G0lf') // 's¤Ñ\x11½'
D('s¤Ñ\x11½') // 'G0lf'
nderscore
источник