diff --git a/README.md b/README.md index bc67cf9..07d58f1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ - ================== -| TypeX Emulation | - ================== +# TypeX Emulation -This is a Javascript implementation of the British Cipher Machine - TypeX. I have translated this to Javascript from a [version written in C][1]. +This is a Javascript implementation of the British Rotor Cipher Machine - [TypeX][2]. The Enigma has been used as a basis for this code as they have very similar workings, this version is a translation to Javascript from a [version written in C][1]. Improvements that I have made to the original code include: -1. It no longer uses files for input / output. +1. No longer relies on files for input / output. 2. I have broken down the transformation into a better (more readable) format: The transformation steps are: @@ -27,27 +25,33 @@ The transformation steps are: 3. I wrote this with the intention of using it in a brute force attack. To do this we can iterate through all possible rotor settings / orientations. Please see brute_force.js for an example. -4. Input validation has been modularised. +4. Input validation is cleaner. 5. Removed goto's, general housekeeping. +6. Speed is almost double to that of the C implementation due to caching and no file read / writes (which helps when it comes to brute forcing). + ##### Example 1 - Encoding ```javascript var demo1 = TypeX.init('01234', '00100', 'AOAKN', 'This is the string to be encoded'); -console.log(demo1); //demo1 == KLHESNYNIMQAZHIZROBHDZHKWRQFFRTY ``` ##### Example 2 - Decoding ```javascript var demo2 = TypeX.init('01234', '00100', 'AOAKN', 'KLHESNYNIMQAZHIZROBHDZHKWRQFFRTY'); -console.log(demo2); //demo2 == THISXISXTHEXSTRINGXTOXBEXENCODED ``` ##### Brute Force -The code in brute_force.js loops through every possible rotor position and orientation. This assumes that we know the indicator key. +The code in brute_force.js loops through every possible rotor position and orientation. It then inserts (in batches) the results into a Mongo collection. + +To run this Javascript you will need Node with the [native Mongo module][3] installed. + +The brute force method assumes that we know the indicator key. + +The indicator key is 5 letters (A-Z), that indicate the starting position of each rotor. ```javascript //Rotor orientations (5^2) @@ -73,8 +77,12 @@ if((/(\d)(?=.*\1)/).test(rotorPos)) continue; var cipher_text = TypeX.init(rotorPos, rotorOri, 'AOAKN', 'KLHESNYNIMQAZHIZROBHDZHKWRQFFRTY'); ``` -In the above example, there are 215,000 possible rotor settings, of which we can harvest them into a database. We can then crawl this database and search for cribs, or we can perform a common bigram / trigram count which is probably an easier way to reduce this number. +In the above example, there are 215,000 possible rotor settings, we can then harvest them into a database for further processing. + +We can then crawl this database and search for cribs, or we can perform a common bigram / trigram count which is probably an easier way to reduce this number. -See function ngram(str, n) in brute_force.js for an example of how to add these counts to your database. +See brute_force.js for an example of how to add an ngram count to your database. -[1]: http://scholarworks.sjsu.edu/cgi/viewcontent.cgi?article=1244&context=etd_projects \ No newline at end of file +[1]: http://scholarworks.sjsu.edu/cgi/viewcontent.cgi?article=1244&context=etd_projects +[2]: http://en.wikipedia.org/wiki/Typex +[3]: https://github.com/mongodb/node-mongodb-native \ No newline at end of file diff --git a/brute_force.js b/brute_force.js new file mode 100644 index 0000000..ee2c1cc --- /dev/null +++ b/brute_force.js @@ -0,0 +1,123 @@ +require("./typex.js"); + +var mongo = require('mongodb'); + +var Inserter = function (collection) { + this.collection = collection; + this.data = []; + this.maxThreads = 30; + this.currentThreads = 0; + this.batchSize = 1000; + this.queue = 0; + this.inserted = 0; + this.startTime = Date.now(); +}; + +Inserter.prototype.add = function(data) { + this.data.push(data); +}; + +// Use force=true for last insert +Inserter.prototype.insert = function(force) { + var that = this; + if (this.data.length >= this.batchSize || force) { + if (this.currentThreads >= this.maxThreads) { + this.queue++; + return; + } + this.currentThreads++; + console.log('Threads: ' + this.currentThreads); + this.collection.insert(this.data.splice(0, this.batchSize), {safe:true}, function() { + that.inserted += that.batchSize; + var currentTime = Date.now(); + var workTime = Math.round((currentTime - that.startTime) / 1000) + console.log('Speed: ' + that.inserted / workTime + ' per sec'); + that.currentThreads--; + if (that.queue > 0) { + that.queue--; + that.insert(); + } + }); + } +}; + +ngram = function(str,n) { + //http://norvig.com/mayzner.html + var ngrams = [[],[], + ["th","he","in","er","an"], // 2grams + ["the","and","ing","ion","tio"] // 3grams + ]; + + var total = 0; + for (var i in ngrams[n]) { + var re = new RegExp(ngrams[n][i], 'gi'); + if((didMatch = str.match(re))) { + total += didMatch.length; + } + } + return total; + +}; + +var db = new mongo.Db('test', new mongo.Server('localhost', 27017, {w:1}), {native_parser:false}); + +db.open(function(err, db) { + db.collection('typexResults', function(err, collection) { + + var inserter = new Inserter(collection); + var cipher_text = 'HVPKDFNFJWYIDDCRQXSRDJHFPGOVFNMIAPXPABUZWYYNPCMPNWHJRZHNLXKGMEMKKONOIBAKEEQWAOTARBQRHDJOFMTPZEHLKXGHRGGHTJRZCQFNKTQKLDTSFQIRW'; + var indicator = 'AOAKN'; + x = 0; + + //Rotor orientations (5^2) + for (r1 = 0; r1 <= 1; r1++) { + for (r2 = 0; r2 <= 1; r2++) { + for (r3 = 0; r3 <= 1; r3++) { + for (r4 = 0; r4 <= 1; r4++) { + for (r5 = 0; r5 <= 1; r5++) { + + //Rotor positions (5^7) + for (a = 0; a <=7; a++) { + for (b = 0; b <=7; b++) { + for (c = 0; c <=7; c++) { + for (d = 0; d <=7; d++) { + for (e = 0; e <=7; e++) { + + rotorPos = a.toString() + b + c + d + e; + rotorOri = r1.toString() + r2 + r3 + r4 + r5; + + if((/(\d)(?=.*\1)/).test(rotorPos)) continue; + + var ct_val = TypeX.init(rotorPos, rotorOri, indicator, cipher_text); + + inserter.add({ + c_text: ct_val, + two_gram: ngram(ct_val,2), + three_gram: ngram(ct_val,3), + rotor_position: rotorPos, + rotor_orientation: rotorOri + }); + + if(x%5000===0) { + inserter.insert(); + } + + x++; + + } + } + } + } + } + + } + } + } + } + } + + //Final batch insert + inserter.insert(true); + + }); +}); \ No newline at end of file