Last active
August 29, 2015 14:16
-
-
Save ccckmit/b0a90a7bd9d3d3e5baa8 to your computer and use it in GitHub Desktop.
javascript version of enigma machine (in world war II)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 原始程式來源: http://practicalcryptography.com/ciphers/enigma-cipher/ 網頁內的 javascript 程式碼 | |
var c = console; | |
var plaintext = 'ABCDEF'; | |
c.log('>> plaintext2 : '+plaintext); | |
var ciphertext = Encrypt(plaintext, 'AAA', 'AAA', '123', 'POMLIUKJNHYTGBVFREDC'); | |
c.log('>> ciphertext : '+ciphertext); | |
var plaintext2 = Encrypt(ciphertext, 'AAA', 'AAA', '123', 'POMLIUKJNHYTGBVFREDC'); | |
c.log('>> plaintext2 : '+plaintext); | |
function Encrypt(plaintext, keysettings, ringsettings, rotorsettings, plugboardsettings) { | |
c.log('plaintext='+plaintext); | |
c.log('keysetting='+keysettings); | |
c.log('ringsetting='+ringsettings); | |
c.log('plugboardsettings='+plugboardsettings+' len='+plugboardsettings.length); | |
c.log('rotorsettings='+rotorsettings); | |
// do some error checking | |
if(plaintext.length < 1){ c.log("please enter some plaintext (letters and numbers only)"); return; } | |
if(keysettings.length != 3){ c.log("Key settings must consist of 3 uppercase characters."); return; } | |
if(ringsettings.length != 3){ c.log("Ring settings must consist of 3 uppercase characters."); return; } | |
if(plugboardsettings.length > 26){ c.log("There cannot be more than 13 pairs in the plugboard settings."); return; } | |
if(plugboardsettings.length % 2 != 0){ c.log("There must be an even number of characters in the plugboard settings."); return; } | |
if(rotorsettings.length != 3){ c.log("Rotor settings must consist of 3 numbers 1-9."); return; } | |
// interpret the rotor settings (strings 1-8 to int 0-7) | |
var rotors = rotorsettings.split(""); | |
rotors[0]=rotors[0].valueOf()-1;rotors[1]=rotors[1].valueOf()-1;rotors[2]=rotors[2].valueOf()-1; | |
// parse plugboard settings, store as a simple substitution key | |
var plugboard = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
var parr = plugboard.split(""); | |
for(i=0,j=1;i<plugboardsettings.length;i+=2,j+=2){ | |
ichar = plugboard.indexOf(plugboardsettings.charAt(i)); | |
jchar = plugboard.indexOf(plugboardsettings.charAt(j)); | |
temp = parr[jchar]; parr[jchar]=parr[ichar]; parr[ichar]=temp; | |
} | |
plugboard = parr.join(""); | |
// interpret key and ring settings (convert from letters to numbers 0-25) | |
key=keysettings.split(""); | |
key[0]=code(key[0]); key[1]=code(key[1]); key[2]=code(key[2]); | |
ring=ringsettings.split(""); | |
ring[0]=code(ring[0]); ring[1]=code(ring[1]); ring[2]=code(ring[2]); | |
// do the actual enigma enciphering | |
ciphertext = ""; | |
for(i=0; i < plaintext.length; i++){ | |
ch=plaintext.charAt(i); | |
// if the current character is not a letter, pass it through unchanged | |
if(!ch.match(/[A-Z]/)){ | |
ciphertext = ciphertext + ch; | |
}else{ | |
key=increment_settings(key,rotors); | |
ciphertext = ciphertext + enigma(ch,key,rotors,ring,plugboard); | |
} | |
} | |
c.log('ciphertext='+ciphertext); | |
return ciphertext; | |
} | |
function enigma(ch,key,rotors,ring,plugboard){ | |
// apply plugboard transformation | |
ch = simplesub(ch,plugboard); | |
// apply rotor transformations from right to left | |
ch = rotor(ch,rotors[2],key[2]-ring[2]); | |
ch = rotor(ch,rotors[1],key[1]-ring[1]); | |
ch = rotor(ch,rotors[0],key[0]-ring[0]); | |
// use reflector B | |
ch = simplesub(ch,"YRUHQSLDPXNGOKMIEBFZCWVJAT"); | |
// apply inverse rotor transformations from left to right | |
ch = rotor(ch,rotors[0]+8,key[0]-ring[0]); | |
ch = rotor(ch,rotors[1]+8,key[1]-ring[1]); | |
ch = rotor(ch,rotors[2]+8,key[2]-ring[2]); | |
// apply plugboard transformation again | |
ch = simplesub(ch,plugboard); | |
return ch; | |
} | |
function increment_settings(key,r){ | |
//notch = [['Q','Q'],['E','E'],['V','V'],['J','J'],['Z','Z'],['Z','M'],['Z','M'],['Z','M']]; | |
// The notch array stores the positions at which each rotor kicks over the rotor to its left | |
var notch = [[16,16],[4,4],[21,21],[9,9],[25,25],[25,12],[25,12],[25,12]]; | |
if(key[1] == notch[r[1]][0] || key[1] == notch[r[1]][1]){ | |
key[0] = (key[0]+1)%26; | |
key[1] = (key[1]+1)%26; | |
} | |
if(key[2] == notch[r[2]][0] || key[2] == notch[r[2]][1]){ | |
key[1] = (key[1]+1)%26; | |
} | |
key[2] = (key[2]+1)%26; | |
return key; | |
} | |
// perform a simple substitution cipher | |
function simplesub(ch,key){ | |
return key.charAt(code(ch)); | |
} | |
function rotor(ch,r,offset){ | |
// The first eight strings represent the rotor substitutions I through VIII. The second 8 are the | |
// inverse transformations | |
var key = ["EKMFLGDQVZNTOWYHXUSPAIBRCJ","AJDKSIRUXBLHWTMCQGZNPYFVOE","BDFHJLCPRTXVZNYEIWGAKMUSQO", | |
"ESOVPZJAYQUIRHXLNFTGKDCMWB","VZBRGITYUPSDNHLXAWMJQOFECK","JPGVOUMFYQBENHZRDKASXLICTW", | |
"NZJHGRCXMYSWBOUFAIVLPEKQDT","FKQHTLXOCBJSPDZRAMEWNIUYGV", | |
// inverses | |
"UWYGADFPVZBECKMTHXSLRINQOJ","AJPCZWRLFBDKOTYUQGENHXMIVS","TAGBPCSDQEUFVNZHYIXJWLRKOM", | |
"HZWVARTNLGUPXQCEJMBSKDYOIF","QCYLXWENFTZOSMVJUDKGIARPHB","SKXQLHCNWARVGMEBJPTYFDZUIO", | |
"QMGYVPEDRCWTIANUXFKZOSLHJB","QJINSAYDVKBFRUHMCPLEWZTGXO"]; | |
// the following code looks a bit horrible, but it is essentially just doing a simple substitution | |
// taking into account 16 possible keys (8 rotors and their inverses) and the offset (which is calculated | |
// from the indicator and ring settings). The offset essentially shifts the rotor key to the left or right | |
var chcode = (code(ch)+26+offset)%26; | |
var mapch = (code( key[r].charAt(chcode) ) +26-offset)%26 +65; | |
return String.fromCharCode(mapch); | |
} | |
// return the number 0-25 given a letter [A-Za-z] | |
function code(ch){return ch.toUpperCase().charCodeAt(0) - 65;} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
$ node enigma.js
plaintext=ABCDEF
keysetting=AAA
ringsetting=AAA
plugboardsettings=POMLIUKJNHYTGBVFREDC len=20
rotorsettings=123
ciphertext=GWKGRC
plaintext=GWKGRC
keysetting=AAA
ringsetting=AAA
plugboardsettings=POMLIUKJNHYTGBVFREDC len=20
rotorsettings=123
ciphertext=ABCDEF