/* * jsmcrypt version 0.1 - Copyright 2012 F. Doering * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ //this creates a static class mcrypt that is already initialized var mcrypt=mcrypt?mcrypt:new function(){ //this allows the user to create instances of this class that keep //track of their own key, cipher, and mode //calling syntax becomes var myMcrypt=new mcrypt(); //var mcrypt=function(){ /********** * Private * **********/ /************************ * START OF CIPHER DEFFS * ************************/ /* Cipher Data * This is an object, keyed with the cipher name whose value is an * array containing the number of octets (bytes) in the block size, * and the number of octets in the key. */ var ciphers={ // block size, key size "rijndael-128" :[ 16, 32], "rijndael-192" :[ 24, 32], "rijndael-256" :[ 32, 32], "serpent" :[ 16, 32], } /* blockCipherCalls * This object is keyed by the cipher names and the vaules are * functions that calls external block ciphers to encypt or * decrypt a single block. These functions must have the arguments: * function(cipher_name,block,key,encrypt) * where: chipher_name is the text of the cipher name, * block is an array of inegers representing octets * key is a string * and encrypt indicates whether it should encrypt or decrypt * the block. * the function should modify the block as its output */ var blockCipherCalls={}; blockCipherCalls['rijndael-128']=function(cipher,block,key,encrypt){ if(key.length<32) key+=Array(33-key.length).join(String.fromCharCode(0)); if(encrypt) Rijndael.Encrypt(block,key); else Rijndael.Decrypt(block,key); return block; }; blockCipherCalls['rijndael-192']=blockCipherCalls['rijndael-128']; blockCipherCalls['rijndael-256']=blockCipherCalls['rijndael-128']; blockCipherCalls.serpent=function(cipher,block,key,encrypt){ if(encrypt) Serpent.Encrypt(block); else Serpent.Decrypt(block); return block; }; blockCipherCalls.serpent.init=function(cipher,key,encrypt){ var keyA=[]; for(var i=0;i=0; i--) iv[i] = IV.charCodeAt(i); break; case 'ecb': break; default: throw "mcrypt.Crypt: Unsupported mode of opperation"+cMode; } var chunks=Math.ceil(text.length/chunkS); var orig=text.length; text += Array(chunks * chunkS - orig + 1).join(String.fromCharCode((chunks * chunkS - orig))); var out=''; switch(mode){ case 'ecb': for(var i = 0; i < chunks; i++){ for(var j = 0; j < chunkS; j++) iv[j]=text.charCodeAt((i*chunkS)+j); blockCipherCalls[cipher](cipher,iv, cKey,encrypt); for(var j = 0; j < chunkS; j++) out+=String.fromCharCode(iv[j]); } break; case 'cbc': if(encrypt){ for(var i = 0; i < chunks; i++){ for(var j = 0; j < chunkS; j++) iv[j]=text.charCodeAt((i*chunkS)+j)^iv[j]; blockCipherCalls[cipher](cipher,iv, cKey,true); for(var j = 0; j < chunkS; j++) out+=String.fromCharCode(iv[j]); } } else{ for(var i = 0; i < chunks; i++){ var temp=iv; iv=new Array(chunkS); for(var j = 0; j < chunkS; j++) iv[j]=text.charCodeAt((i*chunkS)+j); var decr=iv.slice(0); blockCipherCalls[cipher](cipher,decr, cKey,false); for(var j = 0; j < chunkS; j++) out+=String.fromCharCode(temp[j]^decr[j]); } } break; case 'cfb': for(var i = 0; i < chunks; i++){ var temp=iv.slice(0); blockCipherCalls[cipher](cipher,temp, cKey,true); temp=temp[0]^text.charCodeAt(i); iv.push(encrypt?temp:text.charCodeAt(i)); iv.shift(); out+=String.fromCharCode(temp); } out=out.substr(0,orig); break; case 'ncfb': for(var i = 0; i < chunks; i++){ blockCipherCalls[cipher](cipher,iv, cKey,true); for(var j = 0; j < chunkS; j++){ var temp=text.charCodeAt((i*chunkS)+j); iv[j]=temp^iv[j]; out+=String.fromCharCode(iv[j]); if(!encrypt) iv[j]=temp; } } out=out.substr(0,orig); break; case 'nofb': for(var i = 0; i < chunks; i++){ blockCipherCalls[cipher](cipher,iv, cKey,true); for(var j = 0; j < chunkS; j++) out+=String.fromCharCode(text.charCodeAt((i*chunkS)+j)^iv[j]); } out=out.substr(0,orig); break; case 'ctr': for(var i = 0; i < chunks; i++){ temp=iv.slice(0); blockCipherCalls[cipher](cipher,temp, cKey,true); for(var j = 0; j < chunkS; j++) out+=String.fromCharCode(text.charCodeAt((i*chunkS)+j)^temp[j]); var carry=1; var index=chunkS; do{ index--; iv[index]+=1; carry=iv[index]>>8; iv[index]&=255; }while(carry) } out=out.substr(0,orig); break; } if(blockCipherCalls[cipher].deinit) blockCipherCalls[cipher].deinit(cipher,key,encrypt); return out; }; //Gets the block size of the specified cipher pub.get_block_size=function(cipher,mode){ if(!cipher) cipher=cCipher; if(!ciphers[cipher]) return false; return ciphers[cipher][0]; } //Gets the name of the specified cipher pub.get_cipher_name=function(cipher){ if(!cipher) cipher=cCipher; if(!ciphers[cipher]) return false; return cipher; } //Returns the size of the IV belonging to a specific cipher/mode combination pub.get_iv_size=function(cipher,mode){ if(!cipher) cipher=cCipher; if(!ciphers[cipher]) return false; return ciphers[cipher][0]; } //Gets the key size of the specified cipher pub.get_key_size=function(cipher,mode){ if(!cipher) cipher=cCipher; if(!ciphers[cipher]) return false; return ciphers[cipher][1]; } //Gets an array of all supported ciphers pub.list_algorithms=function(){ var ret=[]; for(var i in ciphers) ret.push(i); return ret; } pub.list_modes=function(){ return ['ecb','cbc','cfb','ncfb','nofb','ctr']; } /********** * Private * **********/ var cMode='cbc'; var cCipher='rijndael-128'; var cKey='12345678911234567892123456789312'; return pub; };