Shifty XORyption

15

Escriba un programa o función (o conjunto de programas / funciones) para cifrar y descifrar datos con la siguiente especificación:

Cifrado

  1. Calcule un hash XOR de la entrada haciendo XOR cada byte entre sí.

  2. XOR cada byte de la entrada por este hash.

  3. Desplaza el resultado cuatro bits hacia la izquierda.

  4. Rellene el lado izquierdo con los primeros cuatro bits del hash XOR.

  5. Rellene el lado derecho con los últimos cuatro bits del hash XOR.

Ejemplo

  • Entrada dada: "G0lf"( 0x47306C66)

  • Calcule el hash XOR: 0x47 ^ 0x30 ^ 0x6C ^ 0x66 = 0x7D

  • XOR cada byte por hash: 0x3A4D111B

  • Resultado esperado (después de shift y pad): "s¤Ñ\x11½"( 0x73A4D111BD)

Reglas

  • Su programa / función puede ingresar / salir de cualquier tipo que tenga sentido en el idioma de golf que elija (String, Byte Array, etc.) siempre que la entrada / salida sean los bytes reales. Por ejemplo, no puede generar una cadena hexadecimal.

  • El cifrado y el descifrado se pueden separar en programas separados (la puntuación será el tamaño combinado) o en uno solo. Los métodos individuales pueden tomar un argumento sobre si debe cifrar o descifrar.

  • Se puede esperar que la entrada para el cifrado tenga al menos 1 byte de tamaño.

  • Se puede esperar que la entrada para el descifrado sea de al menos 2 bytes.

  • Los bytes no imprimibles no necesitan escapar en la salida.

nderscore
fuente
1
¿Se podría usar una matriz decimal como formulario de salida?
Aprıʇǝɥʇuʎs
@ ɐɔıʇɥʇuʎs Sería aceptable tomar entradas y salidas como una matriz de enteros para representar bytes.
nderscore
¿Existe una longitud de entrada máxima (por ejemplo, 14 bytes (56 bits), de modo que el resultado final se ajuste a un entero de 64 bits)?
Pomo de la puerta
1
Solo una nota: desde el punto de vista de la criptografía, esto no es un cifrado, ya que no tiene clave (o una clave de 0 bits).
Paŭlo Ebermann
1
Solo estoy esperando que alguien publique algo sobre nunca rodar su propio cifrado, ignorando el sitio en el que se encuentra ...
user253751

Respuestas:

9

CJam, 28 + 27 = 55 bytes

Para cada parte, presento un programa que espera que la entrada / salida tenga la forma de una matriz de enteros y otra que use una cadena. El recuento de bytes anterior es para la versión de matriz entera, pero la secuencia de comandos vinculada y la explicación son para la versión basada en cadenas (que puede usarse para probar el ejemplo dado en la pregunta).

Cifrado

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

Descifrado

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

Aquí hay un script de prueba que realiza un viaje de ida y vuelta completo e imprime el código cifrado antes de volver a descifrarlo.

Explicación

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.
Martin Ender
fuente
6

CJam, 36 + 34 = 70 bytes

Un enfoque un poco diferente usando formas binarias

Encriptador :

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

Cómo funciona:

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

Descifrador :

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

Cómo funciona:

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

Prueba el encriptador y desencriptador en línea

Optimizador
fuente
6

Pyth, 69 bytes

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

Esto combina cifrado y descifrado, simplemente agregue un 0argumento para el cifrado o un 1para descifrado. La razón de esto es simple. Convertir cadenas en bits (o enteros de 4 bits) o al revés es realmente muy largo en Pyth. Al combinar las dos funciones en un solo programa, puedo ahorrar muchos bytes.

Demostraciones en línea: cifrado y descifrado .

Explicación:

La primera parte convierte la entrada en una lista de enteros de 4 bits (cada carácter se convierte en 2 enteros de 4 bits) y los almacena 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

La segunda parte determina los valores hash y los almacena J. Si los Q==0calcula por xor, de lo contrario toma el primer y último valor de 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)

La siguiente parte hace el xor usando los valores hash. Cuando Q == 0se realiza en la lista completa K, de lo contrario solo en la lista Ksin el primer y último valor.

=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

Y la última parte se convierte de Knuevo en caracteres:

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
fuente
0

Javascript ( ES6 ) 83 + 73 = 156

Ambas funciones toman la entrada como y salen una matriz de números para representar bytes.

Cifrar 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)

Descifrar 75 73

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

Demostración (solo 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 />');


Usando cadenas 131 + 129 = 260

Y solo por diversión ... aquí hay algunas versiones que usan cadenas para entrada / salida en su lugar.

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
fuente