├── package.json ├── LICENSE ├── README.md ├── test.js ├── sha1.js ├── sha256.js ├── tea-block.js ├── aes.js └── aes-ctr.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crypto-libraries", 3 | "description": "Collection of cryptographic routines", 4 | "repository": { "type": "git", "url": "https://github.com/chrisveness/crypto" }, 5 | "author": "Chris Veness", 6 | "version": "0.0.0", 7 | "devDependencies": { 8 | "browserify": "^4.0.0", 9 | "tap-spec": "^0.2.0", 10 | "tape": "^2.12.0" 11 | }, 12 | "testling": { 13 | "files": "test.js", 14 | "browsers": [ 15 | "iexplore/7..latest", 16 | "chrome/26..latest", 17 | "firefox/21..latest", 18 | "safari/4..latest", 19 | "opera/11.5..latest", 20 | "iphone/6..latest", 21 | "ipad/6..latest", 22 | "android-browser/4.2..latest" 23 | ] 24 | }, 25 | "scripts": { 26 | "test": "tape test.js | tap-spec" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Chris Veness 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | crypto 2 | ====== 3 | 4 | Libraries of cryptographic functions implemented in JavaScript. 5 | 6 | aes.js 7 | ------ 8 | 9 | This is a reference implementation of the algorithm described in the FIPS-197 standard. It implements 10 | the standard very closely, in order to aid in understanding the standard and the algorithm itself. 11 | 12 | This comprises: 13 | 14 | - `cipher`: takes a 128-bit input block and applies the cipher algorithm to produce a 128-bit output block 15 | - `keyExpansion`: applies a key expansion to a 128-/192-/256-bit cipher key to produce a 2D byte-array 16 | key schedule for the cipher routine 17 | 18 | More details are available at www.movable-type.co.uk/scripts/aes.html. 19 | 20 | aes-ctr.js 21 | ---------- 22 | 23 | This is a counter-mode (CTR) wrapper for the AES function. 24 | 25 | This comprises: 26 | 27 | - `encrypt`: encrypt a plaintext using a supplied password 28 | - `decrypt`: decrypt an encrypted ciphertext using a supplied password 29 | 30 | Note that there are no standards for data storage formats of AES encryption mode wrapper functions, 31 | so this is unlikely to inter-operate with standard library functions. 32 | 33 | More details are available at www.movable-type.co.uk/scripts/aes.html. 34 | 35 | sha1.js 36 | ------- 37 | 38 | This is a reference implementation of the algorithm described in the FIPS-180-2 standard. It implements 39 | the standard very closely, in order to aid in understanding the standard and the algorithm itself. 40 | 41 | This comprises: 42 | 43 | - `hash`: takes a (Unicode) string and generates a hash (of the UTF-8 encoded string) 44 | 45 | More details are available at www.movable-type.co.uk/scripts/sha1.html. 46 | 47 | sha256.js 48 | ------- 49 | 50 | This is a reference implementation of the algorithm described in the FIPS-180-2 standard. It implements 51 | the standard very closely, in order to aid in understanding the standard and the algorithm itself. 52 | 53 | This comprises: 54 | 55 | - `hash`: takes a (Unicode) string and generates a hash (of the UTF-8 encoded string) 56 | 57 | More details are available at www.movable-type.co.uk/scripts/sha256.html. 58 | 59 | 60 | tea-block.js 61 | ------------ 62 | 63 | Wheeler & Needham’s *Tiny Encryption Algorithm* is a simple but powerful encryption algorithm which 64 | provides strong encryption in just a few lines of concise, clear code. This implements the (corrected) 65 | ‘Block TEA’ variant (xxtea). 66 | 67 | The library includes: 68 | 69 | - `encrypt` a text with a password 70 | - `decrypt` an encrypted text 71 | - `encode` an array of longs using a 128-bit key 72 | - `decode` an encoded array of longs 73 | 74 | More details are available at www.movable-type.co.uk/scripts/tea-block.html. 75 | 76 | Documentation 77 | ------------- 78 | 79 | Documentation for all these methods is available at www.movable-type.co.uk/scripts/js/crypto/docs. 80 | 81 | Browser support 82 | --------------- 83 | 84 | [![browser support](https://ci.testling.com/chrisveness/crypto.png)](https://ci.testling.com/chrisveness/crypto) 85 | 86 | IE9- doesn’t have btoa()/atob(): if you need to support IE9-, you can use David Chambers’ 87 | [Base64 polyfill](https://github.com/davidchambers/Base64.js). 88 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2 | // Crypto Test Harness (c) Chris Veness 2014 */ 3 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 4 | 'use strict' 5 | 6 | var test = require('tape'); 7 | 8 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 9 | /* AES - test vectors: csrc.nist.gov/publications/fips/fips197/fips-197.pdf C.1 */ 10 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 11 | 12 | test('aes', function(assert) { 13 | var Aes = require('./aes.js'); 14 | 15 | var plaintext = vectorToBytes('00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff'); 16 | 17 | var key128 = vectorToBytes('00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f'); 18 | var cipher128 = vectorToBytes('69 c4 e0 d8 6a 7b 04 30 d8 cd b7 80 70 b4 c5 5a'); 19 | 20 | var key192 = vectorToBytes('00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17'); 21 | var cipher192 = vectorToBytes('dd a9 7c a4 86 4c df e0 6e af 70 a0 ec 0d 71 91'); 22 | 23 | var key256 = vectorToBytes('00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f'); 24 | var cipher256 = vectorToBytes('8e a2 b7 ca 51 67 45 bf ea fc 49 90 4b 49 60 89'); 25 | 26 | assert.deepEqual(Aes.cipher(plaintext, Aes.keyExpansion(key128)), cipher128, 'Aes-128-bit test vector'); 27 | assert.deepEqual(Aes.cipher(plaintext, Aes.keyExpansion(key192)), cipher192, 'Aes-192-bit test vector'); 28 | assert.deepEqual(Aes.cipher(plaintext, Aes.keyExpansion(key256)), cipher256, 'Aes-256-bit test vector'); 29 | assert.end(); 30 | 31 | function vectorToBytes(v) { 32 | var a = v.split(/ /); 33 | for (var i=0; i>> 32, but since JS converts 51 | // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators 52 | M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]); 53 | M[N-1][15] = ((msg.length-1)*8) & 0xffffffff; 54 | 55 | // set initial hash value [§5.3.1] 56 | var H0 = 0x67452301; 57 | var H1 = 0xefcdab89; 58 | var H2 = 0x98badcfe; 59 | var H3 = 0x10325476; 60 | var H4 = 0xc3d2e1f0; 61 | 62 | // HASH COMPUTATION [§6.1.2] 63 | 64 | var W = new Array(80); var a, b, c, d, e; 65 | for (var i=0; i>>(32-n)); 117 | }; 118 | 119 | 120 | /** 121 | * Hexadecimal representation of a number. 122 | * @private 123 | */ 124 | Sha1.toHexStr = function(n) { 125 | // note can't use toString(16) as it is implementation-dependant, 126 | // and in IE returns signed numbers when used on full words 127 | var s="", v; 128 | for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); } 129 | return s; 130 | }; 131 | 132 | 133 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 134 | 135 | 136 | /** Extend String object with method to encode multi-byte string to utf8 137 | * - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */ 138 | if (typeof String.prototype.utf8Encode == 'undefined') { 139 | String.prototype.utf8Encode = function() { 140 | return unescape( encodeURIComponent( this ) ); 141 | }; 142 | } 143 | 144 | /** Extend String object with method to decode utf8 string to multi-byte */ 145 | if (typeof String.prototype.utf8Decode == 'undefined') { 146 | String.prototype.utf8Decode = function() { 147 | try { 148 | return decodeURIComponent( escape( this ) ); 149 | } catch (e) { 150 | return this; // invalid UTF-8? return as-is 151 | } 152 | }; 153 | } 154 | 155 | 156 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 157 | if (typeof module != 'undefined' && module.exports) module.exports = Sha1; // CommonJs export 158 | if (typeof define == 'function' && define.amd) define([], function() { return Sha1; }); // AMD 159 | -------------------------------------------------------------------------------- /sha256.js: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2 | /* SHA-256 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */ 3 | /* */ 4 | /* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */ 5 | /* http://csrc.nist.gov/groups/ST/toolkit/examples.html */ 6 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 7 | 8 | /* jshint node:true *//* global define, escape, unescape */ 9 | 'use strict'; 10 | 11 | 12 | /** 13 | * SHA-256 hash function reference implementation. 14 | * 15 | * @namespace 16 | */ 17 | var Sha256 = {}; 18 | 19 | 20 | /** 21 | * Generates SHA-256 hash of string. 22 | * 23 | * @param {string} msg - String to be hashed 24 | * @returns {string} Hash of msg as hex character string 25 | */ 26 | Sha256.hash = function(msg) { 27 | // convert string to UTF-8, as SHA only deals with byte-streams 28 | msg = msg.utf8Encode(); 29 | 30 | // constants [§4.2.2] 31 | var K = [ 32 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 33 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 34 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 35 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 36 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 37 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 38 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 39 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ]; 40 | // initial hash value [§5.3.1] 41 | var H = [ 42 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ]; 43 | 44 | // PREPROCESSING 45 | 46 | msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1] 47 | 48 | // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1] 49 | var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length 50 | var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints 51 | var M = new Array(N); 52 | 53 | for (var i=0; i>> 32, but since JS converts 62 | // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators 63 | M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]); 64 | M[N-1][15] = ((msg.length-1)*8) & 0xffffffff; 65 | 66 | 67 | // HASH COMPUTATION [§6.1.2] 68 | 69 | var W = new Array(64); var a, b, c, d, e, f, g, h; 70 | for (var i=0; i>> n) | (x << (32-n)); 114 | }; 115 | 116 | /** 117 | * Logical functions [§4.1.2]. 118 | * @private 119 | */ 120 | Sha256.Σ0 = function(x) { return Sha256.ROTR(2, x) ^ Sha256.ROTR(13, x) ^ Sha256.ROTR(22, x); }; 121 | Sha256.Σ1 = function(x) { return Sha256.ROTR(6, x) ^ Sha256.ROTR(11, x) ^ Sha256.ROTR(25, x); }; 122 | Sha256.σ0 = function(x) { return Sha256.ROTR(7, x) ^ Sha256.ROTR(18, x) ^ (x>>>3); }; 123 | Sha256.σ1 = function(x) { return Sha256.ROTR(17, x) ^ Sha256.ROTR(19, x) ^ (x>>>10); }; 124 | Sha256.Ch = function(x, y, z) { return (x & y) ^ (~x & z); }; 125 | Sha256.Maj = function(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); }; 126 | 127 | 128 | /** 129 | * Hexadecimal representation of a number. 130 | * @private 131 | */ 132 | Sha256.toHexStr = function(n) { 133 | // note can't use toString(16) as it is implementation-dependant, 134 | // and in IE returns signed numbers when used on full words 135 | var s="", v; 136 | for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); } 137 | return s; 138 | }; 139 | 140 | 141 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 142 | 143 | 144 | /** Extend String object with method to encode multi-byte string to utf8 145 | * - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */ 146 | if (typeof String.prototype.utf8Encode == 'undefined') { 147 | String.prototype.utf8Encode = function() { 148 | return unescape( encodeURIComponent( this ) ); 149 | }; 150 | } 151 | 152 | /** Extend String object with method to decode utf8 string to multi-byte */ 153 | if (typeof String.prototype.utf8Decode == 'undefined') { 154 | String.prototype.utf8Decode = function() { 155 | try { 156 | return decodeURIComponent( escape( this ) ); 157 | } catch (e) { 158 | return this; // invalid UTF-8? return as-is 159 | } 160 | }; 161 | } 162 | 163 | 164 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 165 | if (typeof module != 'undefined' && module.exports) module.exports = Sha256; // CommonJs export 166 | if (typeof define == 'function' && define.amd) define([], function() { return Sha256; }); // AMD 167 | -------------------------------------------------------------------------------- /tea-block.js: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2 | /* Block TEA (xxtea) Tiny Encryption Algorithm (c) Chris Veness 2002-2014 / MIT Licence */ 3 | /* - www.movable-type.co.uk/scripts/tea-block.html */ 4 | /* */ 5 | /* Algorithm: David Wheeler & Roger Needham, Cambridge University Computer Lab */ 6 | /* http://www.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html (1994) */ 7 | /* http://www.cl.cam.ac.uk/ftp/users/djw3/xtea.ps (1997) */ 8 | /* http://www.cl.cam.ac.uk/ftp/users/djw3/xxtea.ps (1998) */ 9 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 10 | 11 | /* jshint node:true *//* global define, escape, unescape, btoa, atob */ 12 | 'use strict'; 13 | 14 | 15 | /** 16 | * Tiny Encryption Algorithm 17 | * 18 | * @namespace 19 | */ 20 | var Tea = {}; 21 | 22 | 23 | /** 24 | * Encrypts text using Corrected Block TEA (xxtea) algorithm. 25 | * 26 | * @param {string} plaintext - String to be encrypted (multi-byte safe). 27 | * @param {string} password - Password to be used for encryption (1st 16 chars). 28 | * @returns {string} Encrypted text (encoded as base64). 29 | */ 30 | Tea.encrypt = function(plaintext, password) { 31 | plaintext = String(plaintext); 32 | password = String(password); 33 | 34 | if (plaintext.length == 0) return(''); // nothing to encrypt 35 | 36 | // v is n-word data vector; converted to array of longs from UTF-8 string 37 | var v = Tea.strToLongs(plaintext.utf8Encode()); 38 | // k is 4-word key; simply convert first 16 chars of password as key 39 | var k = Tea.strToLongs(password.utf8Encode().slice(0,16)); 40 | var n = v.length; 41 | 42 | v = Tea.encode(v, k); 43 | 44 | // convert array of longs to string 45 | var ciphertext = Tea.longsToStr(v); 46 | 47 | // convert binary string to base64 ascii for safe transport 48 | return ciphertext.base64Encode(); 49 | }; 50 | 51 | 52 | /** 53 | * Decrypts text using Corrected Block TEA (xxtea) algorithm. 54 | * 55 | * @param {string} ciphertext - String to be decrypted. 56 | * @param {string} password - Password to be used for decryption (1st 16 chars). 57 | * @returns {string} Decrypted text. 58 | */ 59 | Tea.decrypt = function(ciphertext, password) { 60 | ciphertext = String(ciphertext); 61 | password = String(password); 62 | 63 | if (ciphertext.length == 0) return(''); 64 | 65 | // v is n-word data vector; converted to array of longs from base64 string 66 | var v = Tea.strToLongs(ciphertext.base64Decode()); 67 | // k is 4-word key; simply convert first 16 chars of password as key 68 | var k = Tea.strToLongs(password.utf8Encode().slice(0,16)); 69 | var n = v.length; 70 | 71 | v = Tea.decode(v, k); 72 | 73 | var plaintext = Tea.longsToStr(v); 74 | 75 | // strip trailing null chars resulting from filling 4-char blocks: 76 | plaintext = plaintext.replace(/\0+$/,''); 77 | 78 | return plaintext.utf8Decode(); 79 | }; 80 | 81 | 82 | /** 83 | * XXTEA: encodes array of unsigned 32-bit integers using 128-bit key. 84 | * 85 | * @param {number[]} v - Data vector. 86 | * @param {number[]} k - Key. 87 | * @returns {number[]} Encoded vector. 88 | */ 89 | Tea.encode = function(v, k) { 90 | if (v.length < 2) v[1] = 0; // algorithm doesn't work for n<2 so fudge by adding a null 91 | var n = v.length; 92 | 93 | var z = v[n-1], y = v[0], delta = 0x9E3779B9; 94 | var mx, e, q = Math.floor(6 + 52/n), sum = 0; 95 | 96 | while (q-- > 0) { // 6 + 52/n operations gives between 6 & 32 mixes on each word 97 | sum += delta; 98 | e = sum>>>2 & 3; 99 | for (var p = 0; p < n; p++) { 100 | y = v[(p+1)%n]; 101 | mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z); 102 | z = v[p] += mx; 103 | } 104 | } 105 | 106 | return v; 107 | }; 108 | 109 | 110 | /** 111 | * XXTEA: decodes array of unsigned 32-bit integers using 128-bit key. 112 | * 113 | * @param {number[]} v - Data vector. 114 | * @param {number[]} k - Key. 115 | * @returns {number[]} Decoded vector. 116 | */ 117 | Tea.decode = function(v, k) { 118 | var n = v.length; 119 | 120 | var z = v[n-1], y = v[0], delta = 0x9E3779B9; 121 | var mx, e, q = Math.floor(6 + 52/n), sum = q*delta; 122 | 123 | while (sum != 0) { 124 | e = sum>>>2 & 3; 125 | for (var p = n-1; p >= 0; p--) { 126 | z = v[p>0 ? p-1 : n-1]; 127 | mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z); 128 | y = v[p] -= mx; 129 | } 130 | sum -= delta; 131 | } 132 | 133 | return v; 134 | }; 135 | 136 | 137 | /** 138 | * Converts string to array of longs (each containing 4 chars). 139 | * @private 140 | */ 141 | Tea.strToLongs = function(s) { 142 | // note chars must be within ISO-8859-1 (Unicode code-point <= U+00FF) to fit 4/long 143 | var l = new Array(Math.ceil(s.length/4)); 144 | for (var i=0; i>>8 & 0xFF, l[i]>>>16 & 0xFF, l[i]>>>24 & 0xFF); 161 | } 162 | return a.join(''); // use Array.join() for better performance than repeated string appends 163 | }; 164 | 165 | 166 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 167 | 168 | 169 | /** Extend String object with method to encode multi-byte string to utf8 170 | * - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */ 171 | if (typeof String.prototype.utf8Encode == 'undefined') { 172 | String.prototype.utf8Encode = function() { 173 | return unescape( encodeURIComponent( this ) ); 174 | }; 175 | } 176 | 177 | /** Extend String object with method to decode utf8 string to multi-byte */ 178 | if (typeof String.prototype.utf8Decode == 'undefined') { 179 | String.prototype.utf8Decode = function() { 180 | try { 181 | return decodeURIComponent( escape( this ) ); 182 | } catch (e) { 183 | return this; // invalid UTF-8? return as-is 184 | } 185 | }; 186 | } 187 | 188 | 189 | /** Extend String object with method to encode base64 190 | * - developer.mozilla.org/en-US/docs/Web/API/window.btoa, nodejs.org/api/buffer.html 191 | * note: if btoa()/atob() are not available (eg IE9-), try github.com/davidchambers/Base64.js */ 192 | if (typeof String.prototype.base64Encode == 'undefined') { 193 | String.prototype.base64Encode = function() { 194 | if (typeof btoa != 'undefined') return btoa(this); // browser 195 | if (typeof Buffer != 'undefined') return new Buffer(this, 'utf8').toString('base64'); // Node.js 196 | throw new Error('No Base64 Encode'); 197 | }; 198 | } 199 | 200 | /** Extend String object with method to decode base64 */ 201 | if (typeof String.prototype.base64Decode == 'undefined') { 202 | String.prototype.base64Decode = function() { 203 | if (typeof atob != 'undefined') return atob(this); // browser 204 | if (typeof Buffer != 'undefined') return new Buffer(this, 'base64').toString('utf8'); // Node.js 205 | throw new Error('No Base64 Decode'); 206 | }; 207 | } 208 | 209 | 210 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 211 | if (typeof module != 'undefined' && module.exports) module.exports = Tea; // CommonJS export 212 | if (typeof define == 'function' && define.amd) define([''], function() { return Tea; }); // AMD 213 | -------------------------------------------------------------------------------- /aes.js: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2 | /* AES implementation in JavaScript (c) Chris Veness 2005-2014 / MIT Licence */ 3 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 4 | 5 | /* jshint node:true *//* global define */ 6 | 'use strict'; 7 | 8 | 9 | /** 10 | * AES (Rijndael cipher) encryption routines, 11 | * 12 | * Reference implementation of FIPS-197 http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf. 13 | * 14 | * @namespace 15 | */ 16 | var Aes = {}; 17 | 18 | 19 | /** 20 | * AES Cipher function: encrypt 'input' state with Rijndael algorithm [§5.1]; 21 | * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage. 22 | * 23 | * @param {number[]} input - 16-byte (128-bit) input state array. 24 | * @param {number[][]} w - Key schedule as 2D byte-array (Nr+1 x Nb bytes). 25 | * @returns {number[]} Encrypted output state array. 26 | */ 27 | Aes.cipher = function(input, w) { 28 | var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) 29 | var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys 30 | 31 | var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4] 32 | for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; 33 | 34 | state = Aes.addRoundKey(state, w, 0, Nb); 35 | 36 | for (var round=1; round 6 && i%Nk == 4) { 85 | temp = Aes.subWord(temp); 86 | } 87 | // xor w[i] with w[i-1] and w[i-Nk] 88 | for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; 89 | } 90 | 91 | return w; 92 | }; 93 | 94 | 95 | /** 96 | * Apply SBox to state S [§5.1.1] 97 | * @private 98 | */ 99 | Aes.subBytes = function(s, Nb) { 100 | for (var r=0; r<4; r++) { 101 | for (var c=0; c>> i*8) & 0xff; 63 | for (var i=0; i<2; i++) counterBlock[i+2] = (nonceRnd >>> i*8) & 0xff; 64 | for (var i=0; i<4; i++) counterBlock[i+4] = (nonceSec >>> i*8) & 0xff; 65 | 66 | // and convert it to a string to go on the front of the ciphertext 67 | var ctrTxt = ''; 68 | for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]); 69 | 70 | // generate key schedule - an expansion of the key into distinct Key Rounds for each round 71 | var keySchedule = Aes.keyExpansion(key); 72 | 73 | var blockCount = Math.ceil(plaintext.length/blockSize); 74 | var ciphertxt = new Array(blockCount); // ciphertext as array of strings 75 | 76 | for (var b=0; b>> c*8) & 0xff; 80 | for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8); 81 | 82 | var cipherCntr = Aes.cipher(counterBlock, keySchedule); // -- encrypt counter block -- 83 | 84 | // block size is reduced on final block 85 | var blockLength = b>> c*8) & 0xff; 149 | for (var c=0; c<4; c++) counterBlock[15-c-4] = (((b+1)/0x100000000-1) >>> c*8) & 0xff; 150 | 151 | var cipherCntr = Aes.cipher(counterBlock, keySchedule); // encrypt counter block 152 | 153 | var plaintxtByte = new Array(ciphertext[b].length); 154 | for (var i=0; i