Cryptage CipherSaber

11

Implémentez un programme de chiffrement CipherSaber , comme décrit ci-dessous. Des lignes directrices:

  • La plus petite entrée, en octets, gagne.
    • Cependant, dans une dérogation aux normes de , vous êtes invités à publier des entrées intéressantes, même si elles ne sont pas sérieuses.
  • Une entrée est généralement un programme qui prend le texte en clair de l'entrée standard et écrit le texte chiffré sur la sortie standard, avec la clé spécifiée (par l'utilisateur) d'une manière que vous préférez.
    • Cependant, si vous souhaitez implémenter cela en tant que procédure, c'est bien aussi.
  • L'IV doit provenir d'un générateur de nombres pseudo-aléatoires cryptographiquement sécurisé. Si votre langue ne le prend pas en charge, choisissez-en une autre. ;-)
  • Veuillez ne pas utiliser de bibliothèques, d'appels système ou d'instructions spécifiques à la cryptographie (autres que le PRNG, comme stipulé ci-dessus). Bien sûr, les opérations génériques au niveau du bit bas sont correctes.

CipherSaber est une variante de RC4 / Arcfour, je vais donc commencer par décrire ce dernier, puis les modifications apportées par CipherSaber.

0. RC4 / Arcfour

Arcfour est entièrement spécifié ailleurs , mais pour être complet, je vais le décrire ici. (En cas de divergence entre le projet Internet et cette description, la première est normative.)

Configuration des touches

Configurez deux tableaux Set S2, tous deux de longueur 256, où k_1est le premier octet de la clé et k_nle dernier.

S = [0, ..., 255]
S2 = [k_1, ..., k_n, k_1, ...]

( S2est rempli des octets de la clé, encore et encore, jusqu'à ce que les 256 octets soient remplis.)

Ensuite, initialisez jà 0 et mélangez 256 fois:

j = 0
for i in (0 .. 255)
    j = (j + S[i] + S2[i]) mod 256
    swap S[i], S[j]
end

Ceci termine la configuration des clés. La S2baie n'est plus utilisée ici et peut être nettoyée.

Génération de flux de chiffrement

Initialisez iet jà 0, puis générez le flux de clés comme suit:

i = 0
j = 0
while true
    i = (i + 1) mod 256
    j = (j + S[i]) mod 256
    swap S[i], S[j]
    k = (S[i] + S[j]) mod 256
    yield S[k]
end

Chiffrement / déchiffrement des données

  • Pour crypter, XOR la ​​sortie du flux de clés avec le texte en clair
  • Pour déchiffrer, XOR la ​​sortie du flux de clés avec le texte chiffré

1. CipherSaber

CipherSaber (qui est ce que nous implémentons dans cette question) est une variante de RC4 / Arcfour de deux manières:

10 octets IV / nonce

Lors du cryptage d'un message, 10 octets aléatoires doivent être obtenus, par exemple via /dev/urandom, et être écrits dans les 10 premiers octets de la sortie cryptée. Lors du décryptage d'un message, les 10 premiers octets de l'entrée sont l'IV utilisé pour le crypter.

L'étape de configuration de la clé RC4 / Arcfour est exécutée avec passphrase || IVcomme clé, où passphraseest la phrase de passe spécifiée par l'utilisateur, IVcomme décrit ci-dessus, et ||est la concaténation. Donc, une phrase secrète de "Bonjour, mon monde!" et un IV de "supercalif" (aussi improbable que soit :-P) donnerait une clé de "Bonjour, monde! supercalif".

Itérations multiples de la configuration des clés

Afin d'éviter la vulnérabilité qui a rendu le cryptage WEP complètement rompu, la boucle de brassage de l'étape de configuration des clés de RC4 est exécutée un nombre de fois spécifié par l'utilisateur. La valeur de jdoit être conservée entre les itérations.

2. Vecteurs de test

Voici quelques vecteurs de test que vous pouvez utiliser pour tester vos programmes. De plus, squeamish ossifrage a créé un outil de chiffrement et de déchiffrement CipherSaber que vous pouvez utiliser pour valider vos résultats.

Il vous suffit d'implémenter le programme de cryptage. Vous n'avez pas besoin de fournir le programme de déchiffrement, mais la sortie de votre programme de chiffrement doit aller et venir correctement à l'entrée d'origine lorsqu'elle est traitée avec un programme de déchiffrement correctement implémenté à l'aide de la bonne clé.

Chris Jester-Young
la source

Réponses:

7

Pyth, 100 octets

$import os$KsM$os.urandom(10)$JuuXN@LN,T=+Z+@NT@+CMzKT)bGQU=b256=Z0sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw

Ce script utilise la $commande, qui permet d'exécuter du code Python. Pour empêcher l'exécution de code malveillant sur le serveur, la commande this est désactivée dans le compilateur en ligne. Vous devez l'exécuter avec le compilateur hors ligne que vous pouvez trouver ici .

L'entrée est au format:

secret key
5 (number of repeats)
secret message

Le programme génère la chaîne chiffrée, qui peut contenir des caractères non imprimables. Si vous souhaitez le vérifier à l'aide de l' outil de chiffrement et de déchiffrement CipherSaber , vous pouvez utiliser le code suivant, qui convertit la chaîne en une série de chiffres hexadécimaux.

$import os$KsM$os.urandom(10)$JuuXN@LN,T=+Z+@NT@+CMzKT)bGQU=b256=Z0         
jdm.[2.HCd`0
sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw

Pyth ne prend pas en charge les numéros pseudo-aléatoires sécurisés cryptographiquement et leur importation à partir de Python coûte 25 octets. Un code plus court, qui utilise le générateur de nombres pseudo-aléatoires normaux de Pyth / Python et fonctionne également dans le compilateur en ligne est:

KmO=b256TJuuXN@LN,T=+Z+@NT@+CMzKT)bGQUb=Z0sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw

Essayez-le en ligne: renvoyer une chaîne ou une série de chiffres hexadécimaux

Le code n'a rien de spécial. Juste beaucoup d'affectations sales et de réutilisation immédiate des résultats calculés et en appliquant deux fois l' astuce de permutation de liste .

Explication:

                                  implicit: z = 1st input (= key string)
                                  Q = 2nd input (number of repetitions)
$import os$KsM$os.urandom(10)$
$import os$                       import Python's os module
              $os.urandom(10)$    create 10 cryptographically secure 
                                  pseudo-random bytes
            sM                    convert them to ints
           K                      store them in K

JuuXN@LN,T=+Z+@NT@+CMzKT)bGQU=b256
                             =b256assign b with 256
 u                         QUb    start with G = [0, 1, ..., 255], 
                                  evaluate the following expression Q times and
                                  update G with the result each time:
  u                      bG         start with N = G, 
                                    for each T in [0, 1, ..., 255] evaluate the
                                    following expression and update N each time:
                   CMz                convert key to list of ints
                  +   K               extend it with K
                 @     T              take the Tth element (modulo length)
              @NT                     take the Tth element of N
             +                        add these two values
           +Z                         add Z (with is initially 0)
          =                           and update Z with the result
        ,T  Z                         make the pair of indices [T, Z] 
     @LN                              look-up their values in N
   XN                   )             and switch these two values in N
J                                 assign the result (the key setup) to J

=Z0                               set Z to 0

sCM+K.exCb@=XJ=N@LJ,hk=+Z@Jhk)sNw 
                                w read a string from input (message)
     .e                           map each index k, char b in message to:
                         @Jhk       look-up the (k+1)th element in J
                      =+Z           add it to Z and update Z
                   ,hk  Z           make the pair of indices [k+1,Z]
                @LJ                 look-up their values in J
              =N                    assign the result to N
            XJ N             )      swap these values in J
           =                        and update J with the result
          @  J                sN    take the sum(N)th element of J
        Cb                          convert b to int
       x                            bitwise xor of these two elements
   +K                             insert K at the beginning
 CM                               convert each element to char
s                                 sum them (generate a string)
                                  implicitly print
Jakube
la source
Apparemment, les fonctions Pyth intégrées n'ont pas de numéros pseudo-aléatoires sécurisés cryptographiquement . Vous pouvez conserver votre participation telle quelle, et elle ne sera pas qualifiée pour la coche verte, ou vous pouvez créer une version qui utilise urandom(qui peut être une entrée distincte si vous le souhaitez) si vous vous souciez de "gagner". :-)
Chris Jester-Young
@ ChrisJester-Young Désolé à ce sujet. Je ne pensais pas que le générateur de nombres aléatoires de Python était si peu sûr. Corrigé à un coût de 25 octets.
Jakube
4

Python 2 - 373 350 326 317 octets

Pyth arrivera peut-être plus tard. Définit une fonction, c(p,d,r,m)qui prend des listes d'octets pour la phrase secrète et les données, et int pour les répétitions et le mode qui crypte quand 1 et décrypte quand 0. C'est parce que la seule différence entre elles concerne le IV. Renvoie la liste d'octets.

import os
B=256
def c(p,d,r,m):
    if m:v=map(ord,os.urandom(10))
    else:v,d=d[:10],d[10:]
    p+=v;S=range(B);T=(p*B)[:B];j=0;exec"for i in range(B):j=(j+S[i]+T[i])%B;S[i],S[j]=S[j],S[i]\n"*r;o=[];i=j=0
    for b in d:i=-~i%B;j=(j+S[i])%B;S[i],S[j]=S[j],S[i];k=(S[i]+S[j])%B;o+=[S[k]^b]
    return v+o if m else o

Voici quelques fonctions de code de test / d'assistance:

phrase = "hello"
text = "Mary had a little lamb, little lamb, little lamb"
N = 5

def make_bytes(string):
    return map(ord, string)

def make_string(bytes):
    return "".join(map(chr, bytes))

def make_hex(bytes):
    return " ".join("%02x" % i for i in bytes)

def from_hex(hex_str):
    return [int(i, 16) for i in hex_str.split()]

cipher = c(make_bytes(phrase), make_bytes(text), N, 1)
print make_hex(cipher)
plain = c(make_bytes(phrase), cipher, N, 0)
print make_string(plain)
Maltysen
la source
Il vous suffit d'écrire un programme de cryptage. Vous pouvez donc retirer la else:v,d=d[:10],d[10:]pièce.
Jakube
3

Rubis - 263 caractères

Ceci est ma réponse Ruby à la question d'origine sur stackoverflow en 2010! C'est un encodeur et un décodeur tout en un seul programme

Les paramètres sont les suivants :
e ou d (pour codage ou de décodage)
touche
nombre de fois

$ ruby saber.rb e gnibbler 10 < in.txt | ruby saber.rb d gnibbler 10

o,k,l=ARGV;print o<'e'?(v=STDIN.read(10))*0:v=(0..9).map{rand(256).chr}.join;j=0;E=255
S=Array 0..255;(S*l.to_i).each{|i|j=j+S[i]+((k+v)*E)[i].ord&E;S[i],S[j]=S[j],S[i]};i=j=0
STDIN.each_byte{|c|i=i+1&E;j=j+S[i]&E;S[i],S[j]=S[j],S[i];print (c^S[S[i]+S[j]&E]).chr}
grignoteur
la source
2

C, 312 octets

Accepte une clé et le nombre d'itérations de mélange de clés sur la ligne de commande, puis chiffre tout sur stdin en stdout. Celui-ci utilise la fonction de bibliothèque BSD / Darwin arc4random(), qui est un PRNG basé sur RC4. Il se déclenche automatiquement, de sorte que les résultats seront différents à chaque fois.

unsigned char n,i,j,q,x,t,s[256],k[256];main(int c,char**v){for(strcpy(k,v[1]),n=strlen(k);x<10;x++)putchar(k[n++]=arc4random());do{s[i]=i;}while(++i);for(x=atoi(v[2]);x--;)do{t=s[i];s[i]=s[j+=s[i]+k[i%n]];s[j]=t;}while(++i);for(;(c=getchar())>0;){q+=s[++i];t=s[i];s[i]=s[q];s[q]=t;t=s[i]+s[q];putchar(c^s[t]);}}

Version plus ordonnée:

unsigned char n,i,j,q,x,t,s[256],k[256];
main(int c,char**v) {
  for (strcpy(k,v[1]),n=strlen(k);x<10;x++) putchar(k[n++]=arc4random());
  do {
    s[i]=i;
  }
  while(++i);
  for (x=atoi(v[2]);x--;) do {
    t=s[i];
    s[i]=s[j+=s[i]+k[i%n]];
    s[j]=t;
  }
  while (++i);
  for (;(c=getchar())>0;) {
    q+=s[++i];
    t=s[i];
    s[i]=s[q];
    s[q]=t;
    t=s[i]+s[q];
    putchar(c^s[t]);
  }
}

Exemple:

$ echo -n 'Ciphersaber' | ./csgolf 'hello' 20 | xxd -p
0f6257c330e5e01c3eab07bc9cb4ee4c3eaa514a85
r3mainer
la source
1

Python - 266 caractères

Ceci est ma réponse Python à la question d'origine sur stackoverflow en 2010! C'est un encodeur et un décodeur tout en un seul programme

Les paramètres sont les suivants :
e ou d (pour codage ou de décodage)
touche
nombre de fois

$ python saber.py e gnibbler 10 < in.txt | python saber.py d gnibbler 10

Cette version tente de fusionner les 2 boucles du rc4 en une seule (économise jusqu'à présent 11 octets ...)

import os,sys;X,Y=sys.stdin.read,os.write;_,o,k,l=sys.argv;p='d'<o
V=(X,os.urandom)[p](10);Y(1,V*p);E,S=255,range(256)
for q in S*int(l),X():
 t=q<'';j=0;i=-t
 for c in q:i=i+1&E;j=j+S[i]+t*ord(((k+V)*E)[i])&E;S[i],S[j]=S[j],S[i];t or Y(1,chr(ord(c)^S[S[i]+S[j]&E]))
grignoteur
la source