Aperçu
Votre objectif est d'implémenter le cryptage RC4. Le cryptage RC4, inventé par Ron Rivest (de renommée RSA), a été conçu pour être sécurisé, mais suffisamment simple pour être implémenté de mémoire par des militaires sur le champ de bataille. Aujourd'hui, il y a plusieurs attaques sur RC4, mais il est toujours utilisé dans de nombreux endroits aujourd'hui.
Votre programme doit accepter une seule chaîne avec à la fois une clé et des données. Il sera présenté dans ce format.
\x0Dthis is a keythis is some data to encrypt
Le premier octet représente la longueur de la clé. On peut supposer que la clé ne dépassera pas 255 octets et pas moins de 1 octet. Les données peuvent être arbitrairement longues.
Votre programme doit traiter la clé, puis renvoyer les données chiffrées. Le cryptage et le décryptage RC4 sont identiques, donc en utilisant la même clé pour "crypter" le texte chiffré doit retourner le texte en clair d'origine.
Comment fonctionne RC4
Initialisation
L'initialisation de RC4 est assez simple. Un tableau d'état de 256 octets est initialisé à tous les octets de 0 à 255.
S = [0, 1, 2, 3, ..., 253, 254, 255]
Traitement des clés
Les valeurs de l'état sont échangées en fonction de la clé.
j = 0
for i from 0 to 255
j = (j + S[i] + key[i mod keylength]) mod 256
swap S[i] and S[j]
Chiffrement
Le chiffrement est accompli en utilisant l'état pour générer des octets pseudo-aléatoires, qui sont ensuite XOR pour les données. Les valeurs de l'état sont constamment échangées.
i = j = 0
for each byte B in data
i = (i + 1) mod 256
j = (j + S[i]) mod 256
swap S[i] and S[j]
K = S[(S[i] + S[j]) mod 256]
output K XOR B
Entrées et sorties attendues
Les caractères non imprimables seront affichés dans \xAB
format.
Entrée: \x01\x00\x00\x00\x00\x00\x00
Sortie:\xde\x18\x89A\xa3
Sortie (hex):de188941a3
Entrée: \x0Dthis is a keythis is some data to encrypt
Sortie: \xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Sortie (hex):b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Entrée: \x0dthis is a key\xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
Entrée (hex): 0d746869732069732061206b6579b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
Sortie:this is some data to encrypt
Entrée: Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted
Sortie: \x96\x1f,\x8f\xa3%\x9b\xa3f[mk\xdf\xbc\xac\x8b\x8e\xfa\xfe\x96B=!\xfc;\x13`c\x16q\x04\x11\xd8\x86\xee\x07
Sortie (hex):961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07
la source
\xde
, alors il devrait être long de 1 octet, et le convertir en un nombre (via pythonord()
ou javascript.charCodeAt(0)
) devrait retourner 222 (0xDE).Réponses:
JavaScript (ES6),
169168 octetsPrend l'entrée comme un tableau d'octets. Renvoie un autre tableau d'octets.
Comment?
Il s'agit essentiellement d'une implémentation littérale de la spécification.
Nous divisons d'abord le tableau d'entrée en l (longueur de clé) et s (données utiles: clé + message). Ensuite, par ordre d'exécution:
Nous initialisons le tableau d'états S et définissons m = 255 qui est utilisé à plusieurs reprises plus tard comme masque de bits.
Nous mélangeons le tableau d'état. Les indices I et J qui sont initialisés ici sont effectivement utilisés dans l'étape suivante.
Nous appliquons le cryptage.
Cas de test
Afficher l'extrait de code
la source
138 octets, code machine (16 bits x86)
En cours d'exécution: enregistrer sur codegolf.com, dosbox:
codegolf.com < input.bin
Je ne sais pas si cela va compter comme une entrée, mais j'ai décidé de le faire manuellement en utilisant des éditeurs hexadécimaux. Pas de compilateurs été utilisé pour ce faire.
l'éditeur ht a en fait un assembleur, mais honnêtement, je ne savais pas à ce sujet jusqu'à ce que j'aie fini ¯ \ _ (ツ) _ / ¯
Pourquoi comment
Pourquoi: principalement parce que je voulais vérifier si je pouvais le faire.
Comment: j'ai commencé à créer un octet rempli de
NOP
s et à suivre avec une partie simple: essayer d'écrire la première boucle qui remplitS
tate avec des valeurs de 0 à 255. Je suis passé à python et j'ai rapidement écrit la version python, juste pour avoir quelque chose à tester. Ensuite, je simplifiais le code python en pseudo code / pseudo assembleur. Puis j'ai essayé d'écrire de petits morceaux. J'ai décidé qu'il serait plus facile de lire à partir de stdin, alors j'ai commencé avec quelque chose de petit qui lira un octet, puis j'ai ajouté la lecture du mot de passe et l'initialisation de la clé. Trouver les registres à choisir m'a pris du temps.Je pensais que l'ajout d'une boucle de / cryptage serait facile, mais j'ai d'abord obtenu un décodage à un octet et j'ai ajouté une boucle entière par la suite.
La dernière étape consistait à éliminer les éléments supplémentaires
nops
que j'avais laissés entre les instructions lors de l'écriture (souvent, cela nécessitait également de réparer les sauts).Vous pouvez voir une petite galerie que j'ai essayé de faire en progressant ici .
Dissection
Le programme s'appuie sur certaines valeurs initiales après le démarrage (voir les ressources ci-dessous).
remplir l'état (à 0x200)
lire la longueur, lire le mot de passe, stocker le mot de passe à ds: 0x300
initialiser l'état avec une clé (
BP
est utilisé pour parcourir la clé,SI
est utilisé pour traverser l'état)générer une valeur pseudo aléatoire (en
DL
,DH
est 0 thx à xor à 0x140)SI
- les entiers n'y toucheront pasBX
)DX
)PS Cela pourrait probablement être encore plus court, mais cela a pris 4 soirées, donc je ne sais pas si je veux en passer un autre ...
Outils et ressources
la source
C (gcc) ,
193 188 182 178 171172 172 octetsEssayez-le en ligne!
Modifier: fonctionne maintenant avec des clés de plus de 127 octets.
Edit2: Ajout d'un cas de test avec une clé de 129 octets au lien TIO.
Version légèrement moins golfée
la source
Jeu d'instructions CPU x86, 133 octets
A7D-9F8 = 85h = 133 octets mais je ne sais pas si le calcul est correct car le nombre d'octets précédent de la même fonction donne 130 octets ... Le premier argumenti de la fonction que je nomme "cript" est la chaîne, le deuxième argumenti est la longueur de la chaîne (premier octet + longueur de la clé + longueur du message). Ci-dessous, il y a le fichier de langage d'assemblage pour obtenir ces routines de cryptage:
sous le fichier C pour les résultats de la vérification:
Les resultats:
la source
JavaScript (ES6), 262 octets
J'ai envisagé d'utiliser uniquement des fonctions chaînées, mais j'ai choisi de golfifier l'algorithme donné ici: https://gist.github.com/farhadi/2185197 .
Moins de golf
Afficher l'extrait de code
la source
Python 2 , 203 octets
Essayez-le en ligne!
f
est un générateur (itérable) de chaînes.Non golfé:
la source
Rubis, 234 octets
Non testé.
la source
C, 181 octets
merci à plafondcat pour quelques octets de moins:
f (a, n) dans "a" il y aurait le tableau de caractères 1Byte len + clé + message; en n il y a la taille du tableau all de "a" sans compter le dernier '\ 0'. le code pour le test et le résultat serait celui utilisé pour la fonction d'assemblage.
la source
APL (NARS), 329 caractères, 658 octets
comme toujours, le contrôle d'erreur serait demandé à quelqu'un d'autre ... Cela semble être correct en entrée et en sortie, test:
Oui tout peut être réduit ... mais par exemple rendre plus petit la fonction xor pourrait signifier la rendre moins générale ...
la source
Rouille 348
C'est assez grand, j'espère que quelqu'un pourrait peut-être faire des suggestions.
ungolfed: sur le terrain de jeu play.rust-lang.org
la source
k
place dekey
etm
au lieu demsg
et à lafoo&255
place de(foo)%256