├── src ├── rsa │ ├── raw.js │ ├── exports-keygen.js │ ├── exports-raw.js │ ├── exports-oaep-sha1.js │ ├── exports-oaep-sha256.js │ ├── exports-oaep-sha512.js │ ├── exports-pss-sha1.js │ ├── exports-pss-sha256.js │ ├── exports-pss-sha512.js │ ├── genkey.js │ ├── rsa.js │ └── pkcs1.js ├── random │ ├── globals.js │ ├── exports.js │ ├── isaac.js │ └── random.js ├── globals.js ├── bignum │ ├── exports.js │ ├── extgcd.js │ ├── modulus.js │ ├── prime.js │ └── bignum.js ├── exports.js ├── aes │ ├── ctr │ │ ├── exports.js │ │ └── ctr.js │ ├── cfb │ │ ├── exports.js │ │ └── cfb.js │ ├── ecb │ │ ├── exports.js │ │ └── ecb.js │ ├── cbc │ │ ├── exports.js │ │ └── cbc.js │ ├── exports-gcm.js │ ├── exports-ccm.js │ ├── exports.js │ ├── aes.js │ ├── naes.js │ ├── aes-gcm.js │ └── aes-ccm.js ├── hash │ ├── sha1 │ │ ├── exports.js │ │ └── sha1.js │ ├── sha256 │ │ ├── exports.js │ │ └── sha256.js │ ├── sha512 │ │ ├── exports.js │ │ └── sha512.js │ └── hash.js ├── errors.js ├── hmac │ ├── exports-hmac-sha256.js │ ├── exports-hmac-sha512.js │ ├── exports-hmac-sha1.js │ ├── hmac-sha256.js │ ├── hmac-sha1.js │ ├── hmac.js │ └── hmac-sha512.js ├── pbkdf2 │ ├── exports-pbkdf2-hmac-sha1.js │ ├── exports-pbkdf2-hmac-sha256.js │ ├── exports-pbkdf2-hmac-sha512.js │ ├── pbkdf2-hmac-sha1.js │ ├── pbkdf2-hmac-sha256.js │ ├── pbkdf2-hmac-sha512.js │ └── pbkdf2.js └── utils.js ├── .gitignore ├── .travis.yml ├── bower.json ├── package.json ├── LICENSE ├── test ├── index.html ├── sha1.js ├── sha256.js ├── dummy.js ├── sha512.js ├── isaac.js └── rsa.js └── README.md /src/rsa/raw.js: -------------------------------------------------------------------------------- 1 | 2 | var RSA_RAW = RSA; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | asmcrypto.js 2 | asmcrypto.js.map 3 | node_modules/ 4 | !node_modules/uglify-js/ 5 | -------------------------------------------------------------------------------- /src/random/globals.js: -------------------------------------------------------------------------------- 1 | global.Math.random = Random_getNumber; 2 | 3 | if ( global.crypto === undefined ) global.crypto = {}; 4 | global.crypto.getRandomValues = Random_getValues; 5 | -------------------------------------------------------------------------------- /src/globals.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Error definitions 3 | */ 4 | 5 | global.IllegalStateError = IllegalStateError; 6 | global.IllegalArgumentError = IllegalArgumentError; 7 | global.SecurityError = SecurityError; 8 | -------------------------------------------------------------------------------- /src/bignum/exports.js: -------------------------------------------------------------------------------- 1 | BigNumber.ZERO = BigNumber_ZERO; 2 | BigNumber.ONE = BigNumber_ONE; 3 | 4 | BigNumber.extGCD = BigNumber_extGCD; 5 | 6 | exports.BigNumber = BigNumber; 7 | exports.Modulus = Modulus; 8 | -------------------------------------------------------------------------------- /src/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Util exports 3 | */ 4 | 5 | exports.string_to_bytes = string_to_bytes; 6 | exports.hex_to_bytes = hex_to_bytes; 7 | exports.base64_to_bytes = base64_to_bytes; 8 | exports.bytes_to_string = bytes_to_string; 9 | exports.bytes_to_hex = bytes_to_hex; 10 | exports.bytes_to_base64 = bytes_to_base64; 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.11' 4 | addons: 5 | sauce_connect: 6 | username: vibornoff 7 | access_key: 8 | secure: N5jZowSuf5vPTUSgnYIX4sdFV3u0z/b8DMBSbMzst34VahI428jJlTPfMcswVomflwIA5dO0KgvCvRpKnos4gVIG02PUNYsCSuwg5nBOq025r8PX1nI3tYBK0n1SHHFYQs9swqeiKVVE0bG1AwrIAMNqJS5DnxMBw7z/dM6cPf8= 9 | before_install: 10 | export WITH=ALL 11 | script: 12 | grunt test && grunt sauce 13 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asmcrypto", 3 | "main": "asmcrypto.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "**/.*", 7 | "node_modules", 8 | "test", 9 | "test.html", 10 | "Gruntfile.js", 11 | "package.json" 12 | ], 13 | "keywords": [ 14 | "crypto", 15 | "asmcrypto", 16 | "webcrypto", 17 | "library", 18 | "sha", "sha1", "sha256", "sha512", 19 | "hmac", 20 | "pbkdf", "pbkdf2", 21 | "aes", "aes256", "cbc", "ccm", "cfb", 22 | "rsa", "oaep", "pss", "pkcs" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/rsa/exports-keygen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA keygen exports 3 | */ 4 | function rsa_generate_key ( bitlen, e ) { 5 | if ( bitlen === undefined ) throw new SyntaxError("bitlen required"); 6 | if ( e === undefined ) throw new SyntaxError("e required"); 7 | var key = RSA_generateKey( bitlen, e ); 8 | for ( var i = 0; i < key.length; i++ ) { 9 | if ( is_big_number(key[i]) ) 10 | key[i] = key[i].toBytes(); 11 | } 12 | return key; 13 | } 14 | 15 | exports.RSA = { 16 | generateKey: rsa_generate_key 17 | }; 18 | -------------------------------------------------------------------------------- /src/aes/ctr/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AES-CTR exports 3 | */ 4 | 5 | function AES_CTR_crypt_bytes ( data, key, iv ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return get_AES_CTR_instance( { key: key, iv: iv } ).encrypt(data).result; 9 | } 10 | 11 | exports.AES_CTR = createSimpleCipherInterface( AES_CTR ); 12 | exports.AES_CTR.encrypt = AES_CTR_crypt_bytes; 13 | exports.AES_CTR.decrypt = AES_CTR_crypt_bytes; 14 | 15 | exports.AES_CTR.Encrypt = 16 | exports.AES_CTR.Decrypt = createProgressiveCipherInterface( AES_CTR_Crypt ); 17 | -------------------------------------------------------------------------------- /src/hash/sha1/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SHA1 exports 3 | */ 4 | 5 | function sha1_bytes ( data ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | return get_sha1_instance().reset().process(data).finish().result; 8 | } 9 | 10 | function sha1_hex ( data ) { 11 | var result = sha1_bytes(data); 12 | return bytes_to_hex(result); 13 | } 14 | 15 | function sha1_base64 ( data ) { 16 | var result = sha1_bytes(data); 17 | return bytes_to_base64(result); 18 | } 19 | 20 | sha1_constructor.bytes = sha1_bytes; 21 | sha1_constructor.hex = sha1_hex; 22 | sha1_constructor.base64 = sha1_base64; 23 | 24 | exports.SHA1 = sha1_constructor; 25 | -------------------------------------------------------------------------------- /src/hash/sha256/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SHA256 exports 3 | */ 4 | 5 | function sha256_bytes ( data ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | return get_sha256_instance().reset().process(data).finish().result; 8 | } 9 | 10 | function sha256_hex ( data ) { 11 | var result = sha256_bytes(data); 12 | return bytes_to_hex(result); 13 | } 14 | 15 | function sha256_base64 ( data ) { 16 | var result = sha256_bytes(data); 17 | return bytes_to_base64(result); 18 | } 19 | 20 | sha256_constructor.bytes = sha256_bytes; 21 | sha256_constructor.hex = sha256_hex; 22 | sha256_constructor.base64 = sha256_base64; 23 | 24 | exports.SHA256 = sha256_constructor; 25 | -------------------------------------------------------------------------------- /src/hash/sha512/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SHA512 exports 3 | */ 4 | 5 | function sha512_bytes ( data ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | return get_sha512_instance().reset().process(data).finish().result; 8 | } 9 | 10 | function sha512_hex ( data ) { 11 | var result = sha512_bytes(data); 12 | return bytes_to_hex(result); 13 | } 14 | 15 | function sha512_base64 ( data ) { 16 | var result = sha512_bytes(data); 17 | return bytes_to_base64(result); 18 | } 19 | 20 | sha512_constructor.bytes = sha512_bytes; 21 | sha512_constructor.hex = sha512_hex; 22 | sha512_constructor.base64 = sha512_base64; 23 | 24 | exports.SHA512 = sha512_constructor; 25 | -------------------------------------------------------------------------------- /src/errors.js: -------------------------------------------------------------------------------- 1 | function IllegalStateError () { var err = Error.apply( this, arguments ); this.message = err.message, this.stack = err.stack; } 2 | IllegalStateError.prototype = Object.create( Error.prototype, { name: { value: 'IllegalStateError' } } ); 3 | 4 | function IllegalArgumentError () { var err = Error.apply( this, arguments ); this.message = err.message, this.stack = err.stack; } 5 | IllegalArgumentError.prototype = Object.create( Error.prototype, { name: { value: 'IllegalArgumentError' } } ); 6 | 7 | function SecurityError () { var err = Error.apply( this, arguments ); this.message = err.message, this.stack = err.stack; } 8 | SecurityError.prototype = Object.create( Error.prototype, { name: { value: 'SecurityError' } } ); 9 | -------------------------------------------------------------------------------- /src/rsa/exports-raw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-RAW exports 3 | */ 4 | 5 | function rsa_raw_encrypt_bytes ( data, key ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_RAW({ key: key })).encrypt(data).result; 9 | } 10 | 11 | function rsa_raw_decrypt_bytes ( data, key ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return (new RSA_RAW({ key: key })).decrypt(data).result; 15 | } 16 | 17 | RSA_RAW.encrypt = rsa_raw_encrypt_bytes; 18 | RSA_RAW.decrypt = rsa_raw_decrypt_bytes; 19 | RSA_RAW.sign = rsa_raw_decrypt_bytes; 20 | RSA_RAW.verify = rsa_raw_encrypt_bytes; 21 | 22 | exports.RSA_RAW = RSA_RAW; 23 | -------------------------------------------------------------------------------- /src/rsa/exports-oaep-sha1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-OAEP-SHA1 exports 3 | */ 4 | 5 | function rsa_oaep_sha1_encrypt_bytes ( data, key, label ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_OAEP({ hash: get_sha1_instance(), key: key, label: label })).encrypt(data).result; 9 | } 10 | 11 | function rsa_oaep_sha1_decrypt_bytes ( data, key, label ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return (new RSA_OAEP({ hash: get_sha1_instance(), key: key, label: label })).decrypt(data).result; 15 | } 16 | 17 | exports.RSA_OAEP = RSA_OAEP; 18 | 19 | exports.RSA_OAEP_SHA1 = { 20 | encrypt: rsa_oaep_sha1_encrypt_bytes, 21 | decrypt: rsa_oaep_sha1_decrypt_bytes 22 | }; 23 | -------------------------------------------------------------------------------- /src/rsa/exports-oaep-sha256.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-OAEP-SHA256 exports 3 | */ 4 | 5 | function rsa_oaep_sha256_encrypt_bytes ( data, key, label ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_OAEP({ hash: get_sha256_instance(), key: key, label: label })).encrypt(data).result; 9 | } 10 | 11 | function rsa_oaep_sha256_decrypt_bytes ( data, key, label ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return (new RSA_OAEP({ hash: get_sha256_instance(), key: key, label: label })).decrypt(data).result; 15 | } 16 | 17 | exports.RSA_OAEP = RSA_OAEP; 18 | 19 | exports.RSA_OAEP_SHA256 = { 20 | encrypt: rsa_oaep_sha256_encrypt_bytes, 21 | decrypt: rsa_oaep_sha256_decrypt_bytes 22 | }; 23 | -------------------------------------------------------------------------------- /src/rsa/exports-oaep-sha512.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-OAEP-SHA512 exports 3 | */ 4 | 5 | function rsa_oaep_sha512_encrypt_bytes ( data, key, label ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_OAEP({ hash: get_sha512_instance(), key: key, label: label })).encrypt(data).result; 9 | } 10 | 11 | function rsa_oaep_sha512_decrypt_bytes ( data, key, label ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return (new RSA_OAEP({ hash: get_sha512_instance(), key: key, label: label })).decrypt(data).result; 15 | } 16 | 17 | exports.RSA_OAEP = RSA_OAEP; 18 | 19 | exports.RSA_OAEP_SHA512 = { 20 | encrypt: rsa_oaep_sha512_encrypt_bytes, 21 | decrypt: rsa_oaep_sha512_decrypt_bytes 22 | }; 23 | -------------------------------------------------------------------------------- /src/hash/sha1/sha1.js: -------------------------------------------------------------------------------- 1 | var _sha1_block_size = 64, 2 | _sha1_hash_size = 20; 3 | 4 | function sha1_constructor ( options ) { 5 | options = options || {}; 6 | 7 | this.heap = _heap_init( Uint8Array, options ); 8 | this.asm = options.asm || sha1_asm( global, null, this.heap.buffer ); 9 | 10 | this.BLOCK_SIZE = _sha1_block_size; 11 | this.HASH_SIZE = _sha1_hash_size; 12 | 13 | this.reset(); 14 | } 15 | 16 | sha1_constructor.BLOCK_SIZE = _sha1_block_size; 17 | sha1_constructor.HASH_SIZE = _sha1_hash_size; 18 | var sha1_prototype = sha1_constructor.prototype; 19 | sha1_prototype.reset = hash_reset; 20 | sha1_prototype.process = hash_process; 21 | sha1_prototype.finish = hash_finish; 22 | 23 | var sha1_instance = null; 24 | 25 | function get_sha1_instance () { 26 | if ( sha1_instance === null ) sha1_instance = new sha1_constructor( { heapSize: 0x100000 } ); 27 | return sha1_instance; 28 | } 29 | -------------------------------------------------------------------------------- /src/hmac/exports-hmac-sha256.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HMAC-SHA256 exports 3 | */ 4 | 5 | function hmac_sha256_bytes ( data, password ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( password === undefined ) throw new SyntaxError("password required"); 8 | return get_hmac_sha256_instance().reset( { password: password } ).process(data).finish().result; 9 | } 10 | 11 | function hmac_sha256_hex ( data, password ) { 12 | var result = hmac_sha256_bytes( data, password ); 13 | return bytes_to_hex(result); 14 | } 15 | 16 | function hmac_sha256_base64 ( data, password ) { 17 | var result = hmac_sha256_bytes( data, password ); 18 | return bytes_to_base64(result); 19 | } 20 | 21 | hmac_sha256_constructor.bytes = hmac_sha256_bytes; 22 | hmac_sha256_constructor.hex = hmac_sha256_hex; 23 | hmac_sha256_constructor.base64 = hmac_sha256_base64; 24 | 25 | exports.HMAC_SHA256 = hmac_sha256_constructor; 26 | -------------------------------------------------------------------------------- /src/hmac/exports-hmac-sha512.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HMAC-SHA512 exports 3 | */ 4 | 5 | function hmac_sha512_bytes ( data, password ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( password === undefined ) throw new SyntaxError("password required"); 8 | return get_hmac_sha512_instance().reset( { password: password } ).process(data).finish().result; 9 | } 10 | 11 | function hmac_sha512_hex ( data, password ) { 12 | var result = hmac_sha512_bytes( data, password ); 13 | return bytes_to_hex(result); 14 | } 15 | 16 | function hmac_sha512_base64 ( data, password ) { 17 | var result = hmac_sha512_bytes( data, password ); 18 | return bytes_to_base64(result); 19 | } 20 | 21 | hmac_sha512_constructor.bytes = hmac_sha512_bytes; 22 | hmac_sha512_constructor.hex = hmac_sha512_hex; 23 | hmac_sha512_constructor.base64 = hmac_sha512_base64; 24 | 25 | exports.HMAC_SHA512 = hmac_sha512_constructor; 26 | -------------------------------------------------------------------------------- /src/hmac/exports-hmac-sha1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HMAC-SHA1 exports 3 | */ 4 | 5 | function hmac_sha1_bytes ( data, password ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( password === undefined ) throw new SyntaxError("password required"); 8 | return get_hmac_sha1_instance().reset( { password: password } ).process(data).finish().result; 9 | } 10 | 11 | function hmac_sha1_hex ( data, password ) { 12 | var result = hmac_sha1_bytes( data, password ); 13 | return bytes_to_hex(result); 14 | } 15 | 16 | function hmac_sha1_base64 ( data, password ) { 17 | var result = hmac_sha1_bytes( data, password ); 18 | return bytes_to_base64(result); 19 | } 20 | 21 | exports.HMAC = hmac_constructor; 22 | 23 | hmac_sha1_constructor.bytes = hmac_sha1_bytes; 24 | hmac_sha1_constructor.hex = hmac_sha1_hex; 25 | hmac_sha1_constructor.base64 = hmac_sha1_base64; 26 | 27 | exports.HMAC_SHA1 = hmac_sha1_constructor; 28 | -------------------------------------------------------------------------------- /src/hash/sha256/sha256.js: -------------------------------------------------------------------------------- 1 | var _sha256_block_size = 64, 2 | _sha256_hash_size = 32; 3 | 4 | function sha256_constructor ( options ) { 5 | options = options || {}; 6 | 7 | this.heap = _heap_init( Uint8Array, options ); 8 | this.asm = options.asm || sha256_asm( global, null, this.heap.buffer ); 9 | 10 | this.BLOCK_SIZE = _sha256_block_size; 11 | this.HASH_SIZE = _sha256_hash_size; 12 | 13 | this.reset(); 14 | } 15 | 16 | sha256_constructor.BLOCK_SIZE = _sha256_block_size; 17 | sha256_constructor.HASH_SIZE = _sha256_hash_size; 18 | var sha256_prototype = sha256_constructor.prototype; 19 | sha256_prototype.reset = hash_reset; 20 | sha256_prototype.process = hash_process; 21 | sha256_prototype.finish = hash_finish; 22 | 23 | var sha256_instance = null; 24 | 25 | function get_sha256_instance () { 26 | if ( sha256_instance === null ) sha256_instance = new sha256_constructor( { heapSize: 0x100000 } ); 27 | return sha256_instance; 28 | } 29 | -------------------------------------------------------------------------------- /src/hash/sha512/sha512.js: -------------------------------------------------------------------------------- 1 | var _sha512_block_size = 128, 2 | _sha512_hash_size = 64; 3 | 4 | function sha512_constructor ( options ) { 5 | options = options || {}; 6 | 7 | this.heap = _heap_init( Uint8Array, options ); 8 | this.asm = options.asm || sha512_asm( global, null, this.heap.buffer ); 9 | 10 | this.BLOCK_SIZE = _sha512_block_size; 11 | this.HASH_SIZE = _sha512_hash_size; 12 | 13 | this.reset(); 14 | } 15 | 16 | sha512_constructor.BLOCK_SIZE = _sha512_block_size; 17 | sha512_constructor.HASH_SIZE = _sha512_hash_size; 18 | var sha512_prototype = sha512_constructor.prototype; 19 | sha512_prototype.reset = hash_reset; 20 | sha512_prototype.process = hash_process; 21 | sha512_prototype.finish = hash_finish; 22 | 23 | var sha512_instance = null; 24 | 25 | function get_sha512_instance () { 26 | if ( sha512_instance === null ) sha512_instance = new sha512_constructor( { heapSize: 0x100000 } ); 27 | return sha512_instance; 28 | } 29 | -------------------------------------------------------------------------------- /src/aes/cfb/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AES-CFB exports 3 | */ 4 | 5 | function AES_CFB_encrypt_bytes ( data, key, iv ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return get_AES_CFB_instance( { key: key, iv: iv } ).encrypt(data).result; 9 | } 10 | 11 | function AES_CFB_decrypt_bytes ( data, key, iv ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return get_AES_CFB_instance( { key: key, iv: iv } ).decrypt(data).result; 15 | } 16 | 17 | exports.AES_CFB = createSimpleCipherInterface( AES_CFB ); 18 | exports.AES_CFB.encrypt = AES_CFB_encrypt_bytes; 19 | exports.AES_CFB.decrypt = AES_CFB_decrypt_bytes; 20 | 21 | exports.AES_CFB.Encrypt = createProgressiveCipherInterface( AES_CFB_Encrypt ); 22 | exports.AES_CFB.Decrypt = createProgressiveCipherInterface( AES_CFB_Decrypt ); 23 | 24 | -------------------------------------------------------------------------------- /src/aes/ecb/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AES-ECB exports 3 | */ 4 | 5 | function AES_ECB_encrypt_bytes ( data, key, padding ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return get_AES_ECB_instance( { key: key, padding: padding } ).encrypt(data).result; 9 | } 10 | 11 | function AES_ECB_decrypt_bytes ( data, key, padding ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return get_AES_ECB_instance( { key: key, padding: padding } ).decrypt(data).result; 15 | } 16 | 17 | exports.AES_ECB = createSimpleCipherInterface( AES_ECB ); 18 | exports.AES_ECB.encrypt = AES_ECB_encrypt_bytes; 19 | exports.AES_ECB.decrypt = AES_ECB_decrypt_bytes; 20 | 21 | exports.AES_ECB.Encrypt = createProgressiveCipherInterface( AES_ECB_Encrypt ); 22 | exports.AES_ECB.Decrypt = createProgressiveCipherInterface( AES_ECB_Decrypt ); 23 | 24 | -------------------------------------------------------------------------------- /src/random/exports.js: -------------------------------------------------------------------------------- 1 | exports.random = Random_getNumber; 2 | 3 | exports.random.seed = Random_seed; 4 | 5 | Object.defineProperty( Random_getNumber, 'allowWeak', { 6 | get: function () { return _random_allow_weak; }, 7 | set: function ( a ) { _random_allow_weak = a; } 8 | }); 9 | 10 | Object.defineProperty( Random_getNumber, 'skipSystemRNGWarning', { 11 | get: function () { return _random_skip_system_rng_warning; }, 12 | set: function ( w ) { _random_skip_system_rng_warning = w; } 13 | }); 14 | 15 | exports.getRandomValues = Random_getValues; 16 | 17 | exports.getRandomValues.seed = Random_seed; 18 | 19 | Object.defineProperty( Random_getValues, 'allowWeak', { 20 | get: function () { return _random_allow_weak; }, 21 | set: function ( a ) { _random_allow_weak = a; } 22 | }); 23 | 24 | Object.defineProperty( Random_getValues, 'skipSystemRNGWarning', { 25 | get: function () { return _random_skip_system_rng_warning; }, 26 | set: function ( w ) { _random_skip_system_rng_warning = w; } 27 | }); 28 | -------------------------------------------------------------------------------- /src/pbkdf2/exports-pbkdf2-hmac-sha1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PBKDF2-HMAC-SHA1 exports 3 | */ 4 | 5 | function pbkdf2_hmac_sha1_bytes ( password, salt, iterations, dklen ) { 6 | if ( password === undefined ) throw new SyntaxError("password required"); 7 | if ( salt === undefined ) throw new SyntaxError("salt required"); 8 | return get_pbkdf2_hmac_sha1_instance().reset( { password: password } ).generate( salt, iterations, dklen ).result; 9 | } 10 | 11 | function pbkdf2_hmac_sha1_hex ( password, salt, iterations, dklen ) { 12 | var result = pbkdf2_hmac_sha1_bytes( password, salt, iterations, dklen ); 13 | return bytes_to_hex(result); 14 | } 15 | 16 | function pbkdf2_hmac_sha1_base64 ( password, salt, iterations, dklen ) { 17 | var result = pbkdf2_hmac_sha1_bytes( password, salt, iterations, dklen ); 18 | return bytes_to_base64(result); 19 | } 20 | 21 | exports.PBKDF2 = 22 | exports.PBKDF2_HMAC_SHA1 = { 23 | bytes: pbkdf2_hmac_sha1_bytes, 24 | hex: pbkdf2_hmac_sha1_hex, 25 | base64: pbkdf2_hmac_sha1_base64 26 | }; 27 | -------------------------------------------------------------------------------- /src/aes/cbc/exports.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AES-CBC exports 3 | */ 4 | 5 | function AES_CBC_encrypt_bytes ( data, key, padding, iv ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return get_AES_CBC_instance( { key: key, padding: padding, iv: iv } ).encrypt(data).result; 9 | } 10 | 11 | function AES_CBC_decrypt_bytes ( data, key, padding, iv ) { 12 | if ( data === undefined ) throw new SyntaxError("data required"); 13 | if ( key === undefined ) throw new SyntaxError("key required"); 14 | return get_AES_CBC_instance( { key: key, padding: padding, iv: iv } ).decrypt(data).result; 15 | } 16 | 17 | exports.AES_CBC = createSimpleCipherInterface( AES_CBC ); 18 | exports.AES_CBC.encrypt = AES_CBC_encrypt_bytes; 19 | exports.AES_CBC.decrypt = AES_CBC_decrypt_bytes; 20 | 21 | exports.AES_CBC.Encrypt = createProgressiveCipherInterface( AES_CBC_Encrypt ); 22 | exports.AES_CBC.Decrypt = createProgressiveCipherInterface( AES_CBC_Decrypt ); 23 | 24 | -------------------------------------------------------------------------------- /src/pbkdf2/exports-pbkdf2-hmac-sha256.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PBKDF2-HMAC-SHA256 exports 3 | */ 4 | 5 | function pbkdf2_hmac_sha256_bytes ( password, salt, iterations, dklen ) { 6 | if ( password === undefined ) throw new SyntaxError("password required"); 7 | if ( salt === undefined ) throw new SyntaxError("salt required"); 8 | return get_pbkdf2_hmac_sha256_instance().reset( { password: password } ).generate( salt, iterations, dklen ).result; 9 | } 10 | 11 | function pbkdf2_hmac_sha256_hex ( password, salt, iterations, dklen ) { 12 | var result = pbkdf2_hmac_sha256_bytes( password, salt, iterations, dklen ); 13 | return bytes_to_hex(result); 14 | } 15 | 16 | function pbkdf2_hmac_sha256_base64 ( password, salt, iterations, dklen ) { 17 | var result = pbkdf2_hmac_sha256_bytes( password, salt, iterations, dklen ); 18 | return bytes_to_base64(result); 19 | } 20 | 21 | exports.PBKDF2_HMAC_SHA256 = { 22 | bytes: pbkdf2_hmac_sha256_bytes, 23 | hex: pbkdf2_hmac_sha256_hex, 24 | base64: pbkdf2_hmac_sha256_base64 25 | }; 26 | -------------------------------------------------------------------------------- /src/pbkdf2/exports-pbkdf2-hmac-sha512.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PBKDF2-HMAC-SHA512 exports 3 | */ 4 | 5 | function pbkdf2_hmac_sha512_bytes ( password, salt, iterations, dklen ) { 6 | if ( password === undefined ) throw new SyntaxError("password required"); 7 | if ( salt === undefined ) throw new SyntaxError("salt required"); 8 | return get_pbkdf2_hmac_sha512_instance().reset( { password: password } ).generate( salt, iterations, dklen ).result; 9 | } 10 | 11 | function pbkdf2_hmac_sha512_hex ( password, salt, iterations, dklen ) { 12 | var result = pbkdf2_hmac_sha512_bytes( password, salt, iterations, dklen ); 13 | return bytes_to_hex(result); 14 | } 15 | 16 | function pbkdf2_hmac_sha512_base64 ( password, salt, iterations, dklen ) { 17 | var result = pbkdf2_hmac_sha512_bytes( password, salt, iterations, dklen ); 18 | return bytes_to_base64(result); 19 | } 20 | 21 | exports.PBKDF2_HMAC_SHA512 = { 22 | bytes: pbkdf2_hmac_sha512_bytes, 23 | hex: pbkdf2_hmac_sha512_hex, 24 | base64: pbkdf2_hmac_sha512_base64 25 | }; 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asmcrypto.js", 3 | "description": "Asm.js implementation of WebCrypto API", 4 | "homepage": "https://github.com/vibornoff/asmcrypto.js", 5 | "main": "asmcrypto.js", 6 | "version": "0.0.3", 7 | "maintainers": [{ 8 | "name": "Artem S Vybornov", 9 | "email": "vybornov@gmail.com", 10 | "web": "http://github.com/vibornoff" 11 | }], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/vibornoff/asmcrypto.js.git" 15 | }, 16 | "devDependencies": { 17 | "uglify-js": "vibornoff/UglifyJS2", 18 | "grunt": "~0.4.2", 19 | "grunt-cli": "~0.1", 20 | "grunt-contrib-uglify": "~0.2.2", 21 | "grunt-contrib-qunit": "~0.4.0", 22 | "grunt-contrib-connect": "~0.7.1", 23 | "grunt-contrib-watch": "~0.2.0", 24 | "grunt-saucelabs": "~8.0.0", 25 | "grunt-contrib-clean": "~0.4.0" 26 | }, 27 | "scripts": { 28 | "prepublish": "grunt", 29 | "test": "grunt test" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/rsa/exports-pss-sha1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-PSS-SHA1 exports 3 | */ 4 | 5 | function rsa_pss_sha1_sign_bytes ( data, key, slen ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_PSS({ hash: get_sha1_instance(), key: key, saltLength: slen })).sign(data).result; 9 | } 10 | 11 | function rsa_pss_sha1_verify_bytes ( signature, data, key, slen ) { 12 | if ( signature === undefined ) throw new SyntaxError("signature required"); 13 | if ( data === undefined ) throw new SyntaxError("data required"); 14 | if ( key === undefined ) throw new SyntaxError("key required"); 15 | try { 16 | (new RSA_PSS({ hash: get_sha1_instance(), key: key, saltLength: slen })).verify(signature, data); 17 | return true; 18 | } 19 | catch ( e ) { 20 | if ( !( e instanceof SecurityError ) ) 21 | throw e; 22 | } 23 | return false; 24 | } 25 | 26 | exports.RSA_PSS = RSA_PSS; 27 | 28 | exports.RSA_PSS_SHA1 = { 29 | sign: rsa_pss_sha1_sign_bytes, 30 | verify: rsa_pss_sha1_verify_bytes 31 | }; 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Artem S Vybornov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/aes/ctr/ctr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Counter Mode (CTR) 3 | */ 4 | 5 | function AES_CTR ( options ) { 6 | this.iv = null; 7 | 8 | AES.call( this, options ); 9 | 10 | this.mode = 'CTR'; 11 | } 12 | 13 | function AES_CTR_Crypt ( options ) { 14 | AES_CTR.call( this, options ); 15 | } 16 | 17 | var AES_CTR_prototype = AES_CTR.prototype; 18 | AES_CTR_prototype.reset = AES_reset; 19 | AES_CTR_prototype.encrypt = AES_Encrypt_finish; 20 | AES_CTR_prototype.decrypt = AES_Encrypt_finish; 21 | 22 | var AES_CTR_Crypt_prototype = AES_CTR_Crypt.prototype; 23 | AES_CTR_Crypt_prototype.reset = AES_reset; 24 | AES_CTR_Crypt_prototype.process = AES_Encrypt_process; 25 | AES_CTR_Crypt_prototype.finish = AES_Encrypt_finish; 26 | 27 | var get_AES_CTR_instance = function () 28 | { 29 | var _instance = null; 30 | 31 | return function ( options ) { 32 | if ( _instance ) return _instance.reset(options); 33 | 34 | // options = options || {}; 35 | // options.heap = options.heap || _aes_heap_instance; 36 | // options.asm = options.asm || _aes_asm_instance; 37 | 38 | return _instance = new AES_CTR(options); 39 | }; 40 | }(); 41 | -------------------------------------------------------------------------------- /src/aes/exports-gcm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AES-GCM exports 3 | */ 4 | 5 | var gcm_aes_instance = new gcm_aes_constructor( { heap: _aes_heap_instance, asm: _aes_asm_instance } ); 6 | 7 | function gcm_aes_encrypt_bytes ( data, key, iv, adata, tagSize ) { 8 | if ( data === undefined ) throw new SyntaxError("data required"); 9 | if ( key === undefined ) throw new SyntaxError("key required"); 10 | if ( iv === undefined ) throw new SyntaxError("iv required"); 11 | return gcm_aes_instance.reset( { key: key, iv: iv, adata: adata, tagSize: tagSize } ).encrypt(data).result; 12 | } 13 | 14 | function gcm_aes_decrypt_bytes ( data, key, iv, adata, tagSize ) { 15 | if ( data === undefined ) throw new SyntaxError("data required"); 16 | if ( key === undefined ) throw new SyntaxError("key required"); 17 | if ( iv === undefined ) throw new SyntaxError("iv required"); 18 | return gcm_aes_instance.reset( { key: key, iv: iv, adata: adata, tagSize: tagSize } ).decrypt(data).result; 19 | } 20 | 21 | gcm_aes_constructor.encrypt = gcm_aes_encrypt_bytes; 22 | gcm_aes_constructor.decrypt = gcm_aes_decrypt_bytes; 23 | 24 | exports.AES_GCM = gcm_aes_constructor; 25 | -------------------------------------------------------------------------------- /src/rsa/exports-pss-sha256.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-PSS-SHA256 exports 3 | */ 4 | 5 | function rsa_pss_sha256_sign_bytes ( data, key, slen ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_PSS({ hash: get_sha256_instance(), key: key, saltLength: slen })).sign(data).result; 9 | } 10 | 11 | function rsa_pss_sha256_verify_bytes ( signature, data, key, slen ) { 12 | if ( signature === undefined ) throw new SyntaxError("signature required"); 13 | if ( data === undefined ) throw new SyntaxError("data required"); 14 | if ( key === undefined ) throw new SyntaxError("key required"); 15 | try { 16 | (new RSA_PSS({ hash: get_sha256_instance(), key: key, saltLength: slen })).verify(signature, data); 17 | return true; 18 | } 19 | catch ( e ) { 20 | if ( !( e instanceof SecurityError ) ) 21 | throw e; 22 | } 23 | return false; 24 | } 25 | 26 | exports.RSA_PSS = RSA_PSS; 27 | 28 | exports.RSA_PSS_SHA256 = { 29 | sign: rsa_pss_sha256_sign_bytes, 30 | verify: rsa_pss_sha256_verify_bytes 31 | }; 32 | -------------------------------------------------------------------------------- /src/rsa/exports-pss-sha512.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RSA-PSS-SHA512 exports 3 | */ 4 | 5 | function rsa_pss_sha512_sign_bytes ( data, key, slen ) { 6 | if ( data === undefined ) throw new SyntaxError("data required"); 7 | if ( key === undefined ) throw new SyntaxError("key required"); 8 | return (new RSA_PSS({ hash: get_sha512_instance(), key: key, saltLength: slen })).sign(data).result; 9 | } 10 | 11 | function rsa_pss_sha512_verify_bytes ( signature, data, key, slen ) { 12 | if ( signature === undefined ) throw new SyntaxError("signature required"); 13 | if ( data === undefined ) throw new SyntaxError("data required"); 14 | if ( key === undefined ) throw new SyntaxError("key required"); 15 | try { 16 | (new RSA_PSS({ hash: get_sha512_instance(), key: key, saltLength: slen })).verify(signature, data); 17 | return true; 18 | } 19 | catch ( e ) { 20 | if ( !( e instanceof SecurityError ) ) 21 | throw e; 22 | } 23 | return false; 24 | } 25 | 26 | exports.RSA_PSS = RSA_PSS; 27 | 28 | exports.RSA_PSS_SHA512 = { 29 | sign: rsa_pss_sha512_sign_bytes, 30 | verify: rsa_pss_sha512_verify_bytes 31 | }; 32 | -------------------------------------------------------------------------------- /src/aes/exports-ccm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AES-CCM exports 3 | */ 4 | 5 | var ccm_aes_instance = new ccm_aes_constructor( { heap: _aes_heap_instance, asm: _aes_asm_instance } ); 6 | 7 | function ccm_aes_encrypt_bytes ( data, key, nonce, adata, tagSize ) { 8 | if ( data === undefined ) throw new SyntaxError("data required"); 9 | if ( key === undefined ) throw new SyntaxError("key required"); 10 | if ( nonce === undefined ) throw new SyntaxError("nonce required"); 11 | var dataLength = data.length || 0; 12 | return ccm_aes_instance.reset( { key: key, nonce: nonce, adata: adata, tagSize: tagSize, dataLength: dataLength } ).encrypt(data).result; 13 | } 14 | 15 | function ccm_aes_decrypt_bytes ( data, key, nonce, adata, tagSize ) { 16 | if ( data === undefined ) throw new SyntaxError("data required"); 17 | if ( key === undefined ) throw new SyntaxError("key required"); 18 | if ( nonce === undefined ) throw new SyntaxError("nonce required"); 19 | var dataLength = data.length || 0; 20 | tagSize = tagSize || _aes_block_size; 21 | return ccm_aes_instance.reset( { key: key, nonce: nonce, adata: adata, tagSize: tagSize, dataLength: dataLength-tagSize } ).decrypt(data).result; 22 | } 23 | 24 | ccm_aes_constructor.encrypt = ccm_aes_encrypt_bytes; 25 | ccm_aes_constructor.decrypt = ccm_aes_decrypt_bytes; 26 | 27 | exports.AES_CCM = ccm_aes_constructor; 28 | -------------------------------------------------------------------------------- /src/aes/cfb/cfb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cipher Feedback Mode (CFB) 3 | */ 4 | 5 | function AES_CFB ( options ) { 6 | this.iv = null; 7 | 8 | AES.call( this, options ); 9 | 10 | this.mode = 'CFB'; 11 | } 12 | 13 | var AES_CFB_prototype = AES_CFB.prototype; 14 | AES_CFB_prototype.reset = AES_reset; 15 | AES_CFB_prototype.encrypt = AES_Encrypt_finish; 16 | AES_CFB_prototype.decrypt = AES_Decrypt_finish; 17 | 18 | function AES_CFB_Encrypt ( options ) { 19 | AES_CFB.call( this, options ); 20 | } 21 | 22 | var AES_CFB_Encrypt_prototype = AES_CFB_Encrypt.prototype; 23 | AES_CFB_Encrypt_prototype.reset = AES_reset; 24 | AES_CFB_Encrypt_prototype.process = AES_Encrypt_process; 25 | AES_CFB_Encrypt_prototype.finish = AES_Encrypt_finish; 26 | 27 | function AES_CFB_Decrypt ( options ) { 28 | AES_CFB.call( this, options ); 29 | } 30 | 31 | var AES_CFB_Decrypt_prototype = AES_CFB_Decrypt.prototype; 32 | AES_CFB_Decrypt_prototype.reset = AES_reset; 33 | AES_CFB_Decrypt_prototype.process = AES_Decrypt_process; 34 | AES_CFB_Decrypt_prototype.finish = AES_Decrypt_finish; 35 | 36 | var get_AES_CFB_instance = function () 37 | { 38 | var _instance = null; 39 | 40 | return function ( options ) { 41 | if ( _instance ) return _instance.reset(options); 42 | 43 | // options = options || {}; 44 | // options.heap = options.heap || _aes_heap_instance; 45 | // options.asm = options.asm || _aes_asm_instance; 46 | 47 | return _instance = new AES_CFB(options); 48 | }; 49 | }(); 50 | -------------------------------------------------------------------------------- /src/aes/ecb/ecb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Electronic Code Book Mode (ECB) 3 | */ 4 | 5 | function AES_ECB ( options ) { 6 | this.padding = true; 7 | 8 | AES.call( this, options ); 9 | 10 | this.mode = 'ECB'; 11 | } 12 | 13 | var AES_ECB_prototype = AES_ECB.prototype; 14 | AES_ECB_prototype.reset = AES_reset; 15 | AES_ECB_prototype.encrypt = AES_Encrypt_finish; 16 | AES_ECB_prototype.decrypt = AES_Decrypt_finish; 17 | 18 | function AES_ECB_Encrypt ( options ) { 19 | AES_ECB.call( this, options ); 20 | } 21 | 22 | var AES_ECB_Encrypt_prototype = AES_ECB_Encrypt.prototype; 23 | AES_ECB_Encrypt_prototype.reset = AES_reset; 24 | AES_ECB_Encrypt_prototype.process = AES_Encrypt_process; 25 | AES_ECB_Encrypt_prototype.finish = AES_Encrypt_finish; 26 | 27 | function AES_ECB_Decrypt ( options ) { 28 | AES_ECB.call( this, options ); 29 | } 30 | 31 | var AES_ECB_Decrypt_prototype = AES_ECB_Decrypt.prototype; 32 | AES_ECB_Decrypt_prototype.reset = AES_reset; 33 | AES_ECB_Decrypt_prototype.process = AES_Decrypt_process; 34 | AES_ECB_Decrypt_prototype.finish = AES_Decrypt_finish; 35 | 36 | var get_AES_ECB_instance = function () 37 | { 38 | var _instance = null; 39 | 40 | return function ( options ) { 41 | if ( _instance ) return _instance.reset(options); 42 | 43 | // options = options || {}; 44 | // options.heap = options.heap || _aes_heap_instance; 45 | // options.asm = options.asm || _aes_asm_instance; 46 | 47 | return _instance = new AES_ECB(options); 48 | }; 49 | }(); 50 | -------------------------------------------------------------------------------- /src/aes/cbc/cbc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cipher Block Chaining Mode (CBC) 3 | */ 4 | 5 | function AES_CBC ( options ) { 6 | this.padding = true; 7 | this.iv = null; 8 | 9 | AES.call( this, options ); 10 | 11 | this.mode = 'CBC'; 12 | } 13 | 14 | var AES_CBC_prototype = AES_CBC.prototype; 15 | AES_CBC_prototype.reset = AES_reset; 16 | AES_CBC_prototype.encrypt = AES_Encrypt_finish; 17 | AES_CBC_prototype.decrypt = AES_Decrypt_finish; 18 | 19 | function AES_CBC_Encrypt ( options ) { 20 | AES_CBC.call( this, options ); 21 | } 22 | 23 | var AES_CBC_Encrypt_prototype = AES_CBC_Encrypt.prototype; 24 | AES_CBC_Encrypt_prototype.reset = AES_reset; 25 | AES_CBC_Encrypt_prototype.process = AES_Encrypt_process; 26 | AES_CBC_Encrypt_prototype.finish = AES_Encrypt_finish; 27 | 28 | function AES_CBC_Decrypt ( options ) { 29 | AES_CBC.call( this, options ); 30 | } 31 | 32 | var AES_CBC_Decrypt_prototype = AES_CBC_Decrypt.prototype; 33 | AES_CBC_Decrypt_prototype.reset = AES_reset; 34 | AES_CBC_Decrypt_prototype.process = AES_Decrypt_process; 35 | AES_CBC_Decrypt_prototype.finish = AES_Decrypt_finish; 36 | 37 | var get_AES_CBC_instance = function () 38 | { 39 | var _instance = null; 40 | 41 | return function ( options ) { 42 | if ( _instance ) return _instance.reset(options); 43 | 44 | // options = options || {}; 45 | // options.heap = options.heap || _aes_heap_instance; 46 | // options.asm = options.asm || _aes_asm_instance; 47 | 48 | return _instance = new AES_CBC(options); 49 | }; 50 | }(); 51 | -------------------------------------------------------------------------------- /src/hash/hash.js: -------------------------------------------------------------------------------- 1 | function hash_reset () { 2 | this.result = null; 3 | this.pos = 0; 4 | this.len = 0; 5 | 6 | this.asm.reset(); 7 | 8 | return this; 9 | } 10 | 11 | function hash_process ( data ) { 12 | if ( this.result !== null ) 13 | throw new IllegalStateError("state must be reset before processing new data"); 14 | 15 | if ( is_string(data) ) 16 | data = string_to_bytes(data); 17 | 18 | if ( is_buffer(data) ) 19 | data = new Uint8Array(data); 20 | 21 | if ( !is_bytes(data) ) 22 | throw new TypeError("data isn't of expected type"); 23 | 24 | var asm = this.asm, 25 | heap = this.heap, 26 | hpos = this.pos, 27 | hlen = this.len, 28 | dpos = 0, 29 | dlen = data.length, 30 | wlen = 0; 31 | 32 | while ( dlen > 0 ) { 33 | wlen = _heap_write( heap, hpos+hlen, data, dpos, dlen ); 34 | hlen += wlen; 35 | dpos += wlen; 36 | dlen -= wlen; 37 | 38 | wlen = asm.process( hpos, hlen ); 39 | 40 | hpos += wlen; 41 | hlen -= wlen; 42 | 43 | if ( !hlen ) hpos = 0; 44 | } 45 | 46 | this.pos = hpos; 47 | this.len = hlen; 48 | 49 | return this; 50 | } 51 | 52 | function hash_finish () { 53 | if ( this.result !== null ) 54 | throw new IllegalStateError("state must be reset before processing new data"); 55 | 56 | this.asm.finish( this.pos, this.len, 0 ); 57 | 58 | this.result = new Uint8Array(this.HASH_SIZE); 59 | this.result.set( this.heap.subarray( 0, this.HASH_SIZE ) ); 60 | 61 | this.pos = 0; 62 | this.len = 0; 63 | 64 | return this; 65 | } 66 | -------------------------------------------------------------------------------- /src/pbkdf2/pbkdf2-hmac-sha1.js: -------------------------------------------------------------------------------- 1 | function pbkdf2_hmac_sha1_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !( options.hmac instanceof hmac_sha1_constructor ) ) 5 | options.hmac = get_hmac_sha1_instance(); 6 | 7 | pbkdf2_constructor.call( this, options ); 8 | 9 | return this; 10 | } 11 | 12 | function pbkdf2_hmac_sha1_generate ( salt, count, length ) { 13 | if ( this.result !== null ) 14 | throw new IllegalStateError("state must be reset before processing new data"); 15 | 16 | if ( !salt && !is_string(salt) ) 17 | throw new IllegalArgumentError("bad 'salt' value"); 18 | 19 | count = count || this.count; 20 | length = length || this.length; 21 | 22 | this.result = new Uint8Array(length); 23 | 24 | var blocks = Math.ceil( length / this.hmac.HMAC_SIZE ); 25 | 26 | for ( var i = 1; i <= blocks; ++i ) { 27 | var j = ( i - 1 ) * this.hmac.HMAC_SIZE; 28 | var l = ( i < blocks ? 0 : length % this.hmac.HMAC_SIZE ) || this.hmac.HMAC_SIZE; 29 | 30 | this.hmac.reset().process(salt); 31 | this.hmac.hash.asm.pbkdf2_generate_block( this.hmac.hash.pos, this.hmac.hash.len, i, count, 0 ); 32 | 33 | this.result.set( this.hmac.hash.heap.subarray( 0, l ), j ); 34 | } 35 | 36 | return this; 37 | } 38 | 39 | var pbkdf2_hmac_sha1_prototype = pbkdf2_hmac_sha1_constructor.prototype; 40 | pbkdf2_hmac_sha1_prototype.reset = pbkdf2_reset; 41 | pbkdf2_hmac_sha1_prototype.generate = pbkdf2_hmac_sha1_generate; 42 | 43 | var pbkdf2_hmac_sha1_instance = null; 44 | 45 | function get_pbkdf2_hmac_sha1_instance () { 46 | if ( pbkdf2_hmac_sha1_instance === null ) pbkdf2_hmac_sha1_instance = new pbkdf2_hmac_sha1_constructor(); 47 | return pbkdf2_hmac_sha1_instance; 48 | } 49 | -------------------------------------------------------------------------------- /src/pbkdf2/pbkdf2-hmac-sha256.js: -------------------------------------------------------------------------------- 1 | function pbkdf2_hmac_sha256_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !( options.hmac instanceof hmac_sha256_constructor ) ) 5 | options.hmac = get_hmac_sha256_instance(); 6 | 7 | pbkdf2_constructor.call( this, options ); 8 | 9 | return this; 10 | } 11 | 12 | function pbkdf2_hmac_sha256_generate ( salt, count, length ) { 13 | if ( this.result !== null ) 14 | throw new IllegalStateError("state must be reset before processing new data"); 15 | 16 | if ( !salt && !is_string(salt) ) 17 | throw new IllegalArgumentError("bad 'salt' value"); 18 | 19 | count = count || this.count; 20 | length = length || this.length; 21 | 22 | this.result = new Uint8Array(length); 23 | 24 | var blocks = Math.ceil( length / this.hmac.HMAC_SIZE ); 25 | 26 | for ( var i = 1; i <= blocks; ++i ) { 27 | var j = ( i - 1 ) * this.hmac.HMAC_SIZE; 28 | var l = ( i < blocks ? 0 : length % this.hmac.HMAC_SIZE ) || this.hmac.HMAC_SIZE; 29 | 30 | this.hmac.reset().process(salt); 31 | this.hmac.hash.asm.pbkdf2_generate_block( this.hmac.hash.pos, this.hmac.hash.len, i, count, 0 ); 32 | 33 | this.result.set( this.hmac.hash.heap.subarray( 0, l ), j ); 34 | } 35 | 36 | return this; 37 | } 38 | 39 | var pbkdf2_hmac_sha256_prototype = pbkdf2_hmac_sha256_constructor.prototype; 40 | pbkdf2_hmac_sha256_prototype.reset = pbkdf2_reset; 41 | pbkdf2_hmac_sha256_prototype.generate = pbkdf2_hmac_sha256_generate; 42 | 43 | var pbkdf2_hmac_sha256_instance = null; 44 | 45 | function get_pbkdf2_hmac_sha256_instance () { 46 | if ( pbkdf2_hmac_sha256_instance === null ) pbkdf2_hmac_sha256_instance = new pbkdf2_hmac_sha256_constructor(); 47 | return pbkdf2_hmac_sha256_instance; 48 | } 49 | -------------------------------------------------------------------------------- /src/pbkdf2/pbkdf2-hmac-sha512.js: -------------------------------------------------------------------------------- 1 | function pbkdf2_hmac_sha512_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !( options.hmac instanceof hmac_sha512_constructor ) ) 5 | options.hmac = get_hmac_sha512_instance(); 6 | 7 | pbkdf2_constructor.call( this, options ); 8 | 9 | return this; 10 | } 11 | 12 | function pbkdf2_hmac_sha512_generate ( salt, count, length ) { 13 | if ( this.result !== null ) 14 | throw new IllegalStateError("state must be reset before processing new data"); 15 | 16 | if ( !salt && !is_string(salt) ) 17 | throw new IllegalArgumentError("bad 'salt' value"); 18 | 19 | count = count || this.count; 20 | length = length || this.length; 21 | 22 | this.result = new Uint8Array(length); 23 | 24 | var blocks = Math.ceil( length / this.hmac.HMAC_SIZE ); 25 | 26 | for ( var i = 1; i <= blocks; ++i ) { 27 | var j = ( i - 1 ) * this.hmac.HMAC_SIZE; 28 | var l = ( i < blocks ? 0 : length % this.hmac.HMAC_SIZE ) || this.hmac.HMAC_SIZE; 29 | 30 | this.hmac.reset().process(salt); 31 | this.hmac.hash.asm.pbkdf2_generate_block( this.hmac.hash.pos, this.hmac.hash.len, i, count, 0 ); 32 | 33 | this.result.set( this.hmac.hash.heap.subarray( 0, l ), j ); 34 | } 35 | 36 | return this; 37 | } 38 | 39 | var pbkdf2_hmac_sha512_prototype = pbkdf2_hmac_sha512_constructor.prototype; 40 | pbkdf2_hmac_sha512_prototype.reset = pbkdf2_reset; 41 | pbkdf2_hmac_sha512_prototype.generate = pbkdf2_hmac_sha512_generate; 42 | 43 | var pbkdf2_hmac_sha512_instance = null; 44 | 45 | function get_pbkdf2_hmac_sha512_instance () { 46 | if ( pbkdf2_hmac_sha512_instance === null ) pbkdf2_hmac_sha512_instance = new pbkdf2_hmac_sha512_constructor(); 47 | return pbkdf2_hmac_sha512_instance; 48 | } 49 | -------------------------------------------------------------------------------- /src/rsa/genkey.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate RSA key pair 3 | * 4 | * @param bitlen desired modulus length, default is 2048 5 | * @param e public exponent, default is 65537 6 | */ 7 | function RSA_generateKey ( bitlen, e ) { 8 | bitlen = bitlen || 2048; 9 | e = e || 65537; 10 | 11 | if ( bitlen < 512 ) 12 | throw new IllegalArgumentError("bit length is too small"); 13 | 14 | if ( is_string(e) ) 15 | e = string_to_bytes(e); 16 | 17 | if ( is_buffer(e) ) 18 | e = new Uint8Array(e); 19 | 20 | if ( is_bytes(e) || is_number(e) || is_big_number(e) ) { 21 | e = new BigNumber(e); 22 | } 23 | else { 24 | throw new TypeError("unexpected exponent type"); 25 | } 26 | 27 | if ( ( e.limbs[0] & 1 ) === 0 ) 28 | throw new IllegalArgumentError("exponent must be an odd number"); 29 | 30 | var m, e, d, p, q, p1, q1, dp, dq, u; 31 | 32 | p = BigNumber_randomProbablePrime( 33 | bitlen >> 1, 34 | function ( p ) { 35 | p1 = new BigNumber(p); p1.limbs[0] -= 1; 36 | return BigNumber_extGCD( p1, e ).gcd.valueOf() == 1; 37 | } 38 | ); 39 | 40 | q = BigNumber_randomProbablePrime( 41 | bitlen - (bitlen >> 1), 42 | function ( q ) { 43 | m = new Modulus( p.multiply(q) ); 44 | if ( !( m.limbs[ ( (bitlen + 31) >> 5 ) - 1 ] >>> ( (bitlen - 1) & 31) ) ) return false; 45 | q1 = new BigNumber(q); q1.limbs[0] -= 1; 46 | return BigNumber_extGCD( q1, e ).gcd.valueOf() == 1; 47 | } 48 | ); 49 | 50 | d = new Modulus( p1.multiply(q1) ).inverse(e); 51 | 52 | dp = d.divide(p1).remainder, 53 | dq = d.divide(q1).remainder; 54 | 55 | p = new Modulus(p), 56 | q = new Modulus(q); 57 | 58 | var u = p.inverse(q); 59 | 60 | return [ m, e, d, p, q, dp, dq, u ]; 61 | } 62 | 63 | RSA.generateKey = RSA_generateKey; 64 | -------------------------------------------------------------------------------- /src/pbkdf2/pbkdf2.js: -------------------------------------------------------------------------------- 1 | function pbkdf2_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !options.hmac ) 5 | throw new SyntaxError("option 'hmac' is required"); 6 | 7 | if ( !options.hmac.HMAC_SIZE ) 8 | throw new SyntaxError("option 'hmac' supplied doesn't seem to be a valid HMAC function"); 9 | 10 | this.hmac = options.hmac; 11 | this.count = options.count || 4096; 12 | this.length = options.length || this.hmac.HMAC_SIZE; 13 | 14 | this.result = null; 15 | 16 | var password = options.password; 17 | if ( password || is_string(password) ) 18 | this.reset(options); 19 | 20 | return this; 21 | } 22 | 23 | function pbkdf2_reset ( options ) { 24 | this.result = null; 25 | 26 | this.hmac.reset(options); 27 | 28 | return this; 29 | } 30 | 31 | function pbkdf2_generate ( salt, count, length ) { 32 | if ( this.result !== null ) 33 | throw new IllegalStateError("state must be reset before processing new data"); 34 | 35 | if ( !salt && !is_string(salt) ) 36 | throw new IllegalArgumentError("bad 'salt' value"); 37 | 38 | count = count || this.count; 39 | length = length || this.length; 40 | 41 | this.result = new Uint8Array(length); 42 | 43 | var blocks = Math.ceil( length / this.hmac.HMAC_SIZE ); 44 | 45 | for ( var i = 1; i <= blocks; ++i ) { 46 | var j = ( i - 1 ) * this.hmac.HMAC_SIZE; 47 | var l = ( i < blocks ? 0 : length % this.hmac.HMAC_SIZE ) || this.hmac.HMAC_SIZE; 48 | var tmp = new Uint8Array( this.hmac.reset().process(salt).process( new Uint8Array([ i>>>24&0xff, i>>>16&0xff, i>>>8&0xff, i&0xff ]) ).finish().result ); 49 | this.result.set( tmp.subarray( 0, l ), j ); 50 | for ( var k = 1; k < count; ++k ) { 51 | tmp = new Uint8Array( this.hmac.reset().process(tmp).finish().result ); 52 | for ( var r = 0; r < l; ++r ) this.result[j+r] ^= tmp[r]; 53 | } 54 | } 55 | 56 | return this; 57 | } 58 | 59 | // methods 60 | var pbkdf2_prototype = pbkdf2_constructor.prototype; 61 | pbkdf2_prototype.reset = pbkdf2_reset; 62 | pbkdf2_prototype.generate = pbkdf2_generate; 63 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | asmCrypto test suite 6 | 7 | 8 | 9 | 26 | 27 | 56 | 57 | 58 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
81 | 82 | -------------------------------------------------------------------------------- /src/bignum/extgcd.js: -------------------------------------------------------------------------------- 1 | function Number_extGCD ( a, b ) { 2 | var sa = ( a < 0 ) ? -1 : 1, 3 | sb = ( b < 0 ) ? -1 : 1, 4 | xi = 1, xj = 0, 5 | yi = 0, yj = 1, 6 | r, q, t, a_cmp_b; 7 | 8 | a *= sa; 9 | b *= sb; 10 | 11 | a_cmp_b = ( a < b ); 12 | if ( a_cmp_b ) { 13 | t = a; a = b, b = t; 14 | t = sa; sa = sb; sb = t; 15 | } 16 | 17 | q = Math.floor( a / b ), r = a - q*b; 18 | while ( r ) { 19 | t = xi - q*xj, xi = xj, xj = t; 20 | t = yi - q*yj, yi = yj, yj = t; 21 | a = b, b = r; 22 | 23 | q = Math.floor( a / b ), r = a - q*b; 24 | } 25 | 26 | xj *= sa; 27 | yj *= sb; 28 | 29 | if ( a_cmp_b ) { 30 | t = xj; xj = yj, yj = t; 31 | } 32 | 33 | return { 34 | gcd: b, 35 | x: xj, 36 | y: yj 37 | }; 38 | } 39 | 40 | function BigNumber_extGCD ( a, b ) { 41 | if ( !is_big_number(a) ) 42 | a = new BigNumber(a); 43 | 44 | if ( !is_big_number(b) ) 45 | b = new BigNumber(b); 46 | 47 | var sa = a.sign, sb = b.sign; 48 | 49 | if ( sa < 0 ) 50 | a = a.negate(); 51 | 52 | if ( sb < 0 ) 53 | b = b.negate(); 54 | 55 | var a_cmp_b = a.compare(b); 56 | if ( a_cmp_b < 0 ) { 57 | var t = a; a = b, b = t; 58 | t = sa; sa = sb; sb = t; 59 | } 60 | 61 | var xi = BigNumber_ONE, xj = BigNumber_ZERO, lx = b.bitLength, 62 | yi = BigNumber_ZERO, yj = BigNumber_ONE, ly = a.bitLength, 63 | z, r, q; 64 | 65 | z = a.divide(b); 66 | while ( (r = z.remainder) !== BigNumber_ZERO ) { 67 | q = z.quotient; 68 | 69 | z = xi.subtract( q.multiply(xj).clamp(lx) ).clamp(lx), xi = xj, xj = z; 70 | z = yi.subtract( q.multiply(yj).clamp(ly) ).clamp(ly), yi = yj, yj = z; 71 | 72 | a = b, b = r; 73 | 74 | z = a.divide(b); 75 | } 76 | 77 | if ( sa < 0 ) 78 | xj = xj.negate(); 79 | 80 | if ( sb < 0 ) 81 | yj = yj.negate(); 82 | 83 | if ( a_cmp_b < 0 ) { 84 | var t = xj; xj = yj, yj = t; 85 | } 86 | 87 | return { 88 | gcd: b, 89 | x: xj, 90 | y: yj 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /src/aes/exports.js: -------------------------------------------------------------------------------- 1 | // shared asm.js module and heap 2 | var _aes_heap_instance = new Uint8Array(0x100000), 3 | _aes_asm_instance = aes_asm( global, null, _aes_heap_instance.buffer ); 4 | 5 | function createSimpleCipherInterface ( Constructor ) 6 | { 7 | return function SimpleCipher ( options ) { 8 | var _instance = new Constructor(options); 9 | 10 | Object.defineProperties( this, { 11 | mode: { 12 | value: _instance.mode 13 | }, 14 | encrypt: { 15 | value: function ( data, options ) { 16 | if ( options && options.key !== undefined ) throw new IllegalStateError("'key' option is forbidden on cipher instance"); 17 | return _instance.reset(options).encrypt(data).result; 18 | } 19 | }, 20 | decrypt: { 21 | value: function ( data, options ) { 22 | if ( options && options.key !== undefined ) throw new IllegalStateError("'key' option is forbidden on cipher instance"); 23 | return _instance.reset(options).decrypt(data).result; 24 | } 25 | } 26 | }); 27 | }; 28 | } 29 | 30 | function createProgressiveCipherInterface ( Constructor ) 31 | { 32 | return function ProgressiveCipher ( options ) { 33 | var _instance = new Constructor(options); 34 | 35 | if ( _instance.hasOwnProperty('padding') ) { 36 | Object.defineProperty( this, 'padding', { 37 | value: _instance.padding 38 | }); 39 | } 40 | 41 | if ( _instance.hasOwnProperty('iv') ) { 42 | Object.defineProperty( this, 'iv', { 43 | value: _instance.iv 44 | }); 45 | } 46 | 47 | Object.defineProperties( this, { 48 | mode: { 49 | value: _instance.mode 50 | }, 51 | process: { 52 | value: function ( data ) { 53 | return _instance.process(data).result; 54 | } 55 | }, 56 | finish: { 57 | value: function ( data ) { 58 | return _instance.finish(data).result; 59 | } 60 | } 61 | }); 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/aes/aes.js: -------------------------------------------------------------------------------- 1 | var _aes_block_size = 16; 2 | 3 | function _aes_constructor ( options ) { 4 | options = options || {}; 5 | 6 | this.BLOCK_SIZE = _aes_block_size; 7 | 8 | this.heap = _heap_init( Uint8Array, options ); 9 | this.asm = options.asm || aes_asm( global, null, this.heap.buffer ); 10 | this.pos = _aes_heap_start; 11 | this.len = 0; 12 | 13 | this.key = null; 14 | this.result = null; 15 | 16 | this.reset( options ); 17 | } 18 | 19 | function _aes_reset ( options ) { 20 | options = options || {}; 21 | 22 | this.result = null; 23 | this.pos = _aes_heap_start; 24 | this.len = 0; 25 | 26 | var asm = this.asm; 27 | 28 | var key = options.key; 29 | if ( key !== undefined ) { 30 | if ( is_buffer(key) || is_bytes(key) ) { 31 | key = new Uint8Array(key); 32 | } 33 | else if ( is_string(key) ) { 34 | key = string_to_bytes(key); 35 | } 36 | else { 37 | throw new TypeError("unexpected key type"); 38 | } 39 | 40 | if ( key.length === 16 ) { 41 | asm.init_key_128( key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); 42 | } 43 | else if ( key.length === 24 ) { 44 | // TODO support of 192-bit keys 45 | throw new IllegalArgumentError("illegal key size"); 46 | } 47 | else if ( key.length === 32 ) { 48 | asm.init_key_256( key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7], key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15], key[16], key[17], key[18], key[19], key[20], key[21], key[22], key[23], key[24], key[25], key[26], key[27], key[28], key[29], key[30], key[31]); 49 | } 50 | else { 51 | throw new IllegalArgumentError("illegal key size"); 52 | } 53 | 54 | this.key = key; 55 | } 56 | 57 | return this; 58 | } 59 | 60 | function _aes_init_iv ( iv ) { 61 | var asm = this.asm; 62 | 63 | if ( iv !== undefined ) { 64 | if ( is_buffer(iv) || is_bytes(iv) ) { 65 | iv = new Uint8Array(iv); 66 | } 67 | else if ( is_string(iv) ) { 68 | iv = string_to_bytes(iv); 69 | } 70 | else { 71 | throw new TypeError("unexpected iv type"); 72 | } 73 | 74 | if ( iv.length !== _aes_block_size ) 75 | throw new IllegalArgumentError("illegal iv size"); 76 | 77 | this.iv = iv; 78 | asm.init_state( iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], iv[12], iv[13], iv[14], iv[15] ); 79 | } 80 | else { 81 | this.iv = null; 82 | asm.init_state( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var FloatArray = global.Float64Array || global.Float32Array; // make PhantomJS happy 4 | 5 | function string_to_bytes ( str ) { 6 | var len = str.length, 7 | arr = new Uint8Array( len ); 8 | for ( var i = 0; i < len; i++ ) { 9 | var c = str.charCodeAt(i); 10 | if ( c >>> 8 ) throw new Error("Wide characters are not allowed"); 11 | arr[i] = c; 12 | } 13 | return arr; 14 | } 15 | 16 | function hex_to_bytes ( str ) { 17 | var arr = [], 18 | len = str.length, 19 | i; 20 | if ( len & 1 ) { 21 | str = '0'+str; 22 | len++; 23 | } 24 | for ( i=0; i>> 1; 57 | a |= a >>> 2; 58 | a |= a >>> 4; 59 | a |= a >>> 8; 60 | a |= a >>> 16; 61 | a += 1; 62 | return a; 63 | } 64 | 65 | function is_number ( a ) { 66 | return ( typeof a === 'number' ); 67 | } 68 | 69 | function is_string ( a ) { 70 | return ( typeof a === 'string' ); 71 | } 72 | 73 | function is_buffer ( a ) { 74 | return ( a instanceof ArrayBuffer ); 75 | } 76 | 77 | function is_bytes ( a ) { 78 | return ( a instanceof Uint8Array ); 79 | } 80 | 81 | function is_typed_array ( a ) { 82 | return ( a instanceof Int8Array ) || ( a instanceof Uint8Array ) 83 | || ( a instanceof Int16Array ) || ( a instanceof Uint16Array ) 84 | || ( a instanceof Int32Array ) || ( a instanceof Uint32Array ) 85 | || ( a instanceof Float32Array ) 86 | || ( a instanceof Float64Array ); 87 | } 88 | 89 | function _heap_init ( constructor, options ) { 90 | var heap = options.heap, 91 | size = heap ? heap.byteLength : options.heapSize || 65536; 92 | 93 | if ( size & 0xfff || size <= 0 ) 94 | throw new Error("heap size must be a positive integer and a multiple of 4096"); 95 | 96 | heap = heap || new constructor( new ArrayBuffer(size) ); 97 | 98 | return heap; 99 | } 100 | 101 | function _heap_write ( heap, hpos, data, dpos, dlen ) { 102 | var hlen = heap.length - hpos, 103 | wlen = ( hlen < dlen ) ? hlen : dlen; 104 | 105 | heap.set( data.subarray( dpos, dpos+wlen ), hpos ); 106 | 107 | return wlen; 108 | } 109 | -------------------------------------------------------------------------------- /src/hmac/hmac-sha256.js: -------------------------------------------------------------------------------- 1 | function hmac_sha256_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !( options.hash instanceof sha256_constructor ) ) 5 | options.hash = get_sha256_instance(); 6 | 7 | hmac_constructor.call( this, options ); 8 | 9 | return this; 10 | } 11 | 12 | function hmac_sha256_reset ( options ) { 13 | options = options || {}; 14 | 15 | this.result = null; 16 | this.hash.reset(); 17 | 18 | var password = options.password; 19 | if ( password !== undefined ) { 20 | if ( is_string(password) ) 21 | password = string_to_bytes(password); 22 | 23 | var key = this.key = _hmac_key( this.hash, password ); 24 | this.hash.reset().asm.hmac_init( 25 | (key[0]<<24)|(key[1]<<16)|(key[2]<<8)|(key[3]), 26 | (key[4]<<24)|(key[5]<<16)|(key[6]<<8)|(key[7]), 27 | (key[8]<<24)|(key[9]<<16)|(key[10]<<8)|(key[11]), 28 | (key[12]<<24)|(key[13]<<16)|(key[14]<<8)|(key[15]), 29 | (key[16]<<24)|(key[17]<<16)|(key[18]<<8)|(key[19]), 30 | (key[20]<<24)|(key[21]<<16)|(key[22]<<8)|(key[23]), 31 | (key[24]<<24)|(key[25]<<16)|(key[26]<<8)|(key[27]), 32 | (key[28]<<24)|(key[29]<<16)|(key[30]<<8)|(key[31]), 33 | (key[32]<<24)|(key[33]<<16)|(key[34]<<8)|(key[35]), 34 | (key[36]<<24)|(key[37]<<16)|(key[38]<<8)|(key[39]), 35 | (key[40]<<24)|(key[41]<<16)|(key[42]<<8)|(key[43]), 36 | (key[44]<<24)|(key[45]<<16)|(key[46]<<8)|(key[47]), 37 | (key[48]<<24)|(key[49]<<16)|(key[50]<<8)|(key[51]), 38 | (key[52]<<24)|(key[53]<<16)|(key[54]<<8)|(key[55]), 39 | (key[56]<<24)|(key[57]<<16)|(key[58]<<8)|(key[59]), 40 | (key[60]<<24)|(key[61]<<16)|(key[62]<<8)|(key[63]) 41 | ); 42 | } 43 | else { 44 | this.hash.asm.hmac_reset(); 45 | } 46 | 47 | var verify = options.verify; 48 | if ( verify !== undefined ) { 49 | _hmac_init_verify.call( this, verify ); 50 | } 51 | else { 52 | this.verify = null; 53 | } 54 | 55 | return this; 56 | } 57 | 58 | function hmac_sha256_finish () { 59 | if ( this.key === null ) 60 | throw new IllegalStateError("no key is associated with the instance"); 61 | 62 | if ( this.result !== null ) 63 | throw new IllegalStateError("state must be reset before processing new data"); 64 | 65 | var hash = this.hash, 66 | asm = this.hash.asm, 67 | heap = this.hash.heap; 68 | 69 | asm.hmac_finish( hash.pos, hash.len, 0 ); 70 | 71 | var verify = this.verify; 72 | var result = new Uint8Array(_sha256_hash_size); 73 | result.set( heap.subarray( 0, _sha256_hash_size ) ); 74 | 75 | if ( verify ) { 76 | if ( verify.length === result.length ) { 77 | var diff = 0; 78 | for ( var i = 0; i < verify.length; i++ ) { 79 | diff |= ( verify[i] ^ result[i] ); 80 | } 81 | this.result = !diff; 82 | } else { 83 | this.result = false; 84 | } 85 | } 86 | else { 87 | this.result = result; 88 | } 89 | 90 | return this; 91 | } 92 | 93 | hmac_sha256_constructor.BLOCK_SIZE = sha256_constructor.BLOCK_SIZE; 94 | hmac_sha256_constructor.HMAC_SIZE = sha256_constructor.HASH_SIZE; 95 | 96 | var hmac_sha256_prototype = hmac_sha256_constructor.prototype; 97 | hmac_sha256_prototype.reset = hmac_sha256_reset; 98 | hmac_sha256_prototype.process = hmac_process; 99 | hmac_sha256_prototype.finish = hmac_sha256_finish; 100 | 101 | var hmac_sha256_instance = null; 102 | 103 | function get_hmac_sha256_instance () { 104 | if ( hmac_sha256_instance === null ) hmac_sha256_instance = new hmac_sha256_constructor(); 105 | return hmac_sha256_instance; 106 | } 107 | -------------------------------------------------------------------------------- /src/hmac/hmac-sha1.js: -------------------------------------------------------------------------------- 1 | function hmac_sha1_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !( options.hash instanceof sha1_constructor ) ) 5 | options.hash = get_sha1_instance(); 6 | 7 | hmac_constructor.call( this, options ); 8 | 9 | return this; 10 | } 11 | 12 | function hmac_sha1_reset ( options ) { 13 | options = options || {}; 14 | 15 | this.result = null; 16 | this.hash.reset(); 17 | 18 | var password = options.password; 19 | if ( password !== undefined ) { 20 | if ( is_string(password) ) 21 | password = string_to_bytes(password); 22 | 23 | var key = this.key = _hmac_key( this.hash, password ); 24 | this.hash.reset().asm.hmac_init( 25 | (key[0]<<24)|(key[1]<<16)|(key[2]<<8)|(key[3]), 26 | (key[4]<<24)|(key[5]<<16)|(key[6]<<8)|(key[7]), 27 | (key[8]<<24)|(key[9]<<16)|(key[10]<<8)|(key[11]), 28 | (key[12]<<24)|(key[13]<<16)|(key[14]<<8)|(key[15]), 29 | (key[16]<<24)|(key[17]<<16)|(key[18]<<8)|(key[19]), 30 | (key[20]<<24)|(key[21]<<16)|(key[22]<<8)|(key[23]), 31 | (key[24]<<24)|(key[25]<<16)|(key[26]<<8)|(key[27]), 32 | (key[28]<<24)|(key[29]<<16)|(key[30]<<8)|(key[31]), 33 | (key[32]<<24)|(key[33]<<16)|(key[34]<<8)|(key[35]), 34 | (key[36]<<24)|(key[37]<<16)|(key[38]<<8)|(key[39]), 35 | (key[40]<<24)|(key[41]<<16)|(key[42]<<8)|(key[43]), 36 | (key[44]<<24)|(key[45]<<16)|(key[46]<<8)|(key[47]), 37 | (key[48]<<24)|(key[49]<<16)|(key[50]<<8)|(key[51]), 38 | (key[52]<<24)|(key[53]<<16)|(key[54]<<8)|(key[55]), 39 | (key[56]<<24)|(key[57]<<16)|(key[58]<<8)|(key[59]), 40 | (key[60]<<24)|(key[61]<<16)|(key[62]<<8)|(key[63]) 41 | ); 42 | } 43 | else { 44 | this.hash.asm.hmac_reset(); 45 | } 46 | 47 | var verify = options.verify; 48 | if ( verify !== undefined ) { 49 | _hmac_init_verify.call( this, verify ); 50 | } 51 | else { 52 | this.verify = null; 53 | } 54 | 55 | return this; 56 | } 57 | 58 | function hmac_sha1_finish () { 59 | if ( this.key === null ) 60 | throw new IllegalStateError("no key is associated with the instance"); 61 | 62 | if ( this.result !== null ) 63 | throw new IllegalStateError("state must be reset before processing new data"); 64 | 65 | var hash = this.hash, 66 | asm = this.hash.asm, 67 | heap = this.hash.heap; 68 | 69 | asm.hmac_finish( hash.pos, hash.len, 0 ); 70 | 71 | var verify = this.verify; 72 | var result = new Uint8Array(_sha1_hash_size); 73 | result.set( heap.subarray( 0, _sha1_hash_size ) ); 74 | 75 | if ( verify ) { 76 | if ( verify.length === result.length ) { 77 | var diff = 0; 78 | for ( var i = 0; i < verify.length; i++ ) { 79 | diff |= ( verify[i] ^ result[i] ); 80 | } 81 | this.result = !diff; 82 | } else { 83 | this.result = false; 84 | } 85 | } 86 | else { 87 | this.result = result; 88 | } 89 | 90 | return this; 91 | } 92 | 93 | hmac_sha1_constructor.BLOCK_SIZE = sha1_constructor.BLOCK_SIZE; 94 | hmac_sha1_constructor.HMAC_SIZE = sha1_constructor.HASH_SIZE; 95 | 96 | var hmac_sha1_prototype = hmac_sha1_constructor.prototype; 97 | hmac_sha1_prototype.reset = hmac_sha1_reset; 98 | hmac_sha1_prototype.process = hmac_process; 99 | hmac_sha1_prototype.finish = hmac_sha1_finish; 100 | 101 | var hmac_sha1_instance = null; 102 | 103 | function get_hmac_sha1_instance () { 104 | if ( hmac_sha1_instance === null ) hmac_sha1_instance = new hmac_sha1_constructor(); 105 | return hmac_sha1_instance; 106 | } 107 | -------------------------------------------------------------------------------- /src/hmac/hmac.js: -------------------------------------------------------------------------------- 1 | function hmac_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !options.hash ) 5 | throw new SyntaxError("option 'hash' is required"); 6 | 7 | if ( !options.hash.HASH_SIZE ) 8 | throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); 9 | 10 | this.hash = options.hash; 11 | this.BLOCK_SIZE = this.hash.BLOCK_SIZE; 12 | this.HMAC_SIZE = this.hash.HASH_SIZE; 13 | 14 | this.key = null; 15 | this.verify = null; 16 | this.result = null; 17 | 18 | if ( options.password !== undefined || options.verify !== undefined ) 19 | this.reset(options); 20 | 21 | return this; 22 | } 23 | 24 | function _hmac_key ( hash, password ) { 25 | if ( is_buffer(password) ) 26 | password = new Uint8Array(password); 27 | 28 | if ( is_string(password) ) 29 | password = string_to_bytes(password); 30 | 31 | if ( !is_bytes(password) ) 32 | throw new TypeError("password isn't of expected type"); 33 | 34 | var key = new Uint8Array( hash.BLOCK_SIZE ); 35 | 36 | if ( password.length > hash.BLOCK_SIZE ) { 37 | key.set( hash.reset().process(password).finish().result ); 38 | } 39 | else { 40 | key.set(password); 41 | } 42 | 43 | return key; 44 | } 45 | 46 | function _hmac_init_verify ( verify ) { 47 | if ( is_buffer(verify) || is_bytes(verify) ) { 48 | verify = new Uint8Array(verify); 49 | } 50 | else if ( is_string(verify) ) { 51 | verify = string_to_bytes(verify); 52 | } 53 | else { 54 | throw new TypeError("verify tag isn't of expected type"); 55 | } 56 | 57 | if ( verify.length !== this.HMAC_SIZE ) 58 | throw new IllegalArgumentError("illegal verification tag size"); 59 | 60 | this.verify = verify; 61 | } 62 | 63 | function hmac_reset ( options ) { 64 | options = options || {}; 65 | var password = options.password; 66 | 67 | if ( this.key === null && !is_string(password) && !password ) 68 | throw new IllegalStateError("no key is associated with the instance"); 69 | 70 | this.result = null; 71 | this.hash.reset(); 72 | 73 | if ( password || is_string(password) ) 74 | this.key = _hmac_key( this.hash, password ); 75 | 76 | var ipad = new Uint8Array(this.key); 77 | for ( var i = 0; i < ipad.length; ++i ) 78 | ipad[i] ^= 0x36; 79 | 80 | this.hash.process(ipad); 81 | 82 | var verify = options.verify; 83 | if ( verify !== undefined ) { 84 | _hmac_init_verify.call( this, verify ); 85 | } 86 | else { 87 | this.verify = null; 88 | } 89 | 90 | return this; 91 | } 92 | 93 | function hmac_process ( data ) { 94 | if ( this.key === null ) 95 | throw new IllegalStateError("no key is associated with the instance"); 96 | 97 | if ( this.result !== null ) 98 | throw new IllegalStateError("state must be reset before processing new data"); 99 | 100 | this.hash.process(data); 101 | 102 | return this; 103 | } 104 | 105 | function hmac_finish () { 106 | if ( this.key === null ) 107 | throw new IllegalStateError("no key is associated with the instance"); 108 | 109 | if ( this.result !== null ) 110 | throw new IllegalStateError("state must be reset before processing new data"); 111 | 112 | var inner_result = this.hash.finish().result; 113 | 114 | var opad = new Uint8Array(this.key); 115 | for ( var i = 0; i < opad.length; ++i ) 116 | opad[i] ^= 0x5c; 117 | 118 | var verify = this.verify; 119 | var result = this.hash.reset().process(opad).process(inner_result).finish().result; 120 | 121 | if ( verify ) { 122 | if ( verify.length === result.length ) { 123 | var diff = 0; 124 | for ( var i = 0; i < verify.length; i++ ) { 125 | diff |= ( verify[i] ^ result[i] ); 126 | } 127 | this.result = !diff; 128 | } else { 129 | this.result = false; 130 | } 131 | } 132 | else { 133 | this.result = result; 134 | } 135 | 136 | return this; 137 | } 138 | 139 | var hmac_prototype = hmac_constructor.prototype; 140 | hmac_prototype.reset = hmac_reset; 141 | hmac_prototype.process = hmac_process; 142 | hmac_prototype.finish = hmac_finish; 143 | -------------------------------------------------------------------------------- /test/sha1.js: -------------------------------------------------------------------------------- 1 | module("SHA1"); 2 | 3 | /////////////////////////////////////////////////////////////////////////////// 4 | 5 | if ( typeof asmCrypto.SHA1 !== 'undefined' ) 6 | { 7 | var sha1_vectors = [ 8 | [ 'a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'], 9 | [ '84983e441c3bd26ebaae4aa1f95129e5e54670f1', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'], 10 | [ 'a49b2446a02c645bf419f995b67091253a04a259', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'], 11 | [ '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12', 'The quick brown fox jumps over the lazy dog' ], 12 | [ 'de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3', 'The quick brown fox jumps over the lazy cog' ] 13 | ]; 14 | 15 | test( "asmCrypto.SHA1.hex", function () { 16 | for ( var i = 0; i < sha1_vectors.length; ++i ) { 17 | equal( 18 | asmCrypto.SHA1.hex( sha1_vectors[i][1] ), 19 | sha1_vectors[i][0], 20 | "vector " + i 21 | ); 22 | } 23 | }); 24 | } 25 | else 26 | { 27 | skip( "asmCrypto.SHA1" ); 28 | } 29 | 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | if ( typeof asmCrypto.HMAC_SHA1 !== 'undefined' ) 33 | { 34 | var hmac_sha1_vectors = [ 35 | [ '5fd596ee78d5553c8ff4e72d266dfd192366da29', asmCrypto.hex_to_bytes('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f'), asmCrypto.hex_to_bytes('53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e') ], 36 | [ 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', '', '' ], 37 | [ 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', 'key', 'The quick brown fox jumps over the lazy dog' ], 38 | [ 'b617318655057264e28bc0b6fb378c8ef146be00', asmCrypto.hex_to_bytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'), 'Hi There' ], 39 | [ 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79', 'Jefe', 'what do ya want for nothing?'] 40 | ]; 41 | 42 | test( "asmCrypto.HMAC_SHA1.hex", function () { 43 | for ( var i = 0; i < hmac_sha1_vectors.length; ++i ) { 44 | equal( 45 | asmCrypto.HMAC_SHA1.hex( hmac_sha1_vectors[i][2], hmac_sha1_vectors[i][1] ), 46 | hmac_sha1_vectors[i][0], 47 | "vector " + i 48 | ); 49 | } 50 | }); 51 | } 52 | else 53 | { 54 | skip( "asmCrypto.HMAC_SHA1" ); 55 | } 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | 59 | if ( typeof asmCrypto.PBKDF2_HMAC_SHA1 !== 'undefined' ) 60 | { 61 | var pbkdf2_hmac_sha1_vectors = [ 62 | [ '0c60c80f961f0e71f3a9b524af6012062fe037a6', 'password', 'salt', 1, 20 ], 63 | [ 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957', 'password', 'salt', 2, 20 ], 64 | [ '4b007901b765489abead49d926f721d065a429c1', 'password', 'salt', 4096, 20 ], 65 | //[ 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984', 'password', 'salt', 16777216, 20 ], 66 | [ '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038', 'passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, 25 ], 67 | [ '56fa6aa75548099dcc37d7f03425e0c3', "pass\0word", "sa\0lt", 4096, 16 ] 68 | ]; 69 | 70 | test( "asmCrypto.PBKDF2_HMAC_SHA1.hex", function () { 71 | for ( var i = 0; i < pbkdf2_hmac_sha1_vectors.length; ++i ) { 72 | equal( 73 | // got 74 | asmCrypto.PBKDF2_HMAC_SHA1.hex( 75 | pbkdf2_hmac_sha1_vectors[i][1], // password 76 | pbkdf2_hmac_sha1_vectors[i][2], // salt 77 | pbkdf2_hmac_sha1_vectors[i][3], // count 78 | pbkdf2_hmac_sha1_vectors[i][4] // dklen 79 | ), 80 | 81 | // expect 82 | pbkdf2_hmac_sha1_vectors[i][0], 83 | 84 | // comment 85 | "asmCrypto.PBKDF2_HMAC_SHA1.hex('" 86 | +pbkdf2_hmac_sha1_vectors[i][1]+"', '" 87 | +pbkdf2_hmac_sha1_vectors[i][2]+"', '" 88 | +pbkdf2_hmac_sha1_vectors[i][3]+"', '" 89 | +pbkdf2_hmac_sha1_vectors[i][4] 90 | +"') is equal to '"+pbkdf2_hmac_sha1_vectors[i][0]+"'" 91 | ); 92 | } 93 | }); 94 | } 95 | else 96 | { 97 | skip( "asmCrypto.PBKDF2_HMAC_SHA1" ); 98 | } 99 | -------------------------------------------------------------------------------- /src/rsa/rsa.js: -------------------------------------------------------------------------------- 1 | function RSA ( options ) { 2 | options = options || {}; 3 | 4 | this.key = null; 5 | this.result = null; 6 | 7 | this.reset(options); 8 | } 9 | 10 | function RSA_reset ( options ) { 11 | options = options || {}; 12 | 13 | this.result = null; 14 | 15 | var key = options.key 16 | if ( key !== undefined ) { 17 | if ( key instanceof Array ) { 18 | var l = key.length; 19 | if ( l !== 2 && l !== 3 && l !== 8 ) 20 | throw new SyntaxError("unexpected key type"); 21 | 22 | var k = []; 23 | k[0] = new Modulus( key[0] ); 24 | k[1] = new BigNumber( key[1] ); 25 | if ( l > 2 ) { 26 | k[2] = new BigNumber( key[2] ); 27 | } 28 | if ( l > 3 ) { 29 | k[3] = new Modulus( key[3] ); 30 | k[4] = new Modulus( key[4] ); 31 | k[5] = new BigNumber( key[5] ); 32 | k[6] = new BigNumber( key[6] ); 33 | k[7] = new BigNumber( key[7] ); 34 | } 35 | 36 | this.key = k; 37 | } 38 | else { 39 | throw new TypeError("unexpected key type"); 40 | } 41 | } 42 | 43 | return this; 44 | } 45 | 46 | function RSA_encrypt ( data ) { 47 | if ( !this.key ) 48 | throw new IllegalStateError("no key is associated with the instance"); 49 | 50 | if ( is_string(data) ) 51 | data = string_to_bytes(data); 52 | 53 | if ( is_buffer(data) ) 54 | data = new Uint8Array(data); 55 | 56 | var msg; 57 | if ( is_bytes(data) ) { 58 | msg = new BigNumber(data); 59 | } 60 | else if ( is_big_number(data) ) { 61 | msg = data; 62 | } 63 | else { 64 | throw new TypeError("unexpected data type"); 65 | } 66 | 67 | if ( this.key[0].compare(msg) <= 0 ) 68 | throw new RangeError("data too large"); 69 | 70 | var m = this.key[0], 71 | e = this.key[1]; 72 | 73 | var result = m.power( msg, e ).toBytes(); 74 | 75 | var bytelen = m.bitLength + 7 >> 3; 76 | if ( result.length < bytelen ) { 77 | var r = new Uint8Array(bytelen); 78 | r.set( result, bytelen - result.length ); 79 | result = r; 80 | } 81 | 82 | this.result = result; 83 | 84 | return this; 85 | } 86 | 87 | function RSA_decrypt ( data ) { 88 | if ( !this.key ) 89 | throw new IllegalStateError("no key is associated with the instance"); 90 | 91 | if ( this.key.length < 3 ) 92 | throw new IllegalStateError("key isn't suitable for decription"); 93 | 94 | if ( is_string(data) ) 95 | data = string_to_bytes(data); 96 | 97 | if ( is_buffer(data) ) 98 | data = new Uint8Array(data); 99 | 100 | var msg; 101 | if ( is_bytes(data) ) { 102 | msg = new BigNumber(data); 103 | } 104 | else if ( is_big_number(data) ) { 105 | msg = data; 106 | } 107 | else { 108 | throw new TypeError("unexpected data type"); 109 | } 110 | 111 | if ( this.key[0].compare(msg) <= 0 ) 112 | throw new RangeError("data too large"); 113 | 114 | var result; 115 | if ( this.key.length > 3 ) { 116 | var m = this.key[0], 117 | p = this.key[3], 118 | q = this.key[4], 119 | dp = this.key[5], 120 | dq = this.key[6], 121 | u = this.key[7]; 122 | 123 | var x = p.power( msg, dp ), 124 | y = q.power( msg, dq ); 125 | 126 | var t = x.subtract(y); 127 | while ( t.sign < 0 ) t = t.add(p); 128 | 129 | var h = p.reduce( u.multiply(t) ); 130 | 131 | result = h.multiply(q).add(y).clamp(m.bitLength).toBytes(); 132 | } 133 | else { 134 | var m = this.key[0], 135 | d = this.key[2]; 136 | 137 | result = m.power( msg, d ).toBytes(); 138 | } 139 | 140 | var bytelen = m.bitLength + 7 >> 3; 141 | if ( result.length < bytelen ) { 142 | var r = new Uint8Array(bytelen); 143 | r.set( result, bytelen - result.length ); 144 | result = r; 145 | } 146 | 147 | this.result = result; 148 | 149 | return this; 150 | } 151 | 152 | var RSA_prototype = RSA.prototype; 153 | RSA_prototype.reset = RSA_reset; 154 | RSA_prototype.encrypt = RSA_encrypt; 155 | RSA_prototype.decrypt = RSA_decrypt; 156 | -------------------------------------------------------------------------------- /test/sha256.js: -------------------------------------------------------------------------------- 1 | module("SHA256"); 2 | 3 | /////////////////////////////////////////////////////////////////////////////// 4 | 5 | if ( typeof asmCrypto.SHA256 !== 'undefined' ) 6 | { 7 | var sha256_vectors = [ 8 | [ 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', '' ], 9 | [ 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', 'abc' ], 10 | [ 'f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650', 'message digest' ], 11 | [ 'f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d', 'secure hash algorithm' ], 12 | [ '6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630', 'SHA256 is considered to be safe' ], 13 | [ '248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq' ], 14 | [ 'f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342', 'For this sample, this 63-byte string will be used as input data' ], 15 | [ 'ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8', 'This is exactly 64 bytes long, not counting the terminating byte' ] 16 | ]; 17 | 18 | test( "asmCrypto.SHA256.hex", function () { 19 | for ( var i = 0; i < sha256_vectors.length; ++i ) { 20 | equal( 21 | asmCrypto.SHA256.hex( sha256_vectors[i][1] ), 22 | sha256_vectors[i][0], 23 | "vector " + i 24 | ); 25 | } 26 | }); 27 | } 28 | else 29 | { 30 | skip( "asmCrypto.SHA256" ); 31 | } 32 | 33 | /////////////////////////////////////////////////////////////////////////////// 34 | 35 | if ( typeof asmCrypto.HMAC_SHA256 !== 'undefined' ) 36 | { 37 | var hmac_sha256_vectors = [ 38 | [ 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad', '', '' ], 39 | [ 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8', 'key', 'The quick brown fox jumps over the lazy dog' ], 40 | [ 'b54d57e9b21940b6496b58d5ac120eda9f1637788b5df058928637f2eca40cd9', 'MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' ] 41 | ]; 42 | 43 | test( "asmCrypto.HMAC_SHA256.hex", function () { 44 | for ( var i = 0; i < hmac_sha256_vectors.length; ++i ) { 45 | equal( 46 | asmCrypto.HMAC_SHA256.hex( hmac_sha256_vectors[i][2], hmac_sha256_vectors[i][1] ), 47 | hmac_sha256_vectors[i][0], 48 | "vector " + i 49 | ); 50 | } 51 | }); 52 | } 53 | else 54 | { 55 | skip( "asmCrypto.HMAC_SHA256" ); 56 | } 57 | 58 | /////////////////////////////////////////////////////////////////////////////// 59 | 60 | if ( typeof asmCrypto.PBKDF2_HMAC_SHA256 !== 'undefined' ) 61 | { 62 | var pbkdf2_hmac_sha256_vectors = [ 63 | [ '120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b', 'password', 'salt', 1, 32 ], 64 | [ 'ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43', 'password', 'salt', 2, 32 ], 65 | [ 'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a', 'password', 'salt', 4096, 32 ], 66 | [ '348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9', 'passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, 40 ], 67 | [ '89b69d0516f829893c696226650a8687', "pass\0word", "sa\0lt", 4096, 16 ], 68 | [ 'cdc8b1780ca68aba97f1f729c9d281719702eb4b308d7d87409817e60188be0d', 'MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword', 'MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword', 4096, 32 ] 69 | ]; 70 | 71 | test( "asmCrypto.PBKDF2_HMAC_SHA256.hex", function () { 72 | for ( var i = 0; i < pbkdf2_hmac_sha256_vectors.length; ++i ) { 73 | equal( 74 | // got 75 | asmCrypto.PBKDF2_HMAC_SHA256.hex( 76 | pbkdf2_hmac_sha256_vectors[i][1], // password 77 | pbkdf2_hmac_sha256_vectors[i][2], // salt 78 | pbkdf2_hmac_sha256_vectors[i][3], // count 79 | pbkdf2_hmac_sha256_vectors[i][4] // dklen 80 | ), 81 | 82 | // expect 83 | pbkdf2_hmac_sha256_vectors[i][0], 84 | 85 | // comment 86 | "asmCrypto.PBKDF2_HMAC_SHA256.hex('" 87 | +pbkdf2_hmac_sha256_vectors[i][1]+"', '" 88 | +pbkdf2_hmac_sha256_vectors[i][2]+"', '" 89 | +pbkdf2_hmac_sha256_vectors[i][3]+"', '" 90 | +pbkdf2_hmac_sha256_vectors[i][4] 91 | +"') is equal to '"+pbkdf2_hmac_sha256_vectors[i][0]+"'" 92 | ); 93 | } 94 | }); 95 | } 96 | else 97 | { 98 | skip( "asmCrypto.PBKDF2_HMAC_SHA256" ); 99 | } 100 | -------------------------------------------------------------------------------- /test/dummy.js: -------------------------------------------------------------------------------- 1 | module("dummy"); 2 | 3 | test( "dummy test", function () { 4 | ok( true, "Passed!" ); 5 | }); 6 | 7 | test( "add with carry proparation", function () { 8 | var a = 0xad4e6ae6, b = 0xedfdecc8, c = 1, d = 0x19b4c57af, dc = 1, 9 | r = 0, rc = 0, u = 0, v = 0; 10 | 11 | r = (a + c)|0, rc = (r>>>0) < (a>>>0) ? 1 : 0; 12 | r = (b + r)|0, rc = (r>>>0) < (b>>>0) ? 1 : rc; 13 | equal( r>>>0, d>>>0, "adc32 result ok" ); 14 | equal( rc, dc, "adc32 carry ok" ); 15 | 16 | u = ( (a & 0xffff) + (b & 0xffff)|0 ) + c|0; 17 | v = ( (a >>> 16) + (b >>> 16)|0 ) + (u >>> 16)|0; 18 | r = (u & 0xffff) | (v << 16); 19 | rc = v >>> 16; 20 | equal( r>>>0, d>>>0, "adc16x2 result ok" ); 21 | equal( rc, dc, "adc16x2 carry ok" ); 22 | }); 23 | 24 | if ( Math.imul ) { 25 | test( "multiply and add", function () { 26 | var imul = Math.imul, 27 | x = 0xad4e6ae6, y = 0xedfdecc8, z = 0x9b4c57af, 28 | h = 0xa11d7fc2, l = 0xde69e35f, 29 | u = 0, v = 0, w = 0, 30 | rh = 0, rl = 0; 31 | 32 | u = imul( x & 0xffff, y & 0xffff ) + (z & 0xffff) | 0; 33 | v = imul( x & 0xffff, y >>> 16 ) + (z >>> 16) | 0; 34 | w = ( imul( x >>> 16, y & 0xffff ) + (v & 0xffff) | 0 ) + (u >>> 16) | 0; 35 | rh = ( imul( x >>> 16, y >>> 16 ) + (v >>> 16) | 0 ) + (w >>> 16) | 0; 36 | rl = (w << 16) | (u & 0xffff); 37 | 38 | equal( h>>>0, rh>>>0, "high part is ok" ); 39 | equal( l>>>0, rl>>>0, "low part is ok" ); 40 | }); 41 | 42 | test( "divide with remainder", function () { 43 | var n0 = 0xad4e6ae6, n1 = 0xedfdecc8, d0 = 0xeeddccbb, q0 = 0xff101123, r0 = 0x39b30255; 44 | 45 | var qh, ql, rh, rl, w0, w1, n, dh, dl, c, imul = Math.imul; 46 | 47 | dh = d0 >>> 16, dl = d0 & 0xffff; 48 | 49 | n = n1; 50 | qh = ( n / dh )|0, rh = n % dh; 51 | while ( ( (rh|0) < 0x10000 ) 52 | & ( ( qh == 0x10000 ) | ( (imul(qh,dl)>>>0) > (((rh<<16)|(n0>>>16))>>>0) ) ) ) 53 | { 54 | qh = (qh-1)|0; 55 | rh = (rh+dh)|0; 56 | } 57 | w0 = imul(qh, dl)|0; 58 | w1 = (w0 >>> 16) + imul(qh, dh)|0; 59 | w0 = w0 << 16; 60 | n = (n0-w0)|0, c = ( (n>>>0) > (n0>>>0) )|0, n0 = n; 61 | n = (n1-c)|0, c = ( (n>>>0) > (n1>>>0) )|0, n1 = (n-w1)|0, c = ( (n1>>>0) > (n>>>0) )|c; 62 | if ( c ) { 63 | qh = (qh-1)|0; 64 | n = (n0+(d0<<16))|0, c = ( (n>>>0) < (n0>>>0) )|0, n0 = n; 65 | n = (n1+c)|0, c = !n, n1 = (n+dh)|0, c = ( (n1>>>0) < (n>>>0) )|c; 66 | } 67 | 68 | n = (n1 << 16) | (n0 >>> 16); 69 | ql = ( n / dh )|0, rl = n % dh; 70 | while ( ( (rl|0) < 0x10000 ) 71 | & ( ( ql == 0x10000 ) | ( (imul(ql,dl)>>>0) > (((rl << 16)|(n0 & 0xffff))>>>0) ) ) ) 72 | { 73 | ql = (ql-1)|0; 74 | rl = (rl+dh)|0; 75 | } 76 | w0 = imul(ql, dl)|0; 77 | w1 = (w0 >>> 16) + imul(ql, dh)|0; 78 | w0 = (w1 << 16) | (w0 & 0xffff); 79 | w1 = w1 >>> 16; 80 | n = (n0-w0)|0, c = ( (n>>>0) > (n0>>>0) )|0, n0 = n; 81 | n = (n1-c)|0, c = ( (n>>>0) > (n1>>>0) )|0, n1 = (n-w1)|0, c = ( (n1>>>0) > (n>>>0) )|c; 82 | if ( c ) { 83 | ql = (ql-1)|0; 84 | n = (n0+d0)|0, c = ( (n>>>0) < (n0>>>0) )|0, n0 = n; 85 | n1 = (n1+c)|0; 86 | } 87 | 88 | equal( ((qh<<16)|ql)>>>0, q0, "quotient ok" ); 89 | equal( n0>>>0, r0, "remainder ok" ); 90 | }); 91 | 92 | test( "imul", function () { 93 | equal( Math.imul(-338592732,968756475)|0, 787375948, "imul works fine" ); 94 | }); 95 | } 96 | else { 97 | skip( "multiply and add" ); 98 | skip( "divide with remainder" ); 99 | skip( "imul" ); 100 | } 101 | 102 | test( "Math.random()", function () { 103 | var r = Math.random(); 104 | ok( typeof r === 'number', "r is number" ); 105 | ok( r >= 0 && r < 1, "0 <= r < 1" ); 106 | }); 107 | 108 | if ( asmCrypto.string_to_bytes ) { 109 | test( "asmCrypto.string_to_bytes()", function () { 110 | var bytes = asmCrypto.string_to_bytes("String not containing Unicode character"); 111 | ok( bytes, "No exception on non-Unicode string" ); 112 | 113 | try { 114 | var bytes = asmCrypto.string_to_bytes("String containing Unicode character: Ͼ"); 115 | ok( false, "No exception on Unicode string") 116 | } 117 | catch ( e ) { 118 | ok( e instanceof Error, "Exception thrown on Unicode string" ); 119 | ok( e.message.match(/wide character/i), "Exception message is about wide character" ); 120 | } 121 | }); 122 | } 123 | else { 124 | skip("asmCrypto.string_to_bytes()"); 125 | } 126 | 127 | testIf( true, "Conditional test should pass", function () { 128 | ok( true, "Passed!" ); 129 | }); 130 | 131 | testIf( false, "Conditional test should skip", function () { 132 | ok( false, "Failed!" ); 133 | }); 134 | -------------------------------------------------------------------------------- /src/hmac/hmac-sha512.js: -------------------------------------------------------------------------------- 1 | function hmac_sha512_constructor ( options ) { 2 | options = options || {}; 3 | 4 | if ( !( options.hash instanceof sha512_constructor ) ) 5 | options.hash = get_sha512_instance(); 6 | 7 | hmac_constructor.call( this, options ); 8 | 9 | return this; 10 | } 11 | 12 | function hmac_sha512_reset ( options ) { 13 | options = options || {}; 14 | 15 | this.result = null; 16 | this.hash.reset(); 17 | 18 | var password = options.password; 19 | if ( password !== undefined ) { 20 | if ( is_string(password) ) 21 | password = string_to_bytes(password); 22 | 23 | var key = this.key = _hmac_key( this.hash, password ); 24 | this.hash.reset().asm.hmac_init( 25 | (key[0]<<24)|(key[1]<<16)|(key[2]<<8)|(key[3]), 26 | (key[4]<<24)|(key[5]<<16)|(key[6]<<8)|(key[7]), 27 | (key[8]<<24)|(key[9]<<16)|(key[10]<<8)|(key[11]), 28 | (key[12]<<24)|(key[13]<<16)|(key[14]<<8)|(key[15]), 29 | (key[16]<<24)|(key[17]<<16)|(key[18]<<8)|(key[19]), 30 | (key[20]<<24)|(key[21]<<16)|(key[22]<<8)|(key[23]), 31 | (key[24]<<24)|(key[25]<<16)|(key[26]<<8)|(key[27]), 32 | (key[28]<<24)|(key[29]<<16)|(key[30]<<8)|(key[31]), 33 | (key[32]<<24)|(key[33]<<16)|(key[34]<<8)|(key[35]), 34 | (key[36]<<24)|(key[37]<<16)|(key[38]<<8)|(key[39]), 35 | (key[40]<<24)|(key[41]<<16)|(key[42]<<8)|(key[43]), 36 | (key[44]<<24)|(key[45]<<16)|(key[46]<<8)|(key[47]), 37 | (key[48]<<24)|(key[49]<<16)|(key[50]<<8)|(key[51]), 38 | (key[52]<<24)|(key[53]<<16)|(key[54]<<8)|(key[55]), 39 | (key[56]<<24)|(key[57]<<16)|(key[58]<<8)|(key[59]), 40 | (key[60]<<24)|(key[61]<<16)|(key[62]<<8)|(key[63]), 41 | (key[64]<<24)|(key[65]<<16)|(key[66]<<8)|(key[67]), 42 | (key[68]<<24)|(key[69]<<16)|(key[70]<<8)|(key[71]), 43 | (key[72]<<24)|(key[73]<<16)|(key[74]<<8)|(key[75]), 44 | (key[76]<<24)|(key[77]<<16)|(key[78]<<8)|(key[79]), 45 | (key[80]<<24)|(key[81]<<16)|(key[82]<<8)|(key[83]), 46 | (key[84]<<24)|(key[85]<<16)|(key[86]<<8)|(key[87]), 47 | (key[88]<<24)|(key[89]<<16)|(key[90]<<8)|(key[91]), 48 | (key[92]<<24)|(key[93]<<16)|(key[94]<<8)|(key[95]), 49 | (key[96]<<24)|(key[97]<<16)|(key[98]<<8)|(key[99]), 50 | (key[100]<<24)|(key[101]<<16)|(key[102]<<8)|(key[103]), 51 | (key[104]<<24)|(key[105]<<16)|(key[106]<<8)|(key[107]), 52 | (key[108]<<24)|(key[109]<<16)|(key[110]<<8)|(key[111]), 53 | (key[112]<<24)|(key[113]<<16)|(key[114]<<8)|(key[115]), 54 | (key[116]<<24)|(key[117]<<16)|(key[118]<<8)|(key[119]), 55 | (key[120]<<24)|(key[121]<<16)|(key[122]<<8)|(key[123]), 56 | (key[124]<<24)|(key[125]<<16)|(key[126]<<8)|(key[127]) 57 | ); 58 | } 59 | else { 60 | this.hash.asm.hmac_reset(); 61 | } 62 | 63 | var verify = options.verify; 64 | if ( verify !== undefined ) { 65 | _hmac_init_verify.call( this, verify ); 66 | } 67 | else { 68 | this.verify = null; 69 | } 70 | 71 | return this; 72 | } 73 | 74 | function hmac_sha512_finish () { 75 | if ( this.key === null ) 76 | throw new IllegalStateError("no key is associated with the instance"); 77 | 78 | if ( this.result !== null ) 79 | throw new IllegalStateError("state must be reset before processing new data"); 80 | 81 | var hash = this.hash, 82 | asm = this.hash.asm, 83 | heap = this.hash.heap; 84 | 85 | asm.hmac_finish( hash.pos, hash.len, 0 ); 86 | 87 | var verify = this.verify; 88 | var result = new Uint8Array(_sha512_hash_size); 89 | result.set( heap.subarray( 0, _sha512_hash_size ) ); 90 | 91 | if ( verify ) { 92 | if ( verify.length === result.length ) { 93 | var diff = 0; 94 | for ( var i = 0; i < verify.length; i++ ) { 95 | diff |= ( verify[i] ^ result[i] ); 96 | } 97 | this.result = !diff; 98 | } else { 99 | this.result = false; 100 | } 101 | } 102 | else { 103 | this.result = result; 104 | } 105 | 106 | return this; 107 | } 108 | 109 | hmac_sha512_constructor.BLOCK_SIZE = sha512_constructor.BLOCK_SIZE; 110 | hmac_sha512_constructor.HMAC_SIZE = sha512_constructor.HASH_SIZE; 111 | 112 | var hmac_sha512_prototype = hmac_sha512_constructor.prototype; 113 | hmac_sha512_prototype.reset = hmac_sha512_reset; 114 | hmac_sha512_prototype.process = hmac_process; 115 | hmac_sha512_prototype.finish = hmac_sha512_finish; 116 | 117 | var hmac_sha512_instance = null; 118 | 119 | function get_hmac_sha512_instance () { 120 | if ( hmac_sha512_instance === null ) hmac_sha512_instance = new hmac_sha512_constructor(); 121 | return hmac_sha512_instance; 122 | } 123 | -------------------------------------------------------------------------------- /test/sha512.js: -------------------------------------------------------------------------------- 1 | module("SHA512"); 2 | 3 | /////////////////////////////////////////////////////////////////////////////// 4 | 5 | if ( typeof asmCrypto.SHA512 !== 'undefined' ) 6 | { 7 | var sha512_vectors = [ 8 | [ 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', '' ], 9 | [ 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'abc' ], 10 | [ '8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu' ], 11 | [ '07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6', 'The quick brown fox jumps over the lazy dog' ], 12 | [ '91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed', 'The quick brown fox jumps over the lazy dog.' ] 13 | ]; 14 | 15 | test( "asmCrypto.SHA512.hex", function () { 16 | for ( var i = 0; i < sha512_vectors.length; ++i ) { 17 | equal( 18 | asmCrypto.SHA512.hex( sha512_vectors[i][1] ), 19 | sha512_vectors[i][0], 20 | "vector " + i 21 | ); 22 | } 23 | }); 24 | } 25 | else 26 | { 27 | skip( "asmCrypto.SHA512" ); 28 | } 29 | 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | if ( typeof asmCrypto.HMAC_SHA512 !== 'undefined' ) 33 | { 34 | var hmac_sha512_vectors = [ 35 | [ '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854', asmCrypto.hex_to_bytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'), 'Hi There'], 36 | [ '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737', 'Jefe', 'what do ya want for nothing?' ], 37 | [ '80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598', asmCrypto.hex_to_bytes('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), 'Test Using Larger Than Block-Size Key - Hash Key First'] 38 | ]; 39 | 40 | test( "asmCrypto.HMAC_SHA512.hex", function () { 41 | for ( var i = 0; i < hmac_sha512_vectors.length; ++i ) { 42 | equal( 43 | asmCrypto.HMAC_SHA512.hex( hmac_sha512_vectors[i][2], hmac_sha512_vectors[i][1] ), 44 | hmac_sha512_vectors[i][0], 45 | "vector " + i 46 | ); 47 | } 48 | }); 49 | } 50 | else 51 | { 52 | skip( "asmCrypto.HMAC_SHA512" ); 53 | } 54 | 55 | /////////////////////////////////////////////////////////////////////////////// 56 | 57 | if ( typeof asmCrypto.PBKDF2_HMAC_SHA512 !== 'undefined' ) 58 | { 59 | var pbkdf2_hmac_sha512_vectors = [ 60 | [ '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce', 'password', 'salt', 1, 64 ], 61 | [ '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce', asmCrypto.string_to_bytes('password'), asmCrypto.string_to_bytes('salt'), 1, 64 ], 62 | [ 'e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e', 'password', 'salt', 2, 64 ], 63 | [ 'd197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5', 'password', 'salt', 4096, 64 ], 64 | [ '8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8', 'passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, 64 ] 65 | ]; 66 | 67 | test( "asmCrypto.PBKDF2_HMAC_SHA512.hex", function () { 68 | for ( var i = 0; i < pbkdf2_hmac_sha512_vectors.length; ++i ) { 69 | equal( 70 | // got 71 | asmCrypto.PBKDF2_HMAC_SHA512.hex( 72 | pbkdf2_hmac_sha512_vectors[i][1], // password 73 | pbkdf2_hmac_sha512_vectors[i][2], // salt 74 | pbkdf2_hmac_sha512_vectors[i][3], // count 75 | pbkdf2_hmac_sha512_vectors[i][4] // dklen 76 | ), 77 | 78 | // expect 79 | pbkdf2_hmac_sha512_vectors[i][0], 80 | 81 | // comment 82 | "asmCrypto.PBKDF2_HMAC_SHA512.hex('" 83 | +pbkdf2_hmac_sha512_vectors[i][1]+"', '" 84 | +pbkdf2_hmac_sha512_vectors[i][2]+"', '" 85 | +pbkdf2_hmac_sha512_vectors[i][3]+"', '" 86 | +pbkdf2_hmac_sha512_vectors[i][4] 87 | +"') is equal to '"+pbkdf2_hmac_sha512_vectors[i][0]+"'" 88 | ); 89 | } 90 | }); 91 | } 92 | else 93 | { 94 | skip( "asmCrypto.PBKDF2_HMAC_SHA512" ); 95 | } 96 | -------------------------------------------------------------------------------- /src/bignum/modulus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Modulus 3 | */ 4 | function Modulus () { 5 | BigNumber.apply( this, arguments ); 6 | 7 | if ( this.valueOf() < 1 ) 8 | throw new RangeError(); 9 | 10 | if ( this.bitLength <= 32 ) 11 | return; 12 | 13 | var comodulus; 14 | 15 | if ( this.limbs[0] & 1 ) { 16 | var bitlen = ( (this.bitLength+31) & -32 ) + 1, limbs = new Uint32Array( (bitlen+31) >> 5 ); 17 | limbs[limbs.length-1] = 1; 18 | comodulus = new BigNumber(); 19 | comodulus.sign = 1; 20 | comodulus.bitLength = bitlen; 21 | comodulus.limbs = limbs; 22 | 23 | var k = Number_extGCD( 0x100000000, this.limbs[0] ).y; 24 | this.coefficient = k < 0 ? -k : 0x100000000-k; 25 | } 26 | else { 27 | /** 28 | * TODO even modulus reduction 29 | * Modulus represented as `N = 2^U * V`, where `V` is odd and thus `GCD(2^U, V) = 1`. 30 | * Calculation `A = TR' mod V` is made as for odd modulo using Montgomery method. 31 | * Calculation `B = TR' mod 2^U` is easy as modulus is a power of 2. 32 | * Using Chinese Remainder Theorem and Garner's Algorithm restore `TR' mod N` from `A` and `B`. 33 | */ 34 | return; 35 | } 36 | 37 | this.comodulus = comodulus; 38 | this.comodulusRemainder = comodulus.divide(this).remainder; 39 | this.comodulusRemainderSquare = comodulus.square().divide(this).remainder; 40 | } 41 | 42 | /** 43 | * Modular reduction 44 | */ 45 | function Modulus_reduce ( a ) { 46 | if ( !is_big_number(a) ) 47 | a = new BigNumber(a); 48 | 49 | if ( a.bitLength <= 32 && this.bitLength <= 32 ) 50 | return new BigNumber( a.valueOf() % this.valueOf() ); 51 | 52 | if ( a.compare(this) < 0 ) 53 | return a; 54 | 55 | return a.divide(this).remainder; 56 | } 57 | 58 | /** 59 | * Modular inverse 60 | */ 61 | function Modulus_inverse ( a ) { 62 | a = this.reduce(a); 63 | 64 | var r = BigNumber_extGCD( this, a ); 65 | if ( r.gcd.valueOf() !== 1 ) return null; 66 | 67 | r = r.y; 68 | if ( r.sign < 0 ) r = r.add(this).clamp(this.bitLength); 69 | 70 | return r; 71 | } 72 | 73 | /** 74 | * Modular exponentiation 75 | */ 76 | function Modulus_power ( g, e ) { 77 | if ( !is_big_number(g) ) 78 | g = new BigNumber(g); 79 | 80 | if ( !is_big_number(e) ) 81 | e = new BigNumber(e); 82 | 83 | // count exponent set bits 84 | var c = 0; 85 | for ( var i = 0; i < e.limbs.length; i++ ) { 86 | var t = e.limbs[i]; 87 | while ( t ) { 88 | if ( t & 1 ) c++; 89 | t >>>= 1; 90 | } 91 | } 92 | 93 | // window size parameter 94 | var k = 8; 95 | if ( e.bitLength <= 4536 ) k = 7; 96 | if ( e.bitLength <= 1736 ) k = 6; 97 | if ( e.bitLength <= 630 ) k = 5; 98 | if ( e.bitLength <= 210 ) k = 4; 99 | if ( e.bitLength <= 60 ) k = 3; 100 | if ( e.bitLength <= 12 ) k = 2; 101 | if ( c <= (1 << (k-1)) ) k = 1; 102 | 103 | // montgomerize base 104 | g = _Montgomery_reduce( this.reduce(g).multiply(this.comodulusRemainderSquare), this ); 105 | 106 | // precompute odd powers 107 | var g2 = _Montgomery_reduce( g.square(), this ), 108 | gn = new Array( 1 << (k-1) ); 109 | gn[0] = g; 110 | gn[1] = _Montgomery_reduce( g.multiply(g2), this ); 111 | for ( var i = 2; i < (1 << (k-1)); i++ ) { 112 | gn[i] = _Montgomery_reduce( gn[i-1].multiply(g2), this ); 113 | } 114 | 115 | // perform exponentiation 116 | var u = this.comodulusRemainder, 117 | r = u; 118 | for ( var i = e.limbs.length-1; i >= 0; i-- ) { 119 | var t = e.limbs[i]; 120 | for ( var j = 32; j > 0; ) { 121 | if ( t & 0x80000000 ) { 122 | var n = t >>> (32-k), l = k; 123 | while ( (n & 1) === 0 ) { n >>>= 1; l--; } 124 | var m = gn[n>>>1]; 125 | while ( n ) { n >>>= 1; if ( r !== u ) r = _Montgomery_reduce( r.square(), this ); } 126 | r = ( r !== u ) ? _Montgomery_reduce( r.multiply(m), this ) : m; 127 | t <<= l, j -= l; 128 | } 129 | else { 130 | if ( r !== u ) r = _Montgomery_reduce( r.square(), this ); 131 | t <<= 1, j--; 132 | } 133 | } 134 | } 135 | 136 | // de-montgomerize result 137 | r = _Montgomery_reduce( r, this ); 138 | 139 | return r; 140 | } 141 | 142 | function _Montgomery_reduce ( a, n ) { 143 | var alimbs = a.limbs, alimbcnt = alimbs.length, 144 | nlimbs = n.limbs, nlimbcnt = nlimbs.length, 145 | y = n.coefficient; 146 | 147 | _bigint_asm.sreset(); 148 | 149 | var pA = _bigint_asm.salloc( alimbcnt<<2 ), 150 | pN = _bigint_asm.salloc( nlimbcnt<<2 ), 151 | pR = _bigint_asm.salloc( nlimbcnt<<2 ); 152 | 153 | _bigint_asm.z( pR-pA+(nlimbcnt<<2), 0, pA ); 154 | 155 | _bigint_heap.set( alimbs, pA>>2 ); 156 | _bigint_heap.set( nlimbs, pN>>2 ); 157 | 158 | _bigint_asm.mredc( pA, alimbcnt<<2, pN, nlimbcnt<<2, y, pR ); 159 | 160 | var result = new BigNumber(); 161 | result.limbs = new Uint32Array( _bigint_heap.subarray( pR>>2, (pR>>2)+nlimbcnt ) ); 162 | result.bitLength = n.bitLength; 163 | result.sign = 1; 164 | 165 | return result; 166 | } 167 | 168 | var ModulusPrototype = Modulus.prototype = new BigNumber; 169 | ModulusPrototype.reduce = Modulus_reduce; 170 | ModulusPrototype.inverse = Modulus_inverse; 171 | ModulusPrototype.power = Modulus_power; 172 | -------------------------------------------------------------------------------- /src/bignum/prime.js: -------------------------------------------------------------------------------- 1 | // Tests if the number supplied is a Miller-Rabin strong probable prime 2 | function _BigNumber_isMillerRabinProbablePrime ( rounds ) { 3 | var t = new BigNumber(this), 4 | s = 0; 5 | t.limbs[0] -= 1; 6 | while ( t.limbs[s>>5] === 0 ) s += 32; 7 | while ( ( ( t.limbs[s>>5] >> (s & 31) ) & 1 ) === 0 ) s++; 8 | t = t.slice(s); 9 | 10 | var m = new Modulus(this), 11 | m1 = this.subtract(BigNumber_ONE), 12 | a = new BigNumber(this), 13 | l = this.limbs.length-1; 14 | while ( a.limbs[l] === 0 ) l--; 15 | 16 | while ( --rounds >= 0 ) { 17 | Random_getValues(a.limbs); 18 | if ( a.limbs[0] < 2 ) a.limbs[0] += 2; 19 | while ( a.compare(m1) >= 0 ) a.limbs[l] >>>= 1; 20 | 21 | var x = m.power( a, t ); 22 | if ( x.compare(BigNumber_ONE) === 0 ) continue; 23 | if ( x.compare(m1) === 0 ) continue; 24 | 25 | var c = s; 26 | while ( --c > 0 ) { 27 | x = x.square().divide(m).remainder; 28 | if ( x.compare(BigNumber_ONE) === 0 ) return false; 29 | if ( x.compare(m1) === 0 ) break; 30 | } 31 | 32 | if ( c === 0 ) return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | function BigNumber_isProbablePrime ( paranoia ) { 39 | paranoia = paranoia || 80; 40 | 41 | var limbs = this.limbs, 42 | i = 0; 43 | 44 | // Oddity test 45 | // (50% false positive probability) 46 | if ( ( limbs[0] & 1 ) === 0 ) return false; 47 | if ( paranoia <= 1 ) return true; 48 | 49 | // Magic divisors (3, 5, 17) test 50 | // (~25% false positive probability) 51 | var s3 = 0, s5 = 0, s17 = 0; 52 | for ( i = 0; i < limbs.length; i++ ) { 53 | var l3 = limbs[i]; 54 | while ( l3 ) { 55 | s3 += (l3 & 3); 56 | l3 >>>= 2; 57 | } 58 | 59 | var l5 = limbs[i]; 60 | while ( l5 ) { 61 | s5 += (l5 & 3); 62 | l5 >>>= 2; 63 | s5 -= (l5 & 3); 64 | l5 >>>= 2; 65 | } 66 | 67 | var l17 = limbs[i]; 68 | while ( l17 ) { 69 | s17 += (l17 & 15); 70 | l17 >>>= 4; 71 | s17 -= (l17 & 15); 72 | l17 >>>= 4; 73 | } 74 | } 75 | if ( !(s3 % 3) || !(s5 % 5) || !(s17 % 17) ) return false; 76 | if ( paranoia <= 2 ) return true; 77 | 78 | // Miller-Rabin test 79 | // (≤ 4^(-k) false positive probability) 80 | return _BigNumber_isMillerRabinProbablePrime.call( this, paranoia >>> 1 ); 81 | } 82 | 83 | // Small primes for trail division 84 | var _primes = [ 2, 3 /* and so on, computed lazily */ ]; 85 | 86 | // Returns an array populated with first n primes. 87 | function _small_primes ( n ) { 88 | if ( _primes.length >= n ) 89 | return _primes.slice( 0, n ); 90 | 91 | for ( var p = _primes[_primes.length-1] + 2; _primes.length < n; p += 2 ) { 92 | for ( var i = 0, d = _primes[i]; d*d <= p; d = _primes[++i] ) { 93 | if ( p % d == 0 ) break; 94 | } 95 | if ( d*d > p ) _primes.push(p); 96 | } 97 | 98 | return _primes; 99 | } 100 | 101 | // Returns strong pseudoprime of a specified bit length 102 | function BigNumber_randomProbablePrime ( bitlen, filter ) { 103 | var limbcnt = (bitlen + 31) >> 5, 104 | prime = new BigNumber({ sign: 1, bitLength: bitlen, limbs: limbcnt }), 105 | limbs = prime.limbs; 106 | 107 | // Number of small divisors to try that minimizes the total cost of the trial division 108 | // along with the first round of Miller-Rabin test for a certain bit length. 109 | var k = 10000; 110 | if ( bitlen <= 512 ) k = 2200; 111 | if ( bitlen <= 256 ) k = 600; 112 | 113 | var divisors = _small_primes(k), 114 | remainders = new Uint32Array(k); 115 | 116 | // Number of Miller-Rabin iterations for an error rate of less than 2^-80 117 | // Damgaard, Landrock, Pomerance: Average case error estimates for the strong probable prime test. 118 | var s = (bitlen * global.Math.LN2) | 0, 119 | r = 27; 120 | if ( bitlen >= 250 ) r = 12; 121 | if ( bitlen >= 450 ) r = 6; 122 | if ( bitlen >= 850 ) r = 3; 123 | if ( bitlen >= 1300 ) r = 2; 124 | 125 | while ( true ) { 126 | // populate `prime` with random bits, clamp to the appropriate bit length 127 | Random_getValues(limbs); 128 | limbs[0] |= 1; 129 | limbs[limbcnt-1] |= 1 << ((bitlen - 1) & 31); 130 | if ( bitlen & 31 ) limbs[limbcnt-1] &= pow2_ceil((bitlen + 1) & 31) - 1; 131 | 132 | // remainders from division to small primes 133 | remainders[0] = 1; 134 | for ( var i = 1; i < k; i++ ) { 135 | remainders[i] = prime.divide( divisors[i] ).remainder.valueOf(); 136 | } 137 | 138 | // try no more than `s` subsequent candidates 139 | seek: 140 | for ( var j = 0; j < s; j += 2, limbs[0] += 2 ) { 141 | // check for small factors 142 | for ( var i = 1; i < k; i++ ) { 143 | if ( ( remainders[i] + j ) % divisors[i] === 0 ) continue seek; 144 | } 145 | 146 | // additional check just before the heavy lifting 147 | if ( typeof filter === 'function' && !filter(prime) ) continue; 148 | 149 | // proceed to Miller-Rabin test 150 | if ( _BigNumber_isMillerRabinProbablePrime.call( prime, r ) ) return prime; 151 | } 152 | } 153 | } 154 | 155 | BigNumberPrototype.isProbablePrime = BigNumber_isProbablePrime; 156 | 157 | BigNumber.randomProbablePrime = BigNumber_randomProbablePrime; 158 | -------------------------------------------------------------------------------- /test/isaac.js: -------------------------------------------------------------------------------- 1 | /* 2 | module("ISAAC"); 3 | 4 | /////////////////////////////////////////////////////////////////////////////// 5 | 6 | // Taken from http://burtleburtle.net/bob/rand/randvect.txt 7 | 8 | var isaac_vector = [ 9 | 0x7a68710f, 0x6554abda, 0x90c10757, 0x0b5e435f, 0xaf7d1fb8, 0x01913fd3, 0x6a158d10, 0xb8f6fd4a, 10 | 0xc2b9aa36, 0x96da2655, 0xfe1e42d5, 0x56e6cd21, 0xd5b2d750, 0x7229ea81, 0x5de87abb, 0xb6b9d766, 11 | 0x1e16614c, 0x3b708f99, 0x5cf824cd, 0xa4ca0cf1, 0x62d31911, 0x7cdd662f, 0xcb9e1563, 0x79ae4c10, 12 | 0x080c79ec, 0x18080c8e, 0x4a0a283c, 0x3dde9f39, 0x09c36f90, 0xad567643, 0x08294766, 0xb4415f7d, 13 | 0x5597ec0f, 0x78ffa568, 0x8bace62e, 0x4188bfcd, 0xc87c8006, 0xafa92a6d, 0x50fc8194, 0xcae8deba, 14 | 0x33f6d7b1, 0x53245b79, 0x61119a5a, 0x7e315aeb, 0xe75b41c9, 0xd2a93b51, 0xec46b0b6, 0x1ed3ff4e, 15 | 0x5d023e65, 0xadf6bc23, 0xf7f58f7b, 0xe4f3a26a, 0x0c571a7d, 0xed35e5ee, 0xeadebeac, 0x30bcc764, 16 | 0x66f1e0ab, 0x826dfa89, 0x0d9c7e7e, 0xe7e26581, 0xd5990dfb, 0x02c9b944, 0x4112d96c, 0x3ff1e524, 17 | 0xc35e4580, 0xfdfef62d, 0xb83f957a, 0xbfc7f7cc, 0xb510ce0e, 0xcd7411a7, 0x04db4e13, 0x76904b6d, 18 | 0x08607f04, 0x3718d597, 0x46c0a6f5, 0x8406b137, 0x309bfb78, 0xf7d3f39f, 0x8c2f0d55, 0xc613f157, 19 | 0x127dd430, 0x72c9137d, 0x68a39358, 0x07c28cd1, 0x848f520a, 0xdd2dc1d5, 0x9388b13b, 0x28e7cb78, 20 | 0x03fb88f4, 0xb0b84e7b, 0x14c8009b, 0x884d6825, 0x21c171ec, 0x0809e494, 0x6a107589, 0x12595a19, 21 | 0x0bb3263f, 0x4d8fae82, 0x2a98121a, 0xb00960ba, 0x6708a2bc, 0x35a124b5, 0xbccaaeed, 0x294d37e5, 22 | 0xd405ded8, 0x9f39e2d9, 0x21835c4d, 0xe89b1a3b, 0x7364944b, 0xbd2e5024, 0x6a123f57, 0x34105a8c, 23 | 0x5ad0d3b0, 0xcc033ce3, 0xd51f093d, 0x56a001e3, 0x01a9bd70, 0x8891b3db, 0x13add922, 0x3d77d9a2, 24 | 0x0e7e0e67, 0xd73f72d4, 0x917bdec2, 0xa37f63ff, 0x23d74f4e, 0x3a6ce389, 0x0606cf9f, 0xde11ed34, 25 | 0x70cc94ae, 0xcb0eee4a, 0x13edc0cb, 0xfe29661c, 0xdb6dbe96, 0xb388d96c, 0x33bc405d, 0xa6d12101, 26 | 0x2f36fa86, 0x7ded386f, 0xe6344451, 0xcd57c7f7, 0x1b0dcdc1, 0xcd49ebdb, 0x9e8a51da, 0x12a0594b, 27 | 0x60d4d5f8, 0x91c8d925, 0xe43d0fbb, 0x5d2a542f, 0x451e7ec8, 0x2b36505c, 0x37c0ed05, 0x2364a1aa, 28 | 0x814bc24c, 0xe3a662d9, 0xf2b5cc05, 0xb8b0ccfc, 0xb058bafb, 0x3aea3dec, 0x0d028684, 0x64af0fef, 29 | 0x210f3925, 0xb67ec13a, 0x97166d14, 0xf7e1cdd0, 0x5adb60e7, 0xd5295ebc, 0x28833522, 0x60eda8da, 30 | 0x7bc76811, 0xac9fe69d, 0x30ab93ec, 0x03696614, 0x15e3a5b9, 0xecc5dc91, 0x1d3b8e97, 0x7275e277, 31 | 0x538e1f4e, 0x6cb167db, 0xa7a2f402, 0x2db35dfe, 0xa8bcc22d, 0xd8c58a6a, 0x6a529b0b, 0x0fd43963, 32 | 0xafc17a97, 0x943c3c74, 0x95138769, 0x6f4e0772, 0xb143b688, 0x3b18e752, 0x69d2e4ae, 0x8107c9ff, 33 | 0xcdbc62e2, 0x5781414f, 0x8b87437e, 0xa70e1101, 0x91dabc65, 0x4e232cd0, 0x229749b5, 0xd7386806, 34 | 0xb3c3f24b, 0x60dc5207, 0x0bdb9c30, 0x1a70e7e9, 0xf37c71d5, 0x44b89b08, 0xb4d2f976, 0xb40e27bc, 35 | 0xffdf8a80, 0x9c411a2a, 0xd0f7b37d, 0xef53cec4, 0xeca4d58a, 0x0b923200, 0xcf22e064, 0x8ebfa303, 36 | 0xf7cf814c, 0x32ae2a2b, 0xb5e13dae, 0xc998f9ff, 0x349947b0, 0x29cf72ce, 0x17e38f85, 0xf3b26129, 37 | 0xd45d6d81, 0x09b3ce98, 0x860536b8, 0xe5792e1b, 0x12ad6419, 0xf5f71c69, 0xcbc8b7c2, 0x8f651659, 38 | 0xa0cc74f3, 0xd78cb99e, 0x51c08d83, 0x29f55449, 0x002ed713, 0x38a824f3, 0x57161df6, 0x7452e319, 39 | 0x25890e2e, 0xc7442433, 0x4a5f6355, 0x6a83e1e0, 0x823cedb6, 0xf1d444eb, 0x88381097, 0x5de3743e, 40 | 0x46ca4f9a, 0xd8370487, 0xedec154a, 0x433f1afb, 0xf5fad54f, 0x98db2fb4, 0xe448e96d, 0xf650e4c8, 41 | 42 | 0x4bb5af29, 0x9d855e89, 0xc54cd95b, 0x46d95ca5, 0xef73fbf0, 0xf943f672, 0x86ba527f, 0x9d8d1908, 43 | 0xf3310c92, 0x05340e15, 0x07cffad9, 0x21e2547e, 0x8c17eff0, 0xd32be060, 0x8aba3ffb, 0x94d40125, 44 | 0xc5a87748, 0x824c2009, 0x73c0e762, 0xcdfec2af, 0x0e6c51b3, 0xa86f875e, 0xbc6172c7, 0xf7f395f1, 45 | 0x3f7579b3, 0x7aa114ed, 0x165b1015, 0xd531161a, 0xe36ef5bb, 0xdc153e5f, 0x1d0cb81b, 0xceffc147, 46 | 0x6079e4ce, 0xc3142d8f, 0xa617a083, 0xb54fed6f, 0xc3c7be2c, 0x02614abf, 0x6fb5ce56, 0xd21e796c, 47 | 0x2d0985de, 0xe9f84163, 0xc1a71e3c, 0x2887d96f, 0x57c4c925, 0x05efe294, 0x88157153, 0x9a30c4e8, 48 | 0x8854a0a1, 0x02503f7d, 0x0cd6ef81, 0x1da4f25a, 0xe8fa3860, 0x32e39273, 0x4c8652d6, 0x9ab3a42f, 49 | 0x9ead7f70, 0x836d8003, 0x6cbe7935, 0x721502dd, 0x5a48755c, 0x07497cae, 0xde462f4d, 0x92f57ea7, 50 | 0x1fe26ce0, 0x27c82282, 0xd6ec2f2b, 0x80c6e402, 0xce86fdfc, 0x52649d6c, 0xc798f047, 0x45bae606, 51 | 0x891aec49, 0x66c97340, 0x9ca45e1c, 0x4286619c, 0xf5f9cc3b, 0x4e823ad3, 0xc0d5d42a, 0xaee19096, 52 | 0x3d469303, 0xfe4cb380, 0xc9cd808c, 0x37a97df6, 0x308f751f, 0x276df0b4, 0xe5fbb9c7, 0x97ca2070, 53 | 0x88412761, 0x2ce5d3d5, 0xd7b43abe, 0xa30519ad, 0x26414ff3, 0xc5bde908, 0x275ead3a, 0x26ceb003, 54 | 0xbf1bd691, 0x037464c0, 0xe24124c0, 0x81d4cc5f, 0x484525e4, 0x1c3a4524, 0x9e7e4f04, 0xe1279bff, 55 | 0x6dd1943a, 0x403dae08, 0x82846526, 0xd5683858, 0x29322d0d, 0xa949bea2, 0x74096ae7, 0x85a13f85, 56 | 0x68235b9d, 0x8ef4bce6, 0x142a6e85, 0xdad1b22a, 0xb7546681, 0x959e234e, 0xfd8650d8, 0x3e730fa8, 57 | 0x56f55a71, 0xd20adf03, 0x7cdc78a2, 0x19047c79, 0x253b1d7a, 0x4389a84a, 0x0aeb8165, 0x9c15db3b, 58 | 0xaafef5a7, 0xbe8b06b2, 0xb5fe87c0, 0xe2a4ef71, 0xd9d711f9, 0xecfcf20b, 0x80fac4c2, 0xbbb8abc4, 59 | 0x239e3b0a, 0x858129a6, 0xd97cd348, 0x8a30738a, 0xc5b71937, 0xd649a428, 0x18c1ef9a, 0x75c08a36, 60 | 0xc921f94e, 0xdf9afa29, 0x040f7074, 0x72f5972f, 0x84ef01da, 0x2cb7b77f, 0x867027d7, 0x9ce0199d, 61 | 0x71865c4c, 0x7a36af93, 0x6c48ddd8, 0x19b48fd0, 0x75f4e9e2, 0x0084cfe5, 0x63bfd4d8, 0x9783cdee, 62 | 0x64f2632c, 0xf1b20eaf, 0xcc8bfa2d, 0x39ddf25a, 0x740e0066, 0x9ddb477f, 0x12b2cfb6, 0xd067fce5, 63 | 0x1a4b6a53, 0x001cdb95, 0x12c06908, 0x531ac6bf, 0x513c1764, 0xf7476978, 0x1be79937, 0x8a8dfaa3, 64 | 0x70a1660e, 0xfb737b1a, 0x3f28ee63, 0xc1a51375, 0x84bd6dd6, 0xe4a51d21, 0xeafed133, 0x22ae0582, 65 | 0x4d678f26, 0xf854b522, 0x31907d62, 0x4b55dd99, 0x04d3658a, 0x19c1e69c, 0xc6112fdd, 0xc66699fd, 66 | 0xa0eabe6b, 0x3724d4dc, 0x0d28fe52, 0x46819e2e, 0x96f703ac, 0x21182ca3, 0x2e7b022f, 0x31860f13, 67 | 0x1956b1e5, 0xe1322228, 0x08063a85, 0x1d964589, 0x94d90481, 0x53c078f3, 0x5afb43ae, 0x1e3437f7, 68 | 0x877eb7b4, 0x5d67133c, 0xa385cb2c, 0xb82f2703, 0xef05ee06, 0x931dd7e2, 0x10d210aa, 0xe21339cc, 69 | 0x479c3a22, 0x613b67b2, 0x33c5321c, 0xa5f48ac4, 0xba5590c8, 0xeb244925, 0xd0ef3cc9, 0xd8c423fb, 70 | 0x15cfcc5c, 0x1feb2e4f, 0x36ec0ea3, 0xdbef7d9f, 0xd5ec6bf4, 0x3d3dff8a, 0x1e04a7f7, 0x8766bb54, 71 | 0x9a1d7745, 0xc79a1749, 0xb8d2486d, 0x582e3014, 0xa82427f5, 0x65dfa427, 0xbc5654c1, 0xbd086f26, 72 | 0x0451516d, 0xff4cfc35, 0x81f2864d, 0x31860f05, 0xd0638e1a, 0xb059261d, 0x3d1e9150, 0x21e2a51c, 73 | 0x82d53d12, 0x1010b275, 0x786b2908, 0x4d3cfbda, 0x94a302f4, 0x95c85eaa, 0xd7e1c7be, 0x82ac484f 74 | ]; 75 | 76 | test( "prng", function () { 77 | asmCrypto.ISAAC.seed(0); 78 | ok( "reset done" ); 79 | 80 | asmCrypto.ISAAC.prng(); 81 | for ( var i = 0; i < isaac_vector.length; i++ ) { 82 | equal( asmCrypto.ISAAC.rand(), isaac_vector[i], "isaac_vector["+i+"] is correct" ); 83 | } 84 | }); 85 | */ 86 | -------------------------------------------------------------------------------- /src/random/isaac.js: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Copyright (c) 2014 Artem S Vybornov 3 | * 4 | * Copyright (c) 2012 Yves-Marie K. Rinquin 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the 8 | * "Software"), to deal in the Software without restriction, including 9 | * without limitation the rights to use, copy, modify, merge, publish, 10 | * distribute, sublicense, and/or sell copies of the Software, and to 11 | * permit persons to whom the Software is furnished to do so, subject to 12 | * the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * ---------------------------------------------------------------------- 26 | * 27 | * ISAAC is a cryptographically secure pseudo-random number generator 28 | * (or CSPRNG for short) designed by Robert J. Jenkins Jr. in 1996 and 29 | * based on RC4. It is designed for speed and security. 30 | * 31 | * ISAAC's informations & analysis: 32 | * http://burtleburtle.net/bob/rand/isaac.html 33 | * ISAAC's implementation details: 34 | * http://burtleburtle.net/bob/rand/isaacafa.html 35 | * 36 | * ISAAC succesfully passed TestU01 37 | */ 38 | 39 | var ISAAC = ( function () { 40 | var m = new Uint32Array(256), // internal memory 41 | r = new Uint32Array(256), // result array 42 | acc = 0, // accumulator 43 | brs = 0, // last result 44 | cnt = 0, // counter 45 | gnt = 0; // generation counter 46 | 47 | /* private: randinit function, same as ISAAC reference implementation */ 48 | function randinit() { 49 | var a, b, c, d, e, f, g, h; 50 | 51 | /* private mixing function */ 52 | function mix () { 53 | a ^= b << 11; d = (d + a)|0; b = (b + c)|0; 54 | b ^= c >>> 2; e = (e + b)|0; c = (c + d)|0; 55 | c ^= d << 8; f = (f + c)|0; d = (d + e)|0; 56 | d ^= e >>> 16; g = (g + d)|0; e = (e + f)|0; 57 | e ^= f << 10; h = (h + e)|0; f = (f + g)|0; 58 | f ^= g >>> 4; a = (a + f)|0; g = (g + h)|0; 59 | g ^= h << 8; b = (b + g)|0; h = (h + a)|0; 60 | h ^= a >>> 9; c = (c + h)|0; a = (a + b)|0; 61 | } 62 | 63 | acc = brs = cnt = 0; 64 | 65 | // the golden ratio 66 | a = b = c = d = e = f = g = h = 0x9e3779b9; 67 | 68 | // scramble it 69 | for ( var i = 0; i < 4; i++ ) 70 | mix(); 71 | 72 | // mix it and combine with the internal state 73 | for ( var i = 0; i < 256; i += 8 ) { 74 | a = (a + r[i|0])|0; b = (b + r[i|1])|0; 75 | c = (c + r[i|2])|0; d = (d + r[i|3])|0; 76 | e = (e + r[i|4])|0; f = (f + r[i|5])|0; 77 | g = (g + r[i|6])|0; h = (h + r[i|7])|0; 78 | mix(); 79 | m.set([a, b, c, d, e, f, g, h], i); 80 | } 81 | 82 | // mix it again 83 | for ( var i = 0; i < 256; i += 8 ) { 84 | a = (a + m[i|0])|0; b = (b + m[i|1])|0; 85 | c = (c + m[i|2])|0; d = (d + m[i|3])|0; 86 | e = (e + m[i|4])|0; f = (f + m[i|5])|0; 87 | g = (g + m[i|6])|0; h = (h + m[i|7])|0; 88 | mix(); 89 | m.set([a, b, c, d, e, f, g, h], i); 90 | } 91 | 92 | // fill in the first set of results 93 | prng(1), gnt = 256; 94 | } 95 | 96 | /* public: seeding function */ 97 | function seed ( s ) { 98 | var i, j, k, n, l; 99 | 100 | if ( !is_typed_array(s) ) { 101 | if ( is_number(s) ) { 102 | n = new FloatArray(1), n[0] = s; 103 | s = new Uint8Array(n.buffer); 104 | } 105 | else if ( is_string(s) ) { 106 | s = string_to_bytes(s); 107 | } 108 | else if ( is_buffer(s) ) { 109 | s = new Uint8Array(s); 110 | } 111 | else { 112 | throw new TypeError("bad seed type"); 113 | } 114 | } 115 | else { 116 | s = new Uint8Array(s.buffer); 117 | } 118 | 119 | // preprocess the seed 120 | l = s.length; 121 | for ( j = 0; j < l; j += 1024 ) 122 | { 123 | // xor each chunk of 1024 bytes with r, for randinit() to mix in 124 | for ( k = j, i = 0; ( i < 1024 ) && ( k < l ); k = j | (++i) ) { 125 | r[i >> 2] ^= ( s[k] << ( (i & 3) << 3 ) ); 126 | } 127 | randinit(); 128 | } 129 | } 130 | 131 | /* public: isaac generator, n = number of run */ 132 | function prng ( n ) { 133 | n = n || 1; 134 | 135 | var i, x, y; 136 | 137 | while ( n-- ) { 138 | cnt = (cnt + 1)|0; 139 | brs = (brs + cnt)|0; 140 | 141 | for ( i = 0; i < 256; i += 4 ) { 142 | acc ^= acc << 13; 143 | acc = m[(i + 128) & 0xff] + acc | 0; x = m[i|0]; 144 | m[i|0] = y = m[(x>>>2) & 0xff] + ( acc + brs | 0 ) | 0; 145 | r[i|0] = brs = m[(y>>>10) & 0xff] + x | 0; 146 | 147 | acc ^= acc >>> 6; 148 | acc = m[(i + 129) & 0xff] + acc | 0; x = m[i|1]; 149 | m[i|1] = y = m[(x >>> 2) & 0xff] + ( acc + brs | 0 ) | 0; 150 | r[i|1] = brs = m[(y >>> 10) & 0xff] + x | 0; 151 | 152 | acc ^= acc << 2; 153 | acc = m[(i + 130) & 0xff] + acc | 0; x = m[i|2]; 154 | m[i|2] = y = m[(x >>> 2) & 0xff] + ( acc + brs | 0 ) | 0; 155 | r[i|2] = brs = m[(y >>> 10) & 0xff] + x | 0; 156 | 157 | acc ^= acc >>> 16; 158 | acc = m[(i + 131) & 0xff] + acc | 0; x = m[i|3]; 159 | m[i|3] = y = m[(x >>> 2) & 0xff] + (acc + brs | 0 ) | 0; 160 | r[i|3] = brs = m[(y >>> 10) & 0xff] + x | 0; 161 | } 162 | } 163 | } 164 | 165 | /* public: return a random number */ 166 | function rand() { 167 | if ( !gnt-- ) 168 | prng(1), gnt = 255; 169 | 170 | return r[gnt]; 171 | } 172 | 173 | /* return class object */ 174 | return { 175 | 'seed': seed, 176 | 'prng': prng, 177 | 'rand': rand 178 | }; 179 | })(); 180 | -------------------------------------------------------------------------------- /test/rsa.js: -------------------------------------------------------------------------------- 1 | module("RSA"); 2 | 3 | /////////////////////////////////////////////////////////////////////////////// 4 | 5 | if ( typeof asmCrypto.RSA !== 'undefined' ) 6 | { 7 | var pubkey = [ 8 | asmCrypto.hex_to_bytes('c13f894819c136381a94c193e619851ddfcde5eca770003ec354f3142e0f61f0676d7d4215cc7a13b06e0744aa8316c9c3766cbefa30b2346fba8f1236d7e6548cf87d9578e6904fc4291e096a2737fcd96624f72e762793505f9dfc5fa17b44611add54f5c00bf54373d720cb6f4e5cabae36c4442b39dbf49158414547f453'), 9 | asmCrypto.hex_to_bytes('10001') 10 | ]; 11 | 12 | var privkey = [ 13 | asmCrypto.hex_to_bytes('c13f894819c136381a94c193e619851ddfcde5eca770003ec354f3142e0f61f0676d7d4215cc7a13b06e0744aa8316c9c3766cbefa30b2346fba8f1236d7e6548cf87d9578e6904fc4291e096a2737fcd96624f72e762793505f9dfc5fa17b44611add54f5c00bf54373d720cb6f4e5cabae36c4442b39dbf49158414547f453'), 14 | 65537, 15 | asmCrypto.hex_to_bytes('75497aa8a7f8fc4f50d2b82a6b9d518db027e7449adaff4b18829685c8eecd227ba3984263b896df1c55ab53a1a9ae4b06b6f9896f8fde98b4b725de882ac13fc11b614cb2cc81bcc69b9ad167dda093c5c6637754acd0ec9e9845b1b2244d597c9f63d7ea076bda19feadcdb3bd1ba9018915fec981657fb7a4301cb87a3e1'), 16 | asmCrypto.hex_to_bytes('ef2f8d91d7cd96710d6b3b5ea1b6762b4214efe329e7d0609ab8419744ef8620391e423d5890c864aebb36c0daf5035d27f3427e6a84fde36466a14b56ad1cfb'), 17 | asmCrypto.hex_to_bytes('ced5477e0acb9c836c3c54e33268e064ce8cdfd40452c8b87ab838b36b498ae22fdbdb331f59f61dd3ca1512143e77a68f8f2400dbe9e576a000084e6fcbb689'), 18 | asmCrypto.hex_to_bytes('227882f9a2d5513a27c9ed7b7ce8d3ecf61018666fb2a5f85633f9d7f82a60f521e6377ba9d8ebd87eca2260f6ed5ab7c13b30b91156eb542b331349cd4b13a3'), 19 | asmCrypto.hex_to_bytes('4dea2a3460fcb2c90f4ceaed6b5ff6a802e72eaa3fb6afc64ef476e79fd2e46eb078b1ea60351371c906a7495836effbdeb89d67757076f068f59a2b7211db81'), 20 | asmCrypto.hex_to_bytes('261a93613a93e438fa62858758d1db3b3db8366319517c039acfcc0ce04cd0d7349d7e8d8cb0e8a05ac966d04c18c81c49025de2b50bb87f78facccd19cd8602') 21 | ]; 22 | 23 | test( "asmCrypto.RSA", function () { 24 | equal( typeof asmCrypto.RSA, 'object', "RSA exported" ); 25 | }); 26 | 27 | test( "asmCrypto.RSA.generateKey", function () { 28 | var key = asmCrypto.RSA.generateKey( 1024, 3 ); 29 | ok( key, "generateKey" ); 30 | 31 | var m = new asmCrypto.Modulus( key[0] ), 32 | e = new asmCrypto.BigNumber( key[1] ), 33 | d = new asmCrypto.BigNumber( key[2] ), 34 | p = new asmCrypto.BigNumber( key[3] ), 35 | q = new asmCrypto.BigNumber( key[4] ), 36 | dp = new asmCrypto.BigNumber( key[5] ), 37 | dq = new asmCrypto.BigNumber( key[6] ), 38 | qi = new asmCrypto.BigNumber( key[7] ); 39 | 40 | equal( p.multiply(q).toString(16), m.toString(16), "m == p*q" ); 41 | equal( e.multiply(d).divide(p.subtract(1).multiply(q.subtract(1))).remainder.toString(16), '1', "e*d == 1 mod (p-1)(q-1)" ); 42 | equal( d.divide(p.subtract(1)).remainder.toString(16), dp.toString(16), "dp == d mod (p-1)" ); 43 | equal( d.divide(q.subtract(1)).remainder.toString(16), dq.toString(16), "dq == d mod (q-1)" ); 44 | equal( qi.multiply(q).divide(p).remainder.toString(16), '1', "qi*q == 1 mod p" ); 45 | equal( m.slice(m.bitLength-1).valueOf(), 1, "m highest bit is 1" ); 46 | }); 47 | } 48 | else 49 | { 50 | skip( "asmCrypto.RSA" ); 51 | } 52 | 53 | /////////////////////////////////////////////////////////////////////////////// 54 | 55 | if ( typeof asmCrypto.RSA_RAW !== 'undefined' ) 56 | { 57 | test( "asmCrypto.RSA_RAW.encrypt", function () { 58 | var text = String.fromCharCode(1); 59 | 60 | var ciphertext = asmCrypto.RSA_RAW.encrypt( text, pubkey ); 61 | equal( asmCrypto.bytes_to_hex(ciphertext).replace(/^0+/,''), '1', "ident encrypt" ); 62 | 63 | var result = asmCrypto.RSA_RAW.decrypt( ciphertext, privkey ); 64 | equal( asmCrypto.bytes_to_hex(result).replace(/^0+/,''), '1', "ident decrypt" ); 65 | }); 66 | } 67 | else 68 | { 69 | skip( "asmCrypto.RSA_RAW" ); 70 | } 71 | 72 | /////////////////////////////////////////////////////////////////////////////// 73 | 74 | if ( typeof asmCrypto.RSA_OAEP_SHA256 !== 'undefined' ) 75 | { 76 | test( "asmCrypto.RSA_OAEP_SHA256 encrypt/decrypt", function () { 77 | var cleartext = asmCrypto.string_to_bytes('HelloWorld!'); 78 | 79 | var ciphertext = asmCrypto.RSA_OAEP_SHA256.encrypt( cleartext, pubkey, 'test' ); 80 | ok( ciphertext, "encrypt" ); 81 | 82 | var result = asmCrypto.RSA_OAEP_SHA256.decrypt( ciphertext, privkey, 'test' ); 83 | equal( asmCrypto.bytes_to_string(result), 'HelloWorld!', "decrypt" ); 84 | }); 85 | } 86 | else 87 | { 88 | skip( "asmCrypto.RSA_OAEP_SHA256" ); 89 | } 90 | 91 | /////////////////////////////////////////////////////////////////////////////// 92 | 93 | if ( typeof asmCrypto.RSA_PSS_SHA256 !== 'undefined' ) 94 | { 95 | test( "asmCrypto.RSA_PSS_SHA256 sign/verify", function () { 96 | var text = 'HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!'; 97 | 98 | var signature = asmCrypto.RSA_PSS_SHA256.sign( text, privkey ); 99 | ok( signature, "sign" ); 100 | 101 | var result = asmCrypto.RSA_PSS_SHA256.verify( signature, text, pubkey ); 102 | ok( result, "verify" ); 103 | }); 104 | 105 | test( "asmCrypto.RSA_PSS_SHA256 verify OpenSSL-signed-data", function () { 106 | var key = [ 107 | asmCrypto.hex_to_bytes('f30be5ce8941c8e6e764c78d12f3ce6e02a0dea03577bc0c16029de258321b74ceb43ea94f768aec900011c78eb247ab0e94b4477ea8f086ba7b5ce4b03c0ad7e0bf2f54ed509a536a0f179e27db539f729b38a279873f7b3a360690c8390e289dedca6da1ba232d8edc3c1eb229e1072716ddf3ef88caf4a824c152d6ad38f1'), 108 | 65537 109 | /* 110 | asmCrypto.hex_to_bytes('a2f4032c2ad2b4843bf851e2c0263eed7b4da875f9e3416d4904901ec5cb32a56a416711d5794143c278897326b5595fd2f2d8bc66ab96387ea75f6ce4cc1ce7ba0269a49ce03eb4aea16ca914938e88e5398b10b314276ba9f3f2e448a5f643515ee591cb4c4c5270edccacf7e5b88f86a0c08dc05311513a4ed01802de2511'), 111 | asmCrypto.hex_to_bytes('fc592285e370d57900bfd2f8c66b15274b3381ca7ec485091d5aa0092ca8f2b97f8796e608a2fc6aa1df3647b10198c49801e3201fefa72ef9d7ccafcdae5d37'), 112 | asmCrypto.hex_to_bytes('f6904d99d7cf9f1237c6798e5343fe730149be31e0363bf33039af84a09b5e9d0dd71239384b6cf6421e4ad41097b2cd09fd0114eb29a4339c433f37d7286f17'), 113 | asmCrypto.hex_to_bytes('252e1ce00d3abab9315b12028579918c50902e375fa624d3caf7674cf2bf91c3b2fe8f4525509e5037b9638dfc8e77abbf99c7951c1f7b4a78954b1b3bfaccd1'), 114 | asmCrypto.hex_to_bytes('9f036da89c10208cc53fd14142de0509f278b69abff8fa2cda9b3961159b5e2777b78edf2c3928aaa0f59c58abe2c9c3867f8ee508ccb04340b1f5e17377763d'), 115 | asmCrypto.hex_to_bytes('c07e9ca15c2cc38cc4faab0729403e02b33982b7d1219e15cd74614f3485437d2c800d66a0c368b3cf36513e4b1e05d31d7e0186f00cf036433e35f13b5cfda8') 116 | */ 117 | ]; 118 | 119 | var text = 'Hello There!'; 120 | 121 | var signature = asmCrypto.hex_to_bytes('A68BE713861409B4E536C12066B3D30650C7578F9B7AB61C1A302B42ECA14D58AE11899BC55FCB838F0AE06B99381DE26CE8D6318BD59BBFC4FFF56A995E9EFB0306FF105766F508297D1E74F22648B6BD66C18E06F4748BD258358ECB5BB722AC4AFFA146C04EE7BE84AD77ED2A84B5458D6CA4A7DA4D86DAB3F2B39FD647F4'); 122 | 123 | var saltlen = 32; 124 | 125 | var result = asmCrypto.RSA_PSS_SHA256.verify( signature, text, key, saltlen ); 126 | ok( result, "verify" ); 127 | }); 128 | } 129 | else 130 | { 131 | skip( "asmCrypto.RSA_PSS_SHA256" ); 132 | } 133 | -------------------------------------------------------------------------------- /src/random/random.js: -------------------------------------------------------------------------------- 1 | var _global_console = global.console, 2 | _global_date_now = global.Date.now, 3 | _global_math_random = global.Math.random, 4 | _global_performance = global.performance, 5 | _global_crypto = global.crypto || global.msCrypto, 6 | _global_crypto_getRandomValues; 7 | 8 | if ( _global_crypto !== undefined ) 9 | _global_crypto_getRandomValues = _global_crypto.getRandomValues; 10 | 11 | var _isaac_rand = ISAAC.rand, 12 | _isaac_seed = ISAAC.seed, 13 | _isaac_counter = 0, 14 | _isaac_weak_seeded = false, 15 | _isaac_seeded = false; 16 | 17 | var _random_estimated_entropy = 0, 18 | _random_required_entropy = 256, 19 | _random_allow_weak = false, 20 | _random_skip_system_rng_warning = false, 21 | _random_warn_callstacks = {}; 22 | 23 | var _hires_now; 24 | if ( _global_performance !== undefined ) { 25 | _hires_now = function () { return 1000 * _global_performance.now() | 0 }; 26 | } 27 | else { 28 | var _hires_epoch = 1000 * _global_date_now() | 0; 29 | _hires_now = function () { return 1000 * _global_date_now() - _hires_epoch | 0 }; 30 | } 31 | 32 | /** 33 | * weak_seed 34 | * 35 | * Seeds RNG with native `crypto.getRandomValues` output or with high-resolution 36 | * time and single `Math.random()` value, and various other sources. 37 | * 38 | * We estimate this may give at least ~50 bits of unpredictableness, 39 | * but this has not been analysed thoroughly or precisely. 40 | */ 41 | function Random_weak_seed () { 42 | if ( _global_crypto !== undefined ) { 43 | buffer = new Uint8Array(32); 44 | _global_crypto_getRandomValues.call( _global_crypto, buffer ); 45 | 46 | _isaac_seed(buffer); 47 | } 48 | else { 49 | // Some clarification about brute-force attack cost: 50 | // - entire bitcoin network operates at ~10^16 hash guesses per second; 51 | // - each PBKDF2 iteration requires the same number of hashing operations as bitcoin nonce guess; 52 | // - attacker having such a hashing power is able to break worst-case 50 bits of the randomness in ~3 hours; 53 | // Sounds sad though attacker having such a hashing power more likely would prefer to mine bitcoins. 54 | var buffer = new FloatArray(3), 55 | i, t; 56 | 57 | buffer[0] = _global_math_random(); 58 | buffer[1] = _global_date_now(); 59 | buffer[2] = _hires_now(); 60 | 61 | buffer = new Uint8Array(buffer.buffer); 62 | 63 | var pbkdf2 = get_pbkdf2_hmac_sha256_instance(); 64 | for ( i = 0; i < 100; i++ ) { 65 | buffer = pbkdf2.reset( { password: buffer } ).generate( global.location.href, 1000, 32 ).result; 66 | t = _hires_now(); 67 | buffer[0] ^= t >>> 24, buffer[1] ^= t >>> 16, buffer[2] ^= t >>> 8, buffer[3] ^= t; 68 | } 69 | 70 | _isaac_seed(buffer); 71 | } 72 | 73 | _isaac_counter = 0; 74 | 75 | _isaac_weak_seeded = true; 76 | } 77 | 78 | /** 79 | * seed 80 | * 81 | * Seeds PRNG with supplied random values if these values have enough entropy. 82 | * 83 | * A false return value means the RNG is currently insecure; however a true 84 | * return value does not mean it is necessarily secure (depending on how you 85 | * collected the seed) though asmCrypto will be forced to assume this. 86 | * 87 | * The input buffer will be zeroed to discourage reuse. You should not copy it 88 | * or use it anywhere else before passing it into this function. 89 | * 90 | * **DISCLAIMER!** Seeding with a poor values is an easiest way shoot your legs, so 91 | * do not seed until you're know what entropy is and how to obtail high-quality random values, 92 | * **DO NOT SEED WITH CONSTANT VALUE! YOU'LL GET NO RANDOMNESS FROM CONSTANT!** 93 | */ 94 | function Random_seed ( seed ) { 95 | if ( !is_buffer(seed) && !is_typed_array(seed) ) 96 | throw new TypeError("bad seed type"); 97 | 98 | var bpos = seed.byteOffest || 0, 99 | blen = seed.byteLength || seed.length, 100 | buff = new Uint8Array( ( seed.buffer || seed ), bpos, blen ); 101 | 102 | _isaac_seed(buff); 103 | 104 | _isaac_counter = 0; 105 | 106 | // don't let the user use these bytes again 107 | var nonzero = 0; 108 | for ( var i = 0; i < buff.length; i++ ) { 109 | nonzero |= buff[i]; 110 | buff[i] = 0; 111 | } 112 | 113 | if ( nonzero !== 0 ) { 114 | // TODO we could make a better estimate, but half-length is a prudent 115 | // simple measure that seems unlikely to over-estimate 116 | _random_estimated_entropy += 4 * blen; 117 | } 118 | 119 | _isaac_seeded = ( _random_estimated_entropy >= _random_required_entropy ); 120 | 121 | return _isaac_seeded; 122 | } 123 | 124 | /** 125 | * getValues 126 | * 127 | * Populates the buffer with cryptographically secure random values. These are 128 | * calculated using `crypto.getRandomValues` if it is available, as well as our 129 | * own ISAAC PRNG implementation. 130 | * 131 | * If the former is not available (older browsers such as IE10 [1]), then the 132 | * latter *must* be seeded using `Random.seed`, unless `asmCrypto.random.allowWeak` is true. 133 | * 134 | * *We assume the system RNG is strong*; if you cannot afford this risk, then 135 | * you should also seed ISAAC using `Random.seed`. This is advisable for very 136 | * important situations, such as generation of long-term secrets. See also [2]. 137 | * 138 | * [1] https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues 139 | * [2] https://en.wikipedia.org/wiki/Dual_EC_DRBG 140 | * 141 | * In all cases, we opportunistically seed using various arbitrary sources 142 | * such as high-resolution time and one single value from the insecure 143 | * Math.random(); however this is not reliable as a strong security measure. 144 | */ 145 | function Random_getValues ( buffer ) { 146 | // opportunistically seed ISAAC with a weak seed; this hopefully makes an 147 | // attack harder in the case where the system RNG is weak *and* we haven't 148 | // seeded ISAAC. but don't make any guarantees to the user about this. 149 | if ( !_isaac_weak_seeded ) 150 | Random_weak_seed(); 151 | 152 | // if we have no strong sources then the RNG is weak, handle it 153 | if ( !_isaac_seeded && _global_crypto === undefined ) { 154 | if ( !_random_allow_weak ) 155 | throw new SecurityError("No strong PRNGs available. Use asmCrypto.random.seed()."); 156 | 157 | if ( _global_console !== undefined ) 158 | _global_console.error("No strong PRNGs available; your security is greatly lowered. Use asmCrypto.random.seed()."); 159 | } 160 | 161 | // separate warning about assuming system RNG strong 162 | if ( !_random_skip_system_rng_warning && !_isaac_seeded && _global_crypto !== undefined && _global_console !== undefined ) { 163 | // Hacky way to get call stack 164 | var s = new Error().stack; 165 | _random_warn_callstacks[s] |= 0; 166 | if ( !_random_warn_callstacks[s]++ ) 167 | _global_console.warn("asmCrypto PRNG not seeded; your security relies on your system PRNG. If this is not acceptable, use asmCrypto.random.seed()."); 168 | } 169 | 170 | // proceed to get random values 171 | if ( !is_buffer(buffer) && !is_typed_array(buffer) ) 172 | throw new TypeError("unexpected buffer type"); 173 | 174 | var bpos = buffer.byteOffset || 0, 175 | blen = buffer.byteLength || buffer.length, 176 | bytes = new Uint8Array( ( buffer.buffer || buffer ), bpos, blen ), 177 | i, r; 178 | 179 | // apply system rng 180 | if ( _global_crypto !== undefined ) 181 | _global_crypto_getRandomValues.call( _global_crypto, bytes ); 182 | 183 | // apply isaac rng 184 | for ( i = 0; i < blen; i++ ) { 185 | if ( (i & 3) === 0 ) { 186 | if ( _isaac_counter >= 0x10000000000 ) Random_weak_seed(); 187 | r = _isaac_rand(); 188 | _isaac_counter++; 189 | } 190 | bytes[i] ^= r; 191 | r >>>= 8; 192 | } 193 | } 194 | 195 | /** 196 | * getNumber 197 | * 198 | * A drop-in `Math.random` replacement. 199 | * Intended for prevention of random material leakage out of the user's host. 200 | */ 201 | function Random_getNumber () { 202 | if ( !_isaac_weak_seeded || _isaac_counter >= 0x10000000000 ) 203 | Random_weak_seed(); 204 | 205 | var n = ( 0x100000 * _isaac_rand() + ( _isaac_rand() >>> 12 ) ) / 0x10000000000000; 206 | _isaac_counter += 2; 207 | 208 | return n; 209 | } 210 | -------------------------------------------------------------------------------- /src/aes/naes.js: -------------------------------------------------------------------------------- 1 | function AES ( options ) { 2 | this.BLOCK_SIZE = _aes_block_size; 3 | 4 | options = options || {}; 5 | 6 | this.heap = _heap_init( Uint8Array, options ).subarray( AES_asm.HEAP_DATA ); 7 | this.asm = options.asm || AES_asm( global, null, this.heap.buffer ); 8 | this.mode = null; 9 | this.key = null; 10 | 11 | this.reset( options ); 12 | } 13 | 14 | function AES_set_key ( key ) { 15 | if ( key !== undefined ) { 16 | if ( is_buffer(key) || is_bytes(key) ) { 17 | key = new Uint8Array(key); 18 | } 19 | else if ( is_string(key) ) { 20 | key = string_to_bytes(key); 21 | } 22 | else { 23 | throw new TypeError("unexpected key type"); 24 | } 25 | 26 | var keylen = key.length; 27 | if ( keylen !== 16 && keylen !== 24 && keylen !== 32 ) 28 | throw new IllegalArgumentError("illegal key size"); 29 | 30 | var keyview = new DataView( key.buffer, key.byteOffset, key.byteLength ); 31 | this.asm.set_key( 32 | keylen >> 2, 33 | keyview.getUint32(0), 34 | keyview.getUint32(4), 35 | keyview.getUint32(8), 36 | keyview.getUint32(12), 37 | keylen > 16 ? keyview.getUint32(16) : 0, 38 | keylen > 16 ? keyview.getUint32(20) : 0, 39 | keylen > 24 ? keyview.getUint32(24) : 0, 40 | keylen > 24 ? keyview.getUint32(28) : 0 41 | ); 42 | 43 | this.key = key; 44 | } 45 | else if ( !this.key ) { 46 | throw new Error("key is required"); 47 | } 48 | } 49 | 50 | function AES_set_iv ( iv ) { 51 | if ( iv !== undefined ) { 52 | if ( is_buffer(iv) || is_bytes(iv) ) { 53 | iv = new Uint8Array(iv); 54 | } 55 | else if ( is_string(iv) ) { 56 | iv = string_to_bytes(iv); 57 | } 58 | else { 59 | throw new TypeError("unexpected iv type"); 60 | } 61 | 62 | if ( iv.length !== _aes_block_size ) 63 | throw new IllegalArgumentError("illegal iv size"); 64 | 65 | var ivview = new DataView( iv.buffer, iv.byteOffset, iv.byteLength ); 66 | 67 | this.iv = iv; 68 | this.asm.set_iv( ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12) ); 69 | } 70 | else { 71 | this.iv = null; 72 | this.asm.set_iv( 0, 0, 0, 0 ); 73 | } 74 | } 75 | 76 | function AES_set_padding ( padding ) { 77 | if ( padding !== undefined ) { 78 | this.padding = !!padding; 79 | } 80 | else { 81 | this.padding = true; 82 | } 83 | } 84 | 85 | function AES_reset ( options ) { 86 | options = options || {}; 87 | 88 | this.result = null; 89 | this.pos = 0; 90 | this.len = 0; 91 | 92 | AES_set_key.call( this, options.key ); 93 | if ( this.hasOwnProperty('iv') ) AES_set_iv.call( this, options.iv ); 94 | if ( this.hasOwnProperty('padding') ) AES_set_padding.call( this, options.padding ); 95 | 96 | return this; 97 | } 98 | 99 | function AES_Encrypt_process ( data ) { 100 | if ( is_string(data) ) 101 | data = string_to_bytes(data); 102 | 103 | if ( is_buffer(data) ) 104 | data = new Uint8Array(data); 105 | 106 | if ( !is_bytes(data) ) 107 | throw new TypeError("data isn't of expected type"); 108 | 109 | var asm = this.asm, 110 | heap = this.heap, 111 | amode = AES_asm[this.mode+'_ENC'], 112 | hpos = AES_asm.HEAP_DATA, 113 | ks = this.key.length >> 2, 114 | pos = this.pos, 115 | len = this.len, 116 | dpos = 0, 117 | dlen = data.length || 0, 118 | rpos = 0, 119 | rlen = _aes_block_size * Math.floor( ( len + dlen ) / _aes_block_size ), 120 | wlen = 0; 121 | 122 | var result = new Uint8Array(rlen); 123 | 124 | while ( dlen > 0 ) { 125 | wlen = _heap_write( heap, pos+len, data, dpos, dlen ); 126 | len += wlen; 127 | dpos += wlen; 128 | dlen -= wlen; 129 | 130 | wlen = asm.cipher( ks, amode, hpos + pos, len ); 131 | 132 | result.set( heap.subarray( pos, pos + wlen ), rpos ); 133 | rpos += wlen; 134 | 135 | if ( wlen < len ) { 136 | pos += wlen; 137 | len -= wlen; 138 | } else { 139 | pos = 0; 140 | len = 0; 141 | } 142 | } 143 | 144 | this.result = result; 145 | this.pos = pos; 146 | this.len = len; 147 | 148 | return this; 149 | } 150 | 151 | function AES_Encrypt_finish ( data ) { 152 | var presult = null, 153 | prlen = 0; 154 | 155 | if ( data !== undefined ) { 156 | presult = AES_Encrypt_process.call( this, data ).result; 157 | prlen = presult.length; 158 | } 159 | 160 | var asm = this.asm, 161 | heap = this.heap, 162 | amode = AES_asm[this.mode+'_ENC'], 163 | hpos = AES_asm.HEAP_DATA, 164 | ks = this.key.length >> 2, 165 | pos = this.pos, 166 | len = this.len, 167 | plen = _aes_block_size - len % _aes_block_size, 168 | rlen = len; 169 | 170 | if ( this.hasOwnProperty('padding') ) { 171 | if ( this.padding ) { 172 | for ( var p = 0; p < plen; ++p ) heap[ pos + len + p ] = plen; 173 | len += plen; 174 | rlen = len; 175 | } 176 | else if ( len % _aes_block_size ) { 177 | throw new IllegalArgumentError("data length must be a multiple of " + _aes_block_size); 178 | } 179 | } 180 | else { 181 | len += plen; 182 | } 183 | 184 | var result = new Uint8Array( prlen + rlen ); 185 | 186 | if ( prlen > 0 ) { 187 | result.set( presult ); 188 | } 189 | 190 | if ( len > 0 ) { 191 | asm.cipher( ks, amode, hpos + pos, len ); 192 | result.set( heap.subarray( pos, pos + rlen ), prlen ); 193 | } 194 | 195 | this.result = result; 196 | this.pos = 0; 197 | this.len = 0; 198 | 199 | return this; 200 | } 201 | 202 | function AES_Decrypt_process ( data ) { 203 | if ( is_string(data) ) 204 | data = string_to_bytes(data); 205 | 206 | if ( is_buffer(data) ) 207 | data = new Uint8Array(data); 208 | 209 | if ( !is_bytes(data) ) 210 | throw new TypeError("data isn't of expected type"); 211 | 212 | var asm = this.asm, 213 | heap = this.heap, 214 | amode = AES_asm[this.mode+'_DEC'], 215 | hpos = AES_asm.HEAP_DATA, 216 | ks = this.key.length >> 2, 217 | pos = this.pos, 218 | len = this.len, 219 | dpos = 0, 220 | dlen = data.length || 0, 221 | rpos = 0, 222 | rlen = _aes_block_size * Math.floor( ( len + dlen ) / _aes_block_size ), 223 | plen = 0, 224 | wlen = 0; 225 | 226 | if ( this.hasOwnProperty('padding') && this.padding ) { 227 | plen = len + dlen - rlen || _aes_block_size; 228 | rlen -= plen; 229 | } 230 | 231 | var result = new Uint8Array(rlen); 232 | 233 | while ( dlen > 0 ) { 234 | wlen = _heap_write( heap, pos+len, data, dpos, dlen ); 235 | len += wlen; 236 | dpos += wlen; 237 | dlen -= wlen; 238 | 239 | wlen = asm.cipher( ks, amode, hpos + pos, len - ( !dlen ? plen : 0 ) ); 240 | 241 | result.set( heap.subarray( pos, pos + wlen ), rpos ); 242 | rpos += wlen; 243 | 244 | if ( wlen < len ) { 245 | pos += wlen; 246 | len -= wlen; 247 | } else { 248 | pos = 0; 249 | len = 0; 250 | } 251 | } 252 | 253 | this.result = result; 254 | this.pos = pos; 255 | this.len = len; 256 | 257 | return this; 258 | } 259 | 260 | function AES_Decrypt_finish ( data ) { 261 | var presult = null, 262 | prlen = 0; 263 | 264 | if ( data !== undefined ) { 265 | presult = AES_Decrypt_process.call( this, data ).result; 266 | prlen = presult.length; 267 | } 268 | 269 | var asm = this.asm, 270 | heap = this.heap, 271 | amode = AES_asm[this.mode+'_DEC'], 272 | hpos = AES_asm.HEAP_DATA, 273 | ks = this.key.length >> 2, 274 | pos = this.pos, 275 | len = this.len, 276 | rlen = len; 277 | 278 | if ( len > 0 ) { 279 | if ( len % _aes_block_size ) { 280 | if ( this.hasOwnProperty('padding') ) { 281 | throw new IllegalArgumentError("data length must be a multiple of " + _aes_block_size); 282 | } else { 283 | len += _aes_block_size - ( len % _aes_block_size ); 284 | } 285 | } 286 | 287 | asm.cipher( ks, amode, hpos + pos, len ); 288 | 289 | if ( this.hasOwnProperty('padding') && this.padding ) { 290 | rlen -= heap[ pos + rlen - 1 ]; // FIXME check padding is correct 291 | } 292 | } 293 | 294 | var result = new Uint8Array( prlen + rlen ); 295 | 296 | if ( prlen > 0 ) { 297 | result.set( presult ); 298 | } 299 | 300 | if ( rlen > 0 ) { 301 | result.set( heap.subarray( pos, pos + rlen ), prlen ); 302 | } 303 | 304 | this.result = result; 305 | this.pos = 0; 306 | this.len = 0; 307 | 308 | return this; 309 | } 310 | -------------------------------------------------------------------------------- /src/rsa/pkcs1.js: -------------------------------------------------------------------------------- 1 | function RSA_OAEP ( options ) { 2 | options = options || {}; 3 | 4 | if ( !options.hash ) 5 | throw new SyntaxError("option 'hash' is required"); 6 | 7 | if ( !options.hash.HASH_SIZE ) 8 | throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); 9 | 10 | this.hash = options.hash; 11 | 12 | this.label = null; 13 | 14 | this.reset(options); 15 | } 16 | 17 | function RSA_OAEP_reset ( options ) { 18 | options = options || {}; 19 | 20 | var label = options.label; 21 | if ( label !== undefined ) { 22 | if ( is_buffer(label) || is_bytes(label) ) { 23 | label = new Uint8Array(label); 24 | } 25 | else if ( is_string(label) ) { 26 | label = string_to_bytes(label); 27 | } 28 | else { 29 | throw new TypeError("unexpected label type"); 30 | } 31 | 32 | this.label = ( label.length > 0 ) ? label : null; 33 | } 34 | else { 35 | this.label = null; 36 | } 37 | 38 | RSA_reset.call( this, options ); 39 | } 40 | 41 | function RSA_OAEP_encrypt ( data ) { 42 | if ( !this.key ) 43 | throw new IllegalStateError("no key is associated with the instance"); 44 | 45 | var key_size = Math.ceil( this.key[0].bitLength / 8 ), 46 | hash_size = this.hash.HASH_SIZE, 47 | data_length = data.byteLength || data.length || 0, 48 | ps_length = key_size - data_length - 2*hash_size - 2; 49 | 50 | if ( data_length > key_size - 2*this.hash.HASH_SIZE - 2 ) 51 | throw new IllegalArgumentError("data too large"); 52 | 53 | var message = new Uint8Array(key_size), 54 | seed = message.subarray( 1, hash_size + 1 ), 55 | data_block = message.subarray( hash_size + 1 ); 56 | 57 | if ( is_bytes(data) ) { 58 | data_block.set( data, hash_size + ps_length + 1 ); 59 | } 60 | else if ( is_buffer(data) ) { 61 | data_block.set( new Uint8Array(data), hash_size + ps_length + 1 ); 62 | } 63 | else if ( is_string(data) ) { 64 | data_block.set( string_to_bytes(data), hash_size + ps_length + 1 ); 65 | } 66 | else { 67 | throw new TypeError("unexpected data type"); 68 | } 69 | 70 | data_block.set( this.hash.reset().process( this.label || '' ).finish().result, 0 ); 71 | data_block[ hash_size + ps_length ] = 1; 72 | 73 | Random_getValues(seed); 74 | 75 | var data_block_mask = RSA_MGF1_generate.call( this, seed, data_block.length ); 76 | for ( var i = 0; i < data_block.length; i++ ) 77 | data_block[i] ^= data_block_mask[i]; 78 | 79 | var seed_mask = RSA_MGF1_generate.call( this, data_block, seed.length ); 80 | for ( var i = 0; i < seed.length; i++ ) 81 | seed[i] ^= seed_mask[i]; 82 | 83 | RSA_encrypt.call( this, message ); 84 | 85 | return this; 86 | } 87 | 88 | function RSA_OAEP_decrypt ( data ) { 89 | if ( !this.key ) 90 | throw new IllegalStateError("no key is associated with the instance"); 91 | 92 | var key_size = Math.ceil( this.key[0].bitLength / 8 ), 93 | hash_size = this.hash.HASH_SIZE, 94 | data_length = data.byteLength || data.length || 0; 95 | 96 | if ( data_length !== key_size ) 97 | throw new IllegalArgumentError("bad data"); 98 | 99 | RSA_decrypt.call( this, data ); 100 | 101 | var z = this.result[0], 102 | seed = this.result.subarray( 1, hash_size + 1 ), 103 | data_block = this.result.subarray( hash_size + 1 ); 104 | 105 | if ( z !== 0 ) 106 | throw new SecurityError("decryption failed"); 107 | 108 | var seed_mask = RSA_MGF1_generate.call( this, data_block, seed.length ); 109 | for ( var i = 0; i < seed.length; i++ ) 110 | seed[i] ^= seed_mask[i]; 111 | 112 | var data_block_mask = RSA_MGF1_generate.call( this, seed, data_block.length ); 113 | for ( var i = 0; i < data_block.length; i++ ) 114 | data_block[i] ^= data_block_mask[i]; 115 | 116 | var lhash = this.hash.reset().process( this.label || '' ).finish().result; 117 | for ( var i = 0; i < hash_size; i++ ) { 118 | if ( lhash[i] !== data_block[i] ) 119 | throw new SecurityError("decryption failed"); 120 | } 121 | 122 | var ps_end = hash_size; 123 | for ( ; ps_end < data_block.length; ps_end++ ) { 124 | var psz = data_block[ps_end]; 125 | if ( psz === 1 ) 126 | break; 127 | if ( psz !== 0 ) 128 | throw new SecurityError("decryption failed"); 129 | } 130 | if ( ps_end === data_block.length ) 131 | throw new SecurityError("decryption failed"); 132 | 133 | this.result = data_block.subarray( ps_end + 1 ); 134 | 135 | return this; 136 | } 137 | 138 | function RSA_MGF1_generate( seed, length ) { 139 | seed = seed || ''; 140 | length = length || 0; 141 | 142 | var hash_size = this.hash.HASH_SIZE; 143 | // if ( length > (hash_size * 0x100000000) ) 144 | // throw new IllegalArgumentError("mask length too large"); 145 | 146 | var mask = new Uint8Array(length), 147 | counter = new Uint8Array(4), 148 | chunks = Math.ceil( length / hash_size ); 149 | for ( var i = 0; i < chunks; i++ ) { 150 | counter[0] = i >>> 24, 151 | counter[1] = (i >>> 16) & 255, 152 | counter[2] = (i >>> 8) & 255, 153 | counter[3] = i & 255; 154 | 155 | var submask = mask.subarray( i * hash_size ); 156 | 157 | var chunk = this.hash.reset().process(seed).process(counter).finish().result; 158 | if ( chunk.length > submask.length ) chunk = chunk.subarray( 0, submask.length ); 159 | 160 | submask.set(chunk); 161 | } 162 | 163 | return mask; 164 | } 165 | 166 | function RSA_PSS ( options ) { 167 | options = options || {}; 168 | 169 | if ( !options.hash ) 170 | throw new SyntaxError("option 'hash' is required"); 171 | 172 | if ( !options.hash.HASH_SIZE ) 173 | throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); 174 | 175 | this.hash = options.hash; 176 | 177 | this.saltLength = 4; 178 | 179 | this.reset(options); 180 | } 181 | 182 | function RSA_PSS_reset ( options ) { 183 | options = options || {}; 184 | 185 | RSA_reset.call( this, options ); 186 | 187 | var slen = options.saltLength; 188 | if ( slen !== undefined ) { 189 | if ( !is_number(slen) || slen < 0 ) 190 | throw new TypeError("saltLength should be a non-negative number"); 191 | 192 | if ( this.key !== null && Math.ceil( ( this.key[0].bitLength - 1 ) / 8 ) < this.hash.HASH_SIZE + slen + 2 ) 193 | throw new SyntaxError("saltLength is too large"); 194 | 195 | this.saltLength = slen; 196 | } 197 | else { 198 | this.saltLength = 4; 199 | } 200 | } 201 | 202 | function RSA_PSS_sign ( data ) { 203 | if ( !this.key ) 204 | throw new IllegalStateError("no key is associated with the instance"); 205 | 206 | var key_bits = this.key[0].bitLength, 207 | hash_size = this.hash.HASH_SIZE, 208 | message_length = Math.ceil( ( key_bits - 1 ) / 8 ), 209 | salt_length = this.saltLength, 210 | ps_length = message_length - salt_length - hash_size - 2; 211 | 212 | var message = new Uint8Array(message_length), 213 | h_block = message.subarray( message_length - hash_size - 1, message_length - 1 ), 214 | d_block = message.subarray( 0, message_length - hash_size - 1 ), 215 | d_salt = d_block.subarray( ps_length + 1 ); 216 | 217 | var m_block = new Uint8Array( 8 + hash_size + salt_length ), 218 | m_hash = m_block.subarray( 8, 8 + hash_size ), 219 | m_salt = m_block.subarray( 8 + hash_size ); 220 | 221 | m_hash.set( this.hash.reset().process(data).finish().result ); 222 | 223 | if ( salt_length > 0 ) 224 | Random_getValues(m_salt); 225 | 226 | d_block[ps_length] = 1; 227 | d_salt.set(m_salt); 228 | 229 | h_block.set( this.hash.reset().process(m_block).finish().result ); 230 | 231 | var d_block_mask = RSA_MGF1_generate.call( this, h_block, d_block.length ); 232 | for ( var i = 0; i < d_block.length; i++ ) 233 | d_block[i] ^= d_block_mask[i]; 234 | 235 | message[message_length-1] = 0xbc; 236 | 237 | var zbits = 8*message_length - key_bits + 1; 238 | if ( zbits % 8 ) message[0] &= (0xff >>> zbits); 239 | 240 | RSA_decrypt.call( this, message ); 241 | 242 | return this; 243 | } 244 | 245 | function RSA_PSS_verify ( signature, data ) { 246 | if ( !this.key ) 247 | throw new IllegalStateError("no key is associated with the instance"); 248 | 249 | var key_bits = this.key[0].bitLength, 250 | hash_size = this.hash.HASH_SIZE, 251 | message_length = Math.ceil( ( key_bits - 1 ) / 8 ), 252 | salt_length = this.saltLength, 253 | ps_length = message_length - salt_length - hash_size - 2; 254 | 255 | RSA_encrypt.call( this, signature ); 256 | 257 | var message = this.result; 258 | if ( message[message_length-1] !== 0xbc ) 259 | throw new SecurityError("bad signature"); 260 | 261 | var h_block = message.subarray( message_length - hash_size - 1, message_length - 1 ), 262 | d_block = message.subarray( 0, message_length - hash_size - 1 ), 263 | d_salt = d_block.subarray( ps_length + 1 ); 264 | 265 | var zbits = 8*message_length - key_bits + 1; 266 | if ( (zbits % 8) && (message[0] >>> (8-zbits)) ) 267 | throw new SecurityError("bad signature"); 268 | 269 | var d_block_mask = RSA_MGF1_generate.call( this, h_block, d_block.length ); 270 | for ( var i = 0; i < d_block.length; i++ ) 271 | d_block[i] ^= d_block_mask[i]; 272 | 273 | if ( zbits % 8 ) message[0] &= (0xff >>> zbits); 274 | 275 | for ( var i = 0; i < ps_length; i++ ) { 276 | if ( d_block[i] !== 0 ) 277 | throw new SecurityError("bad signature"); 278 | } 279 | if ( d_block[ps_length] !== 1 ) 280 | throw new SecurityError("bad signature"); 281 | 282 | var m_block = new Uint8Array( 8 + hash_size + salt_length ), 283 | m_hash = m_block.subarray( 8, 8 + hash_size ), 284 | m_salt = m_block.subarray( 8 + hash_size ); 285 | 286 | m_hash.set( this.hash.reset().process(data).finish().result ); 287 | m_salt.set( d_salt ); 288 | 289 | var h_block_verify = this.hash.reset().process(m_block).finish().result; 290 | for ( var i = 0; i < hash_size; i++ ) { 291 | if ( h_block[i] !== h_block_verify[i] ) 292 | throw new SecurityError("bad signature"); 293 | } 294 | 295 | return this; 296 | } 297 | 298 | var RSA_OAEP_prototype = RSA_OAEP.prototype; 299 | RSA_OAEP_prototype.reset = RSA_OAEP_reset; 300 | RSA_OAEP_prototype.encrypt = RSA_OAEP_encrypt; 301 | RSA_OAEP_prototype.decrypt = RSA_OAEP_decrypt; 302 | 303 | var RSA_PSS_prototype = RSA_PSS.prototype; 304 | RSA_PSS_prototype.reset = RSA_PSS_reset; 305 | RSA_PSS_prototype.sign = RSA_PSS_sign; 306 | RSA_PSS_prototype.verify = RSA_PSS_verify; 307 | -------------------------------------------------------------------------------- /src/bignum/bignum.js: -------------------------------------------------------------------------------- 1 | function is_big_number ( a ) { 2 | return ( a instanceof BigNumber ); 3 | } 4 | 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | var _bigint_heap = new Uint32Array(0x100000), 8 | _bigint_asm = bigint_asm( global, null, _bigint_heap.buffer ); 9 | 10 | /////////////////////////////////////////////////////////////////////////////// 11 | 12 | var _BigNumber_ZERO_limbs = new Uint32Array(0); 13 | 14 | function BigNumber ( num ) { 15 | var limbs = _BigNumber_ZERO_limbs, 16 | bitlen = 0, 17 | sign = 0; 18 | 19 | if ( is_string(num) ) 20 | num = string_to_bytes(num); 21 | 22 | if ( is_buffer(num) ) 23 | num = new Uint8Array(num); 24 | 25 | if ( num === undefined ) { 26 | // do nothing 27 | } 28 | else if ( is_number(num) ) { 29 | var absnum = Math.abs(num); 30 | if ( absnum > 0xffffffff ) { 31 | limbs = new Uint32Array(2); 32 | limbs[0] = absnum|0; 33 | limbs[1] = (absnum/0x100000000)|0; 34 | bitlen = 52; 35 | } 36 | else if ( absnum > 0 ) { 37 | limbs = new Uint32Array(1); 38 | limbs[0] = absnum; 39 | bitlen = 32; 40 | } 41 | else { 42 | limbs = _BigNumber_ZERO_limbs; 43 | bitlen = 0; 44 | } 45 | sign = num < 0 ? -1 : 1; 46 | } 47 | else if ( is_bytes(num) ) { 48 | bitlen = num.length * 8; 49 | if ( !bitlen ) 50 | return BigNumber_ZERO; 51 | 52 | limbs = new Uint32Array( (bitlen + 31) >> 5 ); 53 | for ( var i = num.length-4; i >= 0 ; i -= 4 ) { 54 | limbs[(num.length-4-i)>>2] = (num[i] << 24) | (num[i+1] << 16) | (num[i+2] << 8) | num[i+3]; 55 | } 56 | if ( i === -3 ) { 57 | limbs[limbs.length-1] = num[0]; 58 | } 59 | else if ( i === -2 ) { 60 | limbs[limbs.length-1] = (num[0] << 8) | num[1]; 61 | } 62 | else if ( i === -1 ) { 63 | limbs[limbs.length-1] = (num[0] << 16) | (num[1] << 8) | num[2]; 64 | } 65 | 66 | sign = 1; 67 | } 68 | else if ( typeof num === 'object' && num !== null ) { 69 | limbs = new Uint32Array( num.limbs ); 70 | bitlen = num.bitLength; 71 | sign = num.sign; 72 | } 73 | else { 74 | throw new TypeError("number is of unexpected type"); 75 | } 76 | 77 | this.limbs = limbs; 78 | this.bitLength = bitlen; 79 | this.sign = sign; 80 | } 81 | 82 | function BigNumber_toString ( radix ) { 83 | radix = radix || 16; 84 | 85 | var limbs = this.limbs, 86 | bitlen = this.bitLength, 87 | str = ''; 88 | 89 | if ( radix === 16 ) { 90 | // FIXME clamp last limb to (bitlen % 32) 91 | for ( var i = (bitlen+31>>5)-1; i >= 0; i-- ) { 92 | var h = limbs[i].toString(16); 93 | str += '00000000'.substr(h.length); 94 | str += h; 95 | } 96 | 97 | str = str.replace( /^0+/, '' ); 98 | 99 | if ( !str.length ) 100 | str = '0'; 101 | } 102 | else { 103 | throw new IllegalArgumentError("bad radix"); 104 | } 105 | 106 | if ( this.sign < 0 ) 107 | str = '-' + str; 108 | 109 | return str; 110 | } 111 | 112 | function BigNumber_toBytes () { 113 | var bitlen = this.bitLength, 114 | limbs = this.limbs; 115 | 116 | if ( bitlen === 0 ) 117 | return new Uint8Array(0); 118 | 119 | var bytelen = ( bitlen + 7 ) >> 3, 120 | bytes = new Uint8Array(bytelen); 121 | for ( var i = 0; i < bytelen; i++ ) { 122 | var j = bytelen - i - 1; 123 | bytes[i] = limbs[j>>2] >> ( (j & 3) << 3 ); 124 | } 125 | 126 | return bytes; 127 | } 128 | 129 | // Downgrade to Number 130 | function BigNumber_valueOf () { 131 | var limbs = this.limbs, 132 | bits = this.bitLength, 133 | sign = this.sign; 134 | 135 | if ( !sign ) 136 | return 0; 137 | 138 | if ( bits <= 32 ) 139 | return sign * (limbs[0]>>>0); 140 | 141 | if ( bits <= 52 ) 142 | return sign * ( 0x100000000 * (limbs[1]>>>0) + (limbs[0]>>>0) ); 143 | 144 | // normalization 145 | var i, l, e = 0; 146 | for ( i = limbs.length-1; i >= 0; i-- ) { 147 | if ( (l = limbs[i]) === 0 ) continue; 148 | while ( ( (l << e) & 0x80000000 ) === 0 ) e++; 149 | break; 150 | } 151 | 152 | if ( i === 0 ) 153 | return sign * (limbs[0]>>>0); 154 | 155 | return sign * ( 0x100000 * (( (limbs[i] << e) | ( e ? limbs[i-1] >>> (32-e) : 0 ) )>>>0) 156 | + (( (limbs[i-1] << e) | ( e && i > 1 ? limbs[i-2] >>> (32-e) : 0 ) )>>>12) 157 | ) * Math.pow( 2, 32*i-e-52 ); 158 | } 159 | 160 | function BigNumber_clamp ( b ) { 161 | var limbs = this.limbs, 162 | bitlen = this.bitLength; 163 | 164 | // FIXME check b is number and in a valid range 165 | 166 | if ( b >= bitlen ) 167 | return this; 168 | 169 | var clamped = new BigNumber, 170 | n = (b + 31) >> 5, 171 | k = b % 32; 172 | 173 | clamped.limbs = new Uint32Array( limbs.subarray(0,n) ); 174 | clamped.bitLength = b; 175 | clamped.sign = this.sign; 176 | 177 | if ( k ) clamped.limbs[n-1] &= (-1 >>> (32-k)); 178 | 179 | return clamped; 180 | } 181 | 182 | function BigNumber_slice ( f, b ) { 183 | if ( !is_number(f) ) 184 | throw new TypeError("TODO"); 185 | 186 | if ( b !== undefined && !is_number(b) ) 187 | throw new TypeError("TODO"); 188 | 189 | var limbs = this.limbs, 190 | bitlen = this.bitLength; 191 | 192 | if ( f < 0 ) 193 | throw new RangeError("TODO"); 194 | 195 | if ( f >= bitlen ) 196 | return BigNumber_ZERO; 197 | 198 | if ( b === undefined || b > bitlen - f ) 199 | b = bitlen - f; 200 | 201 | var sliced = new BigNumber, slimbs, 202 | n = f >> 5, m = (f + b + 31) >> 5, l = (b + 31) >> 5, 203 | t = f % 32, k = b % 32; 204 | 205 | slimbs = new Uint32Array(l); 206 | if ( t ) { 207 | for ( var i = 0; i < m-n-1; i++ ) { 208 | slimbs[i] = (limbs[n+i]>>>t) | ( limbs[n+i+1]<<(32-t) ); 209 | } 210 | slimbs[i] = limbs[n+i]>>>t; 211 | } 212 | else { 213 | slimbs.set( limbs.subarray(n, m) ); 214 | } 215 | 216 | if ( k ) { 217 | slimbs[l-1] &= (-1 >>> (32-k)); 218 | } 219 | 220 | sliced.limbs = slimbs 221 | sliced.bitLength = b; 222 | sliced.sign = this.sign; 223 | 224 | return sliced; 225 | } 226 | 227 | /////////////////////////////////////////////////////////////////////////////// 228 | 229 | function BigNumber_negate () { 230 | var negative = new BigNumber; 231 | 232 | negative.limbs = this.limbs; 233 | negative.bitLength = this.bitLength; 234 | negative.sign = -1 * this.sign; 235 | 236 | return negative; 237 | } 238 | 239 | function BigNumber_compare ( that ) { 240 | if ( !is_big_number(that) ) 241 | that = new BigNumber(that); 242 | 243 | var alimbs = this.limbs, alimbcnt = alimbs.length, 244 | blimbs = that.limbs, blimbcnt = blimbs.length, 245 | z = 0; 246 | 247 | if ( this.sign < that.sign ) 248 | return -1; 249 | 250 | if ( this.sign > that.sign ) 251 | return 1; 252 | 253 | _bigint_heap.set( alimbs, 0 ); 254 | _bigint_heap.set( blimbs, alimbcnt ); 255 | z = _bigint_asm.cmp( 0, alimbcnt<<2, alimbcnt<<2, blimbcnt<<2 ); 256 | 257 | return z * this.sign; 258 | } 259 | 260 | function BigNumber_add ( that ) { 261 | if ( !is_big_number(that) ) 262 | that = new BigNumber(that); 263 | 264 | if ( !this.sign ) 265 | return that; 266 | 267 | if ( !that.sign ) 268 | return this; 269 | 270 | var abitlen = this.bitLength, alimbs = this.limbs, alimbcnt = alimbs.length, asign = this.sign, 271 | bbitlen = that.bitLength, blimbs = that.limbs, blimbcnt = blimbs.length, bsign = that.sign, 272 | rbitlen, rlimbcnt, rsign, rof, result = new BigNumber; 273 | 274 | rbitlen = ( abitlen > bbitlen ? abitlen : bbitlen ) + ( asign * bsign > 0 ? 1 : 0 ); 275 | rlimbcnt = ( rbitlen + 31 ) >> 5; 276 | 277 | _bigint_asm.sreset(); 278 | 279 | var pA = _bigint_asm.salloc( alimbcnt<<2 ), 280 | pB = _bigint_asm.salloc( blimbcnt<<2 ), 281 | pR = _bigint_asm.salloc( rlimbcnt<<2 ); 282 | 283 | _bigint_asm.z( pR-pA+(rlimbcnt<<2), 0, pA ); 284 | 285 | _bigint_heap.set( alimbs, pA>>2 ); 286 | _bigint_heap.set( blimbs, pB>>2 ); 287 | 288 | if ( asign * bsign > 0 ) { 289 | _bigint_asm.add( pA, alimbcnt<<2, pB, blimbcnt<<2, pR, rlimbcnt<<2 ); 290 | rsign = asign; 291 | } 292 | else if ( asign > bsign ) { 293 | rof = _bigint_asm.sub( pA, alimbcnt<<2, pB, blimbcnt<<2, pR, rlimbcnt<<2 ); 294 | rsign = rof ? bsign : asign; 295 | } 296 | else { 297 | rof = _bigint_asm.sub( pB, blimbcnt<<2, pA, alimbcnt<<2, pR, rlimbcnt<<2 ); 298 | rsign = rof ? asign : bsign; 299 | } 300 | 301 | if ( rof ) 302 | _bigint_asm.neg( pR, rlimbcnt<<2, pR, rlimbcnt<<2 ); 303 | 304 | if ( _bigint_asm.tst( pR, rlimbcnt<<2 ) === 0 ) 305 | return BigNumber_ZERO; 306 | 307 | result.limbs = new Uint32Array( _bigint_heap.subarray( pR>>2, (pR>>2)+rlimbcnt ) ); 308 | result.bitLength = rbitlen; 309 | result.sign = rsign; 310 | 311 | return result; 312 | } 313 | 314 | function BigNumber_subtract ( that ) { 315 | if ( !is_big_number(that) ) 316 | that = new BigNumber(that); 317 | 318 | return this.add( that.negate() ); 319 | } 320 | 321 | function BigNumber_multiply ( that ) { 322 | if ( !is_big_number(that) ) 323 | that = new BigNumber(that); 324 | 325 | if ( !this.sign || !that.sign ) 326 | return BigNumber_ZERO; 327 | 328 | var abitlen = this.bitLength, alimbs = this.limbs, alimbcnt = alimbs.length, 329 | bbitlen = that.bitLength, blimbs = that.limbs, blimbcnt = blimbs.length, 330 | rbitlen, rlimbcnt, result = new BigNumber; 331 | 332 | rbitlen = abitlen + bbitlen; 333 | rlimbcnt = ( rbitlen + 31 ) >> 5; 334 | 335 | _bigint_asm.sreset(); 336 | 337 | var pA = _bigint_asm.salloc( alimbcnt<<2 ), 338 | pB = _bigint_asm.salloc( blimbcnt<<2 ), 339 | pR = _bigint_asm.salloc( rlimbcnt<<2 ); 340 | 341 | _bigint_asm.z( pR-pA+(rlimbcnt<<2), 0, pA ); 342 | 343 | _bigint_heap.set( alimbs, pA>>2 ); 344 | _bigint_heap.set( blimbs, pB>>2 ); 345 | 346 | _bigint_asm.mul( pA, alimbcnt<<2, pB, blimbcnt<<2, pR, rlimbcnt<<2 ); 347 | 348 | result.limbs = new Uint32Array( _bigint_heap.subarray( pR>>2, (pR>>2)+rlimbcnt ) ); 349 | result.sign = this.sign * that.sign; 350 | result.bitLength = rbitlen; 351 | 352 | return result; 353 | } 354 | 355 | function BigNumber_square () { 356 | if ( !this.sign ) 357 | return BigNumber_ZERO; 358 | 359 | var abitlen = this.bitLength, alimbs = this.limbs, alimbcnt = alimbs.length, 360 | rbitlen, rlimbcnt, result = new BigNumber; 361 | 362 | rbitlen = abitlen << 1; 363 | rlimbcnt = ( rbitlen + 31 ) >> 5; 364 | 365 | _bigint_asm.sreset(); 366 | 367 | var pA = _bigint_asm.salloc( alimbcnt<<2 ), 368 | pR = _bigint_asm.salloc( rlimbcnt<<2 ); 369 | 370 | _bigint_asm.z( pR-pA+(rlimbcnt<<2), 0, pA ); 371 | 372 | _bigint_heap.set( alimbs, pA>>2 ); 373 | 374 | _bigint_asm.sqr( pA, alimbcnt<<2, pR ); 375 | 376 | result.limbs = new Uint32Array( _bigint_heap.subarray( pR>>2, (pR>>2)+rlimbcnt ) ); 377 | result.bitLength = rbitlen; 378 | result.sign = 1; 379 | 380 | return result; 381 | } 382 | 383 | function BigNumber_divide ( that ) { 384 | if ( !is_big_number(that) ) 385 | that = new BigNumber(that); 386 | 387 | var abitlen = this.bitLength, alimbs = this.limbs, alimbcnt = alimbs.length, 388 | bbitlen = that.bitLength, blimbs = that.limbs, blimbcnt = blimbs.length, 389 | qlimbcnt, rlimbcnt, quotient = BigNumber_ZERO, remainder = BigNumber_ZERO; 390 | 391 | _bigint_asm.sreset(); 392 | 393 | var pA = _bigint_asm.salloc( alimbcnt<<2 ), 394 | pB = _bigint_asm.salloc( blimbcnt<<2 ), 395 | pR = _bigint_asm.salloc( blimbcnt<<2 ), 396 | pQ = _bigint_asm.salloc( alimbcnt<<2 ); 397 | 398 | _bigint_asm.z( pQ-pA+(alimbcnt<<2), 0, pA ); 399 | 400 | _bigint_heap.set( alimbs, pA>>2 ); 401 | _bigint_heap.set( blimbs, pB>>2 ); 402 | 403 | _bigint_asm.div( pA, alimbcnt<<2, pB, blimbcnt<<2, pR, pQ ); 404 | 405 | qlimbcnt = _bigint_asm.tst( pQ, alimbcnt<<2 )>>2; 406 | if ( qlimbcnt ) { 407 | quotient = new BigNumber; 408 | quotient.limbs = new Uint32Array( _bigint_heap.subarray( pQ>>2, (pQ>>2)+qlimbcnt ) ); 409 | quotient.bitLength = abitlen < (qlimbcnt<<5) ? abitlen : (qlimbcnt<<5); 410 | quotient.sign = this.sign * that.sign; 411 | } 412 | 413 | rlimbcnt = _bigint_asm.tst( pR, blimbcnt<<2 )>>2; 414 | if ( rlimbcnt ) { 415 | remainder = new BigNumber; 416 | remainder.limbs = new Uint32Array( _bigint_heap.subarray( pR>>2, (pR>>2)+rlimbcnt ) );; 417 | remainder.bitLength = bbitlen < (rlimbcnt<<5) ? bbitlen : (rlimbcnt<<5); 418 | remainder.sign = this.sign; 419 | } 420 | 421 | return { 422 | quotient: quotient, 423 | remainder: remainder 424 | }; 425 | } 426 | 427 | /////////////////////////////////////////////////////////////////////////////// 428 | 429 | var BigNumberPrototype = BigNumber.prototype = new Number; 430 | BigNumberPrototype.toString = BigNumber_toString; 431 | BigNumberPrototype.toBytes = BigNumber_toBytes; 432 | BigNumberPrototype.valueOf = BigNumber_valueOf; 433 | BigNumberPrototype.clamp = BigNumber_clamp; 434 | BigNumberPrototype.slice = BigNumber_slice; 435 | 436 | /////////////////////////////////////////////////////////////////////////////// 437 | 438 | BigNumberPrototype.negate = BigNumber_negate; 439 | BigNumberPrototype.compare = BigNumber_compare; 440 | BigNumberPrototype.add = BigNumber_add; 441 | BigNumberPrototype.subtract = BigNumber_subtract; 442 | BigNumberPrototype.multiply = BigNumber_multiply; 443 | BigNumberPrototype.square = BigNumber_square; 444 | BigNumberPrototype.divide = BigNumber_divide; 445 | 446 | /////////////////////////////////////////////////////////////////////////////// 447 | 448 | var BigNumber_ZERO = new BigNumber(0), 449 | BigNumber_ONE = new BigNumber(1); 450 | 451 | Object.freeze(BigNumber_ZERO); 452 | Object.freeze(BigNumber_ONE); 453 | -------------------------------------------------------------------------------- /src/aes/aes-gcm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Galois/Counter mode 3 | */ 4 | 5 | var _gcm_data_maxLength = 68719476704; // 2^36 - 2^5 6 | 7 | function gcm_aes_constructor ( options ) { 8 | this.padding = false; // WAT? 9 | this.mode = 'gcm'; 10 | 11 | this.tagSize = _aes_block_size; 12 | 13 | this.adata = null; 14 | this.iv = null; 15 | this.counter = 1; 16 | 17 | _aes_constructor.call( this, options ); 18 | } 19 | 20 | function gcm_aes_encrypt_constructor ( options ) { 21 | gcm_aes_constructor.call( this, options ); 22 | } 23 | 24 | function gcm_aes_decrypt_constructor ( options ) { 25 | gcm_aes_constructor.call( this, options ); 26 | } 27 | 28 | function _gcm_ghash ( data ) { 29 | var asm = this.asm, 30 | heap = this.heap, 31 | dpos = 0, 32 | dlen = data.length || 0, 33 | hpos = _aes_heap_start, 34 | hlen = 0, 35 | wlen = 0; 36 | 37 | while ( dlen > 0 ) { 38 | wlen = _heap_write( heap, hpos+hlen, data, dpos, dlen ), 39 | hlen += wlen, 40 | dpos += wlen, 41 | dlen -= wlen; 42 | 43 | wlen = asm.gcm_ghash( hpos, hlen ), 44 | hpos += wlen, 45 | hlen -= wlen; 46 | 47 | if ( !hlen ) hpos = _aes_heap_start; 48 | } 49 | 50 | if ( hlen > 0 ) { 51 | while ( hlen < 16 ) heap[hpos|(hlen++)] = 0; 52 | asm.gcm_ghash( hpos, hlen ); 53 | } 54 | } 55 | 56 | function gcm_aes_reset ( options ) { 57 | options = options || {}; 58 | 59 | var asm = this.asm, 60 | heap = this.heap; 61 | 62 | _aes_reset.call( this, options ); 63 | asm.gcm_init(); 64 | 65 | var iv = options.iv; 66 | 67 | if ( iv !== undefined && iv !== null ) { 68 | if ( is_buffer(iv) || is_bytes(iv) ) { 69 | iv = new Uint8Array(iv); 70 | } 71 | else if ( is_string(iv) ) { 72 | iv = string_to_bytes(iv); 73 | } 74 | else { 75 | throw new TypeError("unexpected iv type"); 76 | } 77 | 78 | var ivlen = iv.length || 0; 79 | if ( ivlen !== 12 ) { 80 | asm.init_state( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 81 | 82 | _gcm_ghash.call( this, iv ); 83 | 84 | heap[_aes_heap_start|0] = heap[_aes_heap_start|1] = heap[_aes_heap_start|2] = heap[_aes_heap_start|3] = 85 | heap[_aes_heap_start|4] = heap[_aes_heap_start|5] = heap[_aes_heap_start|6] = heap[_aes_heap_start|7] = 86 | heap[_aes_heap_start|8] = heap[_aes_heap_start|9] = heap[_aes_heap_start|10] = 0, 87 | heap[_aes_heap_start|11] = (ivlen >>> 29), 88 | heap[_aes_heap_start|12] = (ivlen >>> 21) & 255, 89 | heap[_aes_heap_start|13] = (ivlen >>> 13) & 255, 90 | heap[_aes_heap_start|14] = (ivlen >>> 5) & 255, 91 | heap[_aes_heap_start|15] = (ivlen << 3) & 255; 92 | asm.gcm_ghash( _aes_heap_start, _aes_block_size ); 93 | 94 | asm.save_state( _aes_heap_start ); 95 | 96 | this.iv = new Uint8Array( heap.subarray( _aes_heap_start, _aes_heap_start+_aes_block_size ) ); 97 | } 98 | else { 99 | this.iv = new Uint8Array(16); 100 | this.iv.set(iv); 101 | this.iv[15] = 1; 102 | } 103 | } 104 | else { 105 | this.iv = new Uint8Array(16); 106 | this.iv[15] = 1; 107 | } 108 | 109 | var counter = options.counter; 110 | if ( counter !== undefined ) { 111 | if ( !is_number(counter) ) 112 | throw new TypeError("counter must be a number"); 113 | 114 | if ( counter < 1 || counter > 0xffffffff ) 115 | throw new RangeError("counter must be a positive 32-bit integer"); 116 | 117 | this.counter = counter; 118 | } 119 | else { 120 | this.counter = 1; 121 | } 122 | 123 | var tagSize = options.tagSize; 124 | if ( tagSize !== undefined ) { 125 | if ( !is_number(tagSize) ) 126 | throw new TypeError("tagSize must be a number"); 127 | 128 | if ( tagSize < 4 || tagSize > 16 ) 129 | throw new IllegalArgumentError("illegal tagSize value"); 130 | 131 | this.tagSize = tagSize; 132 | } 133 | else { 134 | this.tagSize = _aes_block_size; 135 | } 136 | 137 | asm.init_state( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 138 | 139 | var adata = options.adata; 140 | if ( adata !== undefined && adata !== null ) { 141 | if ( is_buffer(adata) || is_bytes(adata) ) { 142 | adata = new Uint8Array(adata); 143 | } 144 | else if ( is_string(adata) ) { 145 | adata = string_to_bytes(adata); 146 | } 147 | else { 148 | throw new TypeError("unexpected adata type"); 149 | } 150 | 151 | if ( adata.length === 0 || adata.length > _gcm_data_maxLength ) 152 | throw new IllegalArgumentError("illegal adata length"); 153 | 154 | _gcm_ghash.call( this, adata ); 155 | 156 | this.adata = adata; 157 | } 158 | else { 159 | this.adata = null; 160 | } 161 | 162 | return this; 163 | } 164 | 165 | function gcm_aes_encrypt_process ( data ) { 166 | if ( !this.key ) 167 | throw new IllegalStateError("no key is associated with the instance"); 168 | 169 | if ( is_string(data) ) 170 | data = string_to_bytes(data); 171 | 172 | if ( is_buffer(data) ) 173 | data = new Uint8Array(data); 174 | 175 | if ( !is_bytes(data) ) 176 | throw new TypeError("data isn't of expected type"); 177 | 178 | var asm = this.asm, 179 | heap = this.heap, 180 | iv = this.iv, 181 | counter = this.counter, 182 | dpos = 0, 183 | dlen = data.length || 0, 184 | hpos = this.pos, 185 | hlen = this.len, 186 | rpos = 0, 187 | rlen = _aes_block_size * Math.floor( ( hlen + dlen ) / _aes_block_size ), 188 | wlen = 0; 189 | 190 | var result = new Uint8Array(rlen); 191 | 192 | if ( ((counter-1)<<4) + hlen + dlen > _gcm_data_maxLength ) 193 | throw new IllegalStateError("counter overflow"); 194 | 195 | while ( dlen > 0 ) { 196 | wlen = _heap_write( heap, hpos+hlen, data, dpos, dlen ); 197 | hlen += wlen; 198 | dpos += wlen; 199 | dlen -= wlen; 200 | 201 | var ivc = (iv[12] << 24) | (iv[13] << 16) | (iv[14] << 8) | iv[15]; 202 | wlen = asm.gcm_encrypt( hpos, hlen & -15, iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], (ivc+counter)|0 ); 203 | if ( wlen ) result.set( heap.subarray( hpos, hpos+wlen ), rpos ); 204 | counter += (wlen>>>4); 205 | rpos += wlen, 206 | hpos += wlen, 207 | hlen -= wlen; 208 | 209 | if ( !hlen ) hpos = _aes_heap_start; 210 | } 211 | 212 | this.result = result; 213 | this.counter = counter; 214 | this.pos = hpos; 215 | this.len = hlen; 216 | 217 | return this; 218 | } 219 | 220 | function gcm_aes_encrypt_finish () { 221 | if ( !this.key ) 222 | throw new IllegalStateError("no key is associated with the instance"); 223 | 224 | var asm = this.asm, 225 | heap = this.heap, 226 | iv = this.iv, 227 | adata = this.adata, 228 | counter = this.counter, 229 | tagSize = this.tagSize, 230 | pos = this.pos, 231 | hlen = this.len, 232 | wlen = 0; 233 | 234 | var result = new Uint8Array( hlen + tagSize ); 235 | 236 | var ivc = (iv[12] << 24) | (iv[13] << 16) | (iv[14] << 8) | iv[15]; 237 | 238 | if ( hlen > 0 ) { 239 | wlen = asm.gcm_encrypt( pos, hlen, iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], (ivc+counter)|0 ); 240 | if ( wlen ) result.set( heap.subarray( pos, pos+wlen ) ); 241 | } 242 | 243 | var alen = ( adata !== null ) ? adata.length || 0 : 0, 244 | clen = ( (counter-1) << 4) + wlen; 245 | heap[_aes_heap_start|0] = heap[_aes_heap_start|1] = heap[_aes_heap_start|2] = 0, 246 | heap[_aes_heap_start|3] = (alen >>> 29), 247 | heap[_aes_heap_start|4] = (alen >>> 21), 248 | heap[_aes_heap_start|5] = (alen >>> 13) & 255, 249 | heap[_aes_heap_start|6] = (alen >>> 5) & 255, 250 | heap[_aes_heap_start|7] = (alen << 3) & 255, 251 | heap[_aes_heap_start|8] = heap[_aes_heap_start|9] = heap[_aes_heap_start|10] = 0, 252 | heap[_aes_heap_start|11] = (clen >>> 29), 253 | heap[_aes_heap_start|12] = (clen >>> 21) & 255, 254 | heap[_aes_heap_start|13] = (clen >>> 13) & 255, 255 | heap[_aes_heap_start|14] = (clen >>> 5) & 255, 256 | heap[_aes_heap_start|15] = (clen << 3) & 255; 257 | asm.gcm_ghash( _aes_heap_start, _aes_block_size ); 258 | asm.save_state( _aes_heap_start ); 259 | 260 | asm.gcm_encrypt( _aes_heap_start, _aes_block_size, iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], ivc ); 261 | result.set( heap.subarray( _aes_heap_start, _aes_heap_start+tagSize ), wlen ); 262 | 263 | this.result = result; 264 | this.counter = 1; 265 | this.pos = _aes_heap_start; 266 | this.len = 0; 267 | 268 | return this; 269 | } 270 | 271 | function gcm_aes_encrypt ( data ) { 272 | var result1 = gcm_aes_encrypt_process.call( this, data ).result, 273 | result2 = gcm_aes_encrypt_finish.call(this).result; 274 | 275 | var result = new Uint8Array( result1.length + result2.length ); 276 | if ( result1.length ) result.set( result1 ); 277 | if ( result2.length ) result.set( result2, result1.length ); 278 | this.result = result; 279 | 280 | return this; 281 | } 282 | 283 | function gcm_aes_decrypt_process ( data ) { 284 | if ( !this.key ) 285 | throw new IllegalStateError("no key is associated with the instance"); 286 | 287 | if ( is_string(data) ) 288 | data = string_to_bytes(data); 289 | 290 | if ( is_buffer(data) ) 291 | data = new Uint8Array(data); 292 | 293 | if ( !is_bytes(data) ) 294 | throw new TypeError("data isn't of expected type"); 295 | 296 | var asm = this.asm, 297 | heap = this.heap, 298 | iv = this.iv, 299 | counter = this.counter, 300 | tagSize = this.tagSize, 301 | dpos = 0, 302 | dlen = data.length || 0, 303 | hpos = this.pos, 304 | hlen = this.len, 305 | rpos = 0, 306 | rlen = _aes_block_size * Math.floor( ( hlen + dlen - tagSize ) / _aes_block_size ), 307 | wlen = 0; 308 | 309 | var result = new Uint8Array(rlen); 310 | 311 | if ( ((counter-1)<<4) + hlen + dlen - tagSize > _gcm_data_maxLength ) 312 | throw new IllegalStateError("counter overflow"); 313 | 314 | while ( dlen > 0 ) { 315 | wlen = _heap_write( heap, hpos+hlen, data, dpos, dlen ), 316 | hlen += wlen, 317 | dpos += wlen, 318 | dlen -= wlen; 319 | 320 | var ivc = (iv[12] << 24) | (iv[13] << 16) | (iv[14] << 8) | iv[15]; 321 | wlen = asm.gcm_decrypt( hpos, Math.min( hlen, hlen + dlen - tagSize ) & -15, iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], (ivc+counter)|0 ); 322 | if ( wlen ) result.set( heap.subarray( hpos, hpos+wlen ), rpos ); 323 | counter += (wlen>>>4); 324 | rpos += wlen, 325 | hpos += wlen, 326 | hlen -= wlen; 327 | 328 | if ( !hlen ) hpos = _aes_heap_start; 329 | } 330 | 331 | this.result = result; 332 | this.counter = counter; 333 | this.pos = hpos; 334 | this.len = hlen; 335 | 336 | return this; 337 | } 338 | 339 | function gcm_aes_decrypt_finish () { 340 | if ( !this.key ) 341 | throw new IllegalStateError("no key is associated with the instance"); 342 | 343 | var asm = this.asm, 344 | heap = this.heap, 345 | iv = this.iv, 346 | adata = this.adata, 347 | counter = this.counter, 348 | tagSize = this.tagSize, 349 | hpos = this.pos, 350 | hlen = this.len, 351 | rlen = hlen - tagSize, 352 | wlen = 0; 353 | 354 | var result = new Uint8Array(rlen), 355 | atag = new Uint8Array( heap.subarray( hpos+rlen, hpos+hlen ) ); 356 | 357 | var ivc = (iv[12] << 24) | (iv[13] << 16) | (iv[14] << 8) | iv[15]; 358 | 359 | if ( hlen > 0 ) { 360 | wlen = asm.gcm_decrypt( hpos, rlen, iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], (ivc+counter)|0 ); 361 | if ( wlen ) result.set( heap.subarray( hpos, hpos+wlen ) ); 362 | } 363 | 364 | var alen = ( adata !== null ) ? adata.length || 0 : 0, 365 | clen = ( (counter-1) << 4) + wlen; 366 | heap[_aes_heap_start|0] = heap[_aes_heap_start|1] = heap[_aes_heap_start|2] = 0, 367 | heap[_aes_heap_start|3] = (alen >>> 29), 368 | heap[_aes_heap_start|4] = (alen >>> 21), 369 | heap[_aes_heap_start|5] = (alen >>> 13) & 255, 370 | heap[_aes_heap_start|6] = (alen >>> 5) & 255, 371 | heap[_aes_heap_start|7] = (alen << 3) & 255, 372 | heap[_aes_heap_start|8] = heap[_aes_heap_start|9] = heap[_aes_heap_start|10] = 0, 373 | heap[_aes_heap_start|11] = (clen >>> 29), 374 | heap[_aes_heap_start|12] = (clen >>> 21) & 255, 375 | heap[_aes_heap_start|13] = (clen >>> 13) & 255, 376 | heap[_aes_heap_start|14] = (clen >>> 5) & 255, 377 | heap[_aes_heap_start|15] = (clen << 3) & 255; 378 | asm.gcm_ghash( _aes_heap_start, _aes_block_size ); 379 | asm.save_state( _aes_heap_start ); 380 | 381 | asm.gcm_encrypt( _aes_heap_start, _aes_block_size, iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7], iv[8], iv[9], iv[10], iv[11], ivc ); 382 | 383 | var acheck = 0; 384 | for ( var i = 0; i < tagSize; ++i ) acheck |= atag[i] ^ heap[_aes_heap_start|i]; 385 | if ( acheck ) 386 | throw new SecurityError("data integrity check failed"); 387 | 388 | this.result = result; 389 | this.counter = 1; 390 | this.pos = _aes_heap_start; 391 | this.len = 0; 392 | 393 | return this; 394 | } 395 | 396 | function gcm_aes_decrypt ( data ) { 397 | var result1 = gcm_aes_decrypt_process.call( this, data ).result, 398 | result2 = gcm_aes_decrypt_finish.call( this ).result; 399 | 400 | var result = new Uint8Array( result1.length + result2.length ); 401 | if ( result1.length ) result.set( result1 ); 402 | if ( result2.length ) result.set( result2, result1.length ); 403 | this.result = result; 404 | 405 | return this; 406 | } 407 | 408 | var gcm_aes_prototype = gcm_aes_constructor.prototype; 409 | gcm_aes_prototype.reset = gcm_aes_reset; 410 | gcm_aes_prototype.encrypt = gcm_aes_encrypt; 411 | gcm_aes_prototype.decrypt = gcm_aes_decrypt; 412 | 413 | var gcm_aes_encrypt_prototype = gcm_aes_encrypt_constructor.prototype; 414 | gcm_aes_encrypt_prototype.reset = gcm_aes_reset; 415 | gcm_aes_encrypt_prototype.process = gcm_aes_encrypt_process; 416 | gcm_aes_encrypt_prototype.finish = gcm_aes_encrypt_finish; 417 | 418 | var gcm_aes_decrypt_prototype = gcm_aes_decrypt_constructor.prototype; 419 | gcm_aes_decrypt_prototype.reset = gcm_aes_reset; 420 | gcm_aes_decrypt_prototype.process = gcm_aes_decrypt_process; 421 | gcm_aes_decrypt_prototype.finish = gcm_aes_decrypt_finish; 422 | -------------------------------------------------------------------------------- /src/aes/aes-ccm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Counter with CBC-MAC (CCM) 3 | * 4 | * Due to JS limitations (counter is 32-bit unsigned) maximum encrypted message length 5 | * is limited to ~64 GiB ( 2^36 - 16 ) per `nonce`-`key` pair. That also limits `lengthSize` parameter 6 | * maximum value to 5 (not 8 as described in RFC3610). 7 | * 8 | * Additional authenticated data `adata` maximum length is limited to 65279 bytes ( 2^16 - 2^8 ), 9 | * wich is considered enough for the wast majority of use-cases. 10 | * 11 | * And one more important thing: in case of progressive ciphering of a data stream (in other 12 | * words when data can't be held in-memory at a whole and are ciphered chunk-by-chunk) 13 | * you have to know the `dataLength` in advance and pass that value to the cipher options. 14 | */ 15 | 16 | function _cbc_mac_process ( data ) { 17 | var heap = this.heap, 18 | asm = this.asm, 19 | dpos = 0, 20 | dlen = data.length || 0, 21 | wlen = 0; 22 | 23 | while ( dlen > 0 ) { 24 | wlen = _heap_write( heap, _aes_heap_start, data, dpos, dlen ); 25 | asm.cbc_mac( _aes_heap_start, wlen, -1 ); 26 | dpos += wlen; 27 | dlen -= wlen; 28 | } 29 | } 30 | 31 | var _ccm_adata_maxLength = 65279, // 2^16 - 2^8 32 | _ccm_data_maxLength = 68719476720; // 2^36 - 2^4 33 | 34 | function ccm_aes_constructor ( options ) { 35 | this.padding = false; // WAT? 36 | this.mode = 'ccm'; 37 | 38 | this.tagSize = _aes_block_size; 39 | this.lengthSize = 4; 40 | 41 | this.nonce = null; 42 | 43 | this.adata = null; 44 | 45 | this.iv = null; 46 | this.dataLength = -1; 47 | this.dataLeft = -1; 48 | 49 | this.counter = 1; 50 | 51 | _aes_constructor.call( this, options ); 52 | } 53 | 54 | function ccm_aes_encrypt_constructor ( options ) { 55 | ccm_aes_constructor.call( this, options ); 56 | } 57 | 58 | function ccm_aes_decrypt_constructor ( options ) { 59 | ccm_aes_constructor.call( this, options ); 60 | } 61 | 62 | function _ccm_calculate_iv () { 63 | var nonce = this.nonce, 64 | adata = this.adata, 65 | tagSize = this.tagSize, 66 | lengthSize = this.lengthSize, 67 | dataLength = this.dataLength; 68 | 69 | var data = new Uint8Array( _aes_block_size + ( adata ? 2 + adata.length : 0 ) ); 70 | 71 | // B0: flags(adata?, M', L'), nonce, len(data) 72 | data[0] = ( adata ? 64 : 0 ) | ( (tagSize-2)<<2 ) | ( lengthSize-1 ); 73 | data.set( nonce, 1 ); 74 | if (lengthSize > 4) data[11] = ( ( dataLength - (dataLength>>>0) ) / 4294967296 )&15; 75 | if (lengthSize > 3) data[12] = dataLength>>>24; 76 | if (lengthSize > 2) data[13] = dataLength>>>16&255; 77 | data[14] = dataLength>>>8&255; 78 | data[15] = dataLength&255; 79 | 80 | // B*: len(adata), adata 81 | if ( adata ) { 82 | data[16] = adata.length>>>8&255; 83 | data[17] = adata.length&255; 84 | data.set( adata, 18 ); 85 | } 86 | 87 | _cbc_mac_process.call( this, data ); 88 | this.asm.save_state( _aes_heap_start ); 89 | 90 | this.iv = new Uint8Array( this.heap.subarray( _aes_heap_start, _aes_heap_start + _aes_block_size ) ); 91 | } 92 | 93 | function ccm_aes_reset ( options ) { 94 | options = options || {}; 95 | 96 | _aes_reset.call( this, options ); 97 | 98 | _aes_init_iv.call( this, options.iv ); 99 | 100 | var tagSize = options.tagSize; 101 | if ( tagSize !== undefined ) { 102 | if ( !is_number(tagSize) ) 103 | throw new TypeError("tagSize must be a number"); 104 | 105 | if ( tagSize < 4 || tagSize > 16 || tagSize & 1 ) 106 | throw new IllegalArgumentError("illegal tagSize value"); 107 | 108 | this.tagSize = tagSize; 109 | } 110 | else { 111 | this.tagSize = _aes_block_size; 112 | } 113 | 114 | var lengthSize = options.lengthSize, 115 | nonce = options.nonce; 116 | if ( nonce !== undefined ) { 117 | if ( is_buffer(nonce) || is_bytes(nonce) ) { 118 | nonce = new Uint8Array(nonce); 119 | } 120 | else if ( is_string(nonce) ) { 121 | nonce = string_to_bytes(nonce); 122 | } 123 | else { 124 | throw new TypeError("unexpected nonce type"); 125 | } 126 | 127 | if ( nonce.length < 10 || nonce.length > 13 ) 128 | throw new IllegalArgumentError("illegal nonce length"); 129 | 130 | lengthSize = lengthSize || ( 15 - nonce.length ); 131 | 132 | this.nonce = nonce; 133 | } 134 | else { 135 | this.nonce = null; 136 | } 137 | 138 | if ( lengthSize !== undefined ) { 139 | if ( !is_number(lengthSize) ) 140 | throw new TypeError("lengthSize must be a number"); 141 | 142 | if ( lengthSize < 2 || lengthSize > 5 || nonce.length + lengthSize !== 15 ) 143 | throw new IllegalArgumentError("illegal lengthSize value"); 144 | 145 | this.lengthSize = lengthSize; 146 | } 147 | else { 148 | this.lengthSize = lengthSize = 4; 149 | } 150 | 151 | var iv = this.iv; 152 | 153 | var counter = options.counter; 154 | if ( counter !== undefined ) { 155 | if ( iv === null ) 156 | throw new IllegalStateError("iv is also required"); 157 | 158 | if ( !is_number(counter) ) 159 | throw new TypeError("counter must be a number"); 160 | 161 | this.counter = counter; 162 | } 163 | else { 164 | this.counter = 1; 165 | } 166 | 167 | var dataLength = options.dataLength; 168 | if ( dataLength !== undefined ) { 169 | if ( !is_number(dataLength) ) 170 | throw new TypeError("dataLength must be a number"); 171 | 172 | if ( dataLength < 0 || dataLength > _ccm_data_maxLength || dataLength > ( Math.pow( 2, 8*lengthSize ) - 1 ) ) 173 | throw new IllegalArgumentError("illegal dataLength value"); 174 | 175 | this.dataLength = dataLength; 176 | 177 | var dataLeft = options.dataLeft || dataLength; 178 | 179 | if ( !is_number(dataLeft) ) 180 | throw new TypeError("dataLeft must be a number"); 181 | 182 | if ( dataLeft < 0 || dataLeft > dataLength ) 183 | throw new IllegalArgumentError("illegal dataLeft value"); 184 | 185 | this.dataLeft = dataLeft; 186 | } 187 | else { 188 | this.dataLength = dataLength = -1; 189 | this.dataLeft = dataLength; 190 | } 191 | 192 | var adata = options.adata; 193 | if ( adata !== undefined ) { 194 | if ( iv !== null ) 195 | throw new IllegalStateError("you must specify either adata or iv, not both"); 196 | 197 | if ( is_buffer(adata) || is_bytes(adata) ) { 198 | adata = new Uint8Array(adata); 199 | } 200 | else if ( is_string(adata) ) { 201 | adata = string_to_bytes(adata); 202 | } 203 | else { 204 | throw new TypeError("unexpected adata type"); 205 | } 206 | 207 | if ( adata.length === 0 || adata.length > _ccm_adata_maxLength ) 208 | throw new IllegalArgumentError("illegal adata length"); 209 | 210 | this.adata = adata; 211 | this.counter = 1; 212 | } 213 | else { 214 | this.adata = adata = null; 215 | } 216 | 217 | if ( dataLength !== -1 ) 218 | _ccm_calculate_iv.call(this); 219 | 220 | return this; 221 | } 222 | 223 | function ccm_aes_encrypt_process ( data ) { 224 | if ( !this.key ) 225 | throw new IllegalStateError("no key is associated with the instance"); 226 | 227 | if ( is_string(data) ) 228 | data = string_to_bytes(data); 229 | 230 | if ( is_buffer(data) ) 231 | data = new Uint8Array(data); 232 | 233 | if ( !is_bytes(data) ) 234 | throw new TypeError("data isn't of expected type"); 235 | 236 | var dpos = 0, 237 | dlen = data.length || 0, 238 | asm = this.asm, 239 | heap = this.heap, 240 | nonce = this.nonce, 241 | counter = this.counter, 242 | pos = this.pos, 243 | len = this.len, 244 | rpos = 0, 245 | rlen = _aes_block_size * Math.floor( ( len + dlen ) / _aes_block_size ), 246 | wlen = 0; 247 | 248 | if ( ((counter-1)<<4) + len + dlen > _ccm_data_maxLength ) 249 | throw new RangeError("counter overflow"); 250 | 251 | var result = new Uint8Array(rlen); 252 | 253 | var asm_args = [ 0, 0, (this.lengthSize-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 254 | for ( var i = 0; i < nonce.length; i++ ) asm_args[3+i] = nonce[i]; 255 | 256 | while ( dlen > 0 ) { 257 | wlen = _heap_write( heap, pos+len, data, dpos, dlen ); 258 | len += wlen; 259 | dpos += wlen; 260 | dlen -= wlen; 261 | 262 | asm_args[0] = pos; 263 | asm_args[1] = len & ~15; // same as (len - (len % 16)) 264 | asm_args[16] = (counter/0x100000000)>>>0; 265 | asm_args[17] = counter>>>0; 266 | 267 | wlen = asm.ccm_encrypt.apply( asm, asm_args ); 268 | result.set( heap.subarray( pos, pos + wlen ), rpos ); 269 | counter += (wlen>>>4); 270 | rpos += wlen; 271 | 272 | if ( wlen < len ) { 273 | pos += wlen; 274 | len -= wlen; 275 | } else { 276 | pos = _aes_heap_start; 277 | len = 0; 278 | } 279 | } 280 | 281 | this.result = result; 282 | this.counter = counter; 283 | this.pos = pos; 284 | this.len = len; 285 | 286 | return this; 287 | } 288 | 289 | function ccm_aes_encrypt_finish () { 290 | if ( !this.key ) 291 | throw new IllegalStateError("no key is associated with the instance"); 292 | 293 | var asm = this.asm, 294 | heap = this.heap, 295 | nonce = this.nonce, 296 | counter = this.counter, 297 | tagSize = this.tagSize, 298 | pos = this.pos, 299 | len = this.len, 300 | wlen = 0; 301 | 302 | var result = new Uint8Array( len + tagSize ); 303 | 304 | var asm_args = [ 0, 0, (this.lengthSize-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 305 | for ( var i = 0; i < nonce.length; i++ ) asm_args[3+i] = nonce[i]; 306 | 307 | asm_args[0] = pos; 308 | asm_args[1] = len; 309 | asm_args[16] = (counter/0x100000000)>>>0; 310 | asm_args[17] = counter>>>0; 311 | 312 | wlen = asm.ccm_encrypt.apply( asm, asm_args ); 313 | result.set( heap.subarray( pos, pos + wlen ) ); 314 | counter = 1; 315 | pos = _aes_heap_start; 316 | len = 0; 317 | 318 | asm.save_state( _aes_heap_start ); 319 | 320 | asm_args[0] = _aes_heap_start, 321 | asm_args[1] = _aes_block_size, 322 | asm_args[16] = 0; 323 | asm_args[17] = 0; 324 | asm.ccm_encrypt.apply( asm, asm_args ); 325 | 326 | result.set( heap.subarray( _aes_heap_start, _aes_heap_start + tagSize ), wlen ); 327 | 328 | this.result = result; 329 | this.counter = counter; 330 | this.pos = pos; 331 | this.len = len; 332 | 333 | return this; 334 | } 335 | 336 | function ccm_aes_encrypt ( data ) { 337 | this.dataLength = this.dataLeft = data.length || 0; 338 | 339 | var result1 = ccm_aes_encrypt_process.call( this, data ).result, 340 | result2 = ccm_aes_encrypt_finish.call(this).result, 341 | result; 342 | 343 | result = new Uint8Array( result1.length + result2.length ); 344 | result.set(result1); 345 | result.set( result2, result1.length ); 346 | this.result = result; 347 | 348 | return this; 349 | } 350 | 351 | function ccm_aes_decrypt_process ( data ) { 352 | if ( !this.key ) 353 | throw new IllegalStateError("no key is associated with the instance"); 354 | 355 | if ( is_string(data) ) 356 | data = string_to_bytes(data); 357 | 358 | if ( is_buffer(data) ) 359 | data = new Uint8Array(data); 360 | 361 | if ( !is_bytes(data) ) 362 | throw new TypeError("data isn't of expected type"); 363 | 364 | var dpos = 0, 365 | dlen = data.length || 0, 366 | asm = this.asm, 367 | heap = this.heap, 368 | nonce = this.nonce, 369 | counter = this.counter, 370 | tagSize = this.tagSize, 371 | pos = this.pos, 372 | len = this.len, 373 | rpos = 0, 374 | rlen = _aes_block_size * Math.floor( ( len + dlen ) / _aes_block_size ), 375 | wlen = 0; 376 | 377 | if ( ((counter-1)<<4) + len + dlen > _ccm_data_maxLength ) 378 | throw new RangeError("counter overflow"); 379 | 380 | var result = new Uint8Array(rlen); 381 | 382 | var asm_args = [ 0, 0, (this.lengthSize-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 383 | for ( var i = 0; i < nonce.length; i++ ) asm_args[3+i] = nonce[i]; 384 | 385 | while ( dlen > 0 ) { 386 | wlen = _heap_write( heap, pos+len, data, dpos, dlen ); 387 | len += wlen; 388 | dpos += wlen; 389 | dlen -= wlen; 390 | 391 | asm_args[0] = pos; 392 | asm_args[1] = len + dlen - tagSize >= _aes_block_size ? dlen >= tagSize ? len & ~15 : (len + dlen - tagSize) & ~15 : 0; 393 | asm_args[16] = (counter/0x100000000)>>>0; 394 | asm_args[17] = counter>>>0; 395 | 396 | wlen = asm.ccm_decrypt.apply( asm, asm_args ); 397 | result.set( heap.subarray( pos, pos + wlen ), rpos ); 398 | counter += (wlen>>>4); 399 | rpos += wlen; 400 | 401 | if ( wlen < len ) { 402 | pos += wlen; 403 | len -= wlen; 404 | } else { 405 | pos = _aes_heap_start; 406 | len = 0; 407 | } 408 | } 409 | 410 | this.result = result.subarray( 0, rpos ); 411 | this.counter = counter; 412 | this.pos = pos; 413 | this.len = len; 414 | 415 | return this; 416 | } 417 | 418 | function ccm_aes_decrypt_finish () { 419 | if ( !this.key ) 420 | throw new IllegalStateError("no key is associated with the instance"); 421 | 422 | var asm = this.asm, 423 | heap = this.heap, 424 | nonce = this.nonce, 425 | counter = this.counter, 426 | tagSize = this.tagSize, 427 | pos = this.pos, 428 | len = this.len, 429 | rlen = len - tagSize, 430 | wlen = 0; 431 | 432 | if ( len < tagSize ) 433 | throw new IllegalStateError("authentication tag not found"); 434 | 435 | var result = new Uint8Array(rlen), 436 | atag = new Uint8Array( heap.subarray( pos+rlen, pos+len ) ); 437 | 438 | var asm_args = [ 0, 0, (this.lengthSize-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; 439 | for ( var i = 0; i < nonce.length; i++ ) asm_args[3+i] = nonce[i]; 440 | 441 | asm_args[0] = pos; 442 | asm_args[1] = rlen; 443 | asm_args[16] = (counter/0x100000000)>>>0; 444 | asm_args[17] = counter>>>0; 445 | 446 | wlen = asm.ccm_decrypt.apply( asm, asm_args ); 447 | result.set( heap.subarray( pos, pos + wlen ) ); 448 | counter = 1; 449 | pos = _aes_heap_start; 450 | len = 0; 451 | 452 | asm.save_state( _aes_heap_start ); 453 | 454 | asm_args[0] = _aes_heap_start, 455 | asm_args[1] = _aes_block_size, 456 | asm_args[16] = 0; 457 | asm_args[17] = 0; 458 | asm.ccm_encrypt.apply( asm, asm_args ); 459 | 460 | var acheck = 0; 461 | for ( var i = 0; i < tagSize; ++i ) acheck |= atag[i] ^ heap[ _aes_heap_start + i ]; 462 | if ( acheck ) 463 | throw new SecurityError("data integrity check failed"); 464 | 465 | this.result = result; 466 | this.counter = counter; 467 | this.pos = pos; 468 | this.len = len; 469 | 470 | return this; 471 | } 472 | 473 | function ccm_aes_decrypt ( data ) { 474 | this.dataLength = this.dataLeft = data.length || 0; 475 | 476 | var result1 = ccm_aes_decrypt_process.call( this, data ).result, 477 | result2 = ccm_aes_decrypt_finish.call(this).result, 478 | result; 479 | 480 | result = new Uint8Array( result1.length + result2.length ); 481 | result.set(result1); 482 | result.set( result2, result1.length ); 483 | this.result = result; 484 | 485 | return this; 486 | } 487 | 488 | var ccm_aes_prototype = ccm_aes_constructor.prototype; 489 | ccm_aes_prototype.reset = ccm_aes_reset; 490 | ccm_aes_prototype.encrypt = ccm_aes_encrypt; 491 | ccm_aes_prototype.decrypt = ccm_aes_decrypt; 492 | 493 | var ccm_aes_encrypt_prototype = ccm_aes_encrypt_constructor.prototype; 494 | ccm_aes_encrypt_prototype.reset = ccm_aes_reset; 495 | ccm_aes_encrypt_prototype.process = ccm_aes_encrypt_process; 496 | ccm_aes_encrypt_prototype.finish = ccm_aes_encrypt_finish; 497 | 498 | var ccm_aes_decrypt_prototype = ccm_aes_decrypt_constructor.prototype; 499 | ccm_aes_decrypt_prototype.reset = ccm_aes_reset; 500 | ccm_aes_decrypt_prototype.process = ccm_aes_decrypt_process; 501 | ccm_aes_decrypt_prototype.finish = ccm_aes_decrypt_finish; 502 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | asmCrypto [![Build Status](https://travis-ci.org/vibornoff/asmcrypto.js.svg?branch=master)](https://travis-ci.org/vibornoff/asmcrypto.js) [![Selenium Test Status](https://saucelabs.com/buildstatus/vibornoff)](https://saucelabs.com/u/vibornoff) 2 | ========= 3 | 4 | JavaScript implementation of popular cryptographic utilities with performance in mind. 5 | 6 | Synopsis 7 | -------- 8 | 9 | Add `` into your page. 10 | 11 | // Hash whole string at once 12 | digest = asmCrypto.SHA256.hex("The quick brown fox jumps over the lazy dog"); 13 | 14 | Index 15 | ----- 16 | 17 | * [Download] (#download) 18 | * [Build & Test](#build--test) 19 | * [Performance](#performance) 20 | * [API Reference](#api-reference) 21 | * [Message Digest](#sha256) 22 | * [SHA1](#sha1) 23 | * [SHA256](#sha256) 24 | * [SHA512](#sha512) 25 | * [Hash-based Message Authentication](#hmac) 26 | * [HMAC-SHA1](#hmac_sha1) 27 | * [HMAC-SHA256](#hmac_sha256) 28 | * [HMAC-SHA512](#hmac_sha512) 29 | * [Password-based Key Derivation](#pbkdf2) 30 | * [PBKDF2-HMAC-SHA1](#pbkdf2_hmac_sha1) 31 | * [PBKDF2-HMAC-SHA256](#pbkdf2_hmac_sha256) 32 | * [PBKDF2-HMAC-SHA512](#pbkdf2_hmac_sha512) 33 | * [Block Cipher](#aes) 34 | * [AES-CBC](#aes_cbc) 35 | * [AES-CFB](#aes_cfb) 36 | * [AES-CCM](#aes_ccm) 37 | * [Asymmetric encryption](#rsa) 38 | * [RSA](#rsa) 39 | * [RSA-OAEP-SHA256](#rsa_oaep_sha256) 40 | * [RSA-OAEP-SHA512](#rsa_oaep_sha256) 41 | * [RSA-PSS-SHA256](#rsa_pss_sha512) 42 | * [RSA-PSS-SHA512](#rsa_pss_sha512) 43 | * [Cryptographically secure pseudorandom number generator](#cryptographically-secure-pseudorandom-number-generator) 44 | * [Bugs & TODO](#bugs--todo) 45 | * [Donate](#donate) 46 | 47 | Download 48 | -------- 49 | 50 | * [Minified JS file](http://vibornoff.com/asmcrypto.js) 170KB, 51 | * [Source Map file](http://vibornoff.com/asmcrypto.js.map) 313KB, 52 | * [All-in-One archive](http://vibornoff.com/asmcrypto.tar.gz) 178KB. 53 | 54 | Build & Test 55 | ------------ 56 | 57 | Before you start check that [npm](http://npmjs.org/) is installed: 58 | 59 | npm --version 60 | 61 | Then download and build the stuff: 62 | 63 | git clone https://github.com/vibornoff/asmcrypto.js.git 64 | cd asmcrypto.js/ 65 | npm install 66 | 67 | Running tests is always a good idea: 68 | 69 | npm test 70 | 71 | Congratulations! Now you have your `asmcrypto.js` and `asmcrypto.js.map` ready to use ☺ 72 | 73 | Performance 74 | ----------- 75 | 76 | In the development of this project, special attention was paid to the performance issues. 77 | In the result of all the optimizations made this stuff is pretty fast under Firefox and Chrome. 78 | 79 | My *Intel® Core™ i7-3770 CPU @ 3.40GHz* typical processing speeds are: 80 | * *Chrome/31.0* 81 | * SHA256: 51 MiB/s (**9 times faster** than *SJCL* and *CryptoJS*) 82 | * AES-CBC: 47 MiB/s (**13 times faster** than *CryptoJS* and **20 times faster** than *SJCL*) 83 | * *Firefox/26.0* 84 | * SHA256: 144 MiB/s (**5 times faster** than *CryptoJS* and **20 times faster** than *SJCL*) 85 | * AES-CBC: 81 MiB/s (**3 times faster** than *CryptoJS* and **8 times faster** than *SJCL*) 86 | 87 | See benchmarks: 88 | * [SHA256](http://jsperf.com/sha256/34), 89 | * [HMAC-SHA256](http://jsperf.com/hmac-sha256/1), 90 | * [PBKDF2-HMAC-SHA256](http://jsperf.com/pbkdf2-hmac-sha256/2), 91 | * [AES](http://jsperf.com/aes), 92 | * [Modular exponentiation (used internally in RSA)](http://jsperf.com/jsbn-vs-bigint-js-modular-exponentiation-montgomery/4). 93 | 94 | API Reference 95 | ------------- 96 | 97 | ### Message Digest 98 | 99 | #### SHA1 100 | 101 | [Secure Hash Algorithm](http://en.wikipedia.org/wiki/SHA-1) — a cryptographic hash function with 160-bit output. 102 | 103 | A cryptographic hash fuction with 256-bit output. 104 | 105 | ##### SHA1.BLOCK_SIZE = 64 106 | 107 | ##### SHA1.HASH_SIZE = 20 108 | 109 | ##### SHA1.bytes( data ) 110 | 111 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 112 | 113 | Returns raw message digest as an `Uint8Array` object. 114 | 115 | Throws 116 | * `TypeError` when something ridiculous is supplied as input data. 117 | 118 | ##### SHA1.hex( data ) 119 | 120 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 121 | 122 | Returns a string containing hex-encoded message digest. 123 | 124 | Throws 125 | * `TypeError` when something ridiculous is supplied as input data. 126 | 127 | ##### SHA1.base64( data ) 128 | 129 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 130 | 131 | Returns a string containing hex-encoded message digest. 132 | 133 | Throws 134 | * `TypeError` when something ridiculous is supplied as input data. 135 | 136 | #### SHA256 137 | 138 | [Secure Hash Algorithm](http://en.wikipedia.org/wiki/SHA-2) — a cryptographic hash functions family. 139 | 140 | A cryptographic hash fuction with 256-bit output. 141 | 142 | ##### SHA256.BLOCK_SIZE = 64 143 | 144 | ##### SHA256.HASH_SIZE = 32 145 | 146 | ##### SHA256.bytes( data ) 147 | 148 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 149 | 150 | Returns raw message digest as an `Uint8Array` object. 151 | 152 | Throws 153 | * `TypeError` when something ridiculous is supplied as input data. 154 | 155 | ##### SHA256.hex( data ) 156 | 157 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 158 | 159 | Returns a string containing hex-encoded message digest. 160 | 161 | Throws 162 | * `TypeError` when something ridiculous is supplied as input data. 163 | 164 | ##### SHA256.base64( data ) 165 | 166 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 167 | 168 | Returns a string containing hex-encoded message digest. 169 | 170 | Throws 171 | * `TypeError` when something ridiculous is supplied as input data. 172 | 173 | #### SHA512 174 | 175 | A cryptographic hash function with 512-bit output. 176 | 177 | ##### SHA512.BLOCK_SIZE = 128 178 | 179 | ##### SHA512.HASH_SIZE = 64 180 | 181 | ##### SHA512.bytes( data ) 182 | 183 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 184 | 185 | Returns raw message digest as an `Uint8Array` object. 186 | 187 | Throws 188 | * `TypeError` when something ridiculous is supplied as input data. 189 | 190 | ##### SHA512.hex( data ) 191 | 192 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 193 | 194 | Returns a string containing hex-encoded message digest. 195 | 196 | Throws 197 | * `TypeError` when something ridiculous is supplied as input data. 198 | 199 | ##### SHA512.base64( data ) 200 | 201 | Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). 202 | 203 | Returns a string containing hex-encoded message digest. 204 | 205 | Throws 206 | * `TypeError` when something ridiculous is supplied as input data. 207 | 208 | ### HMAC 209 | 210 | [Hash-based Message Authentication Code](http://en.wikipedia.org/wiki/HMAC) 211 | 212 | Used to calculate message authentication code with a cryptographic hash function 213 | in combination with a secret cryptographic key. 214 | 215 | #### HMAC_SHA1 216 | 217 | ##### HMAC_SHA1.BLOCK_SIZE = 64 218 | 219 | ##### HMAC_SHA1.HMAC_SIZE = 20 220 | 221 | ##### HMAC_SHA1.bytes( password, data ) 222 | 223 | Calculates HMAC-SHA1 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 224 | 225 | Returns araw message authentication code as an `Uint8Array` object. 226 | 227 | Throws 228 | * `TypeError` when something ridiculous is supplied as input data. 229 | 230 | ##### HMAC_SHA1.hex( password, data ) 231 | 232 | Calculates HMAC-SHA1 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 233 | 234 | Returns a string containing hex-encoded message authentication code. 235 | 236 | Throws 237 | * `TypeError` when something ridiculous is supplied as input data. 238 | 239 | ##### HMAC_SHA1.base64( password, data ) 240 | 241 | Calculates HMAC-SHA1 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 242 | 243 | Returns a string containing base64-encoded message authentication code. 244 | 245 | Throws 246 | * `TypeError` when something ridiculous is supplied as input data. 247 | 248 | #### HMAC_SHA256 249 | 250 | ##### HMAC_SHA256.BLOCK_SIZE = 64 251 | 252 | ##### HMAC_SHA256.HMAC_SIZE = 32 253 | 254 | ##### HMAC_SHA256.bytes( password, data ) 255 | 256 | Calculates HMAC-SHA256 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 257 | 258 | Returns araw message authentication code as an `Uint8Array` object. 259 | 260 | Throws 261 | * `TypeError` when something ridiculous is supplied as input data. 262 | 263 | ##### HMAC_SHA256.hex( password, data ) 264 | 265 | Calculates HMAC-SHA256 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 266 | 267 | Returns a string containing hex-encoded message authentication code. 268 | 269 | Throws 270 | * `TypeError` when something ridiculous is supplied as input data. 271 | 272 | ##### HMAC_SHA256.base64( password, data ) 273 | 274 | Calculates HMAC-SHA256 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 275 | 276 | Returns a string containing base64-encoded message authentication code. 277 | 278 | Throws 279 | * `TypeError` when something ridiculous is supplied as input data. 280 | 281 | #### HMAC_SHA512 282 | 283 | ##### HMAC_SHA512.BLOCK_SIZE = 128 284 | 285 | ##### HMAC_SHA512.HMAC_SIZE = 64 286 | 287 | ##### HMAC_SHA512.bytes( password, data ) 288 | 289 | Calculates HMAC-SHA512 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 290 | 291 | Returns araw message authentication code as an `Uint8Array` object. 292 | 293 | Throws 294 | * `TypeError` when something ridiculous is supplied as input data. 295 | 296 | ##### HMAC_SHA512.hex( password, data ) 297 | 298 | Calculates HMAC-SHA512 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 299 | 300 | Returns a string containing hex-encoded message authentication code. 301 | 302 | Throws 303 | * `TypeError` when something ridiculous is supplied as input data. 304 | 305 | ##### HMAC_SHA512.base64( password, data ) 306 | 307 | Calculates HMAC-SHA512 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 308 | 309 | Returns a string containing base64-encoded message authentication code. 310 | 311 | Throws 312 | * `TypeError` when something ridiculous is supplied as input data. 313 | 314 | ### PBKDF2 315 | 316 | [Password-Based Key Derivation Function 2](http://en.wikipedia.org/wiki/PBKDF2) 317 | 318 | Applies a cryptographic hash function to the input password or passphrase along with a salt value and repeats the process many times to produce a derived key, 319 | which can then be used as a cryptographic key in subsequent operations. The added computational work makes password cracking much more difficult. 320 | 321 | #### PBKDF2_HMAC_SHA1 322 | 323 | ##### PBKDF2_HMAC_SHA1.bytes( password, salt, iterations, dklen ) 324 | 325 | Derive key from the `password` with `salt`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 326 | 327 | Optional `iterations` (number of key derivatoin rounds) and `dklen` (desired key length) may be supplied. 328 | 329 | Throws 330 | * `TypeError`. 331 | 332 | ##### PBKDF2_HMAC_SHA1.hex( password, salt, iterations, dklen ) 333 | 334 | The same as above except returning value type. 335 | 336 | ##### PBKDF2_HMAC_SHA1.base64( password, salt, iterations, dklen ) 337 | 338 | The same as above except returning value type. 339 | 340 | #### PBKDF2_HMAC_SHA526 341 | 342 | ##### PBKDF2_HMAC_SHA256.bytes( password, salt, iterations, dklen ) 343 | 344 | Derive key from the `password` with `salt`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 345 | 346 | Optional `iterations` (number of key derivatoin rounds) and `dklen` (desired key length) may be supplied. 347 | 348 | Throws 349 | * `TypeError`. 350 | 351 | ##### PBKDF2_HMAC_SHA256.hex( password, salt, iterations, dklen ) 352 | 353 | The same as above except returning value type. 354 | 355 | ##### PBKDF2_HMAC_SHA256.base64( password, salt, iterations, dklen ) 356 | 357 | The same as above except returning value type. 358 | 359 | #### PBKDF2_HMAC_SHA512 360 | 361 | ##### PBKDF2_HMAC_SHA512.bytes( password, salt, iterations, dklen ) 362 | 363 | Derive key from the `password` with `salt`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. 364 | 365 | Optional `iterations` (number of key derivatoin rounds) and `dklen` (desired key length) may be supplied. 366 | 367 | Throws 368 | * `TypeError`. 369 | 370 | ##### PBKDF2_HMAC_SHA512.hex( password, salt, iterations, dklen ) 371 | 372 | The same as above except returning value type. 373 | 374 | ##### PBKDF2_HMAC_SHA512.base64( password, salt, iterations, dklen ) 375 | 376 | The same as above except returning value type. 377 | 378 | ### AES 379 | 380 | Advanced Encryption Standard 381 | 382 | #### AES.BLOCK_SIZE = 16 383 | 384 | #### AES_CBC 385 | 386 | Cipher Block Chaining Mode. 387 | s 388 | ##### AES_CBC.encrypt( data, key, padding, iv ) 389 | 390 | Encrypts supplied `data` with `key` in CBC mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. 391 | 392 | Optional `padding` and `iv` may be passed to override default settings (PKCS#7 padding is on and iv is zero-vector). 393 | 394 | Returns encrypted data as `Uint8Array`. 395 | 396 | ##### AES_CBC.decrypt( data, key, padding, iv ) 397 | 398 | Decrypts supplied `data` with `key` in CBC mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. 399 | 400 | Optional `padding` and `iv` may be passed to override default settings (PKCS#7 padding is on and iv is zero-vector). 401 | 402 | Returns encrypted data as `Uint8Array`. 403 | 404 | #### AES_CFB 405 | 406 | Cipher Feedback Mode. 407 | 408 | ##### AES_CFB.encrypt( data, key, padding, iv ) 409 | 410 | Encrypts supplied `data` with `key` in CFB mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. 411 | 412 | Optional `padding` and `iv` may be passed to override default settings (PKCS#7 padding is on and iv is zero-vector). 413 | 414 | Returns encrypted data as `Uint8Array`. 415 | 416 | ##### AES_CFB.decrypt( data, key, padding, iv ) 417 | 418 | Decrypts supplied `data` with `key` in CFB mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. 419 | 420 | Optional `padding` and `iv` may be passed to override default settings (PKCS#7 padding is on and iv is zero-vector). 421 | 422 | Returns encrypted data as `Uint8Array`. 423 | 424 | #### AES_CCM 425 | 426 | Counter with CBC-MAC mode. 427 | 428 | Due to JS limitations (counter is 32-bit unsigned) maximum encrypted message length is limited to near 64 GiB ( 2^36 - 16 ) per `nonce`-`key` pair. 429 | 430 | Additional authenticated data `adata` maximum length is limited to 65279 bytes ( 2^16 - 2^8 ), 431 | wich is considered enough for the most of use-cases. 432 | 433 | Optional `tagSize`, the size of the authentication tag, may be 4, 6, 8, 12, 16 (default). 434 | 435 | Keep in mind that **same nonce must not be used more than once with the same key**. 436 | 437 | ##### AES_CCM.encrypt( data, key, nonce, adata, tagsize ) 438 | 439 | Encrypts supplied `data` with `key`-`nonce` in CCM mode. 440 | 441 | Returns encrypted data as `Uint8Array`. 442 | 443 | ##### AES_CCM.decrypt( data, key, nonce, adata, tagsize ) 444 | 445 | Decrypts supplied `data` with `key`-`nonce` in CCM mode. 446 | 447 | Returns encrypted data as `Uint8Array`. 448 | 449 | ### RSA 450 | 451 | #### RSA.generateKey( bitlen, pubexp ) 452 | 453 | Generate RSA private key of `bitlen` length along with the public exponent `pubexp`. 454 | 455 | Run 50 rounds of Miller-Rabin test for each prime candidate. 456 | 457 | #### RSA_OAEP_SHA256 458 | 459 | ##### RSA_OAEP_SHA256.encrypt( data, key, label ) 460 | 461 | TODO 462 | 463 | ##### RSA_OAEP_SHA256.decrypt( data, key, label ) 464 | 465 | TODO 466 | 467 | #### RSA_OAEP_SHA512 468 | 469 | ##### RSA_OAEP_SHA512.encrypt( data, key, label ) 470 | 471 | TODO 472 | 473 | ##### RSA_OAEP_SHA512.decrypt( data, key, label ) 474 | 475 | TODO 476 | 477 | #### RSA_PSS_SHA256 478 | 479 | ##### RSA_PSS_SHA256.sign( data, key, slen ) 480 | 481 | TODO 482 | 483 | ##### RSA_PSS_SHA256.verify( signature, data, key, slen ) 484 | 485 | TODO 486 | 487 | #### RSA_PSS_SHA512 488 | 489 | ##### RSA_PSS_SHA512.sign( data, key, slen ) 490 | 491 | TODO 492 | 493 | ##### RSA_PSS_SHA512.verify( signature, data, key, slen ) 494 | 495 | TODO 496 | 497 | ### Cryptographically secure pseudorandom number generator 498 | 499 | TODO 500 | 501 | Bugs & TODO 502 | ----------- 503 | 504 | * Progressive operations are temporary fade out, they'll be back with WebCrypto API; 505 | * Moar docs needed ☺ 506 | 507 | Not yet implemented: 508 | * aes-gcm, 509 | * scrypt, 510 | * dsa, ecdsa, 511 | * rsa-pkcs-v1.5 512 | 513 | Donate 514 | ------ 515 | 516 | If you like this stuff feel free to donate some funds to `1CiGzP1EFLTftqkfvVtbwvZ9Koiuoc4FSC` ☺ 517 | --------------------------------------------------------------------------------