UNPKG

ig-trader

Version:

A client to programmatically spreadbet with IG

340 lines (322 loc) 14.3 kB
/*----------------------------------------------------------------------------*/ // Copyright (c) 2009 pidder <www.pidder.com> // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /*----------------------------------------------------------------------------*/ /* * AES CTR (Counter) Mode for use in pidCrypt Library * The pidCrypt AES CTR is based on the implementation by Chris Veness 2005-2008. * See http://www.movable-type.co.uk/scripts/aes.html for details and for his * great job. * * Depends on pidCrypt (pcrypt.js, pidcrypt_util.js), AES (aes_core.js) /*----------------------------------------------------------------------------*/ /* AES implementation in JavaScript (c) Chris Veness 2005-2008 * You are welcome to re-use these scripts [without any warranty express or * implied] provided you retain my copyright notice and when possible a link to * my website (under a LGPL license). §ection numbers relate the code back to * sections in the standard. /*----------------------------------------------------------------------------*/ var pidCrypt = require('./pidcrypt.js'); var pidCryptUtil = require('./pidcrypt_util.js'); require('./aes_core.js'); if(typeof(pidCrypt) != 'undefined' && typeof(pidCrypt.AES) != 'undefined') { pidCrypt.AES.CTR = function () { this.pidcrypt = new pidCrypt(); this.aes = new pidCrypt.AES(this.pidcrypt); //shortcuts to pidcrypt methods this.getOutput = function(){ return this.pidcrypt.getOutput(); } this.getAllMessages = function(lnbrk){ return this.pidcrypt.getAllMessages(lnbrk); } this.isError = function(){ return this.pidcrypt.isError(); } } /** * Initialize CTR for encryption from password. * @param password: String * @param options { * nBits: aes bit size (128, 192 or 256) * } */ pidCrypt.AES.CTR.prototype.init = function(password, options) { if(!options) options = {}; if(!password) this.pidcrypt.appendError('pidCrypt.AES.CTR.initFromEncryption: Sorry, can not crypt or decrypt without password.\n'); this.pidcrypt.setDefaults(); var pObj = this.pidcrypt.getParams(); //loading defaults for(var o in options) pObj[o] = options[o]; pObj.password = password; pObj.key = password; pObj.dataOut = ''; this.pidcrypt.setParams(pObj); this.aes.init(); } /** * Init CTR Encryption from password. * @param dataIn: plain text * @param password: String * @param options { * nBits: aes bit size (128, 192 or 256) * } */ pidCrypt.AES.CTR.prototype.initEncrypt = function(dataIn, password, options) { this.init(password, options); this.pidcrypt.setParams({dataIn:dataIn, encryptIn: pidCryptUtil.toByteArray(dataIn)})//setting input for encryption } /** * Init CTR for decryption from encrypted text (encrypted with pidCrypt.AES.CTR) * @param crypted: base64 encrypted text * @param password: String * @param options { * nBits: aes bit size (128, 192 or 256) * } */ pidCrypt.AES.CTR.prototype.initDecrypt = function(crypted, password, options){ var pObj = {}; this.init(password, options); pObj.dataIn = crypted; var cipherText = pidCryptUtil.decodeBase64(crypted); // recover nonce from 1st 8 bytes of ciphertext var salt = cipherText.substr(0,8);//nonce in ctr pObj.salt = pidCryptUtil.convertToHex(salt); cipherText = cipherText.substr(8) pObj.decryptIn = pidCryptUtil.toByteArray(cipherText); this.pidcrypt.setParams(pObj); } pidCrypt.AES.CTR.prototype.getAllMessages = function(lnbrk){ return this.pidcrypt.getAllMessages(lnbrk); } pidCrypt.AES.CTR.prototype.getCounterBlock = function(bs){ // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for // nonce in 1st 8 bytes, block counter in 2nd 8 bytes var ctrBlk = new Array(bs); var nonce = (new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970 var nonceSec = Math.floor(nonce/1000); var nonceMs = nonce%1000; // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling // 2nd 4 bytes for (var i=0; i<4; i++) ctrBlk[i] = (nonceSec >>> i*8) & 0xff; for (i=0; i<4; i++) ctrBlk[i+4] = nonceMs & 0xff; return ctrBlk.slice(); } /** * Encrypt a text using AES encryption in CTR mode of operation * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf * one of the pidCrypt.AES.CTR init funtions must be called before execution * * @param plaintext: text to encrypt * * * @return encrypted text */ pidCrypt.AES.CTR.prototype.encryptRaw = function(byteArray) { var aes = this.aes; var pidcrypt = this.pidcrypt; var p = pidcrypt.getParams(); //get parameters for operation set by init if(!byteArray) byteArray = p.encryptIn; pidcrypt.setParams({encryptIn:byteArray}); var password = p.key; // use AES itself to encrypt password to get cipher key (using plain // password as source for key expansion) - gives us well encrypted key var nBytes = Math.floor(p.nBits/8); // no bytes in key var pwBytes = new Array(nBytes); for (var i=0; i<nBytes; i++) pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i); var key = aes.encrypt(pwBytes.slice(0,16), aes.expandKey(pwBytes)); // gives us 16-byte key key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long var counterBlock = this.getCounterBlock(p.blockSize); // and convert it to a string to go on the front of the ciphertext var ctrTxt = pidCryptUtil.byteArray2String(counterBlock.slice(0,8)); pidcrypt.setParams({salt:pidCryptUtil.convertToHex(ctrTxt)}); // generate key schedule - an expansion of the key into distinct Key Rounds // for each round var keySchedule = aes.expandKey(key); var blockCount = Math.ceil(byteArray.length/p.blockSize); var ciphertxt = new Array(blockCount); // ciphertext as array of strings for (var b=0; b<blockCount; b++) { // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB) for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff; for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8) var cipherCntr = aes.encrypt(counterBlock, keySchedule); // -- encrypt counter block -- // block size is reduced on final block var blockLength = b<blockCount-1 ? p.blockSize : (byteArray.length-1)%p.blockSize+1; var cipherChar = new Array(blockLength); for (var i=0; i<blockLength; i++) { // -- xor plaintext with ciphered counter char-by-char -- cipherChar[i] = cipherCntr[i] ^ byteArray[b*p.blockSize+i]; cipherChar[i] = String.fromCharCode(cipherChar[i]); } ciphertxt[b] = cipherChar.join(''); } // alert(pidCryptUtil.encodeBase64(ciphertxt.join(''))); // Array.join is more efficient than repeated string concatenation var ciphertext = ctrTxt + ciphertxt.join(''); pidcrypt.setParams({dataOut:ciphertext, encryptOut:ciphertext}); //remove all parameters from enviroment for more security is debug off if(!pidcrypt.isDebug() && pidcrypt.clear) pidcrypt.clearParams(); return ciphertext; } /** * Encrypt a text using AES encryption in CTR mode of operation * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf * one of the pidCrypt.AES.CTR init funtions must be called before execution * * Unicode multi-byte character safe * * * @param plaintext: text to encrypt * * * @return encrypted text */ pidCrypt.AES.CTR.prototype.encrypt = function(plaintext) { var pidcrypt = this.pidcrypt; var p = pidcrypt.getParams(); //get parameters for operation set by init if(!plaintext) plaintext = p.dataIn; if(p.UTF8){ plaintext = pidCryptUtil.encodeUTF8(plaintext); pidcrypt.setParams({key:pidCryptUtil.encodeUTF8(pidcrypt.getParam('key'))}); } pidcrypt.setParams({dataIn:plaintext, encryptIn: pidCryptUtil.toByteArray(plaintext)}); var ciphertext = this.encryptRaw(); ciphertext = pidCryptUtil.encodeBase64(ciphertext); // encode in base64 pidcrypt.setParams({dataOut:ciphertext}); //remove all parameters from enviroment for more security is debug off if(!pidcrypt.isDebug() && pidcrypt.clear) pidcrypt.clearParams(); return ciphertext; } /** * Encrypt a text using AES encryption in CTR mode of operation * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf * one of the pidCrypt.AES.CTR init funtions must be called before execution * * Unicode multi-byte character safe * * @param dataIn: plain text * @param password: String * @param options { * nBits: aes bit size (128, 192 or 256) * } * * @return encrypted text */ pidCrypt.AES.CTR.prototype.encryptText = function(dataIn, password, options) { this.initEncrypt(dataIn, password, options); return this.encrypt(); } /** * Decrypt a text encrypted by AES in CTR mode of operation * * one of the pidCrypt.AES.CTR init funtions must be called before execution * * @param ciphertext: text to decrypt * * @return decrypted text as String */ pidCrypt.AES.CTR.prototype.decryptRaw = function(byteArray) { var pidcrypt = this.pidcrypt; var aes = this.aes; var p = pidcrypt.getParams(); //get parameters for operation set by init if(!byteArray) byteArray = p.decryptIn; pidcrypt.setParams({decryptIn:byteArray}); if(!p.dataIn) pidcrypt.setParams({dataIn:byteArray}); // use AES to encrypt password (mirroring encrypt routine) var nBytes = Math.floor(p.nBits/8); // no bytes in key var pwBytes = new Array(nBytes); for (var i=0; i<nBytes; i++) { pwBytes[i] = isNaN(p.key.charCodeAt(i)) ? 0 : p.key.charCodeAt(i); } var key = aes.encrypt(pwBytes.slice(0,16), aes.expandKey(pwBytes)); // gives us 16-byte key key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long var counterBlock = new Array(8); var ctrTxt = pidCryptUtil.convertFromHex(p.salt); for (i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i); // generate key schedule var keySchedule = aes.expandKey(key); // separate ciphertext into blocks (skipping past initial 8 bytes) var nBlocks = Math.ceil((byteArray.length) / p.blockSize); var blockArray = new Array(nBlocks); for (var b=0; b<nBlocks; b++) blockArray[b] = byteArray.slice(b*p.blockSize, b*p.blockSize+p.blockSize); // plaintext will get generated block-by-block into array of block-length // strings var plaintxt = new Array(blockArray.length); var cipherCntr = []; var plaintxtByte = []; for (b=0; b<nBlocks; b++) { // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) for (var c=0; c<4; c++) counterBlock[15-c] = ((b) >>> c*8) & 0xff; for (c=0; c<4; c++) counterBlock[15-c-4] = (((b+1)/0x100000000-1) >>> c*8) & 0xff; cipherCntr = aes.encrypt(counterBlock, keySchedule); // encrypt counter block plaintxtByte = new Array(blockArray[b].length); for (i=0; i<blockArray[b].length; i++) { // -- xor plaintxt with ciphered counter byte-by-byte -- plaintxtByte[i] = cipherCntr[i] ^ blockArray[b][i]; plaintxtByte[i] = String.fromCharCode(plaintxtByte[i]); } plaintxt[b] = plaintxtByte.join(''); } // join array of blocks into single plaintext string var plaintext = plaintxt.join(''); pidcrypt.setParams({dataOut:plaintext}); //remove all parameters from enviroment for more security is debug off if(!pidcrypt.isDebug() && pidcrypt.clear) pidcrypt.clearParams(); return plaintext; } /** * Decrypt a text encrypted by AES in CTR mode of operation * * one of the pidCrypt.AES.CTR init funtions must be called before execution * * @param ciphertext: text to decrypt * * @return decrypted text as String */ pidCrypt.AES.CTR.prototype.decrypt = function(ciphertext) { var pidcrypt = this.pidcrypt; var p = pidcrypt.getParams(); //get parameters for operation set by init if(ciphertext) pidcrypt.setParams({dataIn:ciphertext, decryptIn: pidCryptUtil.toByteArray(ciphertext)}); if(p.UTF8){ pidcrypt.setParams({key:pidCryptUtil.encodeUTF8(pidcrypt.getParam('key'))}); } var plaintext = this.decryptRaw(); plaintext = pidCryptUtil.decodeUTF8(plaintext); // decode from UTF8 back to Unicode multi-byte chars pidcrypt.setParams({dataOut:plaintext}); //remove all parameters from enviroment for more security is debug off if(!pidcrypt.isDebug() && pidcrypt.clear) pidcrypt.clearParams(); return plaintext; } /** * Decrypt a text encrypted by AES in CTR mode of operation * * one of the pidCrypt.AES.CTR init funtions must be called before execution * * @param crypted: base64 encrypted text * @param password: String * @param options { * * @return decrypted text as String */ pidCrypt.AES.CTR.prototype.decryptText = function(crypted, password, options) { this.initDecrypt(crypted, password, options); return this.decrypt(); } }