diff --git a/.esmrc b/.esmrc new file mode 100644 index 0000000..2017636 --- /dev/null +++ b/.esmrc @@ -0,0 +1,8 @@ +{ + "mode": "all", + "cjs": { + "namedExports": true, + "vars": true, + "interop": true + } +} diff --git a/.gitignore b/.gitignore index 4654e5c..dc9feaa 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ test/aes.asm.js.map doc/ node_modules/ .idea/ -package-lock.json +dist_es5 +dist_es8 diff --git a/.npmignore b/.npmignore index 0ee4f76..47269b6 100644 --- a/.npmignore +++ b/.npmignore @@ -2,3 +2,4 @@ doc/ node_modules/ .idea/ package-lock.json +*.ts diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4b9a2d9 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.travis.yml b/.travis.yml index 8f2ca84..92c29d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: node_js node_js: - '8' -- '9' +- '10' sudo: required before_install: export WITH=ALL script: - grunt test + npm test diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index af5f7c2..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,120 +0,0 @@ -// Grunt setup -module.exports = function (grunt) { - grunt.loadNpmTasks('grunt-contrib-uglify-es'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-jsdoc'); - grunt.loadNpmTasks('grunt-rollup'); - grunt.loadNpmTasks('grunt-shell'); - - // Finally, configure - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - - rollup: { - options: { - format: 'umd', - sourceMap: true, - banner: "/*! asmCrypto<%= pkg.version && ' v'+pkg.version %>, (c) 2018 asmCrypto.js, opensource.org/licenses/<%= pkg.license %> */", - }, - default: { - options: { - moduleName: 'asmCrypto', - }, - files: { - 'asmcrypto.js': './src/entry-default.js', - }, - }, - all: { - options: { - moduleName: 'asmCrypto', - }, - files: { - 'asmcrypto.all.js': './src/entry-export_all.js', - }, - }, - all_esm: { - options: { - format: 'es', - }, - files: { - 'asmcrypto.mjs': './src/entry-export_all.js', - }, - }, - test_AES_ASM: { - options: { - moduleName: 'AES_asm', - }, - files: { - 'test/aes.asm.js': './src/aes/aes.asm.js', - }, - }, - }, - - shell: { - test: { - command: '"./node_modules/.bin/qunit-puppeteer" http://localhost:9999/index.html' - } - }, - - uglify: { - options: { - mangle: {}, - compress: {}, - sourceMap: true, - sourceMapIn: 'asmcrypto.js.map', - sourceMapIncludeSources: true, - screwIE8: true, - banner: "/*! asmCrypto<%= pkg.version && ' v'+pkg.version %>, (c) 2018 asmCrypto.js, opensource.org/licenses/<%= pkg.license %> */", - }, - all: { - files: { - 'asmcrypto.min.js': 'asmcrypto.js', - }, - }, - }, - - jsdoc: { - all: { - src: ['src/**/*.js', 'README.md'], - options: { - destination: 'doc', - }, - }, - }, - - connect: { - all: { - options: { - hostname: 'localhost', - port: 9999, - base: ['test', '.'], - directory: 'test', - }, - }, - }, - - watch: { - all: { - files: 'src/**/*.js', - tasks: ['rollup:all', 'rollup:test_AES_ASM'], - }, - }, - - clean: [ - 'asmcrypto.js', - 'asmcrypto.js.map', - 'test/aes.asm.js', - 'test/aes.asm.js.map', - 'doc/', - ], - }); - - grunt.registerTask('default', ['rollup:default', 'rollup:test_AES_ASM', 'uglify']); - grunt.registerTask('all', ['rollup:all']); - grunt.registerTask('esm', ['rollup:all_esm']); - grunt.registerTask('devel', ['rollup:all', 'rollup:test_AES_ASM', 'connect', 'watch']); - grunt.registerTask('test', ['connect', 'shell']); -}; diff --git a/README.md b/README.md index c81d44c..51fa9d5 100644 --- a/README.md +++ b/README.md @@ -3,58 +3,9 @@ asmCrypto [![Build Status](https://travis-ci.org/asmcrypto/asmcrypto.js.svg?bran JavaScript implementation of popular cryptographic utilities with performance in mind. -Synopsis --------- - -Add `` into your page. - - // Hash whole string at once - digest = asmCrypto.SHA256.hex("The quick brown fox jumps over the lazy dog"); - -Index ------ - -* [Build & Test](#build--test) -* [Performance](#performance) -* [API Reference](#api-reference) - * [Message Digest](#sha256) - * [SHA1](#sha1) - * [SHA256](#sha256) - * [SHA512](#sha512) - * [Hash-based Message Authentication](#hmac) - * [HMAC-SHA1](#hmac_sha1) - * [HMAC-SHA256](#hmac_sha256) - * [HMAC-SHA512](#hmac_sha512) - * [Password-based Key Derivation](#pbkdf2) - * [PBKDF2-HMAC-SHA1](#pbkdf2_hmac_sha1) - * [PBKDF2-HMAC-SHA256](#pbkdf2_hmac_sha256) - * [PBKDF2-HMAC-SHA512](#pbkdf2_hmac_sha512) - * [Block Cipher](#aes) - * [AES-EBC](#aes_ecb) - * [AES-CBC](#aes_cbc) - * [AES-CFB](#aes_cfb) - * [AES-OFB](#aes_ofb) - * [AES-CTR](#aes_ctr) - * [AES-CCM](#aes_ccm) - * [AES-GCM](#aes_gcm) - * [Asymmetric encryption](#rsa) - * [RSA](#rsa) - * [RSA-OAEP-SHA1](#rsa_oaep_sha1) - * [RSA-OAEP-SHA256](#rsa_oaep_sha256) - * [RSA-OAEP-SHA512](#rsa_oaep_sha512) - * [RSA-PSS-SHA1](#rsa_pss_sha1) - * [RSA-PSS-SHA256](#rsa_pss_sha256) - * [RSA-PSS-SHA512](#rsa_pss_sha512) - * [Cryptographically secure pseudorandom number generator](#cryptographically-secure-pseudorandom-number-generator) - - Build & Test ------------ -Before you start check that [npm](http://npmjs.org/) is installed: - - npm --version - Then download and build the stuff: git clone https://github.com/asmcrypto/asmcrypto.js.git @@ -67,494 +18,18 @@ Running tests is always a good idea: Congratulations! Now you have your `asmcrypto.js` ready to use ☺ -Performance ------------ - -In the development of this project, special attention was paid to the performance issues. -In the result of all the optimizations made this stuff is pretty fast under Firefox and Chrome. - Support ----------- -* NodeJS 8 and NodeJS 9 -* IE11 (temporarily disabled, use previous versions: 0.16.x) +* NodeJS 10 +* IE11 * last two Chrome versions * last two Firefox versions and the latest Firefox ESR * last two Edge versions * last two Safari versions -API Reference -------------- - -### Message Digest - -#### SHA1 - -[Secure Hash Algorithm](http://en.wikipedia.org/wiki/SHA-1) — a cryptographic hash function with 160-bit output. - -A cryptographic hash fuction with 256-bit output. - -##### SHA1.BLOCK_SIZE = 64 - -##### SHA1.HASH_SIZE = 20 - -##### SHA1.bytes( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns raw message digest as an `Uint8Array` object. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### SHA1.hex( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns a string containing hex-encoded message digest. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### SHA1.base64( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns a string containing hex-encoded message digest. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -#### SHA256 - -[Secure Hash Algorithm](http://en.wikipedia.org/wiki/SHA-2) — a cryptographic hash functions family. - -A cryptographic hash fuction with 256-bit output. - -##### SHA256.BLOCK_SIZE = 64 - -##### SHA256.HASH_SIZE = 32 - -##### SHA256.bytes( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns raw message digest as an `Uint8Array` object. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### SHA256.hex( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns a string containing hex-encoded message digest. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### SHA256.base64( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns a string containing hex-encoded message digest. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -#### SHA512 - -A cryptographic hash function with 512-bit output. - -##### SHA512.BLOCK_SIZE = 128 - -##### SHA512.HASH_SIZE = 64 - -##### SHA512.bytes( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns raw message digest as an `Uint8Array` object. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### SHA512.hex( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns a string containing hex-encoded message digest. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### SHA512.base64( data ) - -Calculates message digest of the supplied input `data` (can be a binary string or `ArrayBuffer`/`Uint8Array` object). - -Returns a string containing hex-encoded message digest. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -### HMAC - -[Hash-based Message Authentication Code](http://en.wikipedia.org/wiki/HMAC) - -Used to calculate message authentication code with a cryptographic hash function -in combination with a secret cryptographic key. - -#### HMAC_SHA1 - -##### HMAC_SHA1.BLOCK_SIZE = 64 - -##### HMAC_SHA1.HMAC_SIZE = 20 - -##### HMAC_SHA1.bytes( data, password ) - -Calculates HMAC-SHA1 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns araw message authentication code as an `Uint8Array` object. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### HMAC_SHA1.hex( data, password ) - -Calculates HMAC-SHA1 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns a string containing hex-encoded message authentication code. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### HMAC_SHA1.base64( data, password ) - -Calculates HMAC-SHA1 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns a string containing base64-encoded message authentication code. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -#### HMAC_SHA256 - -##### HMAC_SHA256.BLOCK_SIZE = 64 - -##### HMAC_SHA256.HMAC_SIZE = 32 - -##### HMAC_SHA256.bytes( data, password ) - -Calculates HMAC-SHA256 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns araw message authentication code as an `Uint8Array` object. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### HMAC_SHA256.hex( data, password ) - -Calculates HMAC-SHA256 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns a string containing hex-encoded message authentication code. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### HMAC_SHA256.base64( data, password ) - -Calculates HMAC-SHA256 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns a string containing base64-encoded message authentication code. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -#### HMAC_SHA512 - -##### HMAC_SHA512.BLOCK_SIZE = 128 - -##### HMAC_SHA512.HMAC_SIZE = 64 - -##### HMAC_SHA512.bytes( data, password ) - -Calculates HMAC-SHA512 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns araw message authentication code as an `Uint8Array` object. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### HMAC_SHA512.hex( data, password ) - -Calculates HMAC-SHA512 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns a string containing hex-encoded message authentication code. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -##### HMAC_SHA512.base64( data, password ) - -Calculates HMAC-SHA512 of `data` with `password`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Returns a string containing base64-encoded message authentication code. - -Throws -* `TypeError` when something ridiculous is supplied as input data. - -### PBKDF2 - -[Password-Based Key Derivation Function 2](http://en.wikipedia.org/wiki/PBKDF2) - -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, -which can then be used as a cryptographic key in subsequent operations. The added computational work makes password cracking much more difficult. - -#### PBKDF2_HMAC_SHA1 - -##### PBKDF2_HMAC_SHA1.bytes( password, salt, iterations, dklen ) - -Derive key from the `password` with `salt`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Optional `iterations` (number of key derivatoin rounds) and `dklen` (desired key length) may be supplied. - -Throws -* `TypeError`. - -##### PBKDF2_HMAC_SHA1.hex( password, salt, iterations, dklen ) - -The same as above except returning value type. - -##### PBKDF2_HMAC_SHA1.base64( password, salt, iterations, dklen ) - -The same as above except returning value type. - -#### PBKDF2_HMAC_SHA256 - -##### PBKDF2_HMAC_SHA256.bytes( password, salt, iterations, dklen ) - -Derive key from the `password` with `salt`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Optional `iterations` (number of key derivatoin rounds) and `dklen` (desired key length) may be supplied. - -Throws -* `TypeError`. - -##### PBKDF2_HMAC_SHA256.hex( password, salt, iterations, dklen ) - -The same as above except returning value type. - -##### PBKDF2_HMAC_SHA256.base64( password, salt, iterations, dklen ) - -The same as above except returning value type. - -#### PBKDF2_HMAC_SHA512 - -##### PBKDF2_HMAC_SHA512.bytes( password, salt, iterations, dklen ) - -Derive key from the `password` with `salt`. Both can be either binary strings or `Uint8Array`/`ArrayBuffer` objects. - -Optional `iterations` (number of key derivatoin rounds) and `dklen` (desired key length) may be supplied. - -Throws -* `TypeError`. - -##### PBKDF2_HMAC_SHA512.hex( password, salt, iterations, dklen ) - -The same as above except returning value type. - -##### PBKDF2_HMAC_SHA512.base64( password, salt, iterations, dklen ) - -The same as above except returning value type. - -### AES - -Advanced Encryption Standard - -#### AES_ECB - -TODO - -#### AES_CBC - -Cipher Block Chaining Mode. - -##### AES_CBC.encrypt( data, key, padding, iv ) - -Encrypts supplied `data` with `key` in CBC mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. - -Optional `padding` and `iv` may be passed to override default settings (PKCS#7 padding is on and iv is zero-vector). - -Returns encrypted data as `Uint8Array`. - -##### AES_CBC.decrypt( data, key, padding, iv ) - -Decrypts supplied `data` with `key` in CBC mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. - -Optional `padding` and `iv` may be passed to override default settings (PKCS#7 padding is on and iv is zero-vector). - -Returns encrypted data as `Uint8Array`. - -#### AES_CFB - -Cipher Feedback Mode. - -##### AES_CFB.encrypt( data, key, iv ) - -Encrypts supplied `data` with `key` in CFB mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. - -Optional `iv` may be passed to override default settings (zero-vector `iv`). - -Returns encrypted data as `Uint8Array`. - -##### AES_CFB.decrypt( data, key, iv ) - -Decrypts supplied `data` with `key` in CFB mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. - -Optional `iv` may be passed to override default settings (zero-vector `iv`). - -Returns encrypted data as `Uint8Array`. - -#### AES_OFB - -Output Feedback Mode. - -##### AES_OFB.encrypt( data, key, iv ) - -Encrypts supplied `data` with `key` in OFB mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. - -Optional `iv` may be passed to override default settings (zero-vector `iv`). - -Returns encrypted data as `Uint8Array`. - -##### AES_OFB.decrypt( data, key, iv ) - -Decrypts supplied `data` with `key` in OFB mode. Both can be either binary strings or `Uint8Array` objects or `ArrayBuffer` objects. - -Optional `iv` may be passed to override default settings (zero-vector `iv`). - -Returns encrypted data as `Uint8Array`. - -#### AES_CTR - -TODO - -#### AES_CCM - -Counter with CBC-MAC mode. - -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. - -Additional authenticated data `adata` maximum length is limited to 65279 bytes ( 2^16 - 2^8 ), -wich is considered enough for the most of use-cases. - -Optional `tagSize`, the size of the authentication tag, may be 4, 6, 8, 12, 16 (default). - -Keep in mind that **same nonce must not be used more than once with the same key**. - -##### AES_CCM.encrypt( data, key, nonce, adata, tagsize ) - -Encrypts supplied `data` with `key`-`nonce` in CCM mode. - -Returns encrypted data as `Uint8Array`. - -##### AES_CCM.decrypt( data, key, nonce, adata, tagsize ) - -Decrypts supplied `data` with `key`-`nonce` in CCM mode. - -Returns encrypted data as `Uint8Array`. - -#### AES_GCM - -TODO - -### RSA - -#### RSA.generateKey( bitlen, pubexp ) - -Generate RSA private key of `bitlen` length along with the public exponent `pubexp`. - -#### RSA_OAEP_SHA1 - -##### RSA_OAEP_SHA1.encrypt( data, key, label ) - -TODO - -##### RSA_OAEP_SHA1.decrypt( data, key, label ) - -TODO - -#### RSA_OAEP_SHA256 - -##### RSA_OAEP_SHA256.encrypt( data, key, label ) - -TODO - -##### RSA_OAEP_SHA256.decrypt( data, key, label ) - -TODO - -#### RSA_OAEP_SHA512 - -##### RSA_OAEP_SHA512.encrypt( data, key, label ) - -TODO - -##### RSA_OAEP_SHA512.decrypt( data, key, label ) - -TODO - -#### RSA_PSS_SHA1 - -##### RSA_PSS_SHA1.sign( data, key, slen ) - -TODO - -##### RSA_PSS_SHA1.verify( signature, data, key, slen ) - -TODO - -#### RSA_PSS_SHA256 - -##### RSA_PSS_SHA256.sign( data, key, slen ) - -TODO - -##### RSA_PSS_SHA256.verify( signature, data, key, slen ) - -TODO - -#### RSA_PSS_SHA512 - -##### RSA_PSS_SHA512.sign( data, key, slen ) - -TODO - -##### RSA_PSS_SHA512.verify( signature, data, key, slen ) - -TODO - -### Cryptographically secure pseudorandom number generator - -ISAAC-based CSPRG - -##### random.getValues( buffer ) - -Drop-in replacement for `window.crypto.getRandomValues` - -##### random.getValues.seed( seed ) - -Perform PRNG seeding. - -##### random.getValues.allowWeak = false - -Allow implicitly-only seeded random output. - -##### random.getValues.skipSystemRNGWarning = false - -Disable implicit seeding warning when it's not desirable, e.g. at a unit test run. +AsmCrypto 2.0 +----------- -Not yet implemented: -* scrypt, -* dsa, ecdsa, -* rsa-pkcs-v1.5 +* Moved to TypeScript +* I have no confident knowledge on random generation, so I don't feel right maintaining it. As of 2.0 all custom random generation and seeding code is removed, the underlying browsers and environments have to provide secure random. diff --git a/asmcrypto.js.d.ts b/asmcrypto.js.d.ts deleted file mode 100644 index 545ed89..0000000 --- a/asmcrypto.js.d.ts +++ /dev/null @@ -1,388 +0,0 @@ -declare class BigNumber { - static ZERO: BigNumber; - static ONE: BigNumber; - - constructor(num?: Uint8Array); - - toString(radix?: number): string; - - toBytes(): Uint8Array; - - valueOf(): number; - - clamp(b: number): BigNumber; - - slice(f: number, b: number): BigNumber; - - negate(): BigNumber; - - compare(that: BigNumber): 0 | 1 | -1; - - add(that: BigNumber): BigNumber; - - subtract(that: BigNumber): BigNumber; - - multiply(that: BigNumber): BigNumber; - - square(): BigNumber; - - divide(that: BigNumber): BigNumber; -} - -declare class AES { - BLOCK_SIZE: number; - result: Uint8Array; - - constructor(key: Uint8Array, iv?: Uint8Array, padding?: boolean, heap?: Uint8Array, asm?: Uint8Array); -} - -declare interface AES_reset { - (key: Uint8Array, iv?: Uint8Array, padding?: boolean): M; -} - -declare interface AES_Encrypt_finish { - (data?: Uint8Array): M; -} - -declare interface AES_Decrypt_finish { - (data?: Uint8Array): M; -} - -declare interface AES_Encrypt_process { - (data: Uint8Array): M; -} - -declare interface AES_Decrypt_process { - (data: Uint8Array): M; -} - -declare interface RSA_OAEP_Encrypt { - (data: Uint8Array, key: BigNumber[], label?: Uint8Array): Uint8Array; -} - -declare interface RSA_OAEP_Decrypt { - (data: Uint8Array, key: BigNumber[], label?: Uint8Array): Uint8Array; -} - -declare interface RSA_PSS_Sign { - (data: Uint8Array, key: BigNumber[], slen?: number): Uint8Array; -} - -declare interface RSA_PSS_Verify { - (signature: Uint8Array, data: Uint8Array, key: BigNumber[], slen?: number): boolean; -} - -declare class AES_ECB_Encrypt extends AES { - constructor(key: Uint8Array, heap?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_ECB extends AES { - constructor(key: Uint8Array, heap?: Uint8Array, asm?: Uint8Array); - - encrypt: AES_Encrypt_finish; - decrypt: AES_Decrypt_finish; -} - -declare class AES_ECB_Decrypt extends AES { - constructor(key: Uint8Array, heap?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Decrypt_finish; -} - -declare class AES_CBC_Encrypt extends AES { - constructor(key: Uint8Array, iv: Uint8Array, padding?: boolean, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_CBC_Decrypt extends AES { - constructor(key: Uint8Array, iv: Uint8Array, padding?: boolean, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Decrypt_finish; -} - -declare class AES_CCM_Encrypt extends AES { - constructor(key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, dataLength?: number, tagSize?: number, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_CCM_Decrypt extends AES { - constructor(key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, dataLength?: number, tagSize?: number, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Decrypt_finish; -} - -declare class AES_CFB_Encrypt extends AES { - constructor(key: Uint8Array, iv?: Uint8Array, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_CFB_Decrypt extends AES { - constructor(key: Uint8Array, iv?: Uint8Array, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Decrypt_finish; -} - -declare class AES_GCM_Encrypt extends AES { - constructor(key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, tagSize?: number, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_GCM_Decrypt extends AES { - constructor(key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, tagSize?: number, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Decrypt_finish; -} - -declare class AES_OFB extends AES { - constructor(key: Uint8Array, iv?: Uint8Array, heap?: Uint8Array, asm?: Uint8Array); - - reset: AES_reset; - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_CTR extends AES { - constructor(key: Uint8Array, nonce: Uint8Array, heap?: Uint8Array, asm?: Uint8Array); - - reset(key: Uint8Array, nonce: Uint8Array, counter?: number, counterSize?: number): AES_CTR; - - process: AES_Encrypt_process; - finish: AES_Encrypt_finish; -} - -declare class AES_CBC { - static encrypt: (data: Uint8Array, key: Uint8Array, padding?: boolean, iv?: Uint8Array) => Uint8Array; - static decrypt: (data: Uint8Array, key: Uint8Array, padding?: boolean, iv?: Uint8Array) => Uint8Array; -} - -declare class AES_CCM { - static encrypt: (data: Uint8Array, key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, tagSize?: number) => Uint8Array; - static decrypt: (data: Uint8Array, key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, tagSize?: number) => Uint8Array; -} - -declare class AES_CFB { - static encrypt: (data: Uint8Array, key: Uint8Array, iv?: Uint8Array) => Uint8Array; - static decrypt: (data: Uint8Array, key: Uint8Array, iv?: Uint8Array) => Uint8Array; -} - -declare class AES_CTR { - static encrypt: (data: Uint8Array, key: Uint8Array, nonce: Uint8Array) => Uint8Array; - static decrypt: (data: Uint8Array, key: Uint8Array, nonce: Uint8Array) => Uint8Array; -} - -declare class AES_OFB { - static encrypt: (data: Uint8Array, key: Uint8Array, iv?: Uint8Array) => Uint8Array; - static decrypt: (data: Uint8Array, key: Uint8Array, iv?: Uint8Array) => Uint8Array; -} - -declare class AES_GCM { - static encrypt: (data: Uint8Array, key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, tagSize?: number) => Uint8Array; - static decrypt: (data: Uint8Array, key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, tagSize?: number) => Uint8Array; -} - -declare class SHA1 { - result: Uint8Array; - - static bytes(data: Uint8Array): Uint8Array; - - static hex(data: Uint8Array): string; - - static base64(data: Uint8Array): string; - - constructor(options?: { asm?: Uint8Array, heap?: Uint8Array, heapSize?: number }); - - reset(): SHA1; - - process(data: Uint8Array): SHA1; - - finish(): SHA1; -} - -declare class SHA256 { - result: Uint8Array; - - static bytes(data: Uint8Array): Uint8Array; - - static hex(data: Uint8Array): string; - - static base64(data: Uint8Array): string; - - constructor(options?: { asm?: Uint8Array, heap?: Uint8Array, heapSize?: number }); - - reset(): SHA256; - - process(data: Uint8Array): SHA256; - - finish(): SHA256; -} - -declare class SHA512 { - result: Uint8Array; - - static bytes(data: Uint8Array): Uint8Array; - - static hex(data: Uint8Array): string; - - static base64(data: Uint8Array): string; - - constructor(options?: { asm?: Uint8Array, heap?: Uint8Array, heapSize?: number }); - - reset(): SHA512; - - process(data: Uint8Array): SHA512; - - finish(): SHA512; -} - -declare class HMAC_SHA1 { - result: Uint8Array; - - static bytes(data: Uint8Array, password: Uint8Array): Uint8Array; - - static hex(data: Uint8Array, password: Uint8Array): string; - - static base64(data: Uint8Array, password: Uint8Array): string; - - constructor(options?: { asm?: Uint8Array, heap?: Uint8Array, heapSize?: number, password?: Uint8Array, hash?: SHA1 }); - - reset(options: { password: Uint8Array }): HMAC_SHA1; - - process(data: Uint8Array): HMAC_SHA1; - - finish(): HMAC_SHA1; -} - -declare class HMAC_SHA256 { - result: Uint8Array; - - static bytes(data: Uint8Array, password: Uint8Array): Uint8Array; - - static hex(data: Uint8Array, password: Uint8Array): string; - - static base64(data: Uint8Array, password: Uint8Array): string; - - constructor(options?: { asm?: Uint8Array, heap?: Uint8Array, heapSize?: number, password?: Uint8Array, hash?: SHA256 }); - - reset(options: { password: Uint8Array }): HMAC_SHA256; - - process(data: Uint8Array): HMAC_SHA256; - - finish(): HMAC_SHA256; -} - -declare class HMAC_SHA512 { - result: Uint8Array; - - static bytes(data: Uint8Array, password: Uint8Array): Uint8Array; - - static hex(data: Uint8Array, password: Uint8Array): string; - - static base64(data: Uint8Array, password: Uint8Array): string; - - constructor(options?: { asm?: Uint8Array, heap?: Uint8Array, heapSize?: number, password?: Uint8Array, hash?: SHA512 }); - - reset(options: { password: Uint8Array }): HMAC_SHA512; - - process(data: Uint8Array): HMAC_SHA512; - - finish(): HMAC_SHA512; -} - -declare class PBKDF2_HMAC_SHA1 { - static bytes(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; - - static hex(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; - - static base64(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; -} - -declare class PBKDF2_HMAC_SHA256 { - static bytes(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; - - static hex(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; - - static base64(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; -} - -declare class PBKDF2_HMAC_SHA512 { - static bytes(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; - - static hex(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; - - static base64(password: Uint8Array, salt: Uint8Array, iterations?: number, dklen?: number): Uint8Array; -} - -declare class RSA_OAEP_SHA1 { - static encrypt: RSA_OAEP_Encrypt; - static decrypt: RSA_OAEP_Decrypt; -} - -declare class RSA_OAEP_SHA256 { - static encrypt: RSA_OAEP_Encrypt; - static decrypt: RSA_OAEP_Decrypt; -} - -declare class RSA_OAEP_SHA512 { - static encrypt: RSA_OAEP_Encrypt; - static decrypt: RSA_OAEP_Decrypt; -} - -declare class RSA_PSS_SHA1 { - static sign: RSA_PSS_Sign; - static verify: RSA_PSS_Verify; -} - -declare class RSA_PSS_SHA256 { - static sign: RSA_PSS_Sign; - static verify: RSA_PSS_Verify; -} - -declare class RSA_PSS_SHA512 { - static sign: RSA_PSS_Sign; - static verify: RSA_PSS_Verify; -} - -declare function random(): number; - -declare namespace random { - export function seed(data: Uint8Array): boolean; -} - - -declare function string_to_bytes(s: string): Uint8Array; - -declare function hex_to_bytes(s: string): Uint8Array; - -declare function base64_to_bytes(s: string): Uint8Array; - -declare function bytes_to_string(bytes: Uint8Array): string; - -declare function bytes_to_hex(bytes: Uint8Array): string; - -declare function bytes_to_base64(bytes: Uint8Array): string; diff --git a/bower.json b/bower.json deleted file mode 100644 index d270ec7..0000000 --- a/bower.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "asmcrypto", - "main": "asmcrypto.js", - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "test", - "test.html", - "Gruntfile.js", - "package.json" - ], - "keywords": [ - "crypto", - "asmcrypto", - "webcrypto", - "library", - "sha", "sha1", "sha256", "sha512", - "hmac", - "pbkdf", "pbkdf2", - "aes", "aes256", "cbc", "ccm", "cfb", - "rsa", "oaep", "pss", "pkcs" - ] -} diff --git a/build.js b/build.js new file mode 100644 index 0000000..3c89821 --- /dev/null +++ b/build.js @@ -0,0 +1,88 @@ +import fs from 'fs-extra'; +import ts from 'typescript'; +import rollup from 'rollup'; +import UglifyJS from 'uglify-js'; +import UglifyES from 'uglify-es'; + +(async function() { + // Delete old + await fs.remove('dist_es5'); + await fs.remove('dist_es8'); + + // Run ts + const raw_config = await fs.readFile('tsconfig.json', 'utf8'); + const options_es5_raw = JSON.parse(raw_config).compilerOptions; + options_es5_raw.target = 'es5'; + options_es5_raw.outDir = 'dist_es5'; + const options_es8_raw = JSON.parse(raw_config).compilerOptions; + + const options_es5 = ts.convertCompilerOptionsFromJson(options_es5_raw, '.'); + const options_es8 = ts.convertCompilerOptionsFromJson(options_es8_raw, '.'); + + const program_es5 = ts.createProgram(['src/entry-export_all.ts'], options_es5.options); + const program_es8 = ts.createProgram(['src/entry-export_all.ts'], options_es8.options); + program_es5.emit(); + program_es8.emit(); + + // Copy non-ts resources + await fs.copy('src/aes/aes.asm.js', 'dist_es5/aes/aes.asm.js'); + await fs.copy('src/aes/aes.asm.js', 'dist_es8/aes/aes.asm.js'); + + await fs.copy('src/bignum/bigint.asm.js', 'dist_es5/bignum/bigint.asm.js'); + await fs.copy('src/bignum/bigint.asm.js', 'dist_es8/bignum/bigint.asm.js'); + + await fs.copy('src/hash/sha1/sha1.asm.js', 'dist_es5/hash/sha1/sha1.asm.js'); + await fs.copy('src/hash/sha1/sha1.asm.js', 'dist_es8/hash/sha1/sha1.asm.js'); + + await fs.copy('src/hash/sha256/sha256.asm.js', 'dist_es5/hash/sha256/sha256.asm.js'); + await fs.copy('src/hash/sha256/sha256.asm.js', 'dist_es8/hash/sha256/sha256.asm.js'); + + await fs.copy('src/hash/sha512/sha512.asm.js', 'dist_es5/hash/sha512/sha512.asm.js'); + await fs.copy('src/hash/sha512/sha512.asm.js', 'dist_es8/hash/sha512/sha512.asm.js'); + + const es5bundle = await rollup.rollup({ + input: 'dist_es5/entry-export_all.js', + onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); // this requires Rollup 0.46 + }, + }); + + // Legacy browser export, as a bundle + await es5bundle.write({ + file: 'asmcrypto.all.es5.js', + format: 'iife', + name: 'asmCrypto', + }); + + // NodeJS old + await es5bundle.write({ + file: 'asmcrypto.all.js', + format: 'cjs', + }); + + const legacyCode = await fs.readFile('asmcrypto.all.es5.js', 'utf8'); + const { error, code } = UglifyJS.minify(legacyCode, { compress: { inline: false } }); + if (error) throw new Error(`Uglify failed: ${error}`); + await fs.writeFile('asmcrypto.all.es5.min.js', code, 'utf8'); + + // Modern export, eg. Chrome or NodeJS 10 with ESM + const es8bundle = await rollup.rollup({ + input: 'dist_es8/entry-export_all.js', + onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); // this requires Rollup 0.46 + }, + }); + await es8bundle.write({ + file: 'asmcrypto.all.es8.js', + format: 'es', + }); + + const es8Code = await fs.readFile('asmcrypto.all.es8.js', 'utf8'); + const { error: errorEs8, code: codeEs8 } = UglifyES.minify(es8Code, { compress: { inline: false } }); + if (errorEs8) throw new Error(`Uglify failed: ${error}`); + await fs.writeFile('asmcrypto.all.es8.min.js', codeEs8, 'utf8'); + + console.log('Build complete'); +})(); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..24f1104 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,659 @@ +{ + "name": "asmcrypto.js", + "version": "2.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/chai": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.3.tgz", + "integrity": "sha512-f5dXGzOJycyzSMdaXVhiBhauL4dYydXwVpavfQ1mVCaGjR56a9QfklXObUxlIY9bGTmCPHEEZ04I16BZ/8w5ww==", + "dev": true + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/mocha": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.1.tgz", + "integrity": "sha512-dOrgprHnkDaj1pmrwdcMAf0QRNQzqTB5rxJph+iIQshSmIvtgRqJ0nim8u1vvXU8iOXZrH96+M46JDFTPLingA==", + "dev": true + }, + "@types/node": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.0.tgz", + "integrity": "sha512-hWzNviaVFIr1TqcRA8ou49JaSHp+Rfabmnqg2kNvusKqLhPU0rIsGPUj5WJJ7ld4Bb7qdgLmIhLfCD1qS08IVA==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "dev": true, + "requires": { + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz", + "integrity": "sha512-floiaI4F7hRkTrFe8V2ItOK97QYrX75DjmdzmVITZoAP6Cn06oEDPQRsO6MlHEP/u2SxI3xQ52Kpjw6j5WGfeQ==", + "dev": true, + "requires": { + "fast-diff": "^1.1.1", + "jest-docblock": "^21.0.0" + } + }, + "esm": { + "version": "3.0.36", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.0.36.tgz", + "integrity": "sha512-TbvRhqBH66jIZS8yIPqWPeX3CD8itgi/BZAoCf9zWn5U/RZ6A7R2X/rrtRJ31NG0Gu71jqP5UmGKKpaYTzx81A==", + "dev": true + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", + "dev": true + }, + "fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "jest-docblock": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz", + "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", + "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "make-error": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "prettier": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.4.tgz", + "integrity": "sha512-emsEZ2bAigL1lq6ssgkpPm1MIBqgeTvcp90NxOP5XDqprub/V/WS2Hfgih3mS7/1dqTUvhG+sxx1Dv8crnVexA==", + "dev": true + }, + "resolve": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "rollup": { + "version": "0.59.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.59.4.tgz", + "integrity": "sha512-ISiMqq/aJa+57QxX2MRcvLESHdJ7wSavmr6U1euMr+6UgFe6KM+3QANrYy8LQofwhTC1I7BcAdlLnDiaODs1BA==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "@types/node": "*" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", + "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "ts-node": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-6.0.5.tgz", + "integrity": "sha512-iNhWu2hli9/1p9PGLJ/4OZS+NR0IVEVk63KCrH3qa7jJZxXa+oPheBj5JyM8tuQM9RkBpw1PrNUEUPJR9wTGDw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "chalk": "^2.3.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.3", + "yn": "^2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tslib": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz", + "integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==", + "dev": true + }, + "tslint": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz", + "integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.12.1" + } + }, + "tslint-plugin-prettier": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-1.3.0.tgz", + "integrity": "sha512-6UqeeV6EABp0RdQkW6eC1vwnAXcKMGJgPeJ5soXiKdSm2vv7c3dp+835CM8pjgx9l4uSa7tICm1Kli+SMsADDg==", + "dev": true, + "requires": { + "eslint-plugin-prettier": "^2.2.0", + "tslib": "^1.7.1" + } + }, + "tsutils": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz", + "integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typescript": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.1.tgz", + "integrity": "sha512-h6pM2f/GDchCFlldnriOhs1QHuwbnmj6/v7499eMHqPeW4V2G0elua2eIc2nu8v2NdHV0Gm+tzX83Hr6nUFjQA==", + "dev": true + }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + } + } + }, + "uglify-js": { + "version": "3.3.28", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz", + "integrity": "sha512-68Rc/aA6cswiaQ5SrE979UJcXX+ADA1z33/ZsPd+fbAiVdjZ16OXdbtGO+rJUUBgK6qdf3SOPhQf3K/ybF5Miw==", + "dev": true, + "requires": { + "commander": "~2.15.0", + "source-map": "~0.6.1" + } + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 2c60d4f..f24a6ad 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,21 @@ { "name": "asmcrypto.js", - "version": "0.22.0", + "version": "2.0.0", "description": "Asm.js implementation of WebCrypto API", - "homepage": "https://github.com/vibornoff/asmcrypto.js", - "main": "asmcrypto.js", - "module": "asmcrypto.mjs", + "homepage": "https://github.com/asmcrypto/asmcrypto.js", + "main": "asmcrypto.all.js", + "module": "asmcrypto.all.es8.js", "license": "MIT", "author": { - "name": "Artem S Vybornov", - "email": "vybornov@gmail.com", - "web": "https://github.com/vibornoff" + "name": "Ádám Lippai", + "email": "adam@rigo.sk", + "web": "https://github.com/alippai" }, "contributors": [ { - "name": "Ádám Lippai", - "email": "adam@rigo.sk", - "web": "https://github.com/alippai" + "name": "Artem S Vybornov", + "email": "vybornov@gmail.com", + "web": "https://github.com/vibornoff" }, { "name": "Ximin Luo", @@ -25,27 +25,30 @@ ], "repository": { "type": "git", - "url": "https://github.com/vibornoff/asmcrypto.js.git" + "url": "https://github.com/asmcrypto/asmcrypto.js.git" }, "devDependencies": { - "grunt": "~1.0", - "grunt-cli": "~1.2", - "grunt-contrib-clean": "~1.1", - "grunt-contrib-concat": "~1.0", - "grunt-contrib-connect": "~1.0", - "grunt-contrib-uglify-es": "git+https://github.com/gruntjs/grunt-contrib-uglify.git#harmony", - "grunt-contrib-watch": "~1.0", - "grunt-jsdoc": "~2.2", - "grunt-rollup": "^9.0.0", - "grunt-shell": "^2.1.0", - "prettier": "^1.10.2", - "qunit-puppeteer": "^1.0.1", - "uglify-es": "^3.3.4" + "@types/chai": "^4.1.3", + "@types/mocha": "^5.2.0", + "@types/node": "^10.1.2", + "chai": "^4.1.2", + "esm": "3.0.36", + "fs-extra": "^6.0.1", + "mocha": "^5.2.0", + "prettier": "^1.13.4", + "rollup": "^0.59.1", + "ts-node": "^6.0.3", + "tslint": "^5.10.0", + "tslint-plugin-prettier": "^1.3.0", + "typescript": "^2.8.3", + "uglify-es": "^3.3.9", + "uglify-js": "^3.3.25" }, "scripts": { - "prepublish": "grunt && grunt esm && grunt all", - "test": "grunt test", - "prettier": "prettier --single-quote --trailing-comma all --write \"src/**/*.js\" --print-width 120" + "prepublish": "node -r esm build.js", + "test": "node -r esm build.js && mocha -r esm test/*.js", + "prettier": "prettier --single-quote --trailing-comma all --write \"src/**/*.js\" \"src/**/*.ts\" --print-width 120" }, - "typings": "./asmcrypto.js.d.ts" + "typings": "./dist_es8/entry-export_all.d.ts", + "dependencies": {} } diff --git a/src/aes/aes.asm.d.ts b/src/aes/aes.asm.d.ts new file mode 100644 index 0000000..efe0411 --- /dev/null +++ b/src/aes/aes.asm.d.ts @@ -0,0 +1,122 @@ +declare type AES_mode = 'ECB' | 'CBC' | 'CFB' | 'OFB' | 'CTR' | 'CCM'; +export class AES_asm { + constructor(foreign: any, heap: ArrayBuffer); + + /** + * @param ks - key size, 4/6/8 (for 128/192/256-bit key correspondingly) + * @param k0 - key vector components + * @param k1 - key vector components + * @param k2 - key vector components + * @param k3 - key vector components + * @param k4 - key vector components + * @param k5 - key vector components + * @param k6 - key vector components + * @param k7 - key vector components + */ + set_key( + ks: number, + k0: number, + k1: number, + k2: number, + k3: number, + k4: number, + k5: number, + k6: number, + k7: number, + ): void; + + /** + * Populate the internal iv of the module + */ + set_iv(i0: number, i1: number, i2: number, i3: number): void; + + /** + * Set counter mask for CTR-family modes + */ + set_mask(m0: number, m1: number, m2: number, m3: number): void; + + /** + * Set nonce for CTR-family modes + */ + set_nonce(n0: number, n1: number, n2: number, n3: number): void; + + /** + * Set counter for CTR-family modes + */ + set_counter(c0: number, c1: number, c2: number, c3: number): void; + + /** + * Perform ciphering operation on the supplied data + * + * @param mode - block cipher mode (see {@link AES_asm} mode constants) + * @param pos - offset of the data being processed + * @param len - length of the data being processed + * @return Actual amount of data have been processed + */ + cipher(mode: number, pos: number, len: number): number; + + /** + * GCM initialization + */ + gcm_init(): void; + + /** + * Store the internal iv vector into the heap + * + * @returns The number of bytes have been written into the heap, always 16 + */ + get_iv(pos: number): 16; + + /** + * Calculates MAC of the supplied data + * + * @param mode - block cipher mode (see {@link AES_asm} mode constants) + * @param pos - offset of the data being processed + * @param len - length of the data being processed + * @return Actual amount of data have been processed + */ + mac(mode: number, pos: number, len: number): number; + + /** + * Store the internal state vector into the heap. + * + * @param pos - offset where to put the data + * @return The number of bytes have been written into the heap, always 16. + */ + get_state(pos: number): 16; + + /** + * AES enciphering mode constants + */ + static ENC: { + ECB: 0; + CBC: 2; + CFB: 4; + OFB: 6; + CTR: 7; + [key: string]: number; + }; + + /** + * AES deciphering mode constants + */ + static DEC: { + ECB: 1; + CBC: 3; + CFB: 5; + OFB: 6; + CTR: 7; + [key: string]: number; + }; + + /** + * AES MAC mode constants + */ + static MAC: { + CBC: 0; + GCM: 1; + [key: string]: number; + }; + + static HEAP_DATA: number; +} diff --git a/src/aes/aes.asm.js b/src/aes/aes.asm.js index 846b3bf..5a5d71e 100644 --- a/src/aes/aes.asm.js +++ b/src/aes/aes.asm.js @@ -153,8 +153,8 @@ export var AES_asm = function () { * * @alias AES_asm * @class - * @param {Object} foreign - ignored - * @param {ArrayBuffer} buffer - heap buffer to link with + * @param foreign - ignored + * @param buffer - heap buffer to link with */ var wrapper = function (foreign, buffer) { // Init AES stuff for the first time @@ -304,7 +304,7 @@ export var AES_asm = function () { x0, x1, x2, - x3, + x3 ); } @@ -329,7 +329,7 @@ export var AES_asm = function () { x0, x3, x2, - x1, + x1 ); t = S1, S1 = S3, S3 = t; @@ -355,7 +355,7 @@ export var AES_asm = function () { I0 ^ x0, I1 ^ x1, I2 ^ x2, - I3 ^ x3, + I3 ^ x3 ); I0 = S0, @@ -385,7 +385,7 @@ export var AES_asm = function () { x0, x3, x2, - x1, + x1 ); t = S1, S1 = S3, S3 = t; @@ -420,7 +420,7 @@ export var AES_asm = function () { I0, I1, I2, - I3, + I3 ); I0 = S0 = S0 ^ x0, @@ -449,7 +449,7 @@ export var AES_asm = function () { I0, I1, I2, - I3, + I3 ); S0 = S0 ^ x0, @@ -482,7 +482,7 @@ export var AES_asm = function () { I0, I1, I2, - I3, + I3 ); I0 = S0, @@ -515,7 +515,7 @@ export var AES_asm = function () { N0, N1, N2, - N3, + N3 ); N3 = (~M3 & N3) | M3 & (N3 + 1); @@ -801,7 +801,7 @@ export var AES_asm = function () { DATA[pos | 0] << 24 | DATA[pos | 1] << 16 | DATA[pos | 2] << 8 | DATA[pos | 3], DATA[pos | 4] << 24 | DATA[pos | 5] << 16 | DATA[pos | 6] << 8 | DATA[pos | 7], DATA[pos | 8] << 24 | DATA[pos | 9] << 16 | DATA[pos | 10] << 8 | DATA[pos | 11], - DATA[pos | 12] << 24 | DATA[pos | 13] << 16 | DATA[pos | 14] << 8 | DATA[pos | 15], + DATA[pos | 12] << 24 | DATA[pos | 13] << 16 | DATA[pos | 14] << 8 | DATA[pos | 15] ); DATA[pos | 0] = S0 >>> 24, @@ -852,7 +852,7 @@ export var AES_asm = function () { DATA[pos | 0] << 24 | DATA[pos | 1] << 16 | DATA[pos | 2] << 8 | DATA[pos | 3], DATA[pos | 4] << 24 | DATA[pos | 5] << 16 | DATA[pos | 6] << 8 | DATA[pos | 7], DATA[pos | 8] << 24 | DATA[pos | 9] << 16 | DATA[pos | 10] << 8 | DATA[pos | 11], - DATA[pos | 12] << 24 | DATA[pos | 13] << 16 | DATA[pos | 14] << 8 | DATA[pos | 15], + DATA[pos | 12] << 24 | DATA[pos | 13] << 16 | DATA[pos | 14] << 8 | DATA[pos | 15] ); ret = (ret + 16) | 0, diff --git a/src/aes/aes.js b/src/aes/aes.js deleted file mode 100644 index a52d90a..0000000 --- a/src/aes/aes.js +++ /dev/null @@ -1,357 +0,0 @@ -import { AES_asm } from './aes.asm'; -import { _heap_init, _heap_write, is_bytes, is_number } from '../utils'; -import { IllegalArgumentError, SecurityError } from '../errors'; - -export class AES { - constructor(key, iv, padding, heap, asm) { - this.nonce = null; - this.counter = 0; - this.counterSize = 0; - - this.heap = _heap_init(Uint8Array, heap).subarray(AES_asm.HEAP_DATA); - this.asm = asm || AES_asm(null, this.heap.buffer); - this.mode = null; - this.key = null; - - this.AES_reset(key, iv, padding); - } - - /** - * @param {Uint8Array} key - */ - AES_set_key(key) { - if (key !== undefined) { - if (!is_bytes(key)) { - throw new TypeError('unexpected key type'); - } - - var keylen = key.length; - if (keylen !== 16 && keylen !== 24 && keylen !== 32) throw new IllegalArgumentError('illegal key size'); - - var keyview = new DataView(key.buffer, key.byteOffset, key.byteLength); - this.asm.set_key( - keylen >> 2, - keyview.getUint32(0), - keyview.getUint32(4), - keyview.getUint32(8), - keyview.getUint32(12), - keylen > 16 ? keyview.getUint32(16) : 0, - keylen > 16 ? keyview.getUint32(20) : 0, - keylen > 24 ? keyview.getUint32(24) : 0, - keylen > 24 ? keyview.getUint32(28) : 0, - ); - - this.key = key; - } else if (!this.key) { - throw new Error('key is required'); - } - } - - /** - * This should be mixin instead of inheritance - * - * @param {Uint8Array} nonce - * @param {number} [counter] - * @param {number} [size] - */ - AES_CTR_set_options(nonce, counter, size) { - if (size !== undefined) { - if (size < 8 || size > 48) throw new IllegalArgumentError('illegal counter size'); - - this.counterSize = size; - - var mask = Math.pow(2, size) - 1; - this.asm.set_mask(0, 0, (mask / 0x100000000) | 0, mask | 0); - } else { - this.counterSize = size = 48; - this.asm.set_mask(0, 0, 0xffff, 0xffffffff); - } - - if (nonce !== undefined) { - if (!is_bytes(nonce)) { - throw new TypeError('unexpected nonce type'); - } - - var len = nonce.length; - if (!len || len > 16) throw new IllegalArgumentError('illegal nonce size'); - - this.nonce = nonce; - - var view = new DataView(new ArrayBuffer(16)); - new Uint8Array(view.buffer).set(nonce); - - this.asm.set_nonce(view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)); - } else { - throw new Error('nonce is required'); - } - - if (counter !== undefined) { - if (!is_number(counter)) throw new TypeError('unexpected counter type'); - - if (counter < 0 || counter >= Math.pow(2, size)) throw new IllegalArgumentError('illegal counter value'); - - this.counter = counter; - - this.asm.set_counter(0, 0, (counter / 0x100000000) | 0, counter | 0); - } else { - this.counter = 0; - } - } - - /** - * @param {Uint8Array} iv - */ - AES_set_iv(iv) { - if (iv !== undefined) { - if (!is_bytes(iv)) { - throw new TypeError('unexpected iv type'); - } - - if (iv.length !== 16) throw new IllegalArgumentError('illegal iv size'); - - var ivview = new DataView(iv.buffer, iv.byteOffset, iv.byteLength); - - this.iv = iv; - this.asm.set_iv(ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12)); - } else { - this.iv = null; - this.asm.set_iv(0, 0, 0, 0); - } - } - - /** - * @param {boolean} padding - */ - AES_set_padding(padding) { - if (padding !== undefined) { - this.padding = !!padding; - } else { - this.padding = true; - } - } - - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv] - * @param {boolean} [padding] - */ - AES_reset(key, iv, padding) { - this.result = null; - this.pos = 0; - this.len = 0; - - this.AES_set_key(key); - this.AES_set_iv(iv); - this.AES_set_padding(padding); - - return this; - } - - /** - * @param {Uint8Array} data - */ - AES_Encrypt_process(data) { - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var asm = this.asm, - heap = this.heap, - amode = AES_asm.ENC[this.mode], - hpos = AES_asm.HEAP_DATA, - pos = this.pos, - len = this.len, - dpos = 0, - dlen = data.length || 0, - rpos = 0, - rlen = (len + dlen) & -16, - wlen = 0; - - var result = new Uint8Array(rlen); - - while (dlen > 0) { - wlen = _heap_write(heap, pos + len, data, dpos, dlen); - len += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.cipher(amode, hpos + pos, len); - - if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); - rpos += wlen; - - if (wlen < len) { - pos += wlen; - len -= wlen; - } else { - pos = 0; - len = 0; - } - } - - this.result = result; - this.pos = pos; - this.len = len; - - return this; - } - - /** - * @param {Uint8Array} data - */ - AES_Encrypt_finish(data) { - var presult = null, - prlen = 0; - - if (data !== undefined) { - presult = this.AES_Encrypt_process(data).result; - prlen = presult.length; - } - - var asm = this.asm, - heap = this.heap, - amode = AES_asm.ENC[this.mode], - hpos = AES_asm.HEAP_DATA, - pos = this.pos, - len = this.len, - plen = 16 - len % 16, - rlen = len; - - if (this.hasOwnProperty('padding')) { - if (this.padding) { - for (var p = 0; p < plen; ++p) heap[pos + len + p] = plen; - len += plen; - rlen = len; - } else if (len % 16) { - throw new IllegalArgumentError('data length must be a multiple of the block size'); - } - } else { - len += plen; - } - - var result = new Uint8Array(prlen + rlen); - - if (prlen) result.set(presult); - - if (len) asm.cipher(amode, hpos + pos, len); - - if (rlen) result.set(heap.subarray(pos, pos + rlen), prlen); - - this.result = result; - this.pos = 0; - this.len = 0; - - return this; - } - - /** - * @param {Uint8Array} data - */ - AES_Decrypt_process(data) { - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var asm = this.asm, - heap = this.heap, - amode = AES_asm.DEC[this.mode], - hpos = AES_asm.HEAP_DATA, - pos = this.pos, - len = this.len, - dpos = 0, - dlen = data.length || 0, - rpos = 0, - rlen = (len + dlen) & -16, - plen = 0, - wlen = 0; - - if (this.padding) { - plen = len + dlen - rlen || 16; - rlen -= plen; - } - - var result = new Uint8Array(rlen); - - while (dlen > 0) { - wlen = _heap_write(heap, pos + len, data, dpos, dlen); - len += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.cipher(amode, hpos + pos, len - (!dlen ? plen : 0)); - - if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); - rpos += wlen; - - if (wlen < len) { - pos += wlen; - len -= wlen; - } else { - pos = 0; - len = 0; - } - } - - this.result = result; - this.pos = pos; - this.len = len; - - return this; - } - - /** - * @param {Uint8Array} data - */ - AES_Decrypt_finish(data) { - var presult = null, - prlen = 0; - - if (data !== undefined) { - presult = this.AES_Decrypt_process(data).result; - prlen = presult.length; - } - - var asm = this.asm, - heap = this.heap, - amode = AES_asm.DEC[this.mode], - hpos = AES_asm.HEAP_DATA, - pos = this.pos, - len = this.len, - rlen = len; - - if (len > 0) { - if (len % 16) { - if (this.hasOwnProperty('padding')) { - throw new IllegalArgumentError('data length must be a multiple of the block size'); - } else { - len += 16 - len % 16; - } - } - - asm.cipher(amode, hpos + pos, len); - - if (this.hasOwnProperty('padding') && this.padding) { - var pad = heap[pos + rlen - 1]; - if (pad < 1 || pad > 16 || pad > rlen) throw new SecurityError('bad padding'); - - var pcheck = 0; - for (var i = pad; i > 1; i--) pcheck |= pad ^ heap[pos + rlen - i]; - if (pcheck) throw new SecurityError('bad padding'); - - rlen -= pad; - } - } - - var result = new Uint8Array(prlen + rlen); - - if (prlen > 0) { - result.set(presult); - } - - if (rlen > 0) { - result.set(heap.subarray(pos, pos + rlen), prlen); - } - - this.result = result; - this.pos = 0; - this.len = 0; - - return this; - } -} diff --git a/src/aes/aes.ts b/src/aes/aes.ts new file mode 100644 index 0000000..811caff --- /dev/null +++ b/src/aes/aes.ts @@ -0,0 +1,238 @@ +import { AES_asm, AES_mode } from './aes.asm'; +import { _heap_init, _heap_write, is_bytes } from '../other/utils'; +import { IllegalArgumentError, SecurityError } from '../other/errors'; + +export abstract class AES { + protected readonly heap: Uint8Array; + protected readonly asm: AES_asm; + private readonly mode: string; + protected padding: boolean; // TODO: This should be `private readonly`, hacking for AES-CFB?! + public result!: Uint8Array | null; + protected pos: number = 0; + protected len: number = 0; + + protected constructor(key: Uint8Array, iv: Uint8Array | undefined, padding = true, mode: AES_mode) { + this.mode = mode; + + // The AES "worker" + this.heap = _heap_init().subarray(AES_asm.HEAP_DATA); + this.asm = new AES_asm(null, this.heap.buffer); + + // The AES object state + this.result = null; + this.pos = 0; + this.len = 0; + + // Key + const keylen = key.length; + if (keylen !== 16 && keylen !== 24 && keylen !== 32) throw new IllegalArgumentError('illegal key size'); + + const keyview = new DataView(key.buffer, key.byteOffset, key.byteLength); + this.asm.set_key( + keylen >> 2, + keyview.getUint32(0), + keyview.getUint32(4), + keyview.getUint32(8), + keyview.getUint32(12), + keylen > 16 ? keyview.getUint32(16) : 0, + keylen > 16 ? keyview.getUint32(20) : 0, + keylen > 24 ? keyview.getUint32(24) : 0, + keylen > 24 ? keyview.getUint32(28) : 0, + ); + + // IV + if (iv !== undefined) { + if (iv.length !== 16) throw new IllegalArgumentError('illegal iv size'); + + let ivview = new DataView(iv.buffer, iv.byteOffset, iv.byteLength); + + this.asm.set_iv(ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12)); + } else { + this.asm.set_iv(0, 0, 0, 0); + } + + this.padding = padding; + } + + AES_Encrypt_process(data: Uint8Array): this { + if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); + + let asm = this.asm; + let heap = this.heap; + let amode = AES_asm.ENC[this.mode]; + let hpos = AES_asm.HEAP_DATA; + let pos = this.pos; + let len = this.len; + let dpos = 0; + let dlen = data.length || 0; + let rpos = 0; + let rlen = (len + dlen) & -16; + let wlen = 0; + + let result = new Uint8Array(rlen); + + while (dlen > 0) { + wlen = _heap_write(heap, pos + len, data, dpos, dlen); + len += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.cipher(amode, hpos + pos, len); + + if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); + rpos += wlen; + + if (wlen < len) { + pos += wlen; + len -= wlen; + } else { + pos = 0; + len = 0; + } + } + + this.result = result; + this.pos = pos; + this.len = len; + + return this; + } + + AES_Encrypt_finish(): this { + let asm = this.asm; + let heap = this.heap; + let amode = AES_asm.ENC[this.mode]; + let hpos = AES_asm.HEAP_DATA; + let pos = this.pos; + let len = this.len; + let plen = 16 - (len % 16); + let rlen = len; + + if (this.hasOwnProperty('padding')) { + if (this.padding) { + for (let p = 0; p < plen; ++p) { + heap[pos + len + p] = plen; + } + len += plen; + rlen = len; + } else if (len % 16) { + throw new IllegalArgumentError('data length must be a multiple of the block size'); + } + } else { + len += plen; + } + + if (!this.result) throw new Error('There is no result'); + + const result = new Uint8Array(this.result.length + rlen); + result.set(this.result, 0); + + if (len) asm.cipher(amode, hpos + pos, len); + + if (rlen) result.set(heap.subarray(pos, pos + rlen), this.result.length); + + this.result = result; + this.pos = 0; + this.len = 0; + + return this; + } + + AES_Decrypt_process(data: Uint8Array): this { + if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); + + let asm = this.asm; + let heap = this.heap; + let amode = AES_asm.DEC[this.mode]; + let hpos = AES_asm.HEAP_DATA; + let pos = this.pos; + let len = this.len; + let dpos = 0; + let dlen = data.length || 0; + let rpos = 0; + let rlen = (len + dlen) & -16; + let plen = 0; + let wlen = 0; + + if (this.padding) { + plen = len + dlen - rlen || 16; + rlen -= plen; + } + + const result = new Uint8Array(rlen); + + while (dlen > 0) { + wlen = _heap_write(heap, pos + len, data, dpos, dlen); + len += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.cipher(amode, hpos + pos, len - (!dlen ? plen : 0)); + + if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); + rpos += wlen; + + if (wlen < len) { + pos += wlen; + len -= wlen; + } else { + pos = 0; + len = 0; + } + } + + this.result = result; + this.pos = pos; + this.len = len; + + return this; + } + + AES_Decrypt_finish(): this { + let asm = this.asm; + let heap = this.heap; + let amode = AES_asm.DEC[this.mode]; + let hpos = AES_asm.HEAP_DATA; + let pos = this.pos; + let len = this.len; + let rlen = len; + + if (len > 0) { + if (len % 16) { + if (this.hasOwnProperty('padding')) { + throw new IllegalArgumentError('data length must be a multiple of the block size'); + } else { + len += 16 - (len % 16); + } + } + + asm.cipher(amode, hpos + pos, len); + + if (this.hasOwnProperty('padding') && this.padding) { + let pad = heap[pos + rlen - 1]; + if (pad < 1 || pad > 16 || pad > rlen) throw new SecurityError('bad padding'); + + let pcheck = 0; + for (let i = pad; i > 1; i--) pcheck |= pad ^ heap[pos + rlen - i]; + if (pcheck) throw new SecurityError('bad padding'); + + rlen -= pad; + } + } + + if (!this.result) throw new Error('There is no result'); + + const result = new Uint8Array(rlen + this.result.length); + result.set(this.result, 0); + + if (rlen > 0) { + result.set(heap.subarray(pos, pos + rlen), this.result.length); + } + + this.result = result; + this.pos = 0; + this.len = 0; + + return this; + } +} diff --git a/src/aes/cbc.ts b/src/aes/cbc.ts new file mode 100644 index 0000000..95bd3b7 --- /dev/null +++ b/src/aes/cbc.ts @@ -0,0 +1,25 @@ +import { AES } from './aes'; + +export class AES_CBC extends AES { + static encrypt(data: Uint8Array, key: Uint8Array, padding: boolean = true, iv?: Uint8Array): Uint8Array { + return new AES_CBC(key, iv, padding).encrypt(data).result as Uint8Array; + } + + static decrypt(data: Uint8Array, key: Uint8Array, padding: boolean = true, iv?: Uint8Array): Uint8Array { + return new AES_CBC(key, iv, padding).decrypt(data).result as Uint8Array; + } + + constructor(key: Uint8Array, iv?: Uint8Array, padding: boolean = true) { + super(key, iv, padding, 'CBC'); + } + + encrypt(data: Uint8Array): this { + this.AES_Encrypt_process(data); + return this.AES_Encrypt_finish(); + } + + decrypt(data: Uint8Array): this { + this.AES_Decrypt_process(data); + return this.AES_Decrypt_finish(); + } +} diff --git a/src/aes/cbc/cbc.js b/src/aes/cbc/cbc.js deleted file mode 100644 index 56e4695..0000000 --- a/src/aes/cbc/cbc.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Cipher Block Chaining Mode (CBC) - */ -import { AES } from '../aes'; - -export class AES_CBC extends AES { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv=null] - * @param {boolean} [padding=true] - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv = null, padding = true, heap, asm) { - super(key, iv, padding, heap, asm); - - this.mode = 'CBC'; - this.BLOCK_SIZE = 16; - } - - encrypt(data) { - return this.AES_Encrypt_finish(data); - } - - decrypt(data) { - return this.AES_Decrypt_finish(data); - } -} - -export class AES_CBC_Encrypt extends AES_CBC { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv=null] - * @param {boolean} [padding=true] - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, padding, heap, asm) { - super(key, iv, padding, heap, asm); - } - - /** - * @param {Uint8Array} key - * @returns {AES_CBC_Encrypt} - */ - reset(key) { - return this.AES_reset(key, null, true); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CBC_Encrypt} - */ - process(data) { - return this.AES_Encrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CBC_Encrypt} - */ - finish(data) { - return this.AES_Encrypt_finish(data); - } -} - -export class AES_CBC_Decrypt extends AES_CBC { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv=null] - * @param {boolean} [padding=true] - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, padding, heap, asm) { - super(key, iv, padding, heap, asm); - } - - /** - * @param {Uint8Array} key - * @returns {AES_CBC_Decrypt} - */ - reset(key) { - return this.AES_reset(key, null, true); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CBC_Decrypt} - */ - process(data) { - return this.AES_Decrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CBC_Decrypt} - */ - finish(data) { - return this.AES_Decrypt_finish(data); - } -} diff --git a/src/aes/cbc/exports.js b/src/aes/cbc/exports.js deleted file mode 100644 index 5b2b318..0000000 --- a/src/aes/cbc/exports.js +++ /dev/null @@ -1,33 +0,0 @@ -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_CBC, AES_CBC_Decrypt, AES_CBC_Encrypt } from './cbc'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {boolean} [padding] - * @param {Uint8Array} [iv] - * @returns {Uint8Array} - */ -function AES_CBC_encrypt_bytes(data, key, padding, iv) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_CBC(key, iv, padding, _AES_heap_instance, _AES_asm_instance).encrypt(data).result; -} - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {boolean} [padding] - * @param {Uint8Array} [iv] - * @returns {Uint8Array} - */ -function AES_CBC_decrypt_bytes(data, key, padding, iv) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_CBC(key, iv, padding, _AES_heap_instance, _AES_asm_instance).decrypt(data).result; -} - -AES_CBC.encrypt = AES_CBC_encrypt_bytes; -AES_CBC.decrypt = AES_CBC_decrypt_bytes; - -export { AES_CBC, AES_CBC_Encrypt, AES_CBC_Decrypt }; diff --git a/src/aes/ccm.ts b/src/aes/ccm.ts new file mode 100644 index 0000000..1d67ace --- /dev/null +++ b/src/aes/ccm.ts @@ -0,0 +1,353 @@ +/** + * Counter with CBC-MAC (CCM) + * + * Due to JS limitations (52 bits of Number precision) maximum encrypted message length + * is limited to ~4 PiB ( 2^52 - 16 ) per `nonce`-`key` pair. + * That also limits `lengthSize` parameter maximum value to 7 (not 8 as described in RFC3610). + * + * Additional authenticated data `adata` maximum length is chosen to be no more than 65279 bytes ( 2^16 - 2^8 ), + * which is considered enough for the most of use-cases. + * + * And one more important thing: in case of progressive ciphering of a data stream (in other + * words when data can't be held in-memory at a whole and are ciphered chunk-by-chunk) + * you have to know the `dataLength` in advance and pass that value to the cipher options. + */ + +import { AES_asm } from './aes.asm'; +import { AES } from './aes'; +import { _heap_write } from '../other/utils'; +import { IllegalArgumentError, IllegalStateError, SecurityError } from '../other/errors'; + +const _AES_CCM_adata_maxLength = 65279; // 2^16 - 2^8 +const _AES_CCM_data_maxLength = 4503599627370480; // 2^52 - 2^4 + +export class AES_CCM extends AES { + private readonly tagSize: number; + private readonly lengthSize: number; + private nonce: Uint8Array; + private readonly adata: Uint8Array | undefined; + private counter: number = 1; + private dataLength: number = -1; + + static encrypt( + clear: Uint8Array, + key: Uint8Array, + nonce: Uint8Array, + adata: Uint8Array | undefined, + tagsize: number = 16, + ): Uint8Array { + return new AES_CCM(key, nonce, adata, tagsize, clear.length).encrypt(clear).result as Uint8Array; + } + static decrypt( + cipher: Uint8Array, + key: Uint8Array, + nonce: Uint8Array, + adata: Uint8Array | undefined, + tagsize: number = 16, + ): Uint8Array { + return new AES_CCM(key, nonce, adata, tagsize, cipher.length - tagsize).decrypt(cipher).result as Uint8Array; + } + + constructor( + key: Uint8Array, + nonce: Uint8Array, + adata: Uint8Array | undefined, + tagSize: number = 16, + dataLength: number, + ) { + super(key, undefined, undefined, 'CCM'); + + // Tag size + if (tagSize < 4 || tagSize > 16 || tagSize & 1) throw new IllegalArgumentError('illegal tagSize value'); + this.tagSize = tagSize; + + // Nonce + this.nonce = nonce; + + if (nonce.length < 8 || nonce.length > 13) throw new IllegalArgumentError('illegal nonce length'); + this.lengthSize = 15 - nonce.length; + nonce = new Uint8Array(nonce.length + 1); + nonce[0] = this.lengthSize - 1; + nonce.set(this.nonce, 1); + + if (dataLength < 0 || dataLength > _AES_CCM_data_maxLength || dataLength > Math.pow(2, 8 * this.lengthSize) - 16) + throw new IllegalArgumentError('illegal dataLength value'); + + if (adata !== undefined) { + if (adata.length > _AES_CCM_adata_maxLength) throw new IllegalArgumentError('illegal adata length'); + + this.adata = adata.length ? adata : undefined; + } + + this.dataLength = dataLength; + this.counter = 1; + + this.AES_CCM_calculate_iv(); + this.AES_CTR_set_options(nonce, this.counter, 8 * this.lengthSize); + } + + encrypt(data: Uint8Array): this { + this.dataLength = data.length || 0; + + const result1 = this.AES_CCM_Encrypt_process(data).result as Uint8Array; + const result2 = this.AES_CCM_Encrypt_finish().result as Uint8Array; + + const result = new Uint8Array(result1.length + result2.length); + if (result1.length) result.set(result1); + if (result2.length) result.set(result2, result1.length); + this.result = result; + + return this; + } + + decrypt(data: Uint8Array): this { + this.dataLength = data.length || 0; + + const result1 = this.AES_CCM_Decrypt_process(data).result as Uint8Array; + const result2 = this.AES_CCM_Decrypt_finish().result as Uint8Array; + + const result = new Uint8Array(result1.length + result2.length); + if (result1.length) result.set(result1); + if (result2.length) result.set(result2, result1.length); + this.result = result; + + return this; + } + + AES_CCM_calculate_iv(): void { + const nonce = this.nonce; + const adata = this.adata; + const tagSize = this.tagSize; + const lengthSize = this.lengthSize; + const dataLength = this.dataLength; + + const data = new Uint8Array(16 + (adata ? 2 + adata.length : 0)); + + // B0: flags(adata?, M', L'), nonce, len(data) + data[0] = (adata ? 64 : 0) | ((tagSize - 2) << 2) | (lengthSize - 1); + data.set(nonce, 1); + if (lengthSize > 6) data[9] = ((dataLength / 0x100000000) >>> 16) & 15; + if (lengthSize > 5) data[10] = ((dataLength / 0x100000000) >>> 8) & 255; + if (lengthSize > 4) data[11] = (dataLength / 0x100000000) & 255; + if (lengthSize > 3) data[12] = dataLength >>> 24; + if (lengthSize > 2) data[13] = (dataLength >>> 16) & 255; + data[14] = (dataLength >>> 8) & 255; + data[15] = dataLength & 255; + + // B*: len(adata), adata + if (adata) { + data[16] = (adata.length >>> 8) & 255; + data[17] = adata.length & 255; + data.set(adata, 18); + } + + this._cbc_mac_process(data); + this.asm.get_state(AES_asm.HEAP_DATA); + + const iv = new Uint8Array(this.heap.subarray(0, 16)); + const ivview = new DataView(iv.buffer, iv.byteOffset, iv.byteLength); + this.asm.set_iv(ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12)); + } + + _cbc_mac_process(data: Uint8Array): void { + const heap = this.heap; + const asm = this.asm; + let dpos = 0; + let dlen = data.length || 0; + let wlen = 0; + + while (dlen > 0) { + wlen = _heap_write(heap, 0, data, dpos, dlen); + while (wlen & 15) heap[wlen++] = 0; + dpos += wlen; + dlen -= wlen; + + asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA, wlen); + } + } + + AES_CCM_Encrypt_process(data: Uint8Array): this { + const asm = this.asm; + const heap = this.heap; + + let dpos = 0; + let dlen = data.length || 0; + let counter = this.counter; + let pos = this.pos; + let len = this.len; + + const rlen = (len + dlen) & -16; + let rpos = 0; + let wlen = 0; + + if (((counter - 1) << 4) + len + dlen > _AES_CCM_data_maxLength) + // ??? should check against lengthSize + throw new RangeError('counter overflow'); + + const result = new Uint8Array(rlen); + + while (dlen > 0) { + wlen = _heap_write(heap, pos + len, data, dpos, dlen); + len += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, len); + wlen = asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, wlen); + + if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); + counter += wlen >>> 4; + rpos += wlen; + + if (wlen < len) { + pos += wlen; + len -= wlen; + } else { + pos = 0; + len = 0; + } + } + + this.result = result; + this.counter = counter; + this.pos = pos; + this.len = len; + + return this; + } + + AES_CCM_Encrypt_finish(): this { + const asm = this.asm; + const heap = this.heap; + const tagSize = this.tagSize; + const pos = this.pos; + const len = this.len; + + const result = new Uint8Array(len + tagSize); + + let i = len; + for (; i & 15; i++) heap[pos + i] = 0; + + asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, i); + asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, i); + if (len) result.set(heap.subarray(pos, pos + len)); + + asm.set_counter(0, 0, 0, 0); + asm.get_iv(AES_asm.HEAP_DATA); + asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); + result.set(heap.subarray(0, tagSize), len); + + this.result = result; + this.counter = 1; + this.pos = 0; + this.len = 0; + + return this; + } + + AES_CCM_Decrypt_process(data: Uint8Array): this { + let dpos = 0; + let dlen = data.length || 0; + const asm = this.asm; + const heap = this.heap; + let counter = this.counter; + const tagSize = this.tagSize; + let pos = this.pos; + let len = this.len; + let rpos = 0; + const rlen = len + dlen > tagSize ? (len + dlen - tagSize) & -16 : 0; + const tlen = len + dlen - rlen; + let wlen = 0; + + if (((counter - 1) << 4) + len + dlen > _AES_CCM_data_maxLength) throw new RangeError('counter overflow'); + + const result = new Uint8Array(rlen); + + while (dlen > tlen) { + wlen = _heap_write(heap, pos + len, data, dpos, dlen - tlen); + len += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, wlen); + wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, wlen); + + if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); + counter += wlen >>> 4; + rpos += wlen; + + pos = 0; + len = 0; + } + + if (dlen > 0) { + len += _heap_write(heap, 0, data, dpos, dlen); + } + + this.result = result; + this.counter = counter; + this.pos = pos; + this.len = len; + + return this; + } + + AES_CCM_Decrypt_finish(): this { + const asm = this.asm; + const heap = this.heap; + const tagSize = this.tagSize; + const pos = this.pos; + const len = this.len; + const rlen = len - tagSize; + + if (len < tagSize) throw new IllegalStateError('authentication tag not found'); + + const result = new Uint8Array(rlen); + const atag = new Uint8Array(heap.subarray(pos + rlen, pos + len)); + + asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, (rlen + 15) & -16); + result.set(heap.subarray(pos, pos + rlen)); + + let i = rlen; + for (; i & 15; i++) heap[pos + i] = 0; + asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, i); + + asm.set_counter(0, 0, 0, 0); + asm.get_iv(AES_asm.HEAP_DATA); + asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); + + let acheck = 0; + for (let j = 0; j < tagSize; ++j) acheck |= atag[j] ^ heap[j]; + if (acheck) throw new SecurityError('data integrity check failed'); + + this.result = result; + this.counter = 1; + this.pos = 0; + this.len = 0; + + return this; + } + + private AES_CTR_set_options(nonce: Uint8Array, counter: number, size: number): void { + if (size < 8 || size > 48) throw new IllegalArgumentError('illegal counter size'); + + const mask = Math.pow(2, size) - 1; + this.asm.set_mask(0, 0, (mask / 0x100000000) | 0, mask | 0); + + const len = nonce.length; + if (!len || len > 16) throw new IllegalArgumentError('illegal nonce size'); + + this.nonce = nonce; + + const view = new DataView(new ArrayBuffer(16)); + new Uint8Array(view.buffer).set(nonce); + + this.asm.set_nonce(view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)); + + if (counter < 0 || counter >= Math.pow(2, size)) throw new IllegalArgumentError('illegal counter value'); + + this.counter = counter; + + this.asm.set_counter(0, 0, (counter / 0x100000000) | 0, counter | 0); + } +} diff --git a/src/aes/ccm/ccm.js b/src/aes/ccm/ccm.js deleted file mode 100644 index 488a29f..0000000 --- a/src/aes/ccm/ccm.js +++ /dev/null @@ -1,394 +0,0 @@ -/** - * Counter with CBC-MAC (CCM) - * - * Due to JS limitations (52 bits of Number precision) maximum encrypted message length - * is limited to ~4 PiB ( 2^52 - 16 ) per `nonce`-`key` pair. - * That also limits `lengthSize` parameter maximum value to 7 (not 8 as described in RFC3610). - * - * Additional authenticated data `adata` maximum length is choosen to be no more than 65279 bytes ( 2^16 - 2^8 ), - * wich is considered enough for the most of use-cases. - * - * And one more important thing: in case of progressive ciphering of a data stream (in other - * words when data can't be held in-memory at a whole and are ciphered chunk-by-chunk) - * you have to know the `dataLength` in advance and pass that value to the cipher options. - */ - -import { AES_asm } from '../aes.asm'; -import { AES } from '../aes'; -import { _heap_write, is_bytes, is_number } from '../../utils'; -import { IllegalArgumentError, IllegalStateError, SecurityError } from '../../errors'; - -var _AES_CCM_adata_maxLength = 65279, // 2^16 - 2^8 - _AES_CCM_data_maxLength = 4503599627370480; // 2^52 - 2^4 - -export class AES_CCM extends AES { - constructor(key, nonce, adata, tagSize, dataLength, heap, asm) { - super(key, undefined, undefined, heap, asm); - this.tagSize = 16; - this.lengthSize = 4; - this.nonce = null; - this.adata = null; - this.iv = null; - this.counter = 1; - this.dataLength = -1; - - this.AES_CCM_reset(key, undefined, nonce, adata, undefined, undefined, tagSize, dataLength); - - this.mode = 'CCM'; - this.BLOCK_SIZE = 16; - } - - encrypt(data) { - return this.AES_CCM_encrypt(data); - } - decrypt(data) { - return this.AES_CCM_decrypt(data); - } - - AES_CCM_reset(key, iv, nonce, adata, counter, lengthSize, tagSize, dataLength) { - this.AES_reset(key, iv); - - if (tagSize !== undefined) { - if (!is_number(tagSize)) throw new TypeError('tagSize must be a number'); - - if (tagSize < 4 || tagSize > 16 || tagSize & 1) throw new IllegalArgumentError('illegal tagSize value'); - - this.tagSize = tagSize; - } else { - this.tagSize = 16; - } - - if (nonce !== undefined) { - if (!is_bytes(nonce)) { - throw new TypeError('unexpected nonce type'); - } - - if (nonce.length < 8 || nonce.length > 13) throw new IllegalArgumentError('illegal nonce length'); - - this.nonce = nonce; - this.lengthSize = lengthSize = 15 - nonce.length; - - nonce = new Uint8Array(nonce.length + 1); - (nonce[0] = lengthSize - 1), nonce.set(this.nonce, 1); - } else { - throw new Error('nonce is required'); - } - - // Either counter, iv - if (iv !== undefined) { - if (adata !== undefined) throw new IllegalStateError('you should specify either adata or iv, not both'); - - if (!is_number(counter)) throw new TypeError('counter must be a number'); - - if (counter < 1 || counter >= Math.pow(2, 8 * lengthSize) - 16) - throw new IllegalArgumentError('illegal counter value'); - - this.counter = counter; - } else if (adata !== undefined && adata !== null) { - // Or adata, dataLength - if (!is_bytes(adata)) { - throw new TypeError('unexpected adata type'); - } - - if (adata.length > _AES_CCM_adata_maxLength) throw new IllegalArgumentError('illegal adata length'); - - if (!is_number(dataLength)) throw new TypeError('dataLength must be a number'); - - if (dataLength < 0 || dataLength > _AES_CCM_data_maxLength || dataLength > Math.pow(2, 8 * lengthSize) - 16) - throw new IllegalArgumentError('illegal dataLength value'); - - this.adata = adata.length ? adata : null; - this.dataLength = dataLength; - this.counter = counter = 1; - - this.AES_CCM_calculate_iv(); - iv = this.iv; - } else { - // Assume adata is empty, check dataLength - if (!is_number(dataLength)) throw new TypeError('dataLength must be a number'); - - if (dataLength < 0 || dataLength > _AES_CCM_data_maxLength || dataLength > Math.pow(2, 8 * lengthSize) - 16) - throw new IllegalArgumentError('illegal dataLength value'); - - this.adata = null; - this.dataLength = dataLength; - this.counter = counter = 1; - - this.AES_CCM_calculate_iv(); - iv = this.iv; - } - - this.AES_set_iv(iv); - this.AES_CTR_set_options(nonce, counter, 8 * lengthSize); - - return this; - } - - AES_CCM_calculate_iv() { - var nonce = this.nonce, - adata = this.adata, - tagSize = this.tagSize, - lengthSize = this.lengthSize, - dataLength = this.dataLength; - - var data = new Uint8Array(16 + (adata ? 2 + adata.length : 0)); - - // B0: flags(adata?, M', L'), nonce, len(data) - data[0] = (adata ? 64 : 0) | ((tagSize - 2) << 2) | (lengthSize - 1); - data.set(nonce, 1); - if (lengthSize > 6) data[9] = ((dataLength / 0x100000000) >>> 16) & 15; - if (lengthSize > 5) data[10] = ((dataLength / 0x100000000) >>> 8) & 255; - if (lengthSize > 4) data[11] = (dataLength / 0x100000000) & 255; - if (lengthSize > 3) data[12] = dataLength >>> 24; - if (lengthSize > 2) data[13] = (dataLength >>> 16) & 255; - data[14] = (dataLength >>> 8) & 255; - data[15] = dataLength & 255; - - // B*: len(adata), adata - if (adata) { - data[16] = (adata.length >>> 8) & 255; - data[17] = adata.length & 255; - data.set(adata, 18); - } - - this._cbc_mac_process(data); - this.asm.get_state(AES_asm.HEAP_DATA); - - this.iv = new Uint8Array(this.heap.subarray(0, 16)); - } - - _cbc_mac_process(data) { - var heap = this.heap, - asm = this.asm, - dpos = 0, - dlen = data.length || 0, - wlen = 0; - - while (dlen > 0) { - wlen = _heap_write(heap, 0, data, dpos, dlen); - while (wlen & 15) heap[wlen++] = 0; - dpos += wlen; - dlen -= wlen; - - asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA, wlen); - } - } - - AES_CCM_decrypt(data) { - this.dataLength = data.length || 0; - - var result1 = this.AES_CCM_Decrypt_process(data).result; - var result2 = this.AES_CCM_Decrypt_finish().result; - - var result = new Uint8Array(result1.length + result2.length); - if (result1.length) result.set(result1); - if (result2.length) result.set(result2, result1.length); - this.result = result; - - return this; - } - - AES_CCM_encrypt(data) { - this.dataLength = data.length || 0; - - var result1 = this.AES_CCM_Encrypt_process(data).result; - var result2 = this.AES_CCM_Encrypt_finish().result; - - var result = new Uint8Array(result1.length + result2.length); - if (result1.length) result.set(result1); - if (result2.length) result.set(result2, result1.length); - this.result = result; - - return this; - } - - AES_CCM_Encrypt_process(data) { - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var dpos = 0, - dlen = data.length || 0, - asm = this.asm, - heap = this.heap, - counter = this.counter, - pos = this.pos, - len = this.len, - rpos = 0, - rlen = (len + dlen) & -16, - wlen = 0; - - if (((counter - 1) << 4) + len + dlen > _AES_CCM_data_maxLength) - // ??? should check against lengthSize - throw new RangeError('counter overflow'); - - var result = new Uint8Array(rlen); - - while (dlen > 0) { - wlen = _heap_write(heap, pos + len, data, dpos, dlen); - len += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, len); - wlen = asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, wlen); - - if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); - counter += wlen >>> 4; - rpos += wlen; - - if (wlen < len) { - pos += wlen; - len -= wlen; - } else { - pos = 0; - len = 0; - } - } - - this.result = result; - this.counter = counter; - this.pos = pos; - this.len = len; - - return this; - } - - AES_CCM_Encrypt_finish() { - var asm = this.asm, - heap = this.heap, - tagSize = this.tagSize, - pos = this.pos, - len = this.len, - wlen = 0; - - var result = new Uint8Array(len + tagSize); - - for (var i = len; i & 15; i++) heap[pos + i] = 0; - - wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, i); - wlen = asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, i); - if (len) result.set(heap.subarray(pos, pos + len)); - - asm.set_counter(0, 0, 0, 0); - asm.get_iv(AES_asm.HEAP_DATA); - asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); - result.set(heap.subarray(0, tagSize), len); - - this.result = result; - this.counter = 1; - this.pos = 0; - this.len = 0; - - return this; - } - - AES_CCM_Decrypt_process(data) { - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var dpos = 0, - dlen = data.length || 0, - asm = this.asm, - heap = this.heap, - counter = this.counter, - tagSize = this.tagSize, - pos = this.pos, - len = this.len, - rpos = 0, - rlen = len + dlen > tagSize ? (len + dlen - tagSize) & -16 : 0, - tlen = len + dlen - rlen, - wlen = 0; - - if (((counter - 1) << 4) + len + dlen > _AES_CCM_data_maxLength) throw new RangeError('counter overflow'); - - var result = new Uint8Array(rlen); - - while (dlen > tlen) { - wlen = _heap_write(heap, pos + len, data, dpos, dlen - tlen); - len += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, wlen); - wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, wlen); - - if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); - counter += wlen >>> 4; - rpos += wlen; - - pos = 0; - len = 0; - } - - if (dlen > 0) { - len += _heap_write(heap, 0, data, dpos, dlen); - } - - this.result = result; - this.counter = counter; - this.pos = pos; - this.len = len; - - return this; - } - - AES_CCM_Decrypt_finish() { - var asm = this.asm, - heap = this.heap, - tagSize = this.tagSize, - pos = this.pos, - len = this.len, - rlen = len - tagSize, - wlen = 0; - - if (len < tagSize) throw new IllegalStateError('authentication tag not found'); - - var result = new Uint8Array(rlen), - atag = new Uint8Array(heap.subarray(pos + rlen, pos + len)); - - wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, (rlen + 15) & -16); - result.set(heap.subarray(pos, pos + rlen)); - - for (var i = rlen; i & 15; i++) heap[pos + i] = 0; - wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, i); - - asm.set_counter(0, 0, 0, 0); - asm.get_iv(AES_asm.HEAP_DATA); - asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); - - var acheck = 0; - for (var i = 0; i < tagSize; ++i) acheck |= atag[i] ^ heap[i]; - if (acheck) throw new SecurityError('data integrity check failed'); - - this.result = result; - this.counter = 1; - this.pos = 0; - this.len = 0; - - return this; - } - - reset() {} -} - -export class AES_CCM_Encrypt extends AES_CCM { - constructor(key, nonce, adata, tagSize, dataLength, heap, asm) { - super(key, nonce, adata, tagSize, dataLength, heap, asm); - } - process(data) { - return this.AES_CCM_Encrypt_process(data); - } - finish() { - return this.AES_CCM_Encrypt_finish(); - } -} - -export class AES_CCM_Decrypt extends AES_CCM { - constructor(key, nonce, adata, tagSize, dataLength, heap, asm) { - super(key, nonce, adata, tagSize, dataLength, heap, asm); - } - process(data) { - return this.AES_CCM_Decrypt_process(data); - } - finish() { - return this.AES_CCM_Decrypt_finish(); - } -} diff --git a/src/aes/ccm/exports.js b/src/aes/ccm/exports.js deleted file mode 100644 index a1b690e..0000000 --- a/src/aes/ccm/exports.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * AES-CCM exports - */ - -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_CCM, AES_CCM_Decrypt, AES_CCM_Encrypt } from './ccm'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {Uint8Array} [adata] - * @param {number} [tagSize] - */ -function AES_CCM_encrypt_bytes(data, key, nonce, adata, tagSize) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - if (nonce === undefined) throw new SyntaxError('nonce required'); - var dataLength = data.length || 0; - return new AES_CCM(key, nonce, adata, tagSize, dataLength, _AES_heap_instance, _AES_asm_instance).encrypt(data) - .result; -} - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {Uint8Array} [adata] - * @param {number} [tagSize] - */ -function AES_CCM_decrypt_bytes(data, key, nonce, adata, tagSize) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - if (nonce === undefined) throw new SyntaxError('nonce required'); - var dataLength = data.length || 0; - tagSize = tagSize || 16; - return new AES_CCM(key, nonce, adata, tagSize, dataLength - tagSize, _AES_heap_instance, _AES_asm_instance).decrypt( - data, - ).result; -} - -AES_CCM.encrypt = AES_CCM_encrypt_bytes; -AES_CCM.decrypt = AES_CCM_decrypt_bytes; - -export { AES_CCM, AES_CCM_Encrypt, AES_CCM_Decrypt }; diff --git a/src/aes/cfb.ts b/src/aes/cfb.ts new file mode 100644 index 0000000..1702d01 --- /dev/null +++ b/src/aes/cfb.ts @@ -0,0 +1,26 @@ +import { AES } from './aes'; + +export class AES_CFB extends AES { + static encrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { + return new AES_CFB(key, iv).encrypt(data).result as Uint8Array; + } + + static decrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { + return new AES_CFB(key, iv).decrypt(data).result as Uint8Array; + } + + constructor(key: Uint8Array, iv?: Uint8Array) { + super(key, iv, true, 'CFB'); + delete this.padding; + } + + encrypt(data: Uint8Array): this { + this.AES_Encrypt_process(data); + return this.AES_Encrypt_finish(); + } + + decrypt(data: Uint8Array): this { + this.AES_Decrypt_process(data); + return this.AES_Decrypt_finish(); + } +} diff --git a/src/aes/cfb/cfb.js b/src/aes/cfb/cfb.js deleted file mode 100644 index 3cdd4cb..0000000 --- a/src/aes/cfb/cfb.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Cipher Feedback Mode (CFB) - */ - -import { AES } from '../aes'; - -export class AES_CFB extends AES { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv] - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, heap, asm) { - super(key, iv, true, heap, asm); - delete this.padding; - - this.mode = 'CFB'; - this.BLOCK_SIZE = 16; - } - - encrypt(data) { - return this.AES_Encrypt_finish(data); - } - - decrypt(data) { - return this.AES_Decrypt_finish(data); - } -} - -export class AES_CFB_Encrypt extends AES_CFB { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv=null] - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, heap, asm) { - super(key, iv, heap, asm); - } - - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv] - * @param {boolean} [padding] - * @returns {AES_CFB_Encrypt} - */ - reset(key, iv, padding) { - return this.AES_reset(key, iv, padding); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CFB_Encrypt} - */ - process(data) { - return this.AES_Encrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CFB_Encrypt} - */ - finish(data) { - return this.AES_Encrypt_finish(data); - } -} - -export class AES_CFB_Decrypt extends AES_CFB { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv=null] - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, heap, asm) { - super(key, iv, heap, asm); - } - - /** - * @param {Uint8Array} key - * @param {Uint8Array} [iv] - * @param {boolean} [padding] - * @returns {AES_CFB_Decrypt} - */ - reset(key, iv, padding) { - return this.AES_reset(key, iv, padding); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CFB_Decrypt} - */ - process(data) { - return this.AES_Decrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CFB_Decrypt} - */ - finish(data) { - return this.AES_Decrypt_finish(data); - } -} diff --git a/src/aes/cfb/exports.js b/src/aes/cfb/exports.js deleted file mode 100644 index 6c2e130..0000000 --- a/src/aes/cfb/exports.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * AES-CFB exports - */ - -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_CFB, AES_CFB_Decrypt, AES_CFB_Encrypt } from './cfb'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} [iv] - * @returns {Uint8Array} - */ -function AES_CFB_encrypt_bytes(data, key, iv) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_CFB(key, iv, _AES_heap_instance, _AES_asm_instance).encrypt(data).result; -} - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} [iv] - * @returns {Uint8Array} - */ -function AES_CFB_decrypt_bytes(data, key, iv) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_CFB(key, iv, _AES_heap_instance, _AES_asm_instance).decrypt(data).result; -} - -AES_CFB.encrypt = AES_CFB_encrypt_bytes; -AES_CFB.decrypt = AES_CFB_decrypt_bytes; - -export { AES_CFB, AES_CFB_Encrypt, AES_CFB_Decrypt }; diff --git a/src/aes/cmac/cmac.js b/src/aes/cmac.ts similarity index 52% rename from src/aes/cmac/cmac.js rename to src/aes/cmac.ts index 7d52484..67a9b62 100644 --- a/src/aes/cmac/cmac.js +++ b/src/aes/cmac.ts @@ -1,40 +1,39 @@ -import { AES_ECB } from '../ecb/ecb'; -import { AES_CBC_Encrypt } from '../cbc/cbc'; -import { bytes_to_hex, hex_to_bytes } from '../../utils'; - -/** - * @param {Uint8Array} data - */ -function mul2(data) { +import { AES_ECB } from './ecb'; +import { AES_CBC } from './cbc'; + +function mul2(data: Uint8Array): void { const t = data[0] & 0x80; - for (var i = 0; i < 15; i++) { - data[i] = (data[i] << 1) ^ ((data[i+1] & 0x80) ? 1 : 0); + for (let i = 0; i < 15; i++) { + data[i] = (data[i] << 1) ^ (data[i + 1] & 0x80 ? 1 : 0); } data[15] = (data[15] << 1) ^ (t ? 0x87 : 0); } export class AES_CMAC { - /** - * @param {Uint8Array} key - */ - constructor(key) { - this.k = new AES_ECB(key).encrypt(new Uint8Array(16)).result; + private readonly k: Uint8Array; + private readonly cbc: AES_CBC; + private readonly buffer: Uint8Array; + private bufferLength = 0; + public result!: Uint8Array | null; + + static bytes(data: Uint8Array, key: Uint8Array): Uint8Array { + return new AES_CMAC(key).process(data).finish().result as Uint8Array; + } + + constructor(key: Uint8Array) { + this.k = new AES_ECB(key).encrypt(new Uint8Array(16)).result as Uint8Array; mul2(this.k); - this.cbc = new AES_CBC_Encrypt(key, new Uint8Array(16), false); + this.cbc = new AES_CBC(key, new Uint8Array(16), false); this.buffer = new Uint8Array(16); - this.bufferLength = 0; this.result = null; } - /** - * @param {Uint8Array} data - */ - process(data) { + process(data: Uint8Array): this { if (this.bufferLength + data.length > 16) { - this.cbc.process(this.buffer.subarray(0, this.bufferLength)); + this.cbc.encrypt(this.buffer.subarray(0, this.bufferLength)); const offset = ((this.bufferLength + data.length - 1) & ~15) - this.bufferLength; - this.cbc.process(data.subarray(0, offset)); + this.cbc.encrypt(data.subarray(0, offset)); this.buffer.set(data.subarray(offset)); this.bufferLength = data.length - offset; } else { @@ -44,7 +43,7 @@ export class AES_CMAC { return this; } - finish() { + finish(): this { if (this.bufferLength !== 16) { this.buffer[this.bufferLength] = 0x80; for (let i = this.bufferLength + 1; i < 16; i++) { @@ -57,7 +56,7 @@ export class AES_CMAC { this.buffer[i] ^= this.k[i]; } - this.result = this.cbc.process(this.buffer).result; + this.result = this.cbc.encrypt(this.buffer).result; return this; } } diff --git a/src/aes/cmac/exports.js b/src/aes/cmac/exports.js deleted file mode 100644 index 4009808..0000000 --- a/src/aes/cmac/exports.js +++ /dev/null @@ -1,16 +0,0 @@ -import { AES_CMAC } from './cmac'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @returns {Uint8Array} - */ -function AES_CMAC_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_CMAC(key).process(data).finish().result; -} - -AES_CMAC.bytes = AES_CMAC_bytes; - -export { AES_CMAC }; diff --git a/src/aes/ctr.ts b/src/aes/ctr.ts new file mode 100644 index 0000000..5cd3a87 --- /dev/null +++ b/src/aes/ctr.ts @@ -0,0 +1,59 @@ +import { AES } from './aes'; +import { IllegalArgumentError } from '../other/errors'; + +export class AES_CTR extends AES { + static encrypt(data: Uint8Array, key: Uint8Array, nonce: Uint8Array): Uint8Array { + return new AES_CTR(key, nonce).encrypt(data).result as Uint8Array; + } + + static decrypt(data: Uint8Array, key: Uint8Array, nonce: Uint8Array): Uint8Array { + return new AES_CTR(key, nonce).encrypt(data).result as Uint8Array; + } + + constructor(key: Uint8Array, nonce: Uint8Array) { + super(key, undefined, false, 'CTR'); + delete this.padding; + + this.AES_CTR_set_options(nonce); + } + + encrypt(data: Uint8Array): this { + this.AES_Encrypt_process(data); + return this.AES_Encrypt_finish(); + } + + decrypt(data: Uint8Array): this { + this.AES_Encrypt_process(data); + return this.AES_Encrypt_finish(); + } + + private AES_CTR_set_options(nonce: Uint8Array, counter?: number, size?: number): void { + if (size !== undefined) { + if (size < 8 || size > 48) throw new IllegalArgumentError('illegal counter size'); + + let mask = Math.pow(2, size) - 1; + this.asm.set_mask(0, 0, (mask / 0x100000000) | 0, mask | 0); + } else { + size = 48; + this.asm.set_mask(0, 0, 0xffff, 0xffffffff); + } + + if (nonce !== undefined) { + let len = nonce.length; + if (!len || len > 16) throw new IllegalArgumentError('illegal nonce size'); + + let view = new DataView(new ArrayBuffer(16)); + new Uint8Array(view.buffer).set(nonce); + + this.asm.set_nonce(view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)); + } else { + throw new Error('nonce is required'); + } + + if (counter !== undefined) { + if (counter < 0 || counter >= Math.pow(2, size)) throw new IllegalArgumentError('illegal counter value'); + + this.asm.set_counter(0, 0, (counter / 0x100000000) | 0, counter | 0); + } + } +} diff --git a/src/aes/ctr/ctr.js b/src/aes/ctr/ctr.js deleted file mode 100644 index 763e5fb..0000000 --- a/src/aes/ctr/ctr.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Counter Mode (CTR) - */ - -import { AES } from '../aes'; - -export class AES_CTR extends AES { - /** - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, nonce, heap, asm) { - super(key, undefined, undefined, heap, asm); - this.reset(key, nonce); - - this.AES_CTR_set_options(nonce); - delete this.padding; - - this.mode = 'CTR'; - this.BLOCK_SIZE = 16; - } - - /** - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {number} [counter] - * @param {number} [counterSize] - * @returns {AES_CTR} - */ - reset(key, nonce, counter, counterSize) { - this.AES_reset(key, undefined, undefined); - - this.AES_CTR_set_options(nonce, counter, counterSize); - - return this; - } - - /** - * @param {Uint8Array} data - * @returns {AES_CTR} - */ - encrypt(data) { - return this.AES_Encrypt_finish(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CTR} - */ - decrypt(data) { - return this.AES_Encrypt_finish(data); - } -} - -export class AES_CTR_Crypt extends AES_CTR { - /** - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, nonce, heap, asm) { - super(key, nonce, heap, asm); - this.BLOCK_SIZE = 16; - } - - /** - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {number} [counter] - * @param {number} [counterSize] - * @returns {AES_CTR_Crypt} - */ - reset(key, nonce, counter, counterSize) { - this.AES_reset(key, undefined, undefined); - - this.AES_CTR_set_options(nonce, counter, counterSize); - - return this; - } - - /** - * @param {Uint8Array} data - * @returns {AES_CTR_Crypt} - */ - process(data) { - return this.AES_Encrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_CTR_Crypt} - */ - finish(data) { - return this.AES_Encrypt_finish(data); - } -} diff --git a/src/aes/ctr/exports.js b/src/aes/ctr/exports.js deleted file mode 100644 index b99dcf1..0000000 --- a/src/aes/ctr/exports.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * AES-CTR exports - */ - -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_CTR } from './ctr'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @returns {Uint8Array} - */ -function AES_CTR_crypt_bytes(data, key, nonce) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - if (nonce === undefined) throw new SyntaxError('nonce required'); - return new AES_CTR(key, nonce, _AES_heap_instance, _AES_asm_instance).encrypt(data).result; -} - -AES_CTR.encrypt = AES_CTR_crypt_bytes; -AES_CTR.decrypt = AES_CTR_crypt_bytes; - -export { AES_CTR }; diff --git a/src/aes/ecb.ts b/src/aes/ecb.ts new file mode 100644 index 0000000..33913e0 --- /dev/null +++ b/src/aes/ecb.ts @@ -0,0 +1,25 @@ +import { AES } from './aes'; + +export class AES_ECB extends AES { + static encrypt(data: Uint8Array, key: Uint8Array, padding: boolean = false): Uint8Array { + return new AES_ECB(key, padding).encrypt(data).result as Uint8Array; + } + + static decrypt(data: Uint8Array, key: Uint8Array, padding: boolean = false): Uint8Array { + return new AES_ECB(key, padding).decrypt(data).result as Uint8Array; + } + + constructor(key: Uint8Array, padding: boolean = false) { + super(key, undefined, padding, 'ECB'); + } + + encrypt(data: Uint8Array): this { + this.AES_Encrypt_process(data); + return this.AES_Encrypt_finish(); + } + + decrypt(data: Uint8Array): this { + this.AES_Decrypt_process(data); + return this.AES_Decrypt_finish(); + } +} diff --git a/src/aes/ecb/ecb.js b/src/aes/ecb/ecb.js deleted file mode 100644 index 29ff4e7..0000000 --- a/src/aes/ecb/ecb.js +++ /dev/null @@ -1,96 +0,0 @@ -import { AES } from '../aes'; - -/** - * Electronic Code Book Mode (ECB) - */ -export class AES_ECB extends AES { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, heap, asm) { - super(key, undefined, false, heap, asm); - - this.mode = 'ECB'; - this.BLOCK_SIZE = 16; - } - - encrypt(data) { - return this.AES_Encrypt_finish(data); - } - - decrypt(data) { - return this.AES_Decrypt_finish(data); - } -} - -export class AES_ECB_Encrypt extends AES_ECB { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, heap, asm) { - super(key, heap, asm); - } - - /** - * @param {Uint8Array} key - * @returns {AES_ECB_Encrypt} - */ - reset(key) { - return this.AES_reset(key, null, true); - } - - /** - * @param {Uint8Array} data - * @returns {AES_ECB_Encrypt} - */ - process(data) { - return this.AES_Encrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_ECB_Encrypt} - */ - finish(data) { - return this.AES_Encrypt_finish(data); - } -} - -export class AES_ECB_Decrypt extends AES_ECB { - /** - * @param {Uint8Array} key - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, heap, asm) { - super(key, heap, asm); - } - - /** - * @param {Uint8Array} key - * @returns {AES_ECB_Decrypt} - */ - reset(key) { - return this.AES_reset(key, null, true); - } - - /** - * @param {Uint8Array} data - * @returns {AES_ECB_Decrypt} - */ - process(data) { - return this.AES_Decrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @returns {AES_ECB_Decrypt} - */ - finish(data) { - return this.AES_Decrypt_finish(data); - } -} diff --git a/src/aes/ecb/exports.js b/src/aes/ecb/exports.js deleted file mode 100644 index 6b0966d..0000000 --- a/src/aes/ecb/exports.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * AES-ECB exports - */ - -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_ECB, AES_ECB_Decrypt, AES_ECB_Encrypt } from './ecb'; - -function AES_ECB_encrypt_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_ECB(key, _AES_heap_instance, _AES_asm_instance).encrypt(data).result; -} - -function AES_ECB_decrypt_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_ECB(key, _AES_heap_instance, _AES_asm_instance).decrypt(data).result; -} - -AES_ECB.encrypt = AES_ECB_encrypt_bytes; -AES_ECB.decrypt = AES_ECB_decrypt_bytes; - -export { AES_ECB, AES_ECB_Encrypt, AES_ECB_Decrypt }; diff --git a/src/aes/exports.js b/src/aes/exports.ts similarity index 63% rename from src/aes/exports.js rename to src/aes/exports.ts index 179a9b6..809ae54 100644 --- a/src/aes/exports.js +++ b/src/aes/exports.ts @@ -2,4 +2,4 @@ import { AES_asm } from './aes.asm'; export var _AES_heap_instance = new Uint8Array(0x100000); // 1MB -export var _AES_asm_instance = AES_asm(null, _AES_heap_instance.buffer); +export var _AES_asm_instance = new AES_asm(null, _AES_heap_instance.buffer); diff --git a/src/aes/gcm.ts b/src/aes/gcm.ts new file mode 100644 index 0000000..f966a94 --- /dev/null +++ b/src/aes/gcm.ts @@ -0,0 +1,352 @@ +import { IllegalArgumentError, IllegalStateError, SecurityError } from '../other/errors'; +import { _heap_write } from '../other/utils'; +import { AES } from './aes'; +import { AES_asm } from './aes.asm'; + +const _AES_GCM_data_maxLength = 68719476704; // 2^36 - 2^5 + +export class AES_GCM extends AES { + private readonly adata: Uint8Array | undefined; + private readonly gamma0: number = 0; + + private counter: number = 1; + + static encrypt( + cleartext: Uint8Array, + key: Uint8Array, + nonce: Uint8Array, + adata?: Uint8Array, + tagsize?: number, + ): Uint8Array { + return new AES_GCM(key, nonce, adata, tagsize).encrypt(cleartext).result as Uint8Array; + } + + static decrypt( + ciphertext: Uint8Array, + key: Uint8Array, + nonce: Uint8Array, + adata?: Uint8Array, + tagsize?: number, + ): Uint8Array { + return new AES_GCM(key, nonce, adata, tagsize).decrypt(ciphertext).result as Uint8Array; + } + + constructor(key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, private readonly tagSize: number = 16) { + super(key, undefined, false, 'CTR'); + + // Init GCM + this.asm.gcm_init(); + + // Tag size + if (this.tagSize < 4 || this.tagSize > 16) throw new IllegalArgumentError('illegal tagSize value'); + + // Nonce + const noncelen = nonce.length || 0; + const noncebuf = new Uint8Array(16); + if (noncelen !== 12) { + this._gcm_mac_process(nonce); + + this.heap[0] = 0; + this.heap[1] = 0; + this.heap[2] = 0; + this.heap[3] = 0; + this.heap[4] = 0; + this.heap[5] = 0; + this.heap[6] = 0; + this.heap[7] = 0; + this.heap[8] = 0; + this.heap[9] = 0; + this.heap[10] = 0; + this.heap[11] = noncelen >>> 29; + this.heap[12] = (noncelen >>> 21) & 255; + this.heap[13] = (noncelen >>> 13) & 255; + this.heap[14] = (noncelen >>> 5) & 255; + this.heap[15] = (noncelen << 3) & 255; + this.asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16); + + this.asm.get_iv(AES_asm.HEAP_DATA); + this.asm.set_iv(0, 0, 0, 0); + + noncebuf.set(this.heap.subarray(0, 16)); + } else { + noncebuf.set(nonce); + noncebuf[15] = 1; + } + + const nonceview = new DataView(noncebuf.buffer); + this.gamma0 = nonceview.getUint32(12); + + this.asm.set_nonce(nonceview.getUint32(0), nonceview.getUint32(4), nonceview.getUint32(8), 0); + this.asm.set_mask(0, 0, 0, 0xffffffff); + + // Associated data + if (adata !== undefined) { + if (adata.length > _AES_GCM_data_maxLength) throw new IllegalArgumentError('illegal adata length'); + + if (adata.length) { + this.adata = adata; + this._gcm_mac_process(adata); + } else { + this.adata = undefined; + } + } else { + this.adata = undefined; + } + + // Counter + if (this.counter < 1 || this.counter > 0xffffffff) + throw new RangeError('counter must be a positive 32-bit integer'); + this.asm.set_counter(0, 0, 0, (this.gamma0 + this.counter) | 0); + } + + encrypt(data: Uint8Array) { + return this.AES_GCM_encrypt(data); + } + + decrypt(data: Uint8Array) { + return this.AES_GCM_decrypt(data); + } + + AES_GCM_Encrypt_process(data: Uint8Array) { + let dpos = 0; + let dlen = data.length || 0; + let asm = this.asm; + let heap = this.heap; + let counter = this.counter; + let pos = this.pos; + let len = this.len; + let rpos = 0; + let rlen = (len + dlen) & -16; + let wlen = 0; + + if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength) throw new RangeError('counter overflow'); + + const result = new Uint8Array(rlen); + + while (dlen > 0) { + wlen = _heap_write(heap, pos + len, data, dpos, dlen); + len += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, len); + wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, wlen); + + if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); + counter += wlen >>> 4; + rpos += wlen; + + if (wlen < len) { + pos += wlen; + len -= wlen; + } else { + pos = 0; + len = 0; + } + } + + this.result = result; + this.counter = counter; + this.pos = pos; + this.len = len; + + return this; + } + + AES_GCM_Encrypt_finish() { + let asm = this.asm; + let heap = this.heap; + let counter = this.counter; + let tagSize = this.tagSize; + let adata = this.adata; + let pos = this.pos; + let len = this.len; + + const result = new Uint8Array(len + tagSize); + + asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, (len + 15) & -16); + if (len) result.set(heap.subarray(pos, pos + len)); + + let i = len; + for (; i & 15; i++) heap[pos + i] = 0; + asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, i); + + const alen = adata !== undefined ? adata.length : 0; + const clen = ((counter - 1) << 4) + len; + + heap[0] = 0; + heap[1] = 0; + heap[2] = 0; + heap[3] = alen >>> 29; + heap[4] = alen >>> 21; + heap[5] = (alen >>> 13) & 255; + heap[6] = (alen >>> 5) & 255; + heap[7] = (alen << 3) & 255; + heap[8] = heap[9] = heap[10] = 0; + heap[11] = clen >>> 29; + heap[12] = (clen >>> 21) & 255; + heap[13] = (clen >>> 13) & 255; + heap[14] = (clen >>> 5) & 255; + heap[15] = (clen << 3) & 255; + + asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16); + asm.get_iv(AES_asm.HEAP_DATA); + + asm.set_counter(0, 0, 0, this.gamma0); + asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); + result.set(heap.subarray(0, tagSize), len); + + this.result = result; + this.counter = 1; + this.pos = 0; + this.len = 0; + + return this; + } + + AES_GCM_Decrypt_process(data: Uint8Array) { + let dpos = 0; + let dlen = data.length || 0; + let asm = this.asm; + let heap = this.heap; + let counter = this.counter; + let tagSize = this.tagSize; + let pos = this.pos; + let len = this.len; + let rpos = 0; + let rlen = len + dlen > tagSize ? (len + dlen - tagSize) & -16 : 0; + let tlen = len + dlen - rlen; + let wlen = 0; + + if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength) throw new RangeError('counter overflow'); + + const result = new Uint8Array(rlen); + + while (dlen > tlen) { + wlen = _heap_write(heap, pos + len, data, dpos, dlen - tlen); + len += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, wlen); + wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, wlen); + + if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); + counter += wlen >>> 4; + rpos += wlen; + + pos = 0; + len = 0; + } + + if (dlen > 0) { + len += _heap_write(heap, 0, data, dpos, dlen); + } + + this.result = result; + this.counter = counter; + this.pos = pos; + this.len = len; + + return this; + } + + AES_GCM_Decrypt_finish() { + let asm = this.asm; + let heap = this.heap; + let tagSize = this.tagSize; + let adata = this.adata; + let counter = this.counter; + let pos = this.pos; + let len = this.len; + let rlen = len - tagSize; + + if (len < tagSize) throw new IllegalStateError('authentication tag not found'); + + const result = new Uint8Array(rlen); + const atag = new Uint8Array(heap.subarray(pos + rlen, pos + len)); + + let i = rlen; + for (; i & 15; i++) heap[pos + i] = 0; + + asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, i); + asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, i); + + if (rlen) result.set(heap.subarray(pos, pos + rlen)); + + const alen = adata !== undefined ? adata.length : 0; + const clen = ((counter - 1) << 4) + len - tagSize; + heap[0] = 0; + heap[1] = 0; + heap[2] = 0; + heap[3] = alen >>> 29; + heap[4] = alen >>> 21; + heap[5] = (alen >>> 13) & 255; + heap[6] = (alen >>> 5) & 255; + heap[7] = (alen << 3) & 255; + heap[8] = heap[9] = heap[10] = 0; + heap[11] = clen >>> 29; + heap[12] = (clen >>> 21) & 255; + heap[13] = (clen >>> 13) & 255; + heap[14] = (clen >>> 5) & 255; + heap[15] = (clen << 3) & 255; + asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16); + asm.get_iv(AES_asm.HEAP_DATA); + + asm.set_counter(0, 0, 0, this.gamma0); + asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); + + let acheck = 0; + for (let i = 0; i < tagSize; ++i) acheck |= atag[i] ^ heap[i]; + if (acheck) throw new SecurityError('data integrity check failed'); + + this.result = result; + this.counter = 1; + this.pos = 0; + this.len = 0; + + return this; + } + + private AES_GCM_decrypt(data: Uint8Array) { + const result1 = this.AES_GCM_Decrypt_process(data).result as Uint8Array; + const result2 = this.AES_GCM_Decrypt_finish().result as Uint8Array; + + const result = new Uint8Array(result1.length + result2.length); + if (result1.length) result.set(result1); + if (result2.length) result.set(result2, result1.length); + this.result = result; + + return this; + } + + private AES_GCM_encrypt(data: Uint8Array) { + const result1 = this.AES_GCM_Encrypt_process(data).result as Uint8Array; + const result2 = this.AES_GCM_Encrypt_finish().result as Uint8Array; + + const result = new Uint8Array(result1.length + result2.length); + if (result1.length) result.set(result1); + if (result2.length) result.set(result2, result1.length); + this.result = result; + + return this; + } + + _gcm_mac_process(data: Uint8Array) { + const heap = this.heap; + const asm = this.asm; + let dpos = 0; + let dlen = data.length || 0; + let wlen = 0; + + while (dlen > 0) { + wlen = _heap_write(heap, 0, data, dpos, dlen); + dpos += wlen; + dlen -= wlen; + + while (wlen & 15) heap[wlen++] = 0; + + asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, wlen); + } + } +} diff --git a/src/aes/gcm/exports.js b/src/aes/gcm/exports.js deleted file mode 100644 index cbee1e8..0000000 --- a/src/aes/gcm/exports.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * AES-GCM exports - */ - -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_GCM, AES_GCM_Decrypt, AES_GCM_Encrypt } from './gcm'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {Uint8Array} [adata] - * @param {number} [tagSize] - * @return {Uint8Array} - */ -function AES_GCM_encrypt_bytes(data, key, nonce, adata, tagSize) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - if (nonce === undefined) throw new SyntaxError('nonce required'); - return new AES_GCM(key, nonce, adata, tagSize, _AES_heap_instance, _AES_asm_instance).encrypt(data).result; -} - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} nonce - * @param {Uint8Array} [adata] - * @param {number} [tagSize] - * @return {Uint8Array} - */ -function AES_GCM_decrypt_bytes(data, key, nonce, adata, tagSize) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - if (nonce === undefined) throw new SyntaxError('nonce required'); - return new AES_GCM(key, nonce, adata, tagSize, _AES_heap_instance, _AES_asm_instance).decrypt(data).result; -} - -AES_GCM.encrypt = AES_GCM_encrypt_bytes; -AES_GCM.decrypt = AES_GCM_decrypt_bytes; - -export { AES_GCM, AES_GCM_Encrypt, AES_GCM_Decrypt }; diff --git a/src/aes/gcm/gcm.js b/src/aes/gcm/gcm.js deleted file mode 100644 index e432410..0000000 --- a/src/aes/gcm/gcm.js +++ /dev/null @@ -1,399 +0,0 @@ -/** - * Galois/Counter mode - */ - -import { IllegalArgumentError, IllegalStateError, SecurityError } from '../../errors'; -import { _heap_write, is_bytes, is_number } from '../../utils'; -import { AES } from '../aes'; -import { AES_asm } from '../aes.asm'; - -var _AES_GCM_data_maxLength = 68719476704; // 2^36 - 2^5 - -export class AES_GCM extends AES { - constructor(key, nonce, adata, tagSize, heap, asm) { - super(key, undefined, false, heap, asm); - - this.nonce = null; - this.adata = null; - this.iv = null; - this.counter = 1; - this.tagSize = 16; - this.mode = 'GCM'; - this.BLOCK_SIZE = 16; - - this.reset(key, tagSize, nonce, adata); - } - - reset(key, tagSize, nonce, adata) { - return this.AES_GCM_reset(key, tagSize, nonce, adata); - } - - encrypt(data) { - return this.AES_GCM_encrypt(data); - } - - decrypt(data) { - return this.AES_GCM_decrypt(data); - } - - AES_GCM_Encrypt_process(data) { - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var dpos = 0, - dlen = data.length || 0, - asm = this.asm, - heap = this.heap, - counter = this.counter, - pos = this.pos, - len = this.len, - rpos = 0, - rlen = (len + dlen) & -16, - wlen = 0; - - if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength) throw new RangeError('counter overflow'); - - var result = new Uint8Array(rlen); - - while (dlen > 0) { - wlen = _heap_write(heap, pos + len, data, dpos, dlen); - len += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, len); - wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, wlen); - - if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); - counter += wlen >>> 4; - rpos += wlen; - - if (wlen < len) { - pos += wlen; - len -= wlen; - } else { - pos = 0; - len = 0; - } - } - - this.result = result; - this.counter = counter; - this.pos = pos; - this.len = len; - - return this; - } - - AES_GCM_Encrypt_finish() { - var asm = this.asm, - heap = this.heap, - counter = this.counter, - tagSize = this.tagSize, - adata = this.adata, - pos = this.pos, - len = this.len; - - var result = new Uint8Array(len + tagSize); - - asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, (len + 15) & -16); - if (len) result.set(heap.subarray(pos, pos + len)); - - for (var i = len; i & 15; i++) heap[pos + i] = 0; - asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, i); - - var alen = adata !== null ? adata.length : 0, - clen = ((counter - 1) << 4) + len; - (heap[0] = heap[1] = heap[2] = 0), - (heap[3] = alen >>> 29), - (heap[4] = alen >>> 21), - (heap[5] = (alen >>> 13) & 255), - (heap[6] = (alen >>> 5) & 255), - (heap[7] = (alen << 3) & 255), - (heap[8] = heap[9] = heap[10] = 0), - (heap[11] = clen >>> 29), - (heap[12] = (clen >>> 21) & 255), - (heap[13] = (clen >>> 13) & 255), - (heap[14] = (clen >>> 5) & 255), - (heap[15] = (clen << 3) & 255); - asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16); - asm.get_iv(AES_asm.HEAP_DATA); - - asm.set_counter(0, 0, 0, this.gamma0); - asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); - result.set(heap.subarray(0, tagSize), len); - - this.result = result; - this.counter = 1; - this.pos = 0; - this.len = 0; - - return this; - } - - AES_GCM_Decrypt_process(data) { - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var dpos = 0, - dlen = data.length || 0, - asm = this.asm, - heap = this.heap, - counter = this.counter, - tagSize = this.tagSize, - pos = this.pos, - len = this.len, - rpos = 0, - rlen = len + dlen > tagSize ? (len + dlen - tagSize) & -16 : 0, - tlen = len + dlen - rlen, - wlen = 0; - - if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength) throw new RangeError('counter overflow'); - - var result = new Uint8Array(rlen); - - while (dlen > tlen) { - wlen = _heap_write(heap, pos + len, data, dpos, dlen - tlen); - len += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, wlen); - wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, wlen); - - if (wlen) result.set(heap.subarray(pos, pos + wlen), rpos); - counter += wlen >>> 4; - rpos += wlen; - - pos = 0; - len = 0; - } - - if (dlen > 0) { - len += _heap_write(heap, 0, data, dpos, dlen); - } - - this.result = result; - this.counter = counter; - this.pos = pos; - this.len = len; - - return this; - } - - AES_GCM_Decrypt_finish() { - var asm = this.asm, - heap = this.heap, - tagSize = this.tagSize, - adata = this.adata, - counter = this.counter, - pos = this.pos, - len = this.len, - rlen = len - tagSize, - wlen = 0; - - if (len < tagSize) throw new IllegalStateError('authentication tag not found'); - - var result = new Uint8Array(rlen), - atag = new Uint8Array(heap.subarray(pos + rlen, pos + len)); - - for (var i = rlen; i & 15; i++) heap[pos + i] = 0; - - wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, i); - wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, i); - if (rlen) result.set(heap.subarray(pos, pos + rlen)); - - var alen = adata !== null ? adata.length : 0, - clen = ((counter - 1) << 4) + len - tagSize; - (heap[0] = heap[1] = heap[2] = 0), - (heap[3] = alen >>> 29), - (heap[4] = alen >>> 21), - (heap[5] = (alen >>> 13) & 255), - (heap[6] = (alen >>> 5) & 255), - (heap[7] = (alen << 3) & 255), - (heap[8] = heap[9] = heap[10] = 0), - (heap[11] = clen >>> 29), - (heap[12] = (clen >>> 21) & 255), - (heap[13] = (clen >>> 13) & 255), - (heap[14] = (clen >>> 5) & 255), - (heap[15] = (clen << 3) & 255); - asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16); - asm.get_iv(AES_asm.HEAP_DATA); - - asm.set_counter(0, 0, 0, this.gamma0); - asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); - - var acheck = 0; - for (var i = 0; i < tagSize; ++i) acheck |= atag[i] ^ heap[i]; - if (acheck) throw new SecurityError('data integrity check failed'); - - this.result = result; - this.counter = 1; - this.pos = 0; - this.len = 0; - - return this; - } - - AES_GCM_decrypt(data) { - var result1 = this.AES_GCM_Decrypt_process(data).result; - var result2 = this.AES_GCM_Decrypt_finish().result; - - var result = new Uint8Array(result1.length + result2.length); - if (result1.length) result.set(result1); - if (result2.length) result.set(result2, result1.length); - this.result = result; - - return this; - } - - AES_GCM_encrypt(data) { - var result1 = this.AES_GCM_Encrypt_process(data).result; - var result2 = this.AES_GCM_Encrypt_finish().result; - - var result = new Uint8Array(result1.length + result2.length); - if (result1.length) result.set(result1); - if (result2.length) result.set(result2, result1.length); - this.result = result; - - return this; - } - - AES_GCM_reset(key, tagSize, nonce, adata, counter, iv) { - this.AES_reset(key, undefined, false); - - var asm = this.asm; - var heap = this.heap; - - asm.gcm_init(); - - var tagSize = tagSize; - if (tagSize !== undefined) { - if (!is_number(tagSize)) throw new TypeError('tagSize must be a number'); - - if (tagSize < 4 || tagSize > 16) throw new IllegalArgumentError('illegal tagSize value'); - - this.tagSize = tagSize; - } else { - this.tagSize = 16; - } - - if (nonce !== undefined) { - if (!is_bytes(nonce)) { - throw new TypeError('unexpected nonce type'); - } - - this.nonce = nonce; - - var noncelen = nonce.length || 0, - noncebuf = new Uint8Array(16); - if (noncelen !== 12) { - this._gcm_mac_process(nonce); - - (heap[0] = heap[1] = heap[2] = heap[3] = heap[4] = heap[5] = heap[6] = heap[7] = heap[8] = heap[9] = heap[10] = 0), - (heap[11] = noncelen >>> 29), - (heap[12] = (noncelen >>> 21) & 255), - (heap[13] = (noncelen >>> 13) & 255), - (heap[14] = (noncelen >>> 5) & 255), - (heap[15] = (noncelen << 3) & 255); - asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16); - - asm.get_iv(AES_asm.HEAP_DATA); - asm.set_iv(); - - noncebuf.set(heap.subarray(0, 16)); - } else { - noncebuf.set(nonce); - noncebuf[15] = 1; - } - - var nonceview = new DataView(noncebuf.buffer); - this.gamma0 = nonceview.getUint32(12); - - asm.set_nonce(nonceview.getUint32(0), nonceview.getUint32(4), nonceview.getUint32(8), 0); - asm.set_mask(0, 0, 0, 0xffffffff); - } else { - throw new Error('nonce is required'); - } - - if (adata !== undefined && adata !== null) { - if (!is_bytes(adata)) { - throw new TypeError('unexpected adata type'); - } - - if (adata.length > _AES_GCM_data_maxLength) throw new IllegalArgumentError('illegal adata length'); - - if (adata.length) { - this.adata = adata; - this._gcm_mac_process(adata); - } else { - this.adata = null; - } - } else { - this.adata = null; - } - - if (counter !== undefined) { - if (!is_number(counter)) throw new TypeError('counter must be a number'); - - if (counter < 1 || counter > 0xffffffff) throw new RangeError('counter must be a positive 32-bit integer'); - - this.counter = counter; - asm.set_counter(0, 0, 0, (this.gamma0 + counter) | 0); - } else { - this.counter = 1; - asm.set_counter(0, 0, 0, (this.gamma0 + 1) | 0); - } - - if (iv !== undefined) { - if (!is_number(iv)) throw new TypeError('iv must be a number'); - - this.iv = iv; - - this.AES_set_iv(iv); - } - - return this; - } - - _gcm_mac_process(data) { - var heap = this.heap, - asm = this.asm, - dpos = 0, - dlen = data.length || 0, - wlen = 0; - - while (dlen > 0) { - wlen = _heap_write(heap, 0, data, dpos, dlen); - dpos += wlen; - dlen -= wlen; - - while (wlen & 15) heap[wlen++] = 0; - - asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, wlen); - } - } -} - -export class AES_GCM_Encrypt extends AES_GCM { - constructor(key, nonce, adata, tagSize, heap, asm) { - super(key, nonce, adata, tagSize, heap, asm); - } - process(data) { - return this.AES_GCM_Encrypt_process(data); - } - finish() { - return this.AES_GCM_Encrypt_finish(); - } -} - -export class AES_GCM_Decrypt extends AES_GCM { - constructor(key, nonce, adata, tagSize, heap, asm) { - super(key, nonce, adata, tagSize, heap, asm); - } - - process(data) { - return this.AES_GCM_Decrypt_process(data); - } - finish() { - return this.AES_GCM_Decrypt_finish(); - } -} diff --git a/src/aes/ofb.ts b/src/aes/ofb.ts new file mode 100644 index 0000000..c2a0411 --- /dev/null +++ b/src/aes/ofb.ts @@ -0,0 +1,25 @@ +import { AES } from './aes'; + +export class AES_OFB extends AES { + static encrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { + return new AES_OFB(key, iv).encrypt(data).result as Uint8Array; + } + + static decrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { + return new AES_OFB(key, iv).decrypt(data).result as Uint8Array; + } + + constructor(key: Uint8Array, iv?: Uint8Array) { + super(key, iv, false, 'OFB'); + } + + encrypt(data: Uint8Array): this { + this.AES_Encrypt_process(data); + return this.AES_Encrypt_finish(); + } + + decrypt(data: Uint8Array): this { + this.AES_Decrypt_process(data); + return this.AES_Decrypt_finish(); + } +} diff --git a/src/aes/ofb/exports.js b/src/aes/ofb/exports.js deleted file mode 100644 index 4201df4..0000000 --- a/src/aes/ofb/exports.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * AES-OFB exports - */ - -import { _AES_asm_instance, _AES_heap_instance } from '../exports'; -import { AES_OFB, AES_OFB_Crypt } from './ofb'; - -/** - * @param {Uint8Array} data - * @param {Uint8Array} key - * @param {Uint8Array} iv - */ -function AES_OFB_crypt_bytes(data, key, iv) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new AES_OFB(key, iv, _AES_heap_instance, _AES_asm_instance).encrypt(data).result; -} - -AES_OFB.encrypt = AES_OFB_crypt_bytes; -AES_OFB.decrypt = AES_OFB_crypt_bytes; - -export { AES_OFB, AES_OFB_Crypt }; diff --git a/src/aes/ofb/ofb.js b/src/aes/ofb/ofb.js deleted file mode 100644 index 394fd30..0000000 --- a/src/aes/ofb/ofb.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Output Feedback (OFB) - */ - -import { AES } from '../aes'; - -export class AES_OFB extends AES { - /** - * @param {Uint8Array} key - * @param {Uint8Array} iv - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, heap, asm) { - super(key, iv, false, heap, asm); - - this.mode = 'OFB'; - this.BLOCK_SIZE = 16; - } - - /** - * @param {Uint8Array} data - * @return {AES_OFB} - */ - encrypt(data) { - return this.AES_Encrypt_finish(data); - } - - /** - * @param {Uint8Array} data - * @return {AES_OFB} - */ - decrypt(data) { - return this.AES_Encrypt_finish(data); - } -} - -export class AES_OFB_Crypt extends AES_OFB { - /** - * @param {Uint8Array} key - * @param {Uint8Array} iv - * @param {Uint8Array} [heap] - * @param {Uint8Array} [asm] - */ - constructor(key, iv, heap, asm) { - super(key, iv, heap, asm); - this.BLOCK_SIZE = 16; - } - - /** - * @param {Uint8Array} data - * @return {AES_OFB_Crypt} - */ - process(data) { - return this.AES_Encrypt_process(data); - } - - /** - * @param {Uint8Array} data - * @return {AES_OFB_Crypt} - */ - finish(data) { - return this.AES_Encrypt_finish(data); - } -} diff --git a/src/bignum/bigint.asm.d.ts b/src/bignum/bigint.asm.d.ts new file mode 100644 index 0000000..9743b67 --- /dev/null +++ b/src/bignum/bigint.asm.d.ts @@ -0,0 +1,51 @@ +declare interface bigintresult { + sreset: (n?: number) => number; + salloc: (n?: number) => number; + sfree: (n?: number) => void; + z: (l?: number, z?: number, A?: number) => void; + tst: (A?: number, lA?: number) => 0; + neg: (A?: number, lA?: number, R?: number, lR?: number) => number; + cmp: (A?: number, lA?: number, B?: number, lB?: number) => 0; + add: ( + A?: number, + lA?: number, + B?: number, + lB?: number, + R?: number, + lR?: number, + ) => number; + sub: ( + A?: number, + lA?: number, + B?: number, + lB?: number, + R?: number, + lR?: number, + ) => number; + mul: ( + A?: number, + lA?: number, + B?: number, + lB?: number, + R?: number, + lR?: number, + ) => void; + sqr: (A?: number, lA?: number, R?: number) => void; + div: ( + N?: number, + lN?: number, + D?: number, + lD?: number, + Q?: number, + ) => void; + mredc: ( + A?: number, + lA?: number, + N?: number, + lN?: number, + y?: number, + R?: number, + ) => void; +} + +export function bigint_asm(stdlib: any, foreign: any, buffer: ArrayBuffer): bigintresult; diff --git a/src/bignum/bignum.js b/src/bignum/bignum.ts similarity index 67% rename from src/bignum/bignum.js rename to src/bignum/bignum.ts index 754691e..2189430 100644 --- a/src/bignum/bignum.js +++ b/src/bignum/bignum.ts @@ -1,23 +1,16 @@ -import { Random_getValues } from '../random/random'; -import { bigint_asm } from './bigint.asm'; -import { is_buffer, is_bytes, is_number, is_string, string_to_bytes, pow2_ceil } from '../utils'; -import { IllegalArgumentError } from '../errors'; +import { bigint_asm, bigintresult } from './bigint.asm'; +import { string_to_bytes } from '../other/utils'; +import { IllegalArgumentError } from '../other/errors'; import { BigNumber_extGCD, Number_extGCD } from './extgcd'; - -export function is_big_number(a) { - return a instanceof BigNumber; -} +import { getRandomValues } from '../other/get-random-values'; /////////////////////////////////////////////////////////////////////////////// -export var _bigint_stdlib = { Uint32Array: Uint32Array, Math: Math }; -export var _bigint_heap = new Uint32Array(0x100000); -export var _bigint_asm; - -// Small primes for trail division -const _primes = [2, 3 /* and so on, computed lazily */]; +export const _bigint_stdlib = { Uint32Array: Uint32Array, Math: Math }; +export const _bigint_heap = new Uint32Array(0x100000); +export let _bigint_asm: bigintresult; -function _half_imul(a, b) { +function _half_imul(a: number, b: number) { return (a * b) | 0; } @@ -34,20 +27,20 @@ if (_bigint_stdlib.Math.imul === undefined) { const _BigNumber_ZERO_limbs = new Uint32Array(0); export class BigNumber { - /** - * @param {string} str - * @return {BigNumber} - */ - static fromString(str) { + public limbs!: Uint32Array; + public bitLength!: number; + public sign!: number; + + static extGCD = BigNumber_extGCD; + static ZERO = BigNumber.fromNumber(0); + static ONE = BigNumber.fromNumber(1); + + static fromString(str: string): BigNumber { const bytes = string_to_bytes(str); return new BigNumber(bytes); } - /** - * @param {number} num - * @return {BigNumber} - */ - static fromNumber(num) { + static fromNumber(num: number): BigNumber { let limbs = _BigNumber_ZERO_limbs; let bitlen = 0; let sign = 0; @@ -71,19 +64,11 @@ export class BigNumber { return BigNumber.fromConfig({ limbs, bitLength: bitlen, sign }); } - /** - * @param {ArrayBuffer} buffer - * @return {BigNumber} - */ - static fromArrayBuffer(buffer) { + static fromArrayBuffer(buffer: ArrayBuffer): BigNumber { return new BigNumber(new Uint8Array(buffer)); } - /** - * @param {{ limbs: Uint32Array, bitLength: number, sign: number }} obj - * @return {BigNumber} - */ - static fromConfig(obj) { + static fromConfig(obj: { limbs: Uint32Array; bitLength: number; sign: number }): BigNumber { const bn = new BigNumber(); bn.limbs = new Uint32Array(obj.limbs); bn.bitLength = obj.bitLength; @@ -91,22 +76,18 @@ export class BigNumber { return bn; } - /** - * @param {Uint8Array} [num] - * @return {BigNumber} - */ - constructor(num) { + constructor(num?: Uint8Array) { let limbs = _BigNumber_ZERO_limbs; let bitlen = 0; let sign = 0; if (num === undefined) { // do nothing - } else if (is_bytes(num)) { + } else { for (var i = 0; !num[i]; i++); bitlen = (num.length - i) * 8; - if (!bitlen) return BigNumber_ZERO; + if (!bitlen) return BigNumber.ZERO; limbs = new Uint32Array((bitlen + 31) >> 5); for (var j = num.length - 4; j >= i; j -= 4) { @@ -121,8 +102,6 @@ export class BigNumber { } sign = 1; - } else { - throw new TypeError('number is of unexpected type'); } this.limbs = limbs; @@ -130,11 +109,7 @@ export class BigNumber { this.sign = sign; } - /** - * @param {number} radix - * @return {string} - */ - toString(radix) { + toString(radix: number): string { radix = radix || 16; const limbs = this.limbs; @@ -161,10 +136,7 @@ export class BigNumber { return str; } - /** - * @return {Uint8Array} - */ - toBytes() { + toBytes(): Uint8Array { const bitlen = this.bitLength; const limbs = this.limbs; @@ -182,10 +154,8 @@ export class BigNumber { /** * Downgrade to Number - * - * @return {number} */ - valueOf() { + valueOf(): number { const limbs = this.limbs; const bits = this.bitLength; const sign = this.sign; @@ -216,11 +186,7 @@ export class BigNumber { ); } - /** - * @param {number} b - * @return {BigNumber} - */ - clamp(b) { + clamp(b: number): BigNumber { const limbs = this.limbs; const bitlen = this.bitLength; @@ -241,22 +207,13 @@ export class BigNumber { return clamped; } - /** - * @param {number} f - * @param {number} [b] - * @return {BigNumber} - */ - slice(f, b) { - if (!is_number(f)) throw new TypeError('TODO'); - - if (b !== undefined && !is_number(b)) throw new TypeError('TODO'); - + slice(f: number, b?: number): BigNumber { const limbs = this.limbs; const bitlen = this.bitLength; if (f < 0) throw new RangeError('TODO'); - if (f >= bitlen) return BigNumber_ZERO; + if (f >= bitlen) return BigNumber.ZERO; if (b === undefined || b > bitlen - f) b = bitlen - f; @@ -288,10 +245,7 @@ export class BigNumber { return sliced; } - /** - * @return {BigNumber} - */ - negate() { + negate(): BigNumber { const negative = new BigNumber(); negative.limbs = this.limbs; @@ -301,11 +255,7 @@ export class BigNumber { return negative; } - /** - * @param {BigNumber} that - * @return {number} - */ - compare(that) { + compare(that: BigNumber): number { var alimbs = this.limbs, alimbcnt = alimbs.length, blimbs = that.limbs, @@ -323,11 +273,7 @@ export class BigNumber { return z * this.sign; } - /** - * @param {BigNumber} that - * @return {BigNumber} - */ - add(that) { + add(that: BigNumber): BigNumber { if (!this.sign) return that; if (!that.sign) return this; @@ -373,7 +319,7 @@ export class BigNumber { if (rof) _bigint_asm.neg(pR, rlimbcnt << 2, pR, rlimbcnt << 2); - if (_bigint_asm.tst(pR, rlimbcnt << 2) === 0) return BigNumber_ZERO; + if (_bigint_asm.tst(pR, rlimbcnt << 2) === 0) return BigNumber.ZERO; result.limbs = new Uint32Array(_bigint_heap.subarray(pR >> 2, (pR >> 2) + rlimbcnt)); result.bitLength = rbitlen; @@ -382,19 +328,12 @@ export class BigNumber { return result; } - /** - * @param {BigNumber} that - * @return {BigNumber} - */ - subtract(that) { + subtract(that: BigNumber): BigNumber { return this.add(that.negate()); } - /** - * @return {BigNumber} - */ - square() { - if (!this.sign) return BigNumber_ZERO; + square(): BigNumber { + if (!this.sign) return BigNumber.ZERO; var abitlen = this.bitLength, alimbs = this.limbs, @@ -424,11 +363,7 @@ export class BigNumber { return result; } - /** - * @param {BigNumber} that - * @return {{quotient: BigNumber, remainder: BigNumber}} - */ - divide(that) { + divide(that: BigNumber): { quotient: BigNumber; remainder: BigNumber } { var abitlen = this.bitLength, alimbs = this.limbs, alimbcnt = alimbs.length, @@ -437,8 +372,8 @@ export class BigNumber { blimbcnt = blimbs.length, qlimbcnt, rlimbcnt, - quotient = BigNumber_ZERO, - remainder = BigNumber_ZERO; + quotient = BigNumber.ZERO, + remainder = BigNumber.ZERO; _bigint_asm.sreset(); @@ -475,12 +410,8 @@ export class BigNumber { }; } - /** - * @param {BigNumber} that - * @return {BigNumber} - */ - multiply(that) { - if (!this.sign || !that.sign) return BigNumber_ZERO; + multiply(that: BigNumber): BigNumber { + if (!this.sign || !that.sign) return BigNumber.ZERO; var abitlen = this.bitLength, alimbs = this.limbs, @@ -515,12 +446,7 @@ export class BigNumber { return result; } - /** - * @param {number} rounds - * @return {boolean} - * @private - */ - isMillerRabinProbablePrime(rounds) { + public isMillerRabinProbablePrime(rounds: number): boolean { var t = BigNumber.fromConfig(this), s = 0; t.limbs[0] -= 1; @@ -529,24 +455,24 @@ export class BigNumber { t = t.slice(s); var m = new Modulus(this), - m1 = this.subtract(BigNumber_ONE), + m1 = this.subtract(BigNumber.ONE), a = BigNumber.fromConfig(this), l = this.limbs.length - 1; while (a.limbs[l] === 0) l--; while (--rounds >= 0) { - Random_getValues(a.limbs); + getRandomValues(a.limbs); if (a.limbs[0] < 2) a.limbs[0] += 2; while (a.compare(m1) >= 0) a.limbs[l] >>>= 1; var x = m.power(a, t); - if (x.compare(BigNumber_ONE) === 0) continue; + if (x.compare(BigNumber.ONE) === 0) continue; if (x.compare(m1) === 0) continue; var c = s; while (--c > 0) { x = x.square().divide(m).remainder; - if (x.compare(BigNumber_ONE) === 0) return false; + if (x.compare(BigNumber.ONE) === 0) return false; if (x.compare(m1) === 0) break; } @@ -556,13 +482,7 @@ export class BigNumber { return true; } - /** - * @param {number} [paranoia] - * @return {boolean} - */ - isProbablePrime(paranoia) { - paranoia = paranoia || 80; - + isProbablePrime(paranoia: number = 80): boolean { var limbs = this.limbs; var i = 0; @@ -608,95 +528,14 @@ export class BigNumber { } } -export const BigNumber_ZERO = BigNumber.fromNumber(0); -export const BigNumber_ONE = BigNumber.fromNumber(1); - -/** - * Returns an array populated with first n primes. - * - * @param {number} n - * @return {number[]} - * @private - */ -function _small_primes(n) { - if (_primes.length >= n) return _primes.slice(0, n); - - for (let p = _primes[_primes.length - 1] + 2; _primes.length < n; p += 2) { - for (var i = 0, d = _primes[i]; d * d <= p; d = _primes[++i]) { - if (p % d == 0) break; - } - if (d * d > p) _primes.push(p); - } - - return _primes; -} - -/** - * Returns strong pseudoprime of a specified bit length - * - * @param {number} bitlen - * @param {function(BigNumber): boolean} filter - * @return {BigNumber} - */ -export function randomProbablePrime(bitlen, filter) { - let limbcnt = (bitlen + 31) >> 5; - const prime = BigNumber.fromConfig({ sign: 1, bitLength: bitlen, limbs: new Uint32Array(limbcnt) }); - const limbs = prime.limbs; - - // Number of small divisors to try that minimizes the total cost of the trial division - // along with the first round of Miller-Rabin test for a certain bit length. - let k = 10000; - if (bitlen <= 512) k = 2200; - if (bitlen <= 256) k = 600; - - let divisors = _small_primes(k); - const remainders = new Uint32Array(k); - - // Number of Miller-Rabin iterations for an error rate of less than 2^-80 - // Damgaard, Landrock, Pomerance: Average case error estimates for the strong probable prime test. - const s = (bitlen * Math.LN2) | 0; - let r = 27; - if (bitlen >= 250) r = 12; - if (bitlen >= 450) r = 6; - if (bitlen >= 850) r = 3; - if (bitlen >= 1300) r = 2; - - while (true) { - // populate `prime` with random bits, clamp to the appropriate bit length - Random_getValues(limbs); - limbs[0] |= 1; - limbs[limbcnt - 1] |= 1 << ((bitlen - 1) & 31); - if (bitlen & 31) limbs[limbcnt - 1] &= pow2_ceil((bitlen + 1) & 31) - 1; - - // remainders from division to small primes - remainders[0] = 1; - for (let i = 1; i < k; i++) { - remainders[i] = prime.divide(BigNumber.fromNumber(divisors[i])).remainder.valueOf(); - } - - // try no more than `s` subsequent candidates - seek: for (let j = 0; j < s; j += 2, limbs[0] += 2) { - // check for small factors - for (let i = 1; i < k; i++) { - if ((remainders[i] + j) % divisors[i] === 0) continue seek; - } - - // additional check just before the heavy lifting - if (typeof filter === 'function' && !filter(prime)) continue; - - // proceed to Miller-Rabin test - if (prime.isMillerRabinProbablePrime(r)) return prime; - } - } -} - export class Modulus extends BigNumber { - /** - * Modulus - * - * @param {BigNumber} number - */ - constructor(number) { + // @ts-ignore + private comodulus!: BigNumber; + private comodulusRemainder!: BigNumber; + private comodulusRemainderSquare!: BigNumber; + private coefficient!: number; + + constructor(number: BigNumber) { super(); this.limbs = number.limbs; this.bitLength = number.bitLength; @@ -706,7 +545,7 @@ export class Modulus extends BigNumber { if (this.bitLength <= 32) return; - let comodulus; + let comodulus: BigNumber; if (this.limbs[0] & 1) { const bitlen = ((this.bitLength + 31) & -32) + 1; @@ -737,12 +576,8 @@ export class Modulus extends BigNumber { /** * Modular reduction - * - * @param {BigNumber} a - * @return {BigNumber} - * @constructor */ - reduce(a) { + reduce(a: BigNumber): BigNumber { if (a.bitLength <= 32 && this.bitLength <= 32) return BigNumber.fromNumber(a.valueOf() % this.valueOf()); if (a.compare(this) < 0) return a; @@ -752,16 +587,12 @@ export class Modulus extends BigNumber { /** * Modular inverse - * - * @param {BigNumber} a - * @return {BigNumber} - * @constructor */ - inverse(a) { + inverse(a: BigNumber): BigNumber { a = this.reduce(a); const r = BigNumber_extGCD(this, a); - if (r.gcd.valueOf() !== 1) return null; + if (r.gcd.valueOf() !== 1) throw new Error('GCD is not 1'); if (r.y.sign < 0) return r.y.add(this).clamp(this.bitLength); @@ -770,13 +601,8 @@ export class Modulus extends BigNumber { /** * Modular exponentiation - * - * @param {BigNumber} g - * @param {BigNumber} e - * @return {BigNumber} - * @constructor */ - power(g, e) { + power(g: BigNumber, e: BigNumber): BigNumber { // count exponent set bits let c = 0; for (let i = 0; i < e.limbs.length; i++) { @@ -798,15 +624,15 @@ export class Modulus extends BigNumber { if (c <= 1 << (k - 1)) k = 1; // montgomerize base - g = _Montgomery_reduce(this.reduce(g).multiply(this.comodulusRemainderSquare), this); + g = Modulus._Montgomery_reduce(this.reduce(g).multiply(this.comodulusRemainderSquare), this); // precompute odd powers - const g2 = _Montgomery_reduce(g.square(), this), + const g2 = Modulus._Montgomery_reduce(g.square(), this), gn = new Array(1 << (k - 1)); gn[0] = g; - gn[1] = _Montgomery_reduce(g.multiply(g2), this); + gn[1] = Modulus._Montgomery_reduce(g.multiply(g2), this); for (let i = 2; i < 1 << (k - 1); i++) { - gn[i] = _Montgomery_reduce(gn[i - 1].multiply(g2), this); + gn[i] = Modulus._Montgomery_reduce(gn[i - 1].multiply(g2), this); } // perform exponentiation @@ -825,52 +651,46 @@ export class Modulus extends BigNumber { var m = gn[n >>> 1]; while (n) { n >>>= 1; - if (r !== u) r = _Montgomery_reduce(r.square(), this); + if (r !== u) r = Modulus._Montgomery_reduce(r.square(), this); } - r = r !== u ? _Montgomery_reduce(r.multiply(m), this) : m; + r = r !== u ? Modulus._Montgomery_reduce(r.multiply(m), this) : m; (t <<= l), (j -= l); } else { - if (r !== u) r = _Montgomery_reduce(r.square(), this); + if (r !== u) r = Modulus._Montgomery_reduce(r.square(), this); (t <<= 1), j--; } } } // de-montgomerize result - return _Montgomery_reduce(r, this); + return Modulus._Montgomery_reduce(r, this); } -} -/** - * @param {BigNumber} a - * @param {Modulus} n - * @return {BigNumber} - * @private - */ -function _Montgomery_reduce(a, n) { - const alimbs = a.limbs; - const alimbcnt = alimbs.length; - const nlimbs = n.limbs; - const nlimbcnt = nlimbs.length; - const y = n.coefficient; + static _Montgomery_reduce(a: BigNumber, n: Modulus): BigNumber { + const alimbs = a.limbs; + const alimbcnt = alimbs.length; + const nlimbs = n.limbs; + const nlimbcnt = nlimbs.length; + const y = n.coefficient; - _bigint_asm.sreset(); + _bigint_asm.sreset(); - const pA = _bigint_asm.salloc(alimbcnt << 2), - pN = _bigint_asm.salloc(nlimbcnt << 2), - pR = _bigint_asm.salloc(nlimbcnt << 2); + const pA = _bigint_asm.salloc(alimbcnt << 2), + pN = _bigint_asm.salloc(nlimbcnt << 2), + pR = _bigint_asm.salloc(nlimbcnt << 2); - _bigint_asm.z(pR - pA + (nlimbcnt << 2), 0, pA); + _bigint_asm.z(pR - pA + (nlimbcnt << 2), 0, pA); - _bigint_heap.set(alimbs, pA >> 2); - _bigint_heap.set(nlimbs, pN >> 2); + _bigint_heap.set(alimbs, pA >> 2); + _bigint_heap.set(nlimbs, pN >> 2); - _bigint_asm.mredc(pA, alimbcnt << 2, pN, nlimbcnt << 2, y, pR); + _bigint_asm.mredc(pA, alimbcnt << 2, pN, nlimbcnt << 2, y, pR); - const result = new BigNumber(); - result.limbs = new Uint32Array(_bigint_heap.subarray(pR >> 2, (pR >> 2) + nlimbcnt)); - result.bitLength = n.bitLength; - result.sign = 1; + const result = new BigNumber(); + result.limbs = new Uint32Array(_bigint_heap.subarray(pR >> 2, (pR >> 2) + nlimbcnt)); + result.bitLength = n.bitLength; + result.sign = 1; - return result; + return result; + } } diff --git a/src/bignum/exports.js b/src/bignum/exports.js deleted file mode 100644 index 87419c1..0000000 --- a/src/bignum/exports.js +++ /dev/null @@ -1,9 +0,0 @@ -import { BigNumber, BigNumber_ONE, BigNumber_ZERO, Modulus } from './bignum'; -import { BigNumber_extGCD } from './extgcd'; - -BigNumber.ZERO = BigNumber_ZERO; -BigNumber.ONE = BigNumber_ONE; - -BigNumber.extGCD = BigNumber_extGCD; - -export { BigNumber, Modulus }; diff --git a/src/bignum/extgcd.js b/src/bignum/extgcd.ts similarity index 62% rename from src/bignum/extgcd.js rename to src/bignum/extgcd.ts index 995a3f4..1f54f8a 100644 --- a/src/bignum/extgcd.js +++ b/src/bignum/extgcd.ts @@ -1,12 +1,6 @@ -import { BigNumber, BigNumber_ONE, BigNumber_ZERO, is_big_number } from './bignum'; - -/** - * @param {number} a - * @param {number} b - * @return {{gcd: number, x: number, y: number}} - * @constructor - */ -export function Number_extGCD(a, b) { +import { BigNumber } from './bignum'; + +export function Number_extGCD(a: number, b: number): { gcd: number; x: number; y: number } { var sa = a < 0 ? -1 : 1, sb = b < 0 ? -1 : 1, xi = 1, @@ -54,45 +48,35 @@ export function Number_extGCD(a, b) { }; } -/** - * @param a - * @param b - * @return {{gcd: BigNumber, x: BigNumber, y: BigNumber}} - * @constructor - */ -export function BigNumber_extGCD(a, b) { - if (!is_big_number(a)) a = new BigNumber(a); - - if (!is_big_number(b)) b = new BigNumber(b); - - var sa = a.sign, - sb = b.sign; +export function BigNumber_extGCD(a: BigNumber, b: BigNumber): { gcd: BigNumber; x: BigNumber; y: BigNumber } { + let sa = a.sign; + let sb = b.sign; if (sa < 0) a = a.negate(); if (sb < 0) b = b.negate(); - var a_cmp_b = a.compare(b); + const a_cmp_b = a.compare(b); if (a_cmp_b < 0) { - var t = a; + let t = a; (a = b), (b = t); - t = sa; + let t2 = sa; sa = sb; - sb = t; + sb = t2; } - var xi = BigNumber_ONE, - xj = BigNumber_ZERO, + var xi = BigNumber.ONE, + xj = BigNumber.ZERO, lx = b.bitLength, - yi = BigNumber_ZERO, - yj = BigNumber_ONE, + yi = BigNumber.ZERO, + yj = BigNumber.ONE, ly = a.bitLength, z, r, q; z = a.divide(b); - while ((r = z.remainder) !== BigNumber_ZERO) { + while ((r = z.remainder) !== BigNumber.ZERO) { q = z.quotient; (z = xi.subtract(q.multiply(xj).clamp(lx)).clamp(lx)), (xi = xj), (xj = z); @@ -108,7 +92,7 @@ export function BigNumber_extGCD(a, b) { if (sb < 0) yj = yj.negate(); if (a_cmp_b < 0) { - var t = xj; + let t = xj; (xj = yj), (yj = t); } diff --git a/src/entry-default.js b/src/entry-default.js deleted file mode 100644 index a9c4f5c..0000000 --- a/src/entry-default.js +++ /dev/null @@ -1,16 +0,0 @@ -export * from './exportedUtils'; - -export * from './errors'; -export * from './aes/cbc/exports'; -export * from './aes/gcm/exports'; -export * from './hash/sha1/exports'; -export * from './hash/sha256/exports'; -export * from './hmac/exports-hmac-sha1'; -export * from './hmac/exports-hmac-sha256'; -export * from './pbkdf2/exports-pbkdf2-hmac-sha1'; -export * from './pbkdf2/exports-pbkdf2-hmac-sha256'; -export * from './random/random'; -export * from './bignum/exports'; -export * from './rsa/pkcs1'; -export * from './random/exports'; -export * from './origin'; diff --git a/src/entry-default.ts b/src/entry-default.ts new file mode 100644 index 0000000..216f411 --- /dev/null +++ b/src/entry-default.ts @@ -0,0 +1,13 @@ +export * from './other/exportedUtils'; + +export * from './other/errors'; +export * from './aes/cbc'; +export * from './aes/gcm'; +export * from './hash/sha1/sha1'; +export * from './hash/sha256/sha256'; +export * from './hmac/hmac-sha1'; +export * from './hmac/hmac-sha256'; +export * from './pbkdf2/pbkdf2-hmac-sha1'; +export * from './pbkdf2/pbkdf2-hmac-sha256'; +export * from './bignum/bignum'; +export * from './rsa/pkcs1'; diff --git a/src/entry-export_all.js b/src/entry-export_all.js deleted file mode 100644 index 55f9b1c..0000000 --- a/src/entry-export_all.js +++ /dev/null @@ -1,31 +0,0 @@ -export * from './exportedUtils'; - -export * from './errors'; -export * from './aes/cbc/exports'; -export * from './aes/ccm/exports'; -export * from './aes/cfb/exports'; -export * from './aes/cmac/exports'; -export * from './aes/ctr/exports'; -export * from './aes/ecb/exports'; -export * from './aes/gcm/exports'; -export * from './aes/ofb/exports'; -export * from './bignum/exports'; -export * from './hash/sha1/exports'; -export * from './hash/sha256/exports'; -export * from './hash/sha512/exports'; -export * from './hmac/exports-hmac-sha1'; -export * from './hmac/exports-hmac-sha256'; -export * from './hmac/exports-hmac-sha512'; -export * from './pbkdf2/exports-pbkdf2-hmac-sha1'; -export * from './pbkdf2/exports-pbkdf2-hmac-sha256'; -export * from './pbkdf2/exports-pbkdf2-hmac-sha512'; -export * from './random/exports'; -export * from './rsa/exports-keygen'; -export * from './rsa/exports-oaep-sha1'; -export * from './rsa/exports-oaep-sha256'; -export * from './rsa/exports-oaep-sha512'; -export * from './rsa/exports-pss-sha1'; -export * from './rsa/exports-pss-sha256'; -export * from './rsa/exports-pss-sha512'; -export * from './rsa/exports-raw'; -export * from './origin'; diff --git a/src/entry-export_all.ts b/src/entry-export_all.ts new file mode 100644 index 0000000..c352d00 --- /dev/null +++ b/src/entry-export_all.ts @@ -0,0 +1,29 @@ +export { + string_to_bytes, + hex_to_bytes, + base64_to_bytes, + bytes_to_string, + bytes_to_hex, + bytes_to_base64, +} from './other/exportedUtils'; +export { IllegalStateError, IllegalArgumentError, SecurityError } from './other/errors'; +export { AES_CBC } from './aes/cbc'; +export { AES_CCM } from './aes/ccm'; +export { AES_CFB } from './aes/cfb'; +export { AES_CMAC } from './aes/cmac'; +export { AES_CTR } from './aes/ctr'; +export { AES_ECB } from './aes/ecb'; +export { AES_GCM } from './aes/gcm'; +export { AES_OFB } from './aes/ofb'; +export { BigNumber, Modulus } from './bignum/bignum'; +export { Sha1 } from './hash/sha1/sha1'; +export { Sha256 } from './hash/sha256/sha256'; +export { Sha512 } from './hash/sha512/sha512'; +export { HmacSha1 } from './hmac/hmac-sha1'; +export { HmacSha256 } from './hmac/hmac-sha256'; +export { HmacSha512 } from './hmac/hmac-sha512'; +export { Pbkdf2HmacSha1 } from './pbkdf2/pbkdf2-hmac-sha1'; +export { Pbkdf2HmacSha256 } from './pbkdf2/pbkdf2-hmac-sha256'; +export { Pbkdf2HmacSha512 } from './pbkdf2/pbkdf2-hmac-sha512'; +export { RSA_OAEP, RSA_PKCS1_v1_5, RSA_PSS } from './rsa/pkcs1'; +export { RSA } from './rsa/rsa'; diff --git a/src/errors.js b/src/errors.js deleted file mode 100644 index d2a8171..0000000 --- a/src/errors.js +++ /dev/null @@ -1,17 +0,0 @@ -export function IllegalStateError() { - var err = Error.apply(this, arguments); - (this.message = err.message), (this.stack = err.stack); -} -IllegalStateError.prototype = Object.create(Error.prototype, { name: { value: 'IllegalStateError' } }); - -export function IllegalArgumentError() { - var err = Error.apply(this, arguments); - (this.message = err.message), (this.stack = err.stack); -} -IllegalArgumentError.prototype = Object.create(Error.prototype, { name: { value: 'IllegalArgumentError' } }); - -export function SecurityError() { - var err = Error.apply(this, arguments); - (this.message = err.message), (this.stack = err.stack); -} -SecurityError.prototype = Object.create(Error.prototype, { name: { value: 'SecurityError' } }); diff --git a/src/hash/hash.js b/src/hash/hash.js deleted file mode 100644 index f55e8ff..0000000 --- a/src/hash/hash.js +++ /dev/null @@ -1,63 +0,0 @@ -import { _heap_write, is_buffer, is_bytes, is_string, string_to_bytes } from '../utils'; -import { IllegalStateError } from '../errors'; - -export function hash_reset() { - this.result = null; - this.pos = 0; - this.len = 0; - - this.asm.reset(); - - return this; -} - -export function hash_process(data) { - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - if (is_string(data)) data = string_to_bytes(data); - - if (is_buffer(data)) data = new Uint8Array(data); - - if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); - - var asm = this.asm, - heap = this.heap, - hpos = this.pos, - hlen = this.len, - dpos = 0, - dlen = data.length, - wlen = 0; - - while (dlen > 0) { - wlen = _heap_write(heap, hpos + hlen, data, dpos, dlen); - hlen += wlen; - dpos += wlen; - dlen -= wlen; - - wlen = asm.process(hpos, hlen); - - hpos += wlen; - hlen -= wlen; - - if (!hlen) hpos = 0; - } - - this.pos = hpos; - this.len = hlen; - - return this; -} - -export function hash_finish() { - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - this.asm.finish(this.pos, this.len, 0); - - this.result = new Uint8Array(this.HASH_SIZE); - this.result.set(this.heap.subarray(0, this.HASH_SIZE)); - - this.pos = 0; - this.len = 0; - - return this; -} diff --git a/src/hash/hash.ts b/src/hash/hash.ts new file mode 100644 index 0000000..52f112e --- /dev/null +++ b/src/hash/hash.ts @@ -0,0 +1,70 @@ +import { _heap_write } from '../other/utils'; +import { IllegalStateError } from '../other/errors'; +import { sha1result } from './sha1/sha1.asm'; +import { sha256result } from './sha256/sha256.asm'; +import { sha512result } from './sha512/sha512.asm'; + +export abstract class Hash { + public result!: Uint8Array | null; + public pos: number = 0; + public len: number = 0; + public asm!: T; + public heap!: Uint8Array; + public BLOCK_SIZE!: number; + public HASH_SIZE!: number; + + reset() { + this.result = null; + this.pos = 0; + this.len = 0; + + this.asm.reset(); + + return this; + } + + process(data: Uint8Array) { + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + let asm = this.asm; + let heap = this.heap; + let hpos = this.pos; + let hlen = this.len; + let dpos = 0; + let dlen = data.length; + let wlen = 0; + + while (dlen > 0) { + wlen = _heap_write(heap, hpos + hlen, data, dpos, dlen); + hlen += wlen; + dpos += wlen; + dlen -= wlen; + + wlen = asm.process(hpos, hlen); + + hpos += wlen; + hlen -= wlen; + + if (!hlen) hpos = 0; + } + + this.pos = hpos; + this.len = hlen; + + return this; + } + + finish() { + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + this.asm.finish(this.pos, this.len, 0); + + this.result = new Uint8Array(this.HASH_SIZE); + this.result.set(this.heap.subarray(0, this.HASH_SIZE)); + + this.pos = 0; + this.len = 0; + + return this; + } +} diff --git a/src/hash/sha1/exports.js b/src/hash/sha1/exports.js deleted file mode 100644 index 3b49d53..0000000 --- a/src/hash/sha1/exports.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * SHA1 exports - */ - -import { get_sha1_instance, sha1_constructor } from './sha1'; -import { bytes_to_base64, bytes_to_hex } from '../../utils'; - -function sha1_bytes(data) { - if (data === undefined) throw new SyntaxError('data required'); - return get_sha1_instance() - .reset() - .process(data) - .finish().result; -} - -function sha1_hex(data) { - var result = sha1_bytes(data); - return bytes_to_hex(result); -} - -function sha1_base64(data) { - var result = sha1_bytes(data); - return bytes_to_base64(result); -} - -export var SHA1 = sha1_constructor; - -SHA1.bytes = sha1_bytes; -SHA1.hex = sha1_hex; -SHA1.base64 = sha1_base64; diff --git a/src/hash/sha1/sha1.asm.d.ts b/src/hash/sha1/sha1.asm.d.ts new file mode 100644 index 0000000..0ba8dc6 --- /dev/null +++ b/src/hash/sha1/sha1.asm.d.ts @@ -0,0 +1,62 @@ +declare interface sha1result { + // SHA1 + reset: () => void; + init: (h0: number, h1: number, h2: number, h3: number, h4: number, total0: number, total1: number) => void; + + /** + * @param offset - multiple of 64 + * @param length + * @returns hashed + */ + process: (offset: number, length: number) => number; + + /** + * @param offset - multiple of 64 + * @param length + * @param output - multiple of 32 + * @returns hashed + */ + finish: (offset: number, length: number, output: number) => number; + + // HMAC-SHA; + hmac_reset: () => void; + hmac_init: ( + p0: number, + p1: number, + p2: number, + p3: number, + p4: number, + p5: number, + p6: number, + p7: number, + p8: number, + p9: number, + p10: number, + p11: number, + p12: number, + p13: number, + p14: number, + p15: number, + ) => void; + + /** + * @param offset - multiple of 64 + * @param length + * @param output - multiple of 32 + * @returns hashed + */ + hmac_finish: (offset: number, length: number, output: number) => number; + + // ; + /** + * PBKDF2-HMAC-SHA + * @param offset - multiple of 64 + * @param length + * @param block + * @param count + * @param output - multiple of 32 + */ + pbkdf2_generate_block: (offset: number, length: number, block: number, count: number, output: number) => 0 | -1; +} + +export function sha1_asm(stdlib: any, foreign: any, buffer: ArrayBuffer): sha1result; diff --git a/src/hash/sha1/sha1.asm.js b/src/hash/sha1/sha1.asm.js index 0653916..62ff31a 100644 --- a/src/hash/sha1/sha1.asm.js +++ b/src/hash/sha1/sha1.asm.js @@ -849,18 +849,18 @@ export function sha1_asm ( stdlib, foreign, buffer ) { } return { - // SHA1 - reset: reset, - init: init, - process: process, - finish: finish, - - // HMAC-SHA1 - hmac_reset: hmac_reset, - hmac_init: hmac_init, - hmac_finish: hmac_finish, - - // PBKDF2-HMAC-SHA1 - pbkdf2_generate_block: pbkdf2_generate_block + // SHA1 + reset: reset, + init: init, + process: process, + finish: finish, + + // HMAC-SHA1 + hmac_reset: hmac_reset, + hmac_init: hmac_init, + hmac_finish: hmac_finish, + + // PBKDF2-HMAC-SHA1 + pbkdf2_generate_block: pbkdf2_generate_block } } diff --git a/src/hash/sha1/sha1.js b/src/hash/sha1/sha1.js deleted file mode 100644 index b4c3bb1..0000000 --- a/src/hash/sha1/sha1.js +++ /dev/null @@ -1,34 +0,0 @@ -import { sha1_asm } from './sha1.asm'; -import { hash_finish, hash_process, hash_reset } from '../hash'; -import { _heap_init } from '../../utils'; - -export var _sha1_block_size = 64; -export var _sha1_hash_size = 20; - -export function sha1_constructor(options) { - options = options || {}; - - this.heap = _heap_init(Uint8Array, options.heap); - this.asm = options.asm || sha1_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer); - - this.BLOCK_SIZE = _sha1_block_size; - this.HASH_SIZE = _sha1_hash_size; - - this.reset(); -} - -sha1_constructor.BLOCK_SIZE = _sha1_block_size; -sha1_constructor.NAME = 'sha1'; - -sha1_constructor.HASH_SIZE = _sha1_hash_size; -var sha1_prototype = sha1_constructor.prototype; -sha1_prototype.reset = hash_reset; -sha1_prototype.process = hash_process; -sha1_prototype.finish = hash_finish; - -var sha1_instance = null; - -export function get_sha1_instance() { - if (sha1_instance === null) sha1_instance = new sha1_constructor({ heapSize: 0x100000 }); - return sha1_instance; -} diff --git a/src/hash/sha1/sha1.ts b/src/hash/sha1/sha1.ts new file mode 100644 index 0000000..55d1292 --- /dev/null +++ b/src/hash/sha1/sha1.ts @@ -0,0 +1,22 @@ +import { sha1_asm, sha1result } from './sha1.asm'; +import { Hash } from '../hash'; +import { _heap_init } from '../../other/utils'; + +export const _sha1_block_size = 64; +export const _sha1_hash_size = 20; + +export class Sha1 extends Hash { + static NAME = 'sha1'; + public NAME = 'sha1'; + public BLOCK_SIZE = _sha1_block_size; + public HASH_SIZE = _sha1_hash_size; + + constructor() { + super(); + + this.heap = _heap_init(); + this.asm = sha1_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer); + + this.reset(); + } +} diff --git a/src/hash/sha256/exports.js b/src/hash/sha256/exports.js deleted file mode 100644 index 73c9549..0000000 --- a/src/hash/sha256/exports.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * SHA256 exports - */ - -import { get_sha256_instance, sha256_constructor } from './sha256'; -import { bytes_to_base64, bytes_to_hex } from '../../utils'; - -function sha256_bytes(data) { - if (data === undefined) throw new SyntaxError('data required'); - return get_sha256_instance() - .reset() - .process(data) - .finish().result; -} - -function sha256_hex(data) { - var result = sha256_bytes(data); - return bytes_to_hex(result); -} - -function sha256_base64(data) { - var result = sha256_bytes(data); - return bytes_to_base64(result); -} - -export var SHA256 = sha256_constructor; -SHA256.bytes = sha256_bytes; -SHA256.hex = sha256_hex; -SHA256.base64 = sha256_base64; diff --git a/src/hash/sha256/sha256.asm.d.ts b/src/hash/sha256/sha256.asm.d.ts new file mode 100644 index 0000000..b68314f --- /dev/null +++ b/src/hash/sha256/sha256.asm.d.ts @@ -0,0 +1,62 @@ +declare interface sha256result { + // SHA1 + reset: () => void; + init: (h0: number, h1: number, h2: number, h3: number, h4: number, total0: number, total1: number) => void; + + /** + * @param offset - multiple of 64 + * @param length + * @returns hashed + */ + process: (offset: number, length: number) => number; + + /** + * @param offset - multiple of 64 + * @param length + * @param output - multiple of 32 + * @returns hashed + */ + finish: (offset: number, length: number, output: number) => number; + + // HMAC-SHA; + hmac_reset: () => void; + hmac_init: ( + p0: number, + p1: number, + p2: number, + p3: number, + p4: number, + p5: number, + p6: number, + p7: number, + p8: number, + p9: number, + p10: number, + p11: number, + p12: number, + p13: number, + p14: number, + p15: number, + ) => void; + + /** + * @param offset - multiple of 64 + * @param length + * @param output - multiple of 32 + * @returns hashed + */ + hmac_finish: (offset: number, length: number, output: number) => number; + + // ; + /** + * PBKDF2-HMAC-SHA + * @param offset - multiple of 64 + * @param length + * @param block + * @param count + * @param output - multiple of 32 + */ + pbkdf2_generate_block: (offset: number, length: number, block: number, count: number, output: number) => 0 | -1; +} + +export function sha256_asm(stdlib: any, foreign: any, buffer: ArrayBuffer): sha256result; diff --git a/src/hash/sha256/sha256.asm.js b/src/hash/sha256/sha256.asm.js index 088b328..acf6908 100644 --- a/src/hash/sha256/sha256.asm.js +++ b/src/hash/sha256/sha256.asm.js @@ -808,18 +808,18 @@ export function sha256_asm ( stdlib, foreign, buffer ) { } return { - // SHA256 - reset: reset, - init: init, - process: process, - finish: finish, - - // HMAC-SHA256 - hmac_reset: hmac_reset, - hmac_init: hmac_init, - hmac_finish: hmac_finish, - - // PBKDF2-HMAC-SHA256 - pbkdf2_generate_block: pbkdf2_generate_block + // SHA256 + reset: reset, + init: init, + process: process, + finish: finish, + + // HMAC-SHA256 + hmac_reset: hmac_reset, + hmac_init: hmac_init, + hmac_finish: hmac_finish, + + // PBKDF2-HMAC-SHA256 + pbkdf2_generate_block: pbkdf2_generate_block } } diff --git a/src/hash/sha256/sha256.js b/src/hash/sha256/sha256.js deleted file mode 100644 index 126341e..0000000 --- a/src/hash/sha256/sha256.js +++ /dev/null @@ -1,34 +0,0 @@ -import { sha256_asm } from './sha256.asm'; -import { hash_finish, hash_process, hash_reset } from '../hash'; -import { _heap_init } from '../../utils'; - -export var _sha256_block_size = 64; -export var _sha256_hash_size = 32; - -export function sha256_constructor(options) { - options = options || {}; - - this.heap = _heap_init(Uint8Array, options.heap); - this.asm = options.asm || sha256_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer); - - this.BLOCK_SIZE = _sha256_block_size; - this.HASH_SIZE = _sha256_hash_size; - - this.reset(); -} - -sha256_constructor.BLOCK_SIZE = _sha256_block_size; -sha256_constructor.HASH_SIZE = _sha256_hash_size; -sha256_constructor.NAME = 'sha256'; - -var sha256_prototype = sha256_constructor.prototype; -sha256_prototype.reset = hash_reset; -sha256_prototype.process = hash_process; -sha256_prototype.finish = hash_finish; - -var sha256_instance = null; - -export function get_sha256_instance() { - if (sha256_instance === null) sha256_instance = new sha256_constructor({ heapSize: 0x100000 }); - return sha256_instance; -} diff --git a/src/hash/sha256/sha256.ts b/src/hash/sha256/sha256.ts new file mode 100644 index 0000000..885d773 --- /dev/null +++ b/src/hash/sha256/sha256.ts @@ -0,0 +1,22 @@ +import { sha256_asm, sha256result } from './sha256.asm'; +import { Hash } from '../hash'; +import { _heap_init } from '../../other/utils'; + +export const _sha256_block_size = 64; +export const _sha256_hash_size = 32; + +export class Sha256 extends Hash { + static NAME = 'sha256'; + public NAME = 'sha256'; + public BLOCK_SIZE = _sha256_block_size; + public HASH_SIZE = _sha256_hash_size; + + constructor() { + super(); + + this.heap = _heap_init(); + this.asm = sha256_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer); + + this.reset(); + } +} diff --git a/src/hash/sha512/exports.js b/src/hash/sha512/exports.js deleted file mode 100644 index f85706e..0000000 --- a/src/hash/sha512/exports.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * SHA512 exports - */ - -import { get_sha512_instance, sha512_constructor } from './sha512'; -import { bytes_to_base64, bytes_to_hex } from '../../utils'; - -function sha512_bytes(data) { - if (data === undefined) throw new SyntaxError('data required'); - return get_sha512_instance() - .reset() - .process(data) - .finish().result; -} - -function sha512_hex(data) { - var result = sha512_bytes(data); - return bytes_to_hex(result); -} - -function sha512_base64(data) { - var result = sha512_bytes(data); - return bytes_to_base64(result); -} - -export var SHA512 = sha512_constructor; - -SHA512.bytes = sha512_bytes; -SHA512.hex = sha512_hex; -SHA512.base64 = sha512_base64; diff --git a/src/hash/sha512/sha512.asm.d.ts b/src/hash/sha512/sha512.asm.d.ts new file mode 100644 index 0000000..31eceff --- /dev/null +++ b/src/hash/sha512/sha512.asm.d.ts @@ -0,0 +1,78 @@ +declare interface sha512result { + // SHA1 + reset: () => void; + init: (h0: number, h1: number, h2: number, h3: number, h4: number, total0: number, total1: number) => void; + + /** + * @param offset - multiple of 64 + * @param length + * @returns hashed + */ + process: (offset: number, length: number) => number; + + /** + * @param offset - multiple of 64 + * @param length + * @param output - multiple of 32 + * @returns hashed + */ + finish: (offset: number, length: number, output: number) => number; + + // HMAC-SHA; + hmac_reset: () => void; + hmac_init: ( + p0h: number, + p0l: number, + p1h: number, + p1l: number, + p2h: number, + p2l: number, + p3h: number, + p3l: number, + p4h: number, + p4l: number, + p5h: number, + p5l: number, + p6h: number, + p6l: number, + p7h: number, + p7l: number, + p8h: number, + p8l: number, + p9h: number, + p9l: number, + p10h: number, + p10l: number, + p11h: number, + p11l: number, + p12h: number, + p12l: number, + p13h: number, + p13l: number, + p14h: number, + p14l: number, + p15h: number, + p15l: number, + ) => void; + + /** + * @param offset - multiple of 64 + * @param length + * @param output - multiple of 32 + * @returns hashed + */ + hmac_finish: (offset: number, length: number, output: number) => number; + + // ; + /** + * PBKDF2-HMAC-SHA + * @param offset - multiple of 64 + * @param length + * @param block + * @param count + * @param output - multiple of 32 + */ + pbkdf2_generate_block: (offset: number, length: number, block: number, count: number, output: number) => 0 | -1; +} + +export function sha512_asm(stdlib: any, foreign: any, buffer: ArrayBuffer): sha512result; diff --git a/src/hash/sha512/sha512.asm.js b/src/hash/sha512/sha512.asm.js index e86af51..6ace1f3 100644 --- a/src/hash/sha512/sha512.asm.js +++ b/src/hash/sha512/sha512.asm.js @@ -3144,18 +3144,18 @@ export function sha512_asm ( stdlib, foreign, buffer ) { } return { - // SHA512 - reset: reset, - init: init, - process: process, - finish: finish, - - // HMAC-SHA512 - hmac_reset: hmac_reset, - hmac_init: hmac_init, - hmac_finish: hmac_finish, - - // PBKDF2-HMAC-SHA512 - pbkdf2_generate_block: pbkdf2_generate_block + // SHA512 + reset: reset, + init: init, + process: process, + finish: finish, + + // HMAC-SHA512 + hmac_reset: hmac_reset, + hmac_init: hmac_init, + hmac_finish: hmac_finish, + + // PBKDF2-HMAC-SHA512 + pbkdf2_generate_block: pbkdf2_generate_block } } diff --git a/src/hash/sha512/sha512.js b/src/hash/sha512/sha512.js deleted file mode 100644 index 4084d4c..0000000 --- a/src/hash/sha512/sha512.js +++ /dev/null @@ -1,34 +0,0 @@ -import { hash_finish, hash_process, hash_reset } from '../hash'; -import { sha512_asm } from './sha512.asm'; -import { _heap_init } from '../../utils'; - -export var _sha512_block_size = 128; -export var _sha512_hash_size = 64; - -export function sha512_constructor(options) { - options = options || {}; - - this.heap = _heap_init(Uint8Array, options.heapx); - this.asm = options.asm || sha512_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer); - - this.BLOCK_SIZE = _sha512_block_size; - this.HASH_SIZE = _sha512_hash_size; - - this.reset(); -} - -sha512_constructor.BLOCK_SIZE = _sha512_block_size; -sha512_constructor.HASH_SIZE = _sha512_hash_size; -sha512_constructor.NAME = 'sha512'; - -var sha512_prototype = sha512_constructor.prototype; -sha512_prototype.reset = hash_reset; -sha512_prototype.process = hash_process; -sha512_prototype.finish = hash_finish; - -var sha512_instance = null; - -export function get_sha512_instance() { - if (sha512_instance === null) sha512_instance = new sha512_constructor({ heapSize: 0x100000 }); - return sha512_instance; -} diff --git a/src/hash/sha512/sha512.ts b/src/hash/sha512/sha512.ts new file mode 100644 index 0000000..ddaaa42 --- /dev/null +++ b/src/hash/sha512/sha512.ts @@ -0,0 +1,22 @@ +import { sha512_asm, sha512result } from './sha512.asm'; +import { Hash } from '../hash'; +import { _heap_init } from '../../other/utils'; + +export const _sha512_block_size = 128; +export const _sha512_hash_size = 64; + +export class Sha512 extends Hash { + static NAME = 'sha512'; + public NAME = 'sha512'; + public BLOCK_SIZE = _sha512_block_size; + public HASH_SIZE = _sha512_hash_size; + + constructor() { + super(); + + this.heap = _heap_init(); + this.asm = sha512_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer); + + this.reset(); + } +} diff --git a/src/hmac/exports-hmac-sha1.js b/src/hmac/exports-hmac-sha1.js deleted file mode 100644 index 0aeb88c..0000000 --- a/src/hmac/exports-hmac-sha1.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * HMAC-SHA1 exports - */ - -import { get_hmac_sha1_instance, hmac_sha1_constructor } from './hmac-sha1'; -import { bytes_to_base64, bytes_to_hex } from '../utils'; - -function hmac_sha1_bytes(data, password) { - if (data === undefined) throw new SyntaxError('data required'); - if (password === undefined) throw new SyntaxError('password required'); - return get_hmac_sha1_instance() - .reset({ password: password }) - .process(data) - .finish().result; -} - -function hmac_sha1_hex(data, password) { - var result = hmac_sha1_bytes(data, password); - return bytes_to_hex(result); -} - -function hmac_sha1_base64(data, password) { - var result = hmac_sha1_bytes(data, password); - return bytes_to_base64(result); -} - -export var HMAC_SHA1 = hmac_sha1_constructor; - -HMAC_SHA1.bytes = hmac_sha1_bytes; -HMAC_SHA1.hex = hmac_sha1_hex; -HMAC_SHA1.base64 = hmac_sha1_base64; diff --git a/src/hmac/exports-hmac-sha256.js b/src/hmac/exports-hmac-sha256.js deleted file mode 100644 index f3181a9..0000000 --- a/src/hmac/exports-hmac-sha256.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * HMAC-SHA256 exports - */ - -import { get_hmac_sha256_instance, hmac_sha256_constructor } from './hmac-sha256'; -import { bytes_to_base64, bytes_to_hex } from '../utils'; - -function hmac_sha256_bytes(data, password) { - if (data === undefined) throw new SyntaxError('data required'); - if (password === undefined) throw new SyntaxError('password required'); - return get_hmac_sha256_instance() - .reset({ password: password }) - .process(data) - .finish().result; -} - -function hmac_sha256_hex(data, password) { - var result = hmac_sha256_bytes(data, password); - return bytes_to_hex(result); -} - -function hmac_sha256_base64(data, password) { - var result = hmac_sha256_bytes(data, password); - return bytes_to_base64(result); -} - -export var HMAC_SHA256 = hmac_sha256_constructor; - -HMAC_SHA256.bytes = hmac_sha256_bytes; -HMAC_SHA256.hex = hmac_sha256_hex; -HMAC_SHA256.base64 = hmac_sha256_base64; diff --git a/src/hmac/exports-hmac-sha512.js b/src/hmac/exports-hmac-sha512.js deleted file mode 100644 index 87bf95c..0000000 --- a/src/hmac/exports-hmac-sha512.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * HMAC-SHA512 exports - */ - -import { get_hmac_sha512_instance, hmac_sha512_constructor } from './hmac-sha512'; -import { bytes_to_base64, bytes_to_hex } from '../utils'; - -function hmac_sha512_bytes(data, password) { - if (data === undefined) throw new SyntaxError('data required'); - if (password === undefined) throw new SyntaxError('password required'); - return get_hmac_sha512_instance() - .reset({ password: password }) - .process(data) - .finish().result; -} - -function hmac_sha512_hex(data, password) { - var result = hmac_sha512_bytes(data, password); - return bytes_to_hex(result); -} - -function hmac_sha512_base64(data, password) { - var result = hmac_sha512_bytes(data, password); - return bytes_to_base64(result); -} - -export var HMAC_SHA512 = hmac_sha512_constructor; - -HMAC_SHA512.bytes = hmac_sha512_bytes; -HMAC_SHA512.hex = hmac_sha512_hex; -HMAC_SHA512.base64 = hmac_sha512_base64; diff --git a/src/hmac/hmac-sha1.js b/src/hmac/hmac-sha1.js deleted file mode 100644 index 182ed0b..0000000 --- a/src/hmac/hmac-sha1.js +++ /dev/null @@ -1,107 +0,0 @@ -import { hmac_constructor, _hmac_key } from './hmac'; -import { _sha1_hash_size, get_sha1_instance, sha1_constructor } from '../hash/sha1/sha1'; -import { is_string, string_to_bytes } from '../utils'; -import { IllegalStateError } from '../errors'; - -export class hmac_sha1_constructor extends hmac_constructor { - constructor(options) { - options = options || {}; - - if (!(options.hash instanceof sha1_constructor)) options.hash = get_sha1_instance(); - - super(options); - } - - reset(options) { - options = options || {}; - - this.result = null; - this.hash.reset(); - - var password = options.password; - if (password !== undefined) { - if (is_string(password)) password = string_to_bytes(password); - - var key = (this.key = _hmac_key(this.hash, password)); - this.hash - .reset() - .asm.hmac_init( - (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3], - (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7], - (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11], - (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15], - (key[16] << 24) | (key[17] << 16) | (key[18] << 8) | key[19], - (key[20] << 24) | (key[21] << 16) | (key[22] << 8) | key[23], - (key[24] << 24) | (key[25] << 16) | (key[26] << 8) | key[27], - (key[28] << 24) | (key[29] << 16) | (key[30] << 8) | key[31], - (key[32] << 24) | (key[33] << 16) | (key[34] << 8) | key[35], - (key[36] << 24) | (key[37] << 16) | (key[38] << 8) | key[39], - (key[40] << 24) | (key[41] << 16) | (key[42] << 8) | key[43], - (key[44] << 24) | (key[45] << 16) | (key[46] << 8) | key[47], - (key[48] << 24) | (key[49] << 16) | (key[50] << 8) | key[51], - (key[52] << 24) | (key[53] << 16) | (key[54] << 8) | key[55], - (key[56] << 24) | (key[57] << 16) | (key[58] << 8) | key[59], - (key[60] << 24) | (key[61] << 16) | (key[62] << 8) | key[63], - ); - } else { - this.hash.asm.hmac_reset(); - } - - var verify = options.verify; - if (verify !== undefined) { - this._hmac_init_verify(verify); - } else { - this.verify = null; - } - - return this; - } - - /** - * @return {hmac_sha1_constructor} - */ - finish() { - if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); - - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - var hash = this.hash, - asm = this.hash.asm, - heap = this.hash.heap; - - asm.hmac_finish(hash.pos, hash.len, 0); - - var verify = this.verify; - var result = new Uint8Array(_sha1_hash_size); - result.set(heap.subarray(0, _sha1_hash_size)); - - if (verify) { - if (verify.length === result.length) { - var diff = 0; - for (var i = 0; i < verify.length; i++) { - diff |= verify[i] ^ result[i]; - } - this.result = !diff; - } else { - this.result = false; - } - } else { - this.result = result; - } - - return this; - } -} - -hmac_sha1_constructor.BLOCK_SIZE = sha1_constructor.BLOCK_SIZE; -hmac_sha1_constructor.HMAC_SIZE = sha1_constructor.HASH_SIZE; - -var hmac_sha1_instance = null; - -/** - * @return {hmac_sha1_constructor} - */ -export function get_hmac_sha1_instance() { - if (hmac_sha1_instance === null) hmac_sha1_instance = new hmac_sha1_constructor(); - return hmac_sha1_instance; -} diff --git a/src/hmac/hmac-sha1.ts b/src/hmac/hmac-sha1.ts new file mode 100644 index 0000000..ec6c7c7 --- /dev/null +++ b/src/hmac/hmac-sha1.ts @@ -0,0 +1,82 @@ +import { Hmac } from './hmac'; +import { _sha1_hash_size, Sha1 } from '../hash/sha1/sha1'; +import { IllegalStateError } from '../other/errors'; +import { sha1result } from '../hash/sha1/sha1.asm'; +import { Hash } from '../hash/hash'; + +export class HmacSha1 extends Hmac> { + public result!: Uint8Array | null; + + constructor(password: Uint8Array, verify?: Uint8Array) { + const hash = new Sha1(); + + // Calculate ipad, init the underlying engine, calculate this.key + super(hash, password, verify); + + this.reset(); + + if (verify !== undefined) { + this._hmac_init_verify(verify); + } else { + this.verify = null; + } + + return this; + } + + reset(): this { + this.result = null; + const key = this.key; + this.hash + .reset() + .asm.hmac_init( + (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3], + (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7], + (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11], + (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15], + (key[16] << 24) | (key[17] << 16) | (key[18] << 8) | key[19], + (key[20] << 24) | (key[21] << 16) | (key[22] << 8) | key[23], + (key[24] << 24) | (key[25] << 16) | (key[26] << 8) | key[27], + (key[28] << 24) | (key[29] << 16) | (key[30] << 8) | key[31], + (key[32] << 24) | (key[33] << 16) | (key[34] << 8) | key[35], + (key[36] << 24) | (key[37] << 16) | (key[38] << 8) | key[39], + (key[40] << 24) | (key[41] << 16) | (key[42] << 8) | key[43], + (key[44] << 24) | (key[45] << 16) | (key[46] << 8) | key[47], + (key[48] << 24) | (key[49] << 16) | (key[50] << 8) | key[51], + (key[52] << 24) | (key[53] << 16) | (key[54] << 8) | key[55], + (key[56] << 24) | (key[57] << 16) | (key[58] << 8) | key[59], + (key[60] << 24) | (key[61] << 16) | (key[62] << 8) | key[63], + ); + return this; + } + + finish(): this { + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + const hash = this.hash; + const asm = this.hash.asm; + const heap = this.hash.heap; + + asm.hmac_finish(hash.pos, hash.len, 0); + + const verify = this.verify; + const result = new Uint8Array(_sha1_hash_size); + result.set(heap.subarray(0, _sha1_hash_size)); + + if (verify) { + if (verify.length === result.length) { + let diff = 0; + for (let i = 0; i < verify.length; i++) { + diff |= verify[i] ^ result[i]; + } + if (diff !== 0) throw new Error("HMAC verification failed, hash value doesn't match"); + } else { + throw new Error("HMAC verification failed, lengths doesn't match"); + } + } else { + this.result = result; + } + + return this; + } +} diff --git a/src/hmac/hmac-sha256.js b/src/hmac/hmac-sha256.js deleted file mode 100644 index a7b18fe..0000000 --- a/src/hmac/hmac-sha256.js +++ /dev/null @@ -1,107 +0,0 @@ -import { hmac_constructor, _hmac_key } from './hmac'; -import { _sha256_hash_size, get_sha256_instance, sha256_constructor } from '../hash/sha256/sha256'; -import { is_string, string_to_bytes } from '../utils'; -import { IllegalStateError } from '../errors'; - -export class hmac_sha256_constructor extends hmac_constructor { - constructor(options) { - options = options || {}; - - if (!(options.hash instanceof sha256_constructor)) options.hash = get_sha256_instance(); - - super(options); - } - - reset(options) { - options = options || {}; - - this.result = null; - this.hash.reset(); - - var password = options.password; - if (password !== undefined) { - if (is_string(password)) password = string_to_bytes(password); - - var key = (this.key = _hmac_key(this.hash, password)); - this.hash - .reset() - .asm.hmac_init( - (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3], - (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7], - (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11], - (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15], - (key[16] << 24) | (key[17] << 16) | (key[18] << 8) | key[19], - (key[20] << 24) | (key[21] << 16) | (key[22] << 8) | key[23], - (key[24] << 24) | (key[25] << 16) | (key[26] << 8) | key[27], - (key[28] << 24) | (key[29] << 16) | (key[30] << 8) | key[31], - (key[32] << 24) | (key[33] << 16) | (key[34] << 8) | key[35], - (key[36] << 24) | (key[37] << 16) | (key[38] << 8) | key[39], - (key[40] << 24) | (key[41] << 16) | (key[42] << 8) | key[43], - (key[44] << 24) | (key[45] << 16) | (key[46] << 8) | key[47], - (key[48] << 24) | (key[49] << 16) | (key[50] << 8) | key[51], - (key[52] << 24) | (key[53] << 16) | (key[54] << 8) | key[55], - (key[56] << 24) | (key[57] << 16) | (key[58] << 8) | key[59], - (key[60] << 24) | (key[61] << 16) | (key[62] << 8) | key[63], - ); - } else { - this.hash.asm.hmac_reset(); - } - - var verify = options.verify; - if (verify !== undefined) { - this._hmac_init_verify(verify); - } else { - this.verify = null; - } - - return this; - } - - /** - * @return {hmac_sha256_constructor} - */ - finish() { - if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); - - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - var hash = this.hash, - asm = this.hash.asm, - heap = this.hash.heap; - - asm.hmac_finish(hash.pos, hash.len, 0); - - var verify = this.verify; - var result = new Uint8Array(_sha256_hash_size); - result.set(heap.subarray(0, _sha256_hash_size)); - - if (verify) { - if (verify.length === result.length) { - var diff = 0; - for (var i = 0; i < verify.length; i++) { - diff |= verify[i] ^ result[i]; - } - this.result = !diff; - } else { - this.result = false; - } - } else { - this.result = result; - } - - return this; - } -} - -hmac_sha256_constructor.BLOCK_SIZE = sha256_constructor.BLOCK_SIZE; -hmac_sha256_constructor.HMAC_SIZE = sha256_constructor.HASH_SIZE; - -var hmac_sha256_instance = null; - -/** - * @return {hmac_sha256_constructor} - */ -export function get_hmac_sha256_instance() { - if (hmac_sha256_instance === null) hmac_sha256_instance = new hmac_sha256_constructor(); - return hmac_sha256_instance; -} diff --git a/src/hmac/hmac-sha256.ts b/src/hmac/hmac-sha256.ts new file mode 100644 index 0000000..e497903 --- /dev/null +++ b/src/hmac/hmac-sha256.ts @@ -0,0 +1,85 @@ +import { Hmac } from './hmac'; +import { IllegalStateError } from '../other/errors'; +import { _sha256_hash_size, Sha256 } from '../hash/sha256/sha256'; +import { sha256result } from '../hash/sha256/sha256.asm'; +import { Hash } from '../hash/hash'; + +export class HmacSha256 extends Hmac> { + public result!: Uint8Array | null; + + constructor(password: Uint8Array, verify?: Uint8Array) { + const hash = new Sha256(); + + // Calculate ipad, init the underlying engine, calculate this.key + super(hash, password, verify); + + this.reset(); + + if (verify !== undefined) { + this._hmac_init_verify(verify); + } else { + this.verify = null; + } + + return this; + } + + reset(): this { + const key = this.key; + + this.hash + .reset() + .asm.hmac_init( + (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3], + (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7], + (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11], + (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15], + (key[16] << 24) | (key[17] << 16) | (key[18] << 8) | key[19], + (key[20] << 24) | (key[21] << 16) | (key[22] << 8) | key[23], + (key[24] << 24) | (key[25] << 16) | (key[26] << 8) | key[27], + (key[28] << 24) | (key[29] << 16) | (key[30] << 8) | key[31], + (key[32] << 24) | (key[33] << 16) | (key[34] << 8) | key[35], + (key[36] << 24) | (key[37] << 16) | (key[38] << 8) | key[39], + (key[40] << 24) | (key[41] << 16) | (key[42] << 8) | key[43], + (key[44] << 24) | (key[45] << 16) | (key[46] << 8) | key[47], + (key[48] << 24) | (key[49] << 16) | (key[50] << 8) | key[51], + (key[52] << 24) | (key[53] << 16) | (key[54] << 8) | key[55], + (key[56] << 24) | (key[57] << 16) | (key[58] << 8) | key[59], + (key[60] << 24) | (key[61] << 16) | (key[62] << 8) | key[63], + ); + + return this; + } + + finish(): this { + if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); + + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + const hash = this.hash; + const asm = this.hash.asm; + const heap = this.hash.heap; + + asm.hmac_finish(hash.pos, hash.len, 0); + + const verify = this.verify; + const result = new Uint8Array(_sha256_hash_size); + result.set(heap.subarray(0, _sha256_hash_size)); + + if (verify) { + if (verify.length === result.length) { + let diff = 0; + for (let i = 0; i < verify.length; i++) { + diff |= verify[i] ^ result[i]; + } + if (diff !== 0) throw new Error("HMAC verification failed, hash value doesn't match"); + } else { + throw new Error("HMAC verification failed, lengths doesn't match"); + } + } else { + this.result = result; + } + + return this; + } +} diff --git a/src/hmac/hmac-sha512.js b/src/hmac/hmac-sha512.js deleted file mode 100644 index a94f093..0000000 --- a/src/hmac/hmac-sha512.js +++ /dev/null @@ -1,123 +0,0 @@ -import { _sha512_hash_size, get_sha512_instance, sha512_constructor } from '../hash/sha512/sha512'; -import { hmac_constructor, _hmac_key } from './hmac'; -import { is_string, string_to_bytes } from '../utils'; -import { IllegalStateError } from '../errors'; - -export class hmac_sha512_constructor extends hmac_constructor { - constructor(options) { - options = options || {}; - - if (!(options.hash instanceof sha512_constructor)) options.hash = get_sha512_instance(); - - super(options); - } - - reset(options) { - options = options || {}; - - this.result = null; - this.hash.reset(); - - var password = options.password; - if (password !== undefined) { - if (is_string(password)) password = string_to_bytes(password); - - var key = (this.key = _hmac_key(this.hash, password)); - this.hash - .reset() - .asm.hmac_init( - (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3], - (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7], - (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11], - (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15], - (key[16] << 24) | (key[17] << 16) | (key[18] << 8) | key[19], - (key[20] << 24) | (key[21] << 16) | (key[22] << 8) | key[23], - (key[24] << 24) | (key[25] << 16) | (key[26] << 8) | key[27], - (key[28] << 24) | (key[29] << 16) | (key[30] << 8) | key[31], - (key[32] << 24) | (key[33] << 16) | (key[34] << 8) | key[35], - (key[36] << 24) | (key[37] << 16) | (key[38] << 8) | key[39], - (key[40] << 24) | (key[41] << 16) | (key[42] << 8) | key[43], - (key[44] << 24) | (key[45] << 16) | (key[46] << 8) | key[47], - (key[48] << 24) | (key[49] << 16) | (key[50] << 8) | key[51], - (key[52] << 24) | (key[53] << 16) | (key[54] << 8) | key[55], - (key[56] << 24) | (key[57] << 16) | (key[58] << 8) | key[59], - (key[60] << 24) | (key[61] << 16) | (key[62] << 8) | key[63], - (key[64] << 24) | (key[65] << 16) | (key[66] << 8) | key[67], - (key[68] << 24) | (key[69] << 16) | (key[70] << 8) | key[71], - (key[72] << 24) | (key[73] << 16) | (key[74] << 8) | key[75], - (key[76] << 24) | (key[77] << 16) | (key[78] << 8) | key[79], - (key[80] << 24) | (key[81] << 16) | (key[82] << 8) | key[83], - (key[84] << 24) | (key[85] << 16) | (key[86] << 8) | key[87], - (key[88] << 24) | (key[89] << 16) | (key[90] << 8) | key[91], - (key[92] << 24) | (key[93] << 16) | (key[94] << 8) | key[95], - (key[96] << 24) | (key[97] << 16) | (key[98] << 8) | key[99], - (key[100] << 24) | (key[101] << 16) | (key[102] << 8) | key[103], - (key[104] << 24) | (key[105] << 16) | (key[106] << 8) | key[107], - (key[108] << 24) | (key[109] << 16) | (key[110] << 8) | key[111], - (key[112] << 24) | (key[113] << 16) | (key[114] << 8) | key[115], - (key[116] << 24) | (key[117] << 16) | (key[118] << 8) | key[119], - (key[120] << 24) | (key[121] << 16) | (key[122] << 8) | key[123], - (key[124] << 24) | (key[125] << 16) | (key[126] << 8) | key[127], - ); - } else { - this.hash.asm.hmac_reset(); - } - - var verify = options.verify; - if (verify !== undefined) { - this._hmac_init_verify(verify); - } else { - this.verify = null; - } - - return this; - } - - /** - * @return {hmac_sha512_constructor} - */ - finish() { - if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); - - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - var hash = this.hash, - asm = this.hash.asm, - heap = this.hash.heap; - - asm.hmac_finish(hash.pos, hash.len, 0); - - var verify = this.verify; - var result = new Uint8Array(_sha512_hash_size); - result.set(heap.subarray(0, _sha512_hash_size)); - - if (verify) { - if (verify.length === result.length) { - var diff = 0; - for (var i = 0; i < verify.length; i++) { - diff |= verify[i] ^ result[i]; - } - this.result = !diff; - } else { - this.result = false; - } - } else { - this.result = result; - } - - return this; - } -} - -hmac_sha512_constructor.BLOCK_SIZE = sha512_constructor.BLOCK_SIZE; -hmac_sha512_constructor.HMAC_SIZE = sha512_constructor.HASH_SIZE; - -var hmac_sha512_instance = null; - -/** - * @return {get_hmac_sha512_instance} - */ -export function get_hmac_sha512_instance() { - if (hmac_sha512_instance === null) hmac_sha512_instance = new hmac_sha512_constructor(); - return hmac_sha512_instance; -} diff --git a/src/hmac/hmac-sha512.ts b/src/hmac/hmac-sha512.ts new file mode 100644 index 0000000..d81fc69 --- /dev/null +++ b/src/hmac/hmac-sha512.ts @@ -0,0 +1,99 @@ +import { Hmac } from './hmac'; +import { IllegalStateError } from '../other/errors'; +import { _sha512_hash_size, Sha512 } from '../hash/sha512/sha512'; +import { Hash } from '../hash/hash'; +import { sha512result } from '../hash/sha512/sha512.asm'; + +export class HmacSha512 extends Hmac> { + public result!: Uint8Array | null; + + constructor(password: Uint8Array, verify?: Uint8Array) { + const hash = new Sha512(); + + // Calculate ipad, init the underlying engine, calculate this.key + super(hash, password, verify); + + this.reset(); + + if (verify !== undefined) { + this._hmac_init_verify(verify); + } else { + this.verify = null; + } + + return this; + } + + reset(): this { + const key = this.key; + this.hash + .reset() + .asm.hmac_init( + (key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3], + (key[4] << 24) | (key[5] << 16) | (key[6] << 8) | key[7], + (key[8] << 24) | (key[9] << 16) | (key[10] << 8) | key[11], + (key[12] << 24) | (key[13] << 16) | (key[14] << 8) | key[15], + (key[16] << 24) | (key[17] << 16) | (key[18] << 8) | key[19], + (key[20] << 24) | (key[21] << 16) | (key[22] << 8) | key[23], + (key[24] << 24) | (key[25] << 16) | (key[26] << 8) | key[27], + (key[28] << 24) | (key[29] << 16) | (key[30] << 8) | key[31], + (key[32] << 24) | (key[33] << 16) | (key[34] << 8) | key[35], + (key[36] << 24) | (key[37] << 16) | (key[38] << 8) | key[39], + (key[40] << 24) | (key[41] << 16) | (key[42] << 8) | key[43], + (key[44] << 24) | (key[45] << 16) | (key[46] << 8) | key[47], + (key[48] << 24) | (key[49] << 16) | (key[50] << 8) | key[51], + (key[52] << 24) | (key[53] << 16) | (key[54] << 8) | key[55], + (key[56] << 24) | (key[57] << 16) | (key[58] << 8) | key[59], + (key[60] << 24) | (key[61] << 16) | (key[62] << 8) | key[63], + (key[64] << 24) | (key[65] << 16) | (key[66] << 8) | key[67], + (key[68] << 24) | (key[69] << 16) | (key[70] << 8) | key[71], + (key[72] << 24) | (key[73] << 16) | (key[74] << 8) | key[75], + (key[76] << 24) | (key[77] << 16) | (key[78] << 8) | key[79], + (key[80] << 24) | (key[81] << 16) | (key[82] << 8) | key[83], + (key[84] << 24) | (key[85] << 16) | (key[86] << 8) | key[87], + (key[88] << 24) | (key[89] << 16) | (key[90] << 8) | key[91], + (key[92] << 24) | (key[93] << 16) | (key[94] << 8) | key[95], + (key[96] << 24) | (key[97] << 16) | (key[98] << 8) | key[99], + (key[100] << 24) | (key[101] << 16) | (key[102] << 8) | key[103], + (key[104] << 24) | (key[105] << 16) | (key[106] << 8) | key[107], + (key[108] << 24) | (key[109] << 16) | (key[110] << 8) | key[111], + (key[112] << 24) | (key[113] << 16) | (key[114] << 8) | key[115], + (key[116] << 24) | (key[117] << 16) | (key[118] << 8) | key[119], + (key[120] << 24) | (key[121] << 16) | (key[122] << 8) | key[123], + (key[124] << 24) | (key[125] << 16) | (key[126] << 8) | key[127], + ); + return this; + } + + finish() { + if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); + + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + const hash = this.hash; + const asm = this.hash.asm; + const heap = this.hash.heap; + + asm.hmac_finish(hash.pos, hash.len, 0); + + const verify = this.verify; + const result = new Uint8Array(_sha512_hash_size); + result.set(heap.subarray(0, _sha512_hash_size)); + + if (verify) { + if (verify.length === result.length) { + let diff = 0; + for (let i = 0; i < verify.length; i++) { + diff |= verify[i] ^ result[i]; + } + if (diff !== 0) throw new Error("HMAC verification failed, hash value doesn't match"); + } else { + throw new Error("HMAC verification failed, lengths doesn't match"); + } + } else { + this.result = result; + } + + return this; + } +} diff --git a/src/hmac/hmac.js b/src/hmac/hmac.js deleted file mode 100644 index 2e9395d..0000000 --- a/src/hmac/hmac.js +++ /dev/null @@ -1,133 +0,0 @@ -import { is_buffer, is_bytes, is_string, string_to_bytes } from '../utils'; -import { IllegalArgumentError, IllegalStateError } from '../errors'; - -export class hmac_constructor { - constructor(options) { - options = options || {}; - - if (!options.hash) throw new SyntaxError("option 'hash' is required"); - - if (!options.hash.HASH_SIZE) - throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); - - this.hash = options.hash; - this.BLOCK_SIZE = this.hash.BLOCK_SIZE; - this.HMAC_SIZE = this.hash.HASH_SIZE; - - this.key = null; - this.verify = null; - this.result = null; - - if (options.password !== undefined || options.verify !== undefined) this.reset(options); - - return this; - } - - reset(options) { - options = options || {}; - var password = options.password; - - if (this.key === null && !is_string(password) && !password) - throw new IllegalStateError('no key is associated with the instance'); - - this.result = null; - this.hash.reset(); - - if (password || is_string(password)) this.key = _hmac_key(this.hash, password); - - var ipad = new Uint8Array(this.key); - for (var i = 0; i < ipad.length; ++i) ipad[i] ^= 0x36; - - this.hash.process(ipad); - - var verify = options.verify; - if (verify !== undefined) { - this._hmac_init_verify(verify); - } else { - this.verify = null; - } - - return this; - } - - process(data) { - if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); - - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - this.hash.process(data); - - return this; - } - - finish() { - if (this.key === null) throw new IllegalStateError('no key is associated with the instance'); - - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - var inner_result = this.hash.finish().result; - - var opad = new Uint8Array(this.key); - for (var i = 0; i < opad.length; ++i) opad[i] ^= 0x5c; - - var verify = this.verify; - var result = this.hash - .reset() - .process(opad) - .process(inner_result) - .finish().result; - - if (verify) { - if (verify.length === result.length) { - var diff = 0; - for (var i = 0; i < verify.length; i++) { - diff |= verify[i] ^ result[i]; - } - this.result = !diff; - } else { - this.result = false; - } - } else { - this.result = result; - } - - return this; - } - - _hmac_init_verify(verify) { - if (is_buffer(verify) || is_bytes(verify)) { - verify = new Uint8Array(verify); - } else if (is_string(verify)) { - verify = string_to_bytes(verify); - } else { - throw new TypeError("verify tag isn't of expected type"); - } - - if (verify.length !== this.HMAC_SIZE) throw new IllegalArgumentError('illegal verification tag size'); - - this.verify = verify; - } -} - -export function _hmac_key(hash, password) { - if (is_buffer(password)) password = new Uint8Array(password); - - if (is_string(password)) password = string_to_bytes(password); - - if (!is_bytes(password)) throw new TypeError("password isn't of expected type"); - - var key = new Uint8Array(hash.BLOCK_SIZE); - - if (password.length > hash.BLOCK_SIZE) { - key.set( - hash - .reset() - .process(password) - .finish().result, - ); - } else { - key.set(password); - } - - return key; -} diff --git a/src/hmac/hmac.ts b/src/hmac/hmac.ts new file mode 100644 index 0000000..014771a --- /dev/null +++ b/src/hmac/hmac.ts @@ -0,0 +1,98 @@ +import { IllegalArgumentError, IllegalStateError } from '../other/errors'; +import { Hash } from '../hash/hash'; +import { sha1result } from '../hash/sha1/sha1.asm'; +import { sha256result } from '../hash/sha256/sha256.asm'; +import { sha512result } from '../hash/sha512/sha512.asm'; + +export abstract class Hmac | Hash | Hash> { + public hash: T; + protected BLOCK_SIZE: number; + public HMAC_SIZE: number; + protected key: Uint8Array; + protected verify!: Uint8Array | null; + public result!: Uint8Array | null; + + protected constructor(hash: T, password: Uint8Array, verify?: Uint8Array) { + if (!hash.HASH_SIZE) throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); + + this.hash = hash; + this.BLOCK_SIZE = this.hash.BLOCK_SIZE; + this.HMAC_SIZE = this.hash.HASH_SIZE; + + this.result = null; + + this.key = _hmac_key(this.hash, password); + + const ipad = new Uint8Array(this.key); + for (let i = 0; i < ipad.length; ++i) ipad[i] ^= 0x36; + + this.hash.reset().process(ipad); + + if (verify !== undefined) { + this._hmac_init_verify(verify); + } else { + this.verify = null; + } + } + + process(data: Uint8Array): this { + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + this.hash.process(data); + + return this; + } + + finish(): this { + if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); + + const inner_result = this.hash.finish().result as Uint8Array; + + const opad = new Uint8Array(this.key); + for (let i = 0; i < opad.length; ++i) opad[i] ^= 0x5c; + + const verify = this.verify; + const result = this.hash + .reset() + .process(opad) + .process(inner_result) + .finish().result as Uint8Array; + + if (verify) { + if (verify.length === result.length) { + let diff = 0; + for (let i = 0; i < verify.length; i++) { + diff |= verify[i] ^ result[i]; + } + if (diff !== 0) throw new Error("HMAC verification failed, hash value doesn't match"); + } else { + throw new Error("HMAC verification failed, lengths doesn't match"); + } + } + + this.result = result; + + return this; + } + + _hmac_init_verify(verify: Uint8Array): void { + if (verify.length !== this.HMAC_SIZE) throw new IllegalArgumentError('illegal verification tag size'); + + this.verify = verify; + } +} + +export function _hmac_key(hash: Hash, password: Uint8Array): Uint8Array { + const key = new Uint8Array(hash.BLOCK_SIZE); + + if (password.length > hash.BLOCK_SIZE) { + key.set(hash + .reset() + .process(password) + .finish().result as Uint8Array); + } else { + key.set(password); + } + + return key; +} diff --git a/src/origin.js b/src/origin.js deleted file mode 100644 index ed28187..0000000 --- a/src/origin.js +++ /dev/null @@ -1,10 +0,0 @@ -var _global_console = typeof console !== 'undefined' ? console : undefined; - -var _secure_origin = - typeof location === 'undefined' || !location.protocol.search(/https:|file:|chrome:|chrome-extension:|moz-extension:/); - -if (!_secure_origin && _global_console !== undefined) { - _global_console.warn( - 'asmCrypto seems to be load from an insecure origin; this may cause to MitM-attack vulnerability. Consider using secure transport protocol.', - ); -} diff --git a/src/other/errors.ts b/src/other/errors.ts new file mode 100644 index 0000000..74326f3 --- /dev/null +++ b/src/other/errors.ts @@ -0,0 +1,20 @@ +export class IllegalStateError extends Error { + constructor(...args: any[]) { + super(...args); + Object.create(Error.prototype, { name: { value: 'IllegalStateError' } }); + } +} + +export class IllegalArgumentError extends Error { + constructor(...args: any[]) { + super(...args); + Object.create(Error.prototype, { name: { value: 'IllegalArgumentError' } }); + } +} + +export class SecurityError extends Error { + constructor(...args: any[]) { + super(...args); + Object.create(Error.prototype, { name: { value: 'SecurityError' } }); + } +} diff --git a/src/exportedUtils.js b/src/other/exportedUtils.ts similarity index 87% rename from src/exportedUtils.js rename to src/other/exportedUtils.ts index 73ceebf..d462dcd 100644 --- a/src/exportedUtils.js +++ b/src/other/exportedUtils.ts @@ -9,4 +9,4 @@ export { bytes_to_string, bytes_to_hex, bytes_to_base64, -} from './utils.js'; +} from './utils'; diff --git a/src/other/get-random-values.ts b/src/other/get-random-values.ts new file mode 100644 index 0000000..3e78305 --- /dev/null +++ b/src/other/get-random-values.ts @@ -0,0 +1,23 @@ +export function getRandomValues(buf: Uint32Array | Uint8Array): void { + try { + if (typeof window === 'undefined') { + const nodeCrypto = require('crypto'); + const bytes = nodeCrypto.randomBytes(buf.length); + buf.set(bytes); + return; + } + } catch (e) { + console.error(e); + throw new Error('No secure random number generator available.'); + } + if (window.crypto && window.crypto.getRandomValues) { + window.crypto.getRandomValues(buf); + return; + } + // @ts-ignore + if (window.msCrypto && window.msCrypto.getRandomValues) { + // @ts-ignore + window.msCrypto.getRandomValues(buf); + return; + } +} diff --git a/src/utils.js b/src/other/utils.ts similarity index 69% rename from src/utils.js rename to src/other/utils.ts index 3c64ef9..a7f4820 100644 --- a/src/utils.js +++ b/src/other/utils.ts @@ -1,13 +1,7 @@ -export var FloatArray = typeof Float64Array !== 'undefined' ? Float64Array : Float32Array; // make PhantomJS happy - -/** - * @param {string} str - * @param {boolean} [utf8] - * @return {Uint8Array} - */ -export function string_to_bytes(str, utf8) { - utf8 = !!utf8; +const local_atob = typeof atob === 'undefined' ? (str: string) => Buffer.from(str, 'base64').toString('binary') : atob; +const local_btoa = typeof btoa === 'undefined' ? (str: string) => Buffer.from(str, 'binary').toString('base64') : btoa; +export function string_to_bytes(str: string, utf8: boolean = false): Uint8Array { var len = str.length, bytes = new Uint8Array(utf8 ? 4 * len : len); @@ -41,7 +35,7 @@ export function string_to_bytes(str, utf8) { return bytes.subarray(0, j); } -export function hex_to_bytes(str) { +export function hex_to_bytes(str: string): Uint8Array { var len = str.length; if (len & 1) { str = '0' + str; @@ -54,13 +48,11 @@ export function hex_to_bytes(str) { return bytes; } -export function base64_to_bytes(str) { - return string_to_bytes(atob(str)); +export function base64_to_bytes(str: string): Uint8Array { + return string_to_bytes(local_atob(str)); } -export function bytes_to_string(bytes, utf8) { - utf8 = !!utf8; - +export function bytes_to_string(bytes: Uint8Array, utf8: boolean = false): string { var len = bytes.length, chars = new Array(len); @@ -95,7 +87,7 @@ export function bytes_to_string(bytes, utf8) { return str; } -export function bytes_to_hex(arr) { +export function bytes_to_hex(arr: Uint8Array): string { var str = ''; for (var i = 0; i < arr.length; i++) { var h = (arr[i] & 0xff).toString(16); @@ -105,11 +97,11 @@ export function bytes_to_hex(arr) { return str; } -export function bytes_to_base64(arr) { - return btoa(bytes_to_string(arr)); +export function bytes_to_base64(arr: Uint8Array): string { + return local_btoa(bytes_to_string(arr)); } -export function pow2_ceil(a) { +export function pow2_ceil(a: number): number { a -= 1; a |= a >>> 1; a |= a >>> 2; @@ -120,23 +112,23 @@ export function pow2_ceil(a) { return a; } -export function is_number(a) { +export function is_number(a: number): boolean { return typeof a === 'number'; } -export function is_string(a) { +export function is_string(a: string): boolean { return typeof a === 'string'; } -export function is_buffer(a) { +export function is_buffer(a: ArrayBuffer): boolean { return a instanceof ArrayBuffer; } -export function is_bytes(a) { +export function is_bytes(a: Uint8Array): boolean { return a instanceof Uint8Array; } -export function is_typed_array(a) { +export function is_typed_array(a: any): boolean { return ( a instanceof Int8Array || a instanceof Uint8Array || @@ -149,19 +141,19 @@ export function is_typed_array(a) { ); } -export function _heap_init(constructor, heap, heapSize) { - var size = heap ? heap.byteLength : heapSize || 65536; +export function _heap_init(heap?: Uint8Array, heapSize?: number): Uint8Array { + const size = heap ? heap.byteLength : heapSize || 65536; if (size & 0xfff || size <= 0) throw new Error('heap size must be a positive integer and a multiple of 4096'); - heap = heap || new constructor(new ArrayBuffer(size)); + heap = heap || new Uint8Array(new ArrayBuffer(size)); return heap; } -export function _heap_write(heap, hpos, data, dpos, dlen) { - var hlen = heap.length - hpos, - wlen = hlen < dlen ? hlen : dlen; +export function _heap_write(heap: Uint8Array, hpos: number, data: Uint8Array, dpos: number, dlen: number): number { + const hlen = heap.length - hpos; + const wlen = hlen < dlen ? hlen : dlen; heap.set(data.subarray(dpos, dpos + wlen), hpos); diff --git a/src/pbkdf2/exports-pbkdf2-hmac-sha1.js b/src/pbkdf2/exports-pbkdf2-hmac-sha1.js deleted file mode 100644 index 5d30996..0000000 --- a/src/pbkdf2/exports-pbkdf2-hmac-sha1.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * PBKDF2-HMAC-SHA1 exports - */ - -import { bytes_to_base64, bytes_to_hex } from '../utils'; -import { get_pbkdf2_hmac_sha1_instance } from './pbkdf2-hmac-sha1'; - -function pbkdf2_hmac_sha1_bytes(password, salt, iterations, dklen) { - if (password === undefined) throw new SyntaxError('password required'); - if (salt === undefined) throw new SyntaxError('salt required'); - return get_pbkdf2_hmac_sha1_instance() - .reset({ password: password }) - .generate(salt, iterations, dklen).result; -} - -function pbkdf2_hmac_sha1_hex(password, salt, iterations, dklen) { - var result = pbkdf2_hmac_sha1_bytes(password, salt, iterations, dklen); - return bytes_to_hex(result); -} - -function pbkdf2_hmac_sha1_base64(password, salt, iterations, dklen) { - var result = pbkdf2_hmac_sha1_bytes(password, salt, iterations, dklen); - return bytes_to_base64(result); -} - -export var PBKDF2 = { - bytes: pbkdf2_hmac_sha1_bytes, - hex: pbkdf2_hmac_sha1_hex, - base64: pbkdf2_hmac_sha1_base64, -}; - -export var PBKDF2_HMAC_SHA1 = { - bytes: pbkdf2_hmac_sha1_bytes, - hex: pbkdf2_hmac_sha1_hex, - base64: pbkdf2_hmac_sha1_base64, -}; diff --git a/src/pbkdf2/exports-pbkdf2-hmac-sha256.js b/src/pbkdf2/exports-pbkdf2-hmac-sha256.js deleted file mode 100644 index 9f3e039..0000000 --- a/src/pbkdf2/exports-pbkdf2-hmac-sha256.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * PBKDF2-HMAC-SHA256 exports - */ - -import { get_pbkdf2_hmac_sha256_instance } from './pbkdf2-hmac-sha256'; -import { bytes_to_base64, bytes_to_hex } from '../utils'; - -function pbkdf2_hmac_sha256_bytes(password, salt, iterations, dklen) { - if (password === undefined) throw new SyntaxError('password required'); - if (salt === undefined) throw new SyntaxError('salt required'); - return get_pbkdf2_hmac_sha256_instance() - .reset({ password: password }) - .generate(salt, iterations, dklen).result; -} - -function pbkdf2_hmac_sha256_hex(password, salt, iterations, dklen) { - var result = pbkdf2_hmac_sha256_bytes(password, salt, iterations, dklen); - return bytes_to_hex(result); -} - -function pbkdf2_hmac_sha256_base64(password, salt, iterations, dklen) { - var result = pbkdf2_hmac_sha256_bytes(password, salt, iterations, dklen); - return bytes_to_base64(result); -} - -export var PBKDF2_HMAC_SHA256 = { - bytes: pbkdf2_hmac_sha256_bytes, - hex: pbkdf2_hmac_sha256_hex, - base64: pbkdf2_hmac_sha256_base64, -}; diff --git a/src/pbkdf2/exports-pbkdf2-hmac-sha512.js b/src/pbkdf2/exports-pbkdf2-hmac-sha512.js deleted file mode 100644 index ecb5ac2..0000000 --- a/src/pbkdf2/exports-pbkdf2-hmac-sha512.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * PBKDF2-HMAC-SHA512 exports - */ - -import { get_pbkdf2_hmac_sha512_instance } from './pbkdf2-hmac-sha512'; -import { bytes_to_base64, bytes_to_hex } from '../utils'; - -function pbkdf2_hmac_sha512_bytes(password, salt, iterations, dklen) { - if (password === undefined) throw new SyntaxError('password required'); - if (salt === undefined) throw new SyntaxError('salt required'); - return get_pbkdf2_hmac_sha512_instance() - .reset({ password: password }) - .generate(salt, iterations, dklen).result; -} - -function pbkdf2_hmac_sha512_hex(password, salt, iterations, dklen) { - var result = pbkdf2_hmac_sha512_bytes(password, salt, iterations, dklen); - return bytes_to_hex(result); -} - -function pbkdf2_hmac_sha512_base64(password, salt, iterations, dklen) { - var result = pbkdf2_hmac_sha512_bytes(password, salt, iterations, dklen); - return bytes_to_base64(result); -} - -export var PBKDF2_HMAC_SHA512 = { - bytes: pbkdf2_hmac_sha512_bytes, - hex: pbkdf2_hmac_sha512_hex, - base64: pbkdf2_hmac_sha512_base64, -}; diff --git a/src/pbkdf2/pbkdf2-hmac-sha1.js b/src/pbkdf2/pbkdf2-hmac-sha1.js deleted file mode 100644 index 98a2ff3..0000000 --- a/src/pbkdf2/pbkdf2-hmac-sha1.js +++ /dev/null @@ -1,46 +0,0 @@ -import { get_hmac_sha1_instance, hmac_sha1_constructor } from '../hmac/hmac-sha1'; -import { pbkdf2_constructor } from './pbkdf2'; -import { is_string } from '../utils'; -import { IllegalArgumentError, IllegalStateError } from '../errors'; - -export class pbkdf2_hmac_sha1_constructor extends pbkdf2_constructor { - constructor(options) { - options = options || {}; - - if (!(options.hmac instanceof hmac_sha1_constructor)) options.hmac = get_hmac_sha1_instance(); - - super(options); - } - - generate(salt, count, length) { - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - if (!salt && !is_string(salt)) throw new IllegalArgumentError("bad 'salt' value"); - - count = count || this.count; - length = length || this.length; - - this.result = new Uint8Array(length); - - var blocks = Math.ceil(length / this.hmac.HMAC_SIZE); - - for (var i = 1; i <= blocks; ++i) { - var j = (i - 1) * this.hmac.HMAC_SIZE; - var l = (i < blocks ? 0 : length % this.hmac.HMAC_SIZE) || this.hmac.HMAC_SIZE; - - this.hmac.reset().process(salt); - this.hmac.hash.asm.pbkdf2_generate_block(this.hmac.hash.pos, this.hmac.hash.len, i, count, 0); - - this.result.set(this.hmac.hash.heap.subarray(0, l), j); - } - - return this; - } -} - -var pbkdf2_hmac_sha1_instance = null; - -export function get_pbkdf2_hmac_sha1_instance() { - if (pbkdf2_hmac_sha1_instance === null) pbkdf2_hmac_sha1_instance = new pbkdf2_hmac_sha1_constructor(); - return pbkdf2_hmac_sha1_instance; -} diff --git a/src/pbkdf2/pbkdf2-hmac-sha1.ts b/src/pbkdf2/pbkdf2-hmac-sha1.ts new file mode 100644 index 0000000..4fcba52 --- /dev/null +++ b/src/pbkdf2/pbkdf2-hmac-sha1.ts @@ -0,0 +1,21 @@ +import { HmacSha1 } from '../hmac/hmac-sha1'; + +export function Pbkdf2HmacSha1(password: Uint8Array, salt: Uint8Array, count: number, length: number): Uint8Array { + const hmac = new HmacSha1(password); + + const result = new Uint8Array(length); + + const blocks = Math.ceil(length / hmac.HMAC_SIZE); + + for (let i = 1; i <= blocks; ++i) { + const j = (i - 1) * hmac.HMAC_SIZE; + const l = (i < blocks ? 0 : length % hmac.HMAC_SIZE) || hmac.HMAC_SIZE; + + hmac.reset().process(salt); + hmac.hash.asm.pbkdf2_generate_block(hmac.hash.pos, hmac.hash.len, i, count, 0); + + result.set(hmac.hash.heap.subarray(0, l), j); + } + + return result; +} diff --git a/src/pbkdf2/pbkdf2-hmac-sha256.js b/src/pbkdf2/pbkdf2-hmac-sha256.js deleted file mode 100644 index 647689e..0000000 --- a/src/pbkdf2/pbkdf2-hmac-sha256.js +++ /dev/null @@ -1,46 +0,0 @@ -import { pbkdf2_constructor } from './pbkdf2'; -import { get_hmac_sha256_instance, hmac_sha256_constructor } from '../hmac/hmac-sha256'; -import { is_string } from '../utils'; -import { IllegalArgumentError, IllegalStateError } from '../errors'; - -export class pbkdf2_hmac_sha256_constructor extends pbkdf2_constructor { - constructor(options) { - options = options || {}; - - if (!(options.hmac instanceof hmac_sha256_constructor)) options.hmac = get_hmac_sha256_instance(); - - super(options); - } - - generate(salt, count, length) { - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - if (!salt && !is_string(salt)) throw new IllegalArgumentError("bad 'salt' value"); - - count = count || this.count; - length = length || this.length; - - this.result = new Uint8Array(length); - - var blocks = Math.ceil(length / this.hmac.HMAC_SIZE); - - for (var i = 1; i <= blocks; ++i) { - var j = (i - 1) * this.hmac.HMAC_SIZE; - var l = (i < blocks ? 0 : length % this.hmac.HMAC_SIZE) || this.hmac.HMAC_SIZE; - - this.hmac.reset().process(salt); - this.hmac.hash.asm.pbkdf2_generate_block(this.hmac.hash.pos, this.hmac.hash.len, i, count, 0); - - this.result.set(this.hmac.hash.heap.subarray(0, l), j); - } - - return this; - } -} - -var pbkdf2_hmac_sha256_instance = null; - -export function get_pbkdf2_hmac_sha256_instance() { - if (pbkdf2_hmac_sha256_instance === null) pbkdf2_hmac_sha256_instance = new pbkdf2_hmac_sha256_constructor(); - return pbkdf2_hmac_sha256_instance; -} diff --git a/src/pbkdf2/pbkdf2-hmac-sha256.ts b/src/pbkdf2/pbkdf2-hmac-sha256.ts new file mode 100644 index 0000000..26bbfde --- /dev/null +++ b/src/pbkdf2/pbkdf2-hmac-sha256.ts @@ -0,0 +1,21 @@ +import { HmacSha256 } from '../hmac/hmac-sha256'; + +export function Pbkdf2HmacSha256(password: Uint8Array, salt: Uint8Array, count: number, length: number): Uint8Array { + const hmac = new HmacSha256(password); + + const result = new Uint8Array(length); + + const blocks = Math.ceil(length / hmac.HMAC_SIZE); + + for (let i = 1; i <= blocks; ++i) { + const j = (i - 1) * hmac.HMAC_SIZE; + const l = (i < blocks ? 0 : length % hmac.HMAC_SIZE) || hmac.HMAC_SIZE; + + hmac.reset().process(salt); + hmac.hash.asm.pbkdf2_generate_block(hmac.hash.pos, hmac.hash.len, i, count, 0); + + result.set(hmac.hash.heap.subarray(0, l), j); + } + + return result; +} diff --git a/src/pbkdf2/pbkdf2-hmac-sha512.js b/src/pbkdf2/pbkdf2-hmac-sha512.js deleted file mode 100644 index eb26895..0000000 --- a/src/pbkdf2/pbkdf2-hmac-sha512.js +++ /dev/null @@ -1,55 +0,0 @@ -import { pbkdf2_constructor } from './pbkdf2'; -import { get_hmac_sha512_instance, hmac_sha512_constructor } from '../hmac/hmac-sha512'; -import { is_string } from '../utils'; -import { IllegalArgumentError, IllegalStateError } from '../errors'; - -export class pbkdf2_hmac_sha512_constructor extends pbkdf2_constructor { - constructor(options) { - options = options || {}; - - if (!(options.hmac instanceof hmac_sha512_constructor)) options.hmac = get_hmac_sha512_instance(); - - super(options); - } - - /** - * @param {Uint8Array} salt - * @param {number} count - * @param {number} length - * @return {pbkdf2_hmac_sha512_constructor} - */ - generate(salt, count, length) { - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - if (!salt && !is_string(salt)) throw new IllegalArgumentError("bad 'salt' value"); - - count = count || this.count; - length = length || this.length; - - this.result = new Uint8Array(length); - - var blocks = Math.ceil(length / this.hmac.HMAC_SIZE); - - for (var i = 1; i <= blocks; ++i) { - var j = (i - 1) * this.hmac.HMAC_SIZE; - var l = (i < blocks ? 0 : length % this.hmac.HMAC_SIZE) || this.hmac.HMAC_SIZE; - - this.hmac.reset().process(salt); - this.hmac.hash.asm.pbkdf2_generate_block(this.hmac.hash.pos, this.hmac.hash.len, i, count, 0); - - this.result.set(this.hmac.hash.heap.subarray(0, l), j); - } - - return this; - } -} - -var pbkdf2_hmac_sha512_instance = null; - -/** - * @return {get_pbkdf2_hmac_sha512_instance} - */ -export function get_pbkdf2_hmac_sha512_instance() { - if (pbkdf2_hmac_sha512_instance === null) pbkdf2_hmac_sha512_instance = new pbkdf2_hmac_sha512_constructor(); - return pbkdf2_hmac_sha512_instance; -} diff --git a/src/pbkdf2/pbkdf2-hmac-sha512.ts b/src/pbkdf2/pbkdf2-hmac-sha512.ts new file mode 100644 index 0000000..bb293ff --- /dev/null +++ b/src/pbkdf2/pbkdf2-hmac-sha512.ts @@ -0,0 +1,21 @@ +import { HmacSha512 } from '../hmac/hmac-sha512'; + +export function Pbkdf2HmacSha512(password: Uint8Array, salt: Uint8Array, count: number, length: number): Uint8Array { + const hmac = new HmacSha512(password); + + const result = new Uint8Array(length); + + const blocks = Math.ceil(length / hmac.HMAC_SIZE); + + for (let i = 1; i <= blocks; ++i) { + const j = (i - 1) * hmac.HMAC_SIZE; + const l = (i < blocks ? 0 : length % hmac.HMAC_SIZE) || hmac.HMAC_SIZE; + + hmac.reset().process(salt); + hmac.hash.asm.pbkdf2_generate_block(hmac.hash.pos, hmac.hash.len, i, count, 0); + + result.set(hmac.hash.heap.subarray(0, l), j); + } + + return result; +} diff --git a/src/pbkdf2/pbkdf2.js b/src/pbkdf2/pbkdf2.js deleted file mode 100644 index 3964dc7..0000000 --- a/src/pbkdf2/pbkdf2.js +++ /dev/null @@ -1,69 +0,0 @@ -import { is_string } from '../utils'; -import { IllegalArgumentError, IllegalStateError } from '../errors'; - -export class pbkdf2_constructor { - constructor(options) { - options = options || {}; - - if (!options.hmac) throw new SyntaxError("option 'hmac' is required"); - - if (!options.hmac.HMAC_SIZE) - throw new SyntaxError("option 'hmac' supplied doesn't seem to be a valid HMAC function"); - - this.hmac = options.hmac; - this.count = options.count || 4096; - this.length = options.length || this.hmac.HMAC_SIZE; - - this.result = null; - - var password = options.password; - if (password || is_string(password)) this.reset(options); - - return this; - } - - reset(options) { - this.result = null; - - this.hmac.reset(options); - - return this; - } - - generate(salt, count, length) { - if (this.result !== null) throw new IllegalStateError('state must be reset before processing new data'); - - if (!salt && !is_string(salt)) throw new IllegalArgumentError("bad 'salt' value"); - - count = count || this.count; - length = length || this.length; - - this.result = new Uint8Array(length); - - var blocks = Math.ceil(length / this.hmac.HMAC_SIZE); - - for (var i = 1; i <= blocks; ++i) { - var j = (i - 1) * this.hmac.HMAC_SIZE; - var l = (i < blocks ? 0 : length % this.hmac.HMAC_SIZE) || this.hmac.HMAC_SIZE; - 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, - ); - this.result.set(tmp.subarray(0, l), j); - for (var k = 1; k < count; ++k) { - tmp = new Uint8Array( - this.hmac - .reset() - .process(tmp) - .finish().result, - ); - for (var r = 0; r < l; ++r) this.result[j + r] ^= tmp[r]; - } - } - - return this; - } -} diff --git a/src/random/exports.js b/src/random/exports.js deleted file mode 100644 index a5ca5e1..0000000 --- a/src/random/exports.js +++ /dev/null @@ -1 +0,0 @@ -export { Random_getNumber as random, Random_getValues as getRandomValues } from './random'; diff --git a/src/random/globals.js b/src/random/globals.js deleted file mode 100644 index e4729cf..0000000 --- a/src/random/globals.js +++ /dev/null @@ -1,6 +0,0 @@ -import { Random_getNumber, Random_getValues } from './random'; - -Math.random = Random_getNumber; - -if (typeof 'crypto' === 'undefined') var crypto = {}; -crypto.getRandomValues = Random_getValues; diff --git a/src/random/isaac.js b/src/random/isaac.js deleted file mode 100644 index a7ab2f4..0000000 --- a/src/random/isaac.js +++ /dev/null @@ -1,202 +0,0 @@ -/* ---------------------------------------------------------------------- - * Copyright (c) 2014 Artem S Vybornov - * - * Copyright (c) 2012 Yves-Marie K. Rinquin - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ---------------------------------------------------------------------- - * - * ISAAC is a cryptographically secure pseudo-random number generator - * (or CSPRNG for short) designed by Robert J. Jenkins Jr. in 1996 and - * based on RC4. It is designed for speed and security. - * - * ISAAC's informations & analysis: - * http://burtleburtle.net/bob/rand/isaac.html - * ISAAC's implementation details: - * http://burtleburtle.net/bob/rand/isaacafa.html - * - * ISAAC succesfully passed TestU01 - */ - -import { FloatArray, is_buffer, is_number, is_string, is_typed_array, string_to_bytes } from '../utils'; - -export var ISAAC = (function() { - var m = new Uint32Array(256), // internal memory - r = new Uint32Array(256), // result array - acc = 0, // accumulator - brs = 0, // last result - cnt = 0, // counter - gnt = 0; // generation counter - - /* private: randinit function, same as ISAAC reference implementation */ - function randinit() { - var a, b, c, d, e, f, g, h; - - /* private mixing function */ - function mix() { - a ^= b << 11; - d = (d + a) | 0; - b = (b + c) | 0; - b ^= c >>> 2; - e = (e + b) | 0; - c = (c + d) | 0; - c ^= d << 8; - f = (f + c) | 0; - d = (d + e) | 0; - d ^= e >>> 16; - g = (g + d) | 0; - e = (e + f) | 0; - e ^= f << 10; - h = (h + e) | 0; - f = (f + g) | 0; - f ^= g >>> 4; - a = (a + f) | 0; - g = (g + h) | 0; - g ^= h << 8; - b = (b + g) | 0; - h = (h + a) | 0; - h ^= a >>> 9; - c = (c + h) | 0; - a = (a + b) | 0; - } - - acc = brs = cnt = 0; - - // the golden ratio - a = b = c = d = e = f = g = h = 0x9e3779b9; - - // scramble it - for (var i = 0; i < 4; i++) mix(); - - // mix it and combine with the internal state - for (var i = 0; i < 256; i += 8) { - a = (a + r[i | 0]) | 0; - b = (b + r[i | 1]) | 0; - c = (c + r[i | 2]) | 0; - d = (d + r[i | 3]) | 0; - e = (e + r[i | 4]) | 0; - f = (f + r[i | 5]) | 0; - g = (g + r[i | 6]) | 0; - h = (h + r[i | 7]) | 0; - mix(); - m.set([a, b, c, d, e, f, g, h], i); - } - - // mix it again - for (var i = 0; i < 256; i += 8) { - a = (a + m[i | 0]) | 0; - b = (b + m[i | 1]) | 0; - c = (c + m[i | 2]) | 0; - d = (d + m[i | 3]) | 0; - e = (e + m[i | 4]) | 0; - f = (f + m[i | 5]) | 0; - g = (g + m[i | 6]) | 0; - h = (h + m[i | 7]) | 0; - mix(); - m.set([a, b, c, d, e, f, g, h], i); - } - - // fill in the first set of results - prng(1), (gnt = 256); - } - - /* public: seeding function */ - function seed(s) { - var i, j, k, n, l; - - if (!is_typed_array(s)) { - if (is_number(s)) { - (n = new FloatArray(1)), (n[0] = s); - s = new Uint8Array(n.buffer); - } else if (is_string(s)) { - s = string_to_bytes(s); - } else if (is_buffer(s)) { - s = new Uint8Array(s); - } else { - throw new TypeError('bad seed type'); - } - } else { - s = new Uint8Array(s.buffer); - } - - // preprocess the seed - l = s.length; - for (j = 0; j < l; j += 1024) { - // xor each chunk of 1024 bytes with r, for randinit() to mix in - for (k = j, i = 0; i < 1024 && k < l; k = j | ++i) { - r[i >> 2] ^= s[k] << ((i & 3) << 3); - } - randinit(); - } - } - - /* public: isaac generator, n = number of run */ - function prng(n) { - n = n || 1; - - var i, x, y; - - while (n--) { - cnt = (cnt + 1) | 0; - brs = (brs + cnt) | 0; - - for (i = 0; i < 256; i += 4) { - acc ^= acc << 13; - acc = (m[(i + 128) & 0xff] + acc) | 0; - x = m[i | 0]; - m[i | 0] = y = (m[(x >>> 2) & 0xff] + ((acc + brs) | 0)) | 0; - r[i | 0] = brs = (m[(y >>> 10) & 0xff] + x) | 0; - - acc ^= acc >>> 6; - acc = (m[(i + 129) & 0xff] + acc) | 0; - x = m[i | 1]; - m[i | 1] = y = (m[(x >>> 2) & 0xff] + ((acc + brs) | 0)) | 0; - r[i | 1] = brs = (m[(y >>> 10) & 0xff] + x) | 0; - - acc ^= acc << 2; - acc = (m[(i + 130) & 0xff] + acc) | 0; - x = m[i | 2]; - m[i | 2] = y = (m[(x >>> 2) & 0xff] + ((acc + brs) | 0)) | 0; - r[i | 2] = brs = (m[(y >>> 10) & 0xff] + x) | 0; - - acc ^= acc >>> 16; - acc = (m[(i + 131) & 0xff] + acc) | 0; - x = m[i | 3]; - m[i | 3] = y = (m[(x >>> 2) & 0xff] + ((acc + brs) | 0)) | 0; - r[i | 3] = brs = (m[(y >>> 10) & 0xff] + x) | 0; - } - } - } - - /* public: return a random number */ - function rand() { - if (!gnt--) prng(1), (gnt = 255); - - return r[gnt]; - } - - /* return class object */ - return { - seed: seed, - prng: prng, - rand: rand, - }; -})(); diff --git a/src/random/random.js b/src/random/random.js deleted file mode 100644 index c8fbe21..0000000 --- a/src/random/random.js +++ /dev/null @@ -1,269 +0,0 @@ -import { ISAAC } from './isaac'; -import { FloatArray, is_buffer, is_typed_array } from '../utils'; -import { get_pbkdf2_hmac_sha256_instance } from '../pbkdf2/pbkdf2-hmac-sha256'; -import { SecurityError } from '../errors'; - -var _global_console = typeof console !== 'undefined' ? console : undefined, - _global_date_now = Date.now, - _global_math_random = Math.random, - _global_performance = typeof performance !== 'undefined' ? performance : undefined, - _global_crypto = typeof crypto !== 'undefined' ? crypto : typeof msCrypto !== 'undefined' ? msCrypto : undefined, - _global_crypto_getRandomValues; - -if (_global_crypto !== undefined) _global_crypto_getRandomValues = _global_crypto.getRandomValues; - -var _isaac_rand = ISAAC.rand, - _isaac_seed = ISAAC.seed, - _isaac_counter = 0, - _isaac_weak_seeded = false, - _isaac_seeded = false; - -var _random_estimated_entropy = 0, - _random_required_entropy = 256, - _random_warn_callstacks = {}; - -export var _random_skip_system_rng_warning = false; -export var _random_allow_weak = false; - -var _hires_now; -if (_global_performance !== undefined) { - _hires_now = function() { - return (1000 * _global_performance.now()) | 0; - }; -} else { - var _hires_epoch = (1000 * _global_date_now()) | 0; - _hires_now = function() { - return (1000 * _global_date_now() - _hires_epoch) | 0; - }; -} - -/** - * weak_seed - * - * Seeds RNG with native `crypto.getRandomValues` output or with high-resolution - * time and single `Math.random()` value, and various other sources. - * - * We estimate this may give at least ~50 bits of unpredictableness, - * but this has not been analysed thoroughly or precisely. - */ -function Random_weak_seed() { - if (_global_crypto !== undefined) { - buffer = new Uint8Array(32); - _global_crypto_getRandomValues.call(_global_crypto, buffer); - - _isaac_seed(buffer); - } else { - // Some clarification about brute-force attack cost: - // - entire bitcoin network operates at ~10^16 hash guesses per second; - // - each PBKDF2 iteration requires the same number of hashing operations as bitcoin nonce guess; - // - attacker having such a hashing power is able to break worst-case 50 bits of the randomness in ~3 hours; - // Sounds sad though attacker having such a hashing power more likely would prefer to mine bitcoins. - var buffer = new FloatArray(3), - i, - t; - - buffer[0] = _global_math_random(); - buffer[1] = _global_date_now(); - buffer[2] = _hires_now(); - - buffer = new Uint8Array(buffer.buffer); - - var salt = ''; - if (typeof location !== 'undefined') { - salt += location.href; - } else if (typeof process !== 'undefined') { - salt += process.pid + process.title; - } - - var pbkdf2 = get_pbkdf2_hmac_sha256_instance(); - for (i = 0; i < 100; i++) { - buffer = pbkdf2.reset({ password: buffer }).generate(salt, 1000, 32).result; - t = _hires_now(); - (buffer[0] ^= t >>> 24), (buffer[1] ^= t >>> 16), (buffer[2] ^= t >>> 8), (buffer[3] ^= t); - } - - _isaac_seed(buffer); - } - - _isaac_counter = 0; - - _isaac_weak_seeded = true; -} - -/** - * seed - * - * Seeds PRNG with supplied random values if these values have enough entropy. - * - * A false return value means the RNG is currently insecure; however a true - * return value does not mean it is necessarily secure (depending on how you - * collected the seed) though asmCrypto will be forced to assume this. - * - * The input buffer will be zeroed to discourage reuse. You should not copy it - * or use it anywhere else before passing it into this function. - * - * **DISCLAIMER!** Seeding with a poor values is an easiest way shoot your legs, so - * do not seed until you're know what entropy is and how to obtail high-quality random values, - * **DO NOT SEED WITH CONSTANT VALUE! YOU'LL GET NO RANDOMNESS FROM CONSTANT!** - */ -export function Random_seed(seed) { - if (!is_buffer(seed) && !is_typed_array(seed)) throw new TypeError('bad seed type'); - - var bpos = seed.byteOffset || 0, - blen = seed.byteLength || seed.length, - buff = new Uint8Array(seed.buffer || seed, bpos, blen); - - _isaac_seed(buff); - - _isaac_counter = 0; - - // don't let the user use these bytes again - var nonzero = 0; - for (var i = 0; i < buff.length; i++) { - nonzero |= buff[i]; - buff[i] = 0; - } - - if (nonzero !== 0) { - // TODO we could make a better estimate, but half-length is a prudent - // simple measure that seems unlikely to over-estimate - _random_estimated_entropy += 4 * blen; - } - - _isaac_seeded = _random_estimated_entropy >= _random_required_entropy; - - return _isaac_seeded; -} - -/** - * getValues - * - * Populates the buffer with cryptographically secure random values. These are - * calculated using `crypto.getRandomValues` if it is available, as well as our - * own ISAAC PRNG implementation. - * - * If the former is not available (older browsers such as IE10 [1]), then the - * latter *must* be seeded using `Random.seed`, unless `asmCrypto.random.allowWeak` is true. - * - * *We assume the system RNG is strong*; if you cannot afford this risk, then - * you should also seed ISAAC using `Random.seed`. This is advisable for very - * important situations, such as generation of long-term secrets. See also [2]. - * - * [1] https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues - * [2] https://en.wikipedia.org/wiki/Dual_EC_DRBG - * - * In all cases, we opportunistically seed using various arbitrary sources - * such as high-resolution time and one single value from the insecure - * Math.random(); however this is not reliable as a strong security measure. - */ -export function Random_getValues(buffer) { - // opportunistically seed ISAAC with a weak seed; this hopefully makes an - // attack harder in the case where the system RNG is weak *and* we haven't - // seeded ISAAC. but don't make any guarantees to the user about this. - if (!_isaac_weak_seeded) Random_weak_seed(); - - // if we have no strong sources then the RNG is weak, handle it - if (!_isaac_seeded && _global_crypto === undefined) { - if (!_random_allow_weak) throw new SecurityError('No strong PRNGs available. Use asmCrypto.random.seed().'); - - if (_global_console !== undefined) - _global_console.error( - 'No strong PRNGs available; your security is greatly lowered. Use asmCrypto.random.seed().', - ); - } - - // separate warning about assuming system RNG strong - if ( - !_random_skip_system_rng_warning && - !_isaac_seeded && - _global_crypto !== undefined && - _global_console !== undefined - ) { - // Hacky way to get call stack - var s = new Error().stack; - _random_warn_callstacks[s] |= 0; - if (!_random_warn_callstacks[s]++) - _global_console.warn( - 'asmCrypto PRNG not seeded; your security relies on your system PRNG. If this is not acceptable, use asmCrypto.random.seed().', - ); - } - - // proceed to get random values - if (!is_buffer(buffer) && !is_typed_array(buffer)) throw new TypeError('unexpected buffer type'); - - var bpos = buffer.byteOffset || 0, - blen = buffer.byteLength || buffer.length, - bytes = new Uint8Array(buffer.buffer || buffer, bpos, blen), - i, - r; - - // apply system rng - if (_global_crypto !== undefined) _global_crypto_getRandomValues.call(_global_crypto, bytes); - - // apply isaac rng - for (i = 0; i < blen; i++) { - if ((i & 3) === 0) { - if (_isaac_counter >= 0x10000000000) Random_weak_seed(); - r = _isaac_rand(); - _isaac_counter++; - } - bytes[i] ^= r; - r >>>= 8; - } - - return buffer; -} - -/** - * getNumber - * - * A drop-in `Math.random` replacement. - * Intended for prevention of random material leakage out of the user's host. - */ -export function Random_getNumber() { - if (!_isaac_weak_seeded || _isaac_counter >= 0x10000000000) Random_weak_seed(); - - var n = (0x100000 * _isaac_rand() + (_isaac_rand() >>> 12)) / 0x10000000000000; - _isaac_counter += 2; - - return n; -} - -Object.defineProperty(Random_getNumber, 'allowWeak', { - get: function() { - return _random_allow_weak; - }, - set: function(a) { - _random_allow_weak = a; - }, -}); - -Object.defineProperty(Random_getNumber, 'skipSystemRNGWarning', { - get: function() { - return _random_skip_system_rng_warning; - }, - set: function(w) { - _random_skip_system_rng_warning = w; - }, -}); - -Object.defineProperty(Random_getValues, 'allowWeak', { - get: function() { - return _random_allow_weak; - }, - set: function(a) { - _random_allow_weak = a; - }, -}); - -Object.defineProperty(Random_getValues, 'skipSystemRNGWarning', { - get: function() { - return _random_skip_system_rng_warning; - }, - set: function(w) { - _random_skip_system_rng_warning = w; - }, -}); - -Random_getNumber.seed = Random_seed; -Random_getValues.seed = Random_seed; diff --git a/src/rsa/exports-keygen.js b/src/rsa/exports-keygen.js deleted file mode 100644 index 448a01f..0000000 --- a/src/rsa/exports-keygen.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * RSA keygen exports - */ -import { is_big_number } from '../bignum/bignum'; -import { RSA_generateKey } from './genkey'; - -function rsa_generate_key(bitlen, e) { - if (bitlen === undefined) throw new SyntaxError('bitlen required'); - if (e === undefined) throw new SyntaxError('e required'); - var key = RSA_generateKey(bitlen, e); - for (var i = 0; i < key.length; i++) { - if (is_big_number(key[i])) key[i] = key[i].toBytes(); - } - return key; -} - -export var RSA = { - generateKey: rsa_generate_key, -}; diff --git a/src/rsa/exports-oaep-sha1.js b/src/rsa/exports-oaep-sha1.js deleted file mode 100644 index ae56849..0000000 --- a/src/rsa/exports-oaep-sha1.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * RSA-OAEP-SHA1 exports - */ - -import { RSA_OAEP } from './pkcs1'; -import { get_sha1_instance } from '../hash/sha1/sha1'; - -function rsa_oaep_sha1_encrypt_bytes(data, key, label) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_OAEP({ hash: get_sha1_instance(), key: key, label: label }).encrypt(data).result; -} - -function rsa_oaep_sha1_decrypt_bytes(data, key, label) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_OAEP({ hash: get_sha1_instance(), key: key, label: label }).decrypt(data).result; -} - -export var RSA_OAEP_SHA1 = { - encrypt: rsa_oaep_sha1_encrypt_bytes, - decrypt: rsa_oaep_sha1_decrypt_bytes, -}; diff --git a/src/rsa/exports-oaep-sha256.js b/src/rsa/exports-oaep-sha256.js deleted file mode 100644 index c2ae3a5..0000000 --- a/src/rsa/exports-oaep-sha256.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * RSA-OAEP-SHA256 exports - */ - -import { RSA_OAEP } from './pkcs1'; -import { get_sha256_instance } from '../hash/sha256/sha256'; - -function rsa_oaep_sha256_encrypt_bytes(data, key, label) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_OAEP({ hash: get_sha256_instance(), key: key, label: label }).encrypt(data).result; -} - -function rsa_oaep_sha256_decrypt_bytes(data, key, label) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_OAEP({ hash: get_sha256_instance(), key: key, label: label }).decrypt(data).result; -} - -export var RSA_OAEP_SHA256 = { - encrypt: rsa_oaep_sha256_encrypt_bytes, - decrypt: rsa_oaep_sha256_decrypt_bytes, -}; diff --git a/src/rsa/exports-oaep-sha512.js b/src/rsa/exports-oaep-sha512.js deleted file mode 100644 index 07df8e0..0000000 --- a/src/rsa/exports-oaep-sha512.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * RSA-OAEP-SHA512 exports - */ - -import { RSA_OAEP } from './pkcs1'; -import { get_sha512_instance } from '../hash/sha512/sha512'; - -function rsa_oaep_sha512_encrypt_bytes(data, key, label) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_OAEP({ hash: get_sha512_instance(), key: key, label: label }).encrypt(data).result; -} - -function rsa_oaep_sha512_decrypt_bytes(data, key, label) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_OAEP({ hash: get_sha512_instance(), key: key, label: label }).decrypt(data).result; -} - -export var RSA_OAEP_SHA512 = { - encrypt: rsa_oaep_sha512_encrypt_bytes, - decrypt: rsa_oaep_sha512_decrypt_bytes, -}; diff --git a/src/rsa/exports-pkcs1-v1_5-sha1.js b/src/rsa/exports-pkcs1-v1_5-sha1.js deleted file mode 100644 index 6be89b9..0000000 --- a/src/rsa/exports-pkcs1-v1_5-sha1.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * RSA-PKCS1-v1_5-SHA1 exports - */ - -function rsa_pkcs1_v1_5_sha1_sign_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_PKCS1_v1_5({ hash: get_sha1_instance(), key: key }).sign(data).result; -} - -function rsa_pkcs1_v1_5_sha1_verify_bytes(signature, data, key) { - if (signature === undefined) throw new SyntaxError('signature required'); - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - try { - new RSA_PKCS1_v1_5({ hash: get_sha1_instance(), key: key }).verify(signature, data); - return true; - } catch (e) { - if (!(e instanceof SecurityError)) throw e; - } - return false; -} - -exports.RSA_PKCS1_v1_5 = RSA_PKCS1_v1_5; - -exports.RSA_PKCS1_v1_5_SHA1 = { - sign: rsa_pkcs1_v1_5_sha1_sign_bytes, - verify: rsa_pkcs1_v1_5_sha1_verify_bytes, -}; diff --git a/src/rsa/exports-pkcs1-v1_5-sha256.js b/src/rsa/exports-pkcs1-v1_5-sha256.js deleted file mode 100644 index 7ecac12..0000000 --- a/src/rsa/exports-pkcs1-v1_5-sha256.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * RSA-PKCS1-v1_5-SHA256 exports - */ - -function rsa_pkcs1_v1_5_sha256_sign_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_PKCS1_v1_5({ hash: get_sha256_instance(), key: key }).sign(data).result; -} - -function rsa_pkcs1_v1_5_sha256_verify_bytes(signature, data, key) { - if (signature === undefined) throw new SyntaxError('signature required'); - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - try { - new RSA_PKCS1_v1_5({ hash: get_sha256_instance(), key: key }).verify(signature, data); - return true; - } catch (e) { - if (!(e instanceof SecurityError)) throw e; - } - return false; -} - -exports.RSA_PKCS1_v1_5 = RSA_PKCS1_v1_5; - -exports.RSA_PKCS1_v1_5_SHA256 = { - sign: rsa_pkcs1_v1_5_sha256_sign_bytes, - verify: rsa_pkcs1_v1_5_sha256_verify_bytes, -}; diff --git a/src/rsa/exports-pkcs1-v1_5-sha512.js b/src/rsa/exports-pkcs1-v1_5-sha512.js deleted file mode 100644 index af3939d..0000000 --- a/src/rsa/exports-pkcs1-v1_5-sha512.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * RSA-PKCS1-v1_5-SHA512 exports - */ - -function rsa_pkcs1_v1_5_sha512_sign_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_PKCS1_v1_5({ hash: get_sha512_instance(), key: key }).sign(data).result; -} - -function rsa_pkcs1_v1_5_sha512_verify_bytes(signature, data, key) { - if (signature === undefined) throw new SyntaxError('signature required'); - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - try { - new RSA_PKCS1_v1_5({ hash: get_sha512_instance(), key: key }).verify(signature, data); - return true; - } catch (e) { - if (!(e instanceof SecurityError)) throw e; - } - return false; -} - -exports.RSA_PKCS1_v1_5 = RSA_PKCS1_v1_5; - -exports.RSA_PKCS1_v1_5_SHA512 = { - sign: rsa_pkcs1_v1_5_sha512_sign_bytes, - verify: rsa_pkcs1_v1_5_sha512_verify_bytes, -}; diff --git a/src/rsa/exports-pss-sha1.js b/src/rsa/exports-pss-sha1.js deleted file mode 100644 index 9c46efa..0000000 --- a/src/rsa/exports-pss-sha1.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * RSA-PSS-SHA1 exports - */ - -import { RSA_PSS } from './pkcs1'; -import { get_sha1_instance } from '../hash/sha1/sha1'; -import { SecurityError } from '../errors'; - -function rsa_pss_sha1_sign_bytes(data, key, slen) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_PSS({ hash: get_sha1_instance(), key: key, saltLength: slen }).sign(data).result; -} - -function rsa_pss_sha1_verify_bytes(signature, data, key, slen) { - if (signature === undefined) throw new SyntaxError('signature required'); - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - try { - new RSA_PSS({ hash: get_sha1_instance(), key: key, saltLength: slen }).verify(signature, data); - return true; - } catch (e) { - if (!(e instanceof SecurityError)) throw e; - } - return false; -} - -export var RSA_PSS_SHA1 = { - sign: rsa_pss_sha1_sign_bytes, - verify: rsa_pss_sha1_verify_bytes, -}; diff --git a/src/rsa/exports-pss-sha256.js b/src/rsa/exports-pss-sha256.js deleted file mode 100644 index 6acc252..0000000 --- a/src/rsa/exports-pss-sha256.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * RSA-PSS-SHA256 exports - */ - -import { get_sha256_instance } from '../hash/sha256/sha256'; -import { RSA_PSS } from './pkcs1'; -import { SecurityError } from '../errors'; - -function rsa_pss_sha256_sign_bytes(data, key, slen) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_PSS({ hash: get_sha256_instance(), key: key, saltLength: slen }).sign(data).result; -} - -function rsa_pss_sha256_verify_bytes(signature, data, key, slen) { - if (signature === undefined) throw new SyntaxError('signature required'); - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - try { - new RSA_PSS({ hash: get_sha256_instance(), key: key, saltLength: slen }).verify(signature, data); - return true; - } catch (e) { - if (!(e instanceof SecurityError)) throw e; - } - return false; -} - -export var RSA_PSS_SHA256 = { - sign: rsa_pss_sha256_sign_bytes, - verify: rsa_pss_sha256_verify_bytes, -}; diff --git a/src/rsa/exports-pss-sha512.js b/src/rsa/exports-pss-sha512.js deleted file mode 100644 index 54e02ff..0000000 --- a/src/rsa/exports-pss-sha512.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * RSA-PSS-SHA512 exports - */ - -import { RSA_PSS } from './pkcs1'; -import { get_sha512_instance } from '../hash/sha512/sha512'; -import { SecurityError } from '../errors'; - -function rsa_pss_sha512_sign_bytes(data, key, slen) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA_PSS({ hash: get_sha512_instance(), key: key, saltLength: slen }).sign(data).result; -} - -function rsa_pss_sha512_verify_bytes(signature, data, key, slen) { - if (signature === undefined) throw new SyntaxError('signature required'); - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - try { - new RSA_PSS({ hash: get_sha512_instance(), key: key, saltLength: slen }).verify(signature, data); - return true; - } catch (e) { - if (!(e instanceof SecurityError)) throw e; - } - return false; -} - -export var RSA_PSS_SHA512 = { - sign: rsa_pss_sha512_sign_bytes, - verify: rsa_pss_sha512_verify_bytes, -}; diff --git a/src/rsa/exports-raw.js b/src/rsa/exports-raw.js deleted file mode 100644 index f9a2387..0000000 --- a/src/rsa/exports-raw.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * RSA-RAW exports - */ - -import RSA from './raw'; - -function rsa_raw_encrypt_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA({ key: key }).encrypt(data).result; -} - -function rsa_raw_decrypt_bytes(data, key) { - if (data === undefined) throw new SyntaxError('data required'); - if (key === undefined) throw new SyntaxError('key required'); - return new RSA({ key: key }).decrypt(data).result; -} - -export var RSA_RAW = RSA; - -RSA_RAW.encrypt = rsa_raw_encrypt_bytes; -RSA_RAW.decrypt = rsa_raw_decrypt_bytes; -RSA_RAW.sign = rsa_raw_decrypt_bytes; -RSA_RAW.verify = rsa_raw_encrypt_bytes; diff --git a/src/rsa/genkey.js b/src/rsa/genkey.js deleted file mode 100644 index 2532bdb..0000000 --- a/src/rsa/genkey.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Generate RSA key pair - * - * @param bitlen desired modulus length, default is 2048 - * @param e public exponent, default is 65537 - */ -import { RSA } from './rsa'; -import { randomProbablePrime } from '../bignum/bignum'; -import { BigNumber_extGCD } from '../bignum/extgcd'; -import { BigNumber, is_big_number, Modulus } from '../bignum/bignum'; -import { is_buffer, is_bytes, is_number, is_string, string_to_bytes } from '../utils'; -import { IllegalArgumentError } from '../errors'; - -export function RSA_generateKey(bitlen, e) { - bitlen = bitlen || 2048; - e = e || 65537; - - if (bitlen < 512) throw new IllegalArgumentError('bit length is too small'); - - if (is_string(e)) e = string_to_bytes(e); - - if (is_buffer(e)) e = new Uint8Array(e); - - if (is_bytes(e)) { - e = new BigNumber(e); - } else if (is_number(e)) { - e = BigNumber.fromNumber(e); - } else if (is_big_number(e)) { - e = BigNumber.fromConfig(e); - } else { - throw new TypeError('unexpected exponent type'); - } - - if ((e.limbs[0] & 1) === 0) throw new IllegalArgumentError('exponent must be an odd number'); - - var m, e, d, p, q, p1, q1, dp, dq, u; - - p = randomProbablePrime(bitlen >> 1, function(p) { - p1 = BigNumber.fromConfig(p); - p1.limbs[0] -= 1; - return BigNumber_extGCD(p1, e).gcd.valueOf() == 1; - }); - - q = randomProbablePrime(bitlen - (bitlen >> 1), function(q) { - m = new Modulus(p.multiply(q)); - if (!(m.limbs[((bitlen + 31) >> 5) - 1] >>> ((bitlen - 1) & 31))) return false; - q1 = BigNumber.fromConfig(q); - q1.limbs[0] -= 1; - return BigNumber_extGCD(q1, e).gcd.valueOf() == 1; - }); - - d = new Modulus(p1.multiply(q1)).inverse(e); - - (dp = d.divide(p1).remainder), (dq = d.divide(q1).remainder); - - (p = new Modulus(p)), (q = new Modulus(q)); - - var u = p.inverse(q); - - return [m, e, d, p, q, dp, dq, u]; -} - -RSA.generateKey = RSA_generateKey; - -export default RSA; diff --git a/src/rsa/pkcs1.js b/src/rsa/pkcs1.js deleted file mode 100644 index 6b0cb8a..0000000 --- a/src/rsa/pkcs1.js +++ /dev/null @@ -1,528 +0,0 @@ -import { RSA_reset, RSA_encrypt, RSA_decrypt } from './rsa'; -import { Random_getValues } from '../random/random'; -import { is_buffer, is_bytes, is_number, is_string, string_to_bytes } from '../utils'; -import { IllegalArgumentError, IllegalStateError, SecurityError } from '../errors'; - -export class RSA_OAEP { - constructor(options) { - options = options || {}; - - if (!options.hash) throw new SyntaxError("option 'hash' is required"); - - if (!options.hash.HASH_SIZE) - throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); - - this.hash = options.hash; - - this.label = null; - - this.reset(options); - } - - reset(options) { - options = options || {}; - - var label = options.label; - if (label !== undefined) { - if (is_buffer(label) || is_bytes(label)) { - label = new Uint8Array(label); - } else if (is_string(label)) { - label = string_to_bytes(label); - } else { - throw new TypeError('unexpected label type'); - } - - this.label = label.length > 0 ? label : null; - } else { - this.label = null; - } - - RSA_reset.call(this, options); - } - - /** - * @param {Uint8Array} data - * @return {RSA_OAEP} - */ - encrypt(data) { - if (!this.key) throw new IllegalStateError('no key is associated with the instance'); - - var key_size = Math.ceil(this.key[0].bitLength / 8), - hash_size = this.hash.HASH_SIZE, - data_length = data.byteLength || data.length || 0, - ps_length = key_size - data_length - 2 * hash_size - 2; - - if (data_length > key_size - 2 * this.hash.HASH_SIZE - 2) throw new IllegalArgumentError('data too large'); - - var message = new Uint8Array(key_size), - seed = message.subarray(1, hash_size + 1), - data_block = message.subarray(hash_size + 1); - - if (is_bytes(data)) { - data_block.set(data, hash_size + ps_length + 1); - } else if (is_buffer(data)) { - data_block.set(new Uint8Array(data), hash_size + ps_length + 1); - } else if (is_string(data)) { - data_block.set(string_to_bytes(data), hash_size + ps_length + 1); - } else { - throw new TypeError('unexpected data type'); - } - - data_block.set( - this.hash - .reset() - .process(this.label || '') - .finish().result, - 0, - ); - data_block[hash_size + ps_length] = 1; - - Random_getValues(seed); - - var data_block_mask = RSA_MGF1_generate.call(this, seed, data_block.length); - for (var i = 0; i < data_block.length; i++) data_block[i] ^= data_block_mask[i]; - - var seed_mask = RSA_MGF1_generate.call(this, data_block, seed.length); - for (var i = 0; i < seed.length; i++) seed[i] ^= seed_mask[i]; - - RSA_encrypt.call(this, message); - - return this; - } - - /** - * @param {Uint8Array} data - * @return {RSA_OAEP} - */ - decrypt(data) { - if (!this.key) throw new IllegalStateError('no key is associated with the instance'); - - var key_size = Math.ceil(this.key[0].bitLength / 8), - hash_size = this.hash.HASH_SIZE, - data_length = data.byteLength || data.length || 0; - - if (data_length !== key_size) throw new IllegalArgumentError('bad data'); - - RSA_decrypt.call(this, data); - - var z = this.result[0], - seed = this.result.subarray(1, hash_size + 1), - data_block = this.result.subarray(hash_size + 1); - - if (z !== 0) throw new SecurityError('decryption failed'); - - var seed_mask = RSA_MGF1_generate.call(this, data_block, seed.length); - for (var i = 0; i < seed.length; i++) seed[i] ^= seed_mask[i]; - - var data_block_mask = RSA_MGF1_generate.call(this, seed, data_block.length); - for (var i = 0; i < data_block.length; i++) data_block[i] ^= data_block_mask[i]; - - var lhash = this.hash - .reset() - .process(this.label || '') - .finish().result; - for (var i = 0; i < hash_size; i++) { - if (lhash[i] !== data_block[i]) throw new SecurityError('decryption failed'); - } - - var ps_end = hash_size; - for (; ps_end < data_block.length; ps_end++) { - var psz = data_block[ps_end]; - if (psz === 1) break; - if (psz !== 0) throw new SecurityError('decryption failed'); - } - if (ps_end === data_block.length) throw new SecurityError('decryption failed'); - - this.result = data_block.subarray(ps_end + 1); - - return this; - } -} - -/** - * @param {Uint8Array} seed - * @param {number} length - * @return {Uint8Array} - * @constructor - */ -function RSA_MGF1_generate(seed, length) { - seed = seed || ''; - length = length || 0; - - var hash_size = this.hash.HASH_SIZE; - // if ( length > (hash_size * 0x100000000) ) - // throw new IllegalArgumentError("mask length too large"); - - var mask = new Uint8Array(length), - counter = new Uint8Array(4), - chunks = Math.ceil(length / hash_size); - for (var i = 0; i < chunks; i++) { - (counter[0] = i >>> 24), (counter[1] = (i >>> 16) & 255), (counter[2] = (i >>> 8) & 255), (counter[3] = i & 255); - - var submask = mask.subarray(i * hash_size); - - var chunk = this.hash - .reset() - .process(seed) - .process(counter) - .finish().result; - if (chunk.length > submask.length) chunk = chunk.subarray(0, submask.length); - - submask.set(chunk); - } - - return mask; -} - -export class RSA_PSS { - constructor(options) { - options = options || {}; - - if (!options.hash) throw new SyntaxError("option 'hash' is required"); - - if (!options.hash.HASH_SIZE) - throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); - - this.hash = options.hash; - - this.saltLength = 4; - - this.reset(options); - } - - reset(options) { - options = options || {}; - - RSA_reset.call(this, options); - - var slen = options.saltLength; - if (slen !== undefined) { - if (!is_number(slen) || slen < 0) throw new TypeError('saltLength should be a non-negative number'); - - if (this.key !== null && Math.ceil((this.key[0].bitLength - 1) / 8) < this.hash.HASH_SIZE + slen + 2) - throw new SyntaxError('saltLength is too large'); - - this.saltLength = slen; - } else { - this.saltLength = 4; - } - } - - /** - * @param {Uint8Array} data - * @return {RSA_PSS} - */ - sign(data) { - if (!this.key) throw new IllegalStateError('no key is associated with the instance'); - - var key_bits = this.key[0].bitLength, - hash_size = this.hash.HASH_SIZE, - message_length = Math.ceil((key_bits - 1) / 8), - salt_length = this.saltLength, - ps_length = message_length - salt_length - hash_size - 2; - - var message = new Uint8Array(message_length), - h_block = message.subarray(message_length - hash_size - 1, message_length - 1), - d_block = message.subarray(0, message_length - hash_size - 1), - d_salt = d_block.subarray(ps_length + 1); - - var m_block = new Uint8Array(8 + hash_size + salt_length), - m_hash = m_block.subarray(8, 8 + hash_size), - m_salt = m_block.subarray(8 + hash_size); - - m_hash.set( - this.hash - .reset() - .process(data) - .finish().result, - ); - - if (salt_length > 0) Random_getValues(m_salt); - - d_block[ps_length] = 1; - d_salt.set(m_salt); - - h_block.set( - this.hash - .reset() - .process(m_block) - .finish().result, - ); - - var d_block_mask = RSA_MGF1_generate.call(this, h_block, d_block.length); - for (var i = 0; i < d_block.length; i++) d_block[i] ^= d_block_mask[i]; - - message[message_length - 1] = 0xbc; - - var zbits = 8 * message_length - key_bits + 1; - if (zbits % 8) message[0] &= 0xff >>> zbits; - - RSA_decrypt.call(this, message); - - return this; - } - - /** - * @param {Uint8Array} signature - * @param {Uint8Array} data - * @return {RSA_PSS} - */ - verify(signature, data) { - if (!this.key) throw new IllegalStateError('no key is associated with the instance'); - - var key_bits = this.key[0].bitLength, - hash_size = this.hash.HASH_SIZE, - message_length = Math.ceil((key_bits - 1) / 8), - salt_length = this.saltLength, - ps_length = message_length - salt_length - hash_size - 2; - - RSA_encrypt.call(this, signature); - - var message = this.result; - if (message[message_length - 1] !== 0xbc) throw new SecurityError('bad signature'); - - var h_block = message.subarray(message_length - hash_size - 1, message_length - 1), - d_block = message.subarray(0, message_length - hash_size - 1), - d_salt = d_block.subarray(ps_length + 1); - - var zbits = 8 * message_length - key_bits + 1; - if (zbits % 8 && message[0] >>> (8 - zbits)) throw new SecurityError('bad signature'); - - var d_block_mask = RSA_MGF1_generate.call(this, h_block, d_block.length); - for (var i = 0; i < d_block.length; i++) d_block[i] ^= d_block_mask[i]; - - if (zbits % 8) message[0] &= 0xff >>> zbits; - - for (var i = 0; i < ps_length; i++) { - if (d_block[i] !== 0) throw new SecurityError('bad signature'); - } - if (d_block[ps_length] !== 1) throw new SecurityError('bad signature'); - - var m_block = new Uint8Array(8 + hash_size + salt_length), - m_hash = m_block.subarray(8, 8 + hash_size), - m_salt = m_block.subarray(8 + hash_size); - - m_hash.set( - this.hash - .reset() - .process(data) - .finish().result, - ); - m_salt.set(d_salt); - - var h_block_verify = this.hash - .reset() - .process(m_block) - .finish().result; - for (var i = 0; i < hash_size; i++) { - if (h_block[i] !== h_block_verify[i]) throw new SecurityError('bad signature'); - } - - return this; - } -} - -export class RSA_PKCS1_v1_5 { - constructor(options) { - options = options || {}; - - if (!options.hash) throw new SyntaxError("option 'hash' is required"); - - if (!options.hash.HASH_SIZE) - throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function"); - - this.hash = options.hash; - - this.reset(options); - } - - reset(options) { - options = options || {}; - - RSA_reset.call(this, options); - } - - /** - * @param {Uint8Array} data - * @return {RSA_PKCS1_v1_5} - */ - sign(data) { - if (!this.key) { - throw new IllegalStateError('no key is associated with the instance'); - } - var prefix = getHashPrefix(this.hash); - var hash_size = this.hash.HASH_SIZE; - - var t_len = prefix.length + hash_size; - var k = (this.key[0].bitLength + 7) >> 3; - if (k < t_len + 11) { - throw new Error('Message too long'); - } - - var m_hash = new Uint8Array(hash_size); - m_hash.set( - this.hash - .reset() - .process(data) - .finish().result, - ); - - // EM = 0x00 || 0x01 || PS || 0x00 || T - var em = new Uint8Array(k); - var i = 0; - em[i++] = 0; // 0x00 - em[i++] = 1; // 0x01 - // PS - for (i; i < k - t_len - 1; i++) { - em[i] = 0xff; - } - em[i++] = 0; - em.set(prefix, i); // 0x00 - // T - em.set(m_hash, em.length - hash_size); - - RSA_decrypt.call(this, em); - - return this; - } - - /** - * @param {Uint8Array} signature - * @param {Uint8Array} data - * @return {RSA_PKCS1_v1_5} - */ - verify(signature, data) { - if (!this.key) { - throw new IllegalStateError('no key is associated with the instance'); - } - var prefix = getHashPrefix(this.hash); - var hash_size = this.hash.HASH_SIZE; - - var t_len = prefix.length + hash_size; - var k = (this.key[0].bitLength + 7) >> 3; - if (k < t_len + 11) { - throw new SecurityError('Bad signature'); - } - - RSA_encrypt.call(this, signature); - - var m_hash = new Uint8Array(hash_size); - m_hash.set( - this.hash - .reset() - .process(data) - .finish().result, - ); - - var res = 1; - // EM = 0x00 || 0x01 || PS || 0x00 || T - var decryptedSignature = this.result; - var i = 0; - res &= decryptedSignature[i++] === 0; // 0x00 - res &= decryptedSignature[i++] === 1; // 0x01 - // PS - for (i; i < k - t_len - 1; i++) { - res &= decryptedSignature[i] === 0xff; - } - res &= decryptedSignature[i++] === 0; // 0x00 - // T - var j = 0; - var n = i + prefix.length; - // prefix - for (i; i < n; i++) { - res &= decryptedSignature[i] === prefix[j++]; - } - j = 0; - n = i + m_hash.length; - // hash - for (i; i < n; i++) { - res &= decryptedSignature[i] === m_hash[j++]; - } - - if (!res) { - throw new SecurityError('Bad signature'); - } - - return this; - } -} - -const HASH_PREFIXES = { - sha1: new Uint8Array([0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]), - sha256: new Uint8Array([ - 0x30, - 0x31, - 0x30, - 0x0d, - 0x06, - 0x09, - 0x60, - 0x86, - 0x48, - 0x01, - 0x65, - 0x03, - 0x04, - 0x02, - 0x01, - 0x05, - 0x00, - 0x04, - 0x20, - ]), - sha384: new Uint8Array([ - 0x30, - 0x41, - 0x30, - 0x0d, - 0x06, - 0x09, - 0x60, - 0x86, - 0x48, - 0x01, - 0x65, - 0x03, - 0x04, - 0x02, - 0x02, - 0x05, - 0x00, - 0x04, - 0x30, - ]), - sha512: new Uint8Array([ - 0x30, - 0x51, - 0x30, - 0x0d, - 0x06, - 0x09, - 0x60, - 0x86, - 0x48, - 0x01, - 0x65, - 0x03, - 0x04, - 0x02, - 0x03, - 0x05, - 0x00, - 0x04, - 0x40, - ]), -}; - -/** - * @param hash - * @return {Uint8Array} - */ -function getHashPrefix(hash) { - var hashName = hash.constructor.NAME; - var prefix = HASH_PREFIXES[hashName]; - if (!prefix) { - throw new Error("Cannot get hash prefix for hash algorithm '" + hashName + "'"); - } - return prefix; -} diff --git a/src/rsa/pkcs1.ts b/src/rsa/pkcs1.ts new file mode 100644 index 0000000..47deee2 --- /dev/null +++ b/src/rsa/pkcs1.ts @@ -0,0 +1,431 @@ +import { RSA } from './rsa'; +import { IllegalArgumentError, IllegalStateError, SecurityError } from '../other/errors'; +import { Sha512 } from '../hash/sha512/sha512'; +import { Sha1 } from '../hash/sha1/sha1'; +import { Sha256 } from '../hash/sha256/sha256'; +import { BigNumber } from '../bignum/bignum'; +import { getRandomValues } from '../other/get-random-values'; + +export class RSA_OAEP { + private readonly rsa: RSA; + private readonly label: Uint8Array | null; + private readonly hash: Sha1 | Sha256 | Sha512; + + constructor(key: Uint8Array[], hash: Sha1 | Sha256 | Sha512, label?: Uint8Array) { + this.rsa = new RSA(key); + + this.hash = hash; + + if (label !== undefined) { + this.label = label.length > 0 ? label : null; + } else { + this.label = null; + } + } + + encrypt(data: Uint8Array): Uint8Array { + const key_size = Math.ceil(this.rsa.key[0].bitLength / 8); + const hash_size = this.hash.HASH_SIZE; + const data_length = data.byteLength || data.length || 0; + const ps_length = key_size - data_length - 2 * hash_size - 2; + + if (data_length > key_size - 2 * this.hash.HASH_SIZE - 2) throw new IllegalArgumentError('data too large'); + + const message = new Uint8Array(key_size); + const seed = message.subarray(1, hash_size + 1); + const data_block = message.subarray(hash_size + 1); + + data_block.set(data, hash_size + ps_length + 1); + + data_block.set(this.hash.process(this.label || new Uint8Array(0)).finish().result as Uint8Array, 0); + data_block[hash_size + ps_length] = 1; + + getRandomValues(seed); + + const data_block_mask = this.RSA_MGF1_generate(seed, data_block.length); + for (let i = 0; i < data_block.length; i++) data_block[i] ^= data_block_mask[i]; + + const seed_mask = this.RSA_MGF1_generate(data_block, seed.length); + for (let i = 0; i < seed.length; i++) seed[i] ^= seed_mask[i]; + + this.rsa.encrypt(new BigNumber(message)); + + return new Uint8Array(this.rsa.result); + } + + decrypt(data: Uint8Array): Uint8Array { + if (!this.rsa.key) throw new IllegalStateError('no key is associated with the instance'); + + const key_size = Math.ceil(this.rsa.key[0].bitLength / 8); + const hash_size = this.hash.HASH_SIZE; + const data_length = data.byteLength || data.length || 0; + + if (data_length !== key_size) throw new IllegalArgumentError('bad data'); + + this.rsa.decrypt(new BigNumber(data)); + + const z = this.rsa.result[0]; + const seed = this.rsa.result.subarray(1, hash_size + 1); + const data_block = this.rsa.result.subarray(hash_size + 1); + + if (z !== 0) throw new SecurityError('decryption failed'); + + const seed_mask = this.RSA_MGF1_generate(data_block, seed.length); + for (let i = 0; i < seed.length; i++) seed[i] ^= seed_mask[i]; + + const data_block_mask = this.RSA_MGF1_generate(seed, data_block.length); + for (let i = 0; i < data_block.length; i++) data_block[i] ^= data_block_mask[i]; + + const lhash = this.hash + .reset() + .process(this.label || new Uint8Array(0)) + .finish().result as Uint8Array; + for (let i = 0; i < hash_size; i++) { + if (lhash[i] !== data_block[i]) throw new SecurityError('decryption failed'); + } + + let ps_end = hash_size; + for (; ps_end < data_block.length; ps_end++) { + const psz = data_block[ps_end]; + if (psz === 1) break; + if (psz !== 0) throw new SecurityError('decryption failed'); + } + if (ps_end === data_block.length) throw new SecurityError('decryption failed'); + + this.rsa.result = data_block.subarray(ps_end + 1); + + return new Uint8Array(this.rsa.result); + } + + RSA_MGF1_generate(seed: Uint8Array, length: number = 0): Uint8Array { + const hash_size = this.hash.HASH_SIZE; + // if ( length > (hash_size * 0x100000000) ) + // throw new IllegalArgumentError("mask length too large"); + + const mask = new Uint8Array(length); + const counter = new Uint8Array(4); + const chunks = Math.ceil(length / hash_size); + for (let i = 0; i < chunks; i++) { + (counter[0] = i >>> 24), (counter[1] = (i >>> 16) & 255), (counter[2] = (i >>> 8) & 255), (counter[3] = i & 255); + + const submask = mask.subarray(i * hash_size); + + let chunk = this.hash + .reset() + .process(seed) + .process(counter) + .finish().result as Uint8Array; + if (chunk.length > submask.length) chunk = chunk.subarray(0, submask.length); + + submask.set(chunk); + } + + return mask; + } +} + +export class RSA_PSS { + private readonly rsa: RSA; + private readonly saltLength: number; + private readonly hash: Sha1 | Sha256 | Sha512; + + constructor(key: Uint8Array[], hash: Sha1 | Sha256 | Sha512, saltLength: number = 4) { + this.rsa = new RSA(key); + + this.hash = hash; + this.saltLength = saltLength; + + if (this.saltLength < 0) throw new TypeError('saltLength should be a non-negative number'); + + if ( + this.rsa.key !== null && + Math.ceil((this.rsa.key[0].bitLength - 1) / 8) < this.hash.HASH_SIZE + this.saltLength + 2 + ) + throw new SyntaxError('saltLength is too large'); + } + + sign(data: Uint8Array): Uint8Array { + const key_bits = this.rsa.key[0].bitLength; + const hash_size = this.hash.HASH_SIZE; + const message_length = Math.ceil((key_bits - 1) / 8); + const salt_length = this.saltLength; + const ps_length = message_length - salt_length - hash_size - 2; + + const message = new Uint8Array(message_length); + const h_block = message.subarray(message_length - hash_size - 1, message_length - 1); + const d_block = message.subarray(0, message_length - hash_size - 1); + const d_salt = d_block.subarray(ps_length + 1); + + const m_block = new Uint8Array(8 + hash_size + salt_length); + const m_hash = m_block.subarray(8, 8 + hash_size); + const m_salt = m_block.subarray(8 + hash_size); + + m_hash.set(this.hash.process(data).finish().result as Uint8Array); + + if (salt_length > 0) getRandomValues(m_salt); + + d_block[ps_length] = 1; + d_salt.set(m_salt); + + h_block.set(this.hash + .reset() + .process(m_block) + .finish().result as Uint8Array); + + const d_block_mask = this.RSA_MGF1_generate(h_block, d_block.length); + for (let i = 0; i < d_block.length; i++) d_block[i] ^= d_block_mask[i]; + + message[message_length - 1] = 0xbc; + + const zbits = 8 * message_length - key_bits + 1; + if (zbits % 8) message[0] &= 0xff >>> zbits; + + this.rsa.decrypt(new BigNumber(message)); + + return this.rsa.result; + } + + verify(signature: Uint8Array, data: Uint8Array): void { + const key_bits = this.rsa.key[0].bitLength; + const hash_size = this.hash.HASH_SIZE; + const message_length = Math.ceil((key_bits - 1) / 8); + const salt_length = this.saltLength; + const ps_length = message_length - salt_length - hash_size - 2; + + this.rsa.encrypt(new BigNumber(signature)); + + const message = this.rsa.result; + if (message[message_length - 1] !== 0xbc) throw new SecurityError('bad signature'); + + const h_block = message.subarray(message_length - hash_size - 1, message_length - 1); + const d_block = message.subarray(0, message_length - hash_size - 1); + const d_salt = d_block.subarray(ps_length + 1); + + const zbits = 8 * message_length - key_bits + 1; + if (zbits % 8 && message[0] >>> (8 - zbits)) throw new SecurityError('bad signature'); + + const d_block_mask = this.RSA_MGF1_generate(h_block, d_block.length); + for (let i = 0; i < d_block.length; i++) d_block[i] ^= d_block_mask[i]; + + if (zbits % 8) message[0] &= 0xff >>> zbits; + + for (let i = 0; i < ps_length; i++) { + if (d_block[i] !== 0) throw new SecurityError('bad signature'); + } + if (d_block[ps_length] !== 1) throw new SecurityError('bad signature'); + + const m_block = new Uint8Array(8 + hash_size + salt_length); + const m_hash = m_block.subarray(8, 8 + hash_size); + const m_salt = m_block.subarray(8 + hash_size); + + m_hash.set(this.hash + .reset() + .process(data) + .finish().result as Uint8Array); + m_salt.set(d_salt); + + const h_block_verify = this.hash + .reset() + .process(m_block) + .finish().result as Uint8Array; + for (let i = 0; i < hash_size; i++) { + if (h_block[i] !== h_block_verify[i]) throw new SecurityError('bad signature'); + } + } + + RSA_MGF1_generate(seed: Uint8Array, length: number = 0): Uint8Array { + const hash_size = this.hash.HASH_SIZE; + // if ( length > (hash_size * 0x100000000) ) + // throw new IllegalArgumentError("mask length too large"); + + const mask = new Uint8Array(length); + const counter = new Uint8Array(4); + const chunks = Math.ceil(length / hash_size); + for (let i = 0; i < chunks; i++) { + (counter[0] = i >>> 24), (counter[1] = (i >>> 16) & 255), (counter[2] = (i >>> 8) & 255), (counter[3] = i & 255); + + const submask = mask.subarray(i * hash_size); + + let chunk = this.hash + .reset() + .process(seed) + .process(counter) + .finish().result as Uint8Array; + if (chunk.length > submask.length) chunk = chunk.subarray(0, submask.length); + + submask.set(chunk); + } + + return mask; + } +} + +export class RSA_PKCS1_v1_5 { + private readonly rsa: RSA; + private readonly hash: Sha1 | Sha256 | Sha512; + constructor(key: Uint8Array[], hash: Sha1 | Sha256 | Sha512) { + this.rsa = new RSA(key); + this.hash = hash; + } + + sign(data: Uint8Array): Uint8Array { + if (!this.rsa.key) { + throw new IllegalStateError('no key is associated with the instance'); + } + const prefix = getHashPrefix(this.hash); + const hash_size = this.hash.HASH_SIZE; + + const t_len = prefix.length + hash_size; + const k = (this.rsa.key[0].bitLength + 7) >> 3; + if (k < t_len + 11) { + throw new Error('Message too long'); + } + + const m_hash = new Uint8Array(hash_size); + m_hash.set(this.hash.process(data).finish().result as Uint8Array); + + // EM = 0x00 || 0x01 || PS || 0x00 || T + const em = new Uint8Array(k); + let i = 0; + em[i++] = 0; // 0x00 + em[i++] = 1; // 0x01 + // PS + for (i; i < k - t_len - 1; i++) { + em[i] = 0xff; + } + em[i++] = 0; + em.set(prefix, i); // 0x00 + // T + em.set(m_hash, em.length - hash_size); + + this.rsa.decrypt(new BigNumber(em)); + + return this.rsa.result; + } + + verify(signature: Uint8Array, data: Uint8Array): void { + const prefix = getHashPrefix(this.hash); + const hash_size = this.hash.HASH_SIZE; + + const t_len = prefix.length + hash_size; + const k = (this.rsa.key[0].bitLength + 7) >> 3; + if (k < t_len + 11) { + throw new SecurityError('Bad signature'); + } + + this.rsa.encrypt(new BigNumber(signature)); + + const m_hash = new Uint8Array(hash_size); + m_hash.set(this.hash.process(data).finish().result as Uint8Array); + + let res = 1; + // EM = 0x00 || 0x01 || PS || 0x00 || T + const decryptedSignature = this.rsa.result; + let i = 0; + res &= decryptedSignature[i++] === 0 ? 1 : 0; // 0x00 + res &= decryptedSignature[i++] === 1 ? 1 : 0; // 0x01 + // PS + for (i; i < k - t_len - 1; i++) { + res &= decryptedSignature[i] === 0xff ? 1 : 0; + } + res &= decryptedSignature[i++] === 0 ? 1 : 0; // 0x00 + // T + let j = 0; + let n = i + prefix.length; + // prefix + for (i; i < n; i++) { + res &= decryptedSignature[i] === prefix[j++] ? 1 : 0; + } + j = 0; + n = i + m_hash.length; + // hash + for (i; i < n; i++) { + res &= decryptedSignature[i] === m_hash[j++] ? 1 : 0; + } + + if (!res) { + throw new SecurityError('Bad signature'); + } + } +} + +const HASH_PREFIXES: { + sha1: Uint8Array; + sha256: Uint8Array; + sha384: Uint8Array; + sha512: Uint8Array; + [key: string]: Uint8Array; +} = { + sha1: new Uint8Array([0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]), + sha256: new Uint8Array([ + 0x30, + 0x31, + 0x30, + 0x0d, + 0x06, + 0x09, + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x02, + 0x01, + 0x05, + 0x00, + 0x04, + 0x20, + ]), + sha384: new Uint8Array([ + 0x30, + 0x41, + 0x30, + 0x0d, + 0x06, + 0x09, + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x02, + 0x02, + 0x05, + 0x00, + 0x04, + 0x30, + ]), + sha512: new Uint8Array([ + 0x30, + 0x51, + 0x30, + 0x0d, + 0x06, + 0x09, + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x02, + 0x03, + 0x05, + 0x00, + 0x04, + 0x40, + ]), +}; + +function getHashPrefix(hash: Sha1 | Sha256 | Sha512): Uint8Array { + const prefix = HASH_PREFIXES[hash.NAME]; + if (!prefix) { + throw new Error("Cannot get hash prefix for hash algorithm '" + hash.NAME + "'"); + } + return prefix; +} diff --git a/src/rsa/raw.js b/src/rsa/raw.js deleted file mode 100644 index 684ec4e..0000000 --- a/src/rsa/raw.js +++ /dev/null @@ -1,3 +0,0 @@ -import { RSA } from './rsa'; - -export default RSA; diff --git a/src/rsa/rsa.js b/src/rsa/rsa.js deleted file mode 100644 index 15ebe30..0000000 --- a/src/rsa/rsa.js +++ /dev/null @@ -1,147 +0,0 @@ -import { BigNumber, is_big_number, Modulus } from '../bignum/bignum'; -import { is_buffer, is_bytes, is_string, string_to_bytes } from '../utils'; -import { IllegalStateError } from '../errors'; - -export function RSA(options) { - options = options || {}; - - this.key = null; - this.result = null; - - this.reset(options); -} - -export function RSA_reset(options) { - options = options || {}; - - this.result = null; - - var key = options.key; - if (key !== undefined) { - if (key instanceof Array) { - var l = key.length; - if (l !== 2 && l !== 3 && l !== 8) throw new SyntaxError('unexpected key type'); - - var k = []; - k[0] = new Modulus(new BigNumber(key[0])); - k[1] = new BigNumber(key[1]); - if (l > 2) { - k[2] = new BigNumber(key[2]); - } - if (l > 3) { - k[3] = new Modulus(new BigNumber(key[3])); - k[4] = new Modulus(new BigNumber(key[4])); - k[5] = new BigNumber(key[5]); - k[6] = new BigNumber(key[6]); - k[7] = new BigNumber(key[7]); - } - - this.key = k; - } else { - throw new TypeError('unexpected key type'); - } - } - - return this; -} - -export function RSA_encrypt(data) { - if (!this.key) throw new IllegalStateError('no key is associated with the instance'); - - if (is_string(data)) data = string_to_bytes(data); - - if (is_buffer(data)) data = new Uint8Array(data); - - var msg; - if (is_bytes(data)) { - msg = new BigNumber(data); - } else if (is_big_number(data)) { - msg = data; - } else { - throw new TypeError('unexpected data type'); - } - - if (this.key[0].compare(msg) <= 0) throw new RangeError('data too large'); - - var m = this.key[0], - e = this.key[1]; - - var result = m.power(msg, e).toBytes(); - - var bytelen = (m.bitLength + 7) >> 3; - if (result.length < bytelen) { - var r = new Uint8Array(bytelen); - r.set(result, bytelen - result.length); - result = r; - } - - this.result = result; - - return this; -} - -export function RSA_decrypt(data) { - if (!this.key) throw new IllegalStateError('no key is associated with the instance'); - - if (this.key.length < 3) throw new IllegalStateError("key isn't suitable for decription"); - - if (is_string(data)) data = string_to_bytes(data); - - if (is_buffer(data)) data = new Uint8Array(data); - - var msg; - if (is_bytes(data)) { - msg = new BigNumber(data); - } else if (is_big_number(data)) { - msg = data; - } else { - throw new TypeError('unexpected data type'); - } - - if (this.key[0].compare(msg) <= 0) throw new RangeError('data too large'); - - var result; - if (this.key.length > 3) { - var m = this.key[0], - p = this.key[3], - q = this.key[4], - dp = this.key[5], - dq = this.key[6], - u = this.key[7]; - - var x = p.power(msg, dp), - y = q.power(msg, dq); - - var t = x.subtract(y); - while (t.sign < 0) t = t.add(p); - - var h = p.reduce(u.multiply(t)); - - result = h - .multiply(q) - .add(y) - .clamp(m.bitLength) - .toBytes(); - } else { - var m = this.key[0], - d = this.key[2]; - - result = m.power(msg, d).toBytes(); - } - - var bytelen = (m.bitLength + 7) >> 3; - if (result.length < bytelen) { - var r = new Uint8Array(bytelen); - r.set(result, bytelen - result.length); - result = r; - } - - this.result = result; - - return this; -} - -var RSA_prototype = RSA.prototype; -RSA_prototype.reset = RSA_reset; -RSA_prototype.encrypt = RSA_encrypt; -RSA_prototype.decrypt = RSA_decrypt; diff --git a/src/rsa/rsa.ts b/src/rsa/rsa.ts new file mode 100644 index 0000000..8473866 --- /dev/null +++ b/src/rsa/rsa.ts @@ -0,0 +1,107 @@ +import { BigNumber, Modulus } from '../bignum/bignum'; +import { IllegalStateError } from '../other/errors'; + +export type key = { + 0: Modulus; + 1: BigNumber; + 2?: BigNumber; + 3?: Modulus; + 4?: Modulus; + 5?: BigNumber; + 6?: BigNumber; + 7?: BigNumber; +}; + +export class RSA { + public readonly key: key; + public result!: Uint8Array; + + constructor(key: Uint8Array[]) { + const l = key.length; + if (l !== 2 && l !== 3 && l !== 8) throw new SyntaxError('unexpected key type'); + + const k0 = new Modulus(new BigNumber(key[0])); + const k1 = new BigNumber(key[1]); + this.key = { + 0: k0, + 1: k1, + }; + if (l > 2) { + this.key[2] = new BigNumber(key[2]); + } + if (l > 3) { + this.key[3] = new Modulus(new BigNumber(key[3])); + this.key[4] = new Modulus(new BigNumber(key[4])); + this.key[5] = new BigNumber(key[5]); + this.key[6] = new BigNumber(key[6]); + this.key[7] = new BigNumber(key[7]); + } + } + + encrypt(msg: BigNumber): this { + if (!this.key) throw new IllegalStateError('no key is associated with the instance'); + + if (this.key[0].compare(msg) <= 0) throw new RangeError('data too large'); + + const m = this.key[0]; + const e = this.key[1]; + + let result = m.power(msg, e).toBytes(); + + const bytelen = (m.bitLength + 7) >> 3; + if (result.length < bytelen) { + const r = new Uint8Array(bytelen); + r.set(result, bytelen - result.length); + result = r; + } + + this.result = result; + + return this; + } + + decrypt(msg: BigNumber): this { + if (this.key[0].compare(msg) <= 0) throw new RangeError('data too large'); + + let result; + let m; + if (this.key[3] !== undefined) { + m = this.key[0] as BigNumber; + const p = this.key[3] as Modulus; + const q = this.key[4] as Modulus; + const dp = this.key[5] as BigNumber; + const dq = this.key[6] as BigNumber; + const u = this.key[7] as BigNumber; + + const x = p.power(msg, dp); + const y = q.power(msg, dq); + + let t = x.subtract(y); + while (t.sign < 0) t = t.add(p); + + const h = p.reduce(u.multiply(t)); + + result = h + .multiply(q) + .add(y) + .clamp(m.bitLength) + .toBytes(); + } else { + m = this.key[0]; + const d = this.key[2] as BigNumber; + + result = m.power(msg, d).toBytes(); + } + + const bytelen = (m.bitLength + 7) >> 3; + if (result.length < bytelen) { + let r = new Uint8Array(bytelen); + r.set(result, bytelen - result.length); + result = r; + } + + this.result = result; + + return this; + } +} diff --git a/test/aes.js b/test/aes.js index 8a8379a..77a62cd 100644 --- a/test/aes.js +++ b/test/aes.js @@ -1,1008 +1,708 @@ -module("AES"); - -Uint32Array.prototype.map = Array.prototype.map; - -/////////////////////////////////////////////////////////////////////////////// - -// -// Asm.js module test -// - -testIf( typeof AES_asm !== 'undefined', "Asm.js module", function () { - AES_asm = AES_asm.AES_asm; - var heap = new Uint8Array(65536); - var keys = new Uint32Array(heap.buffer); - var aes = AES_asm( null, heap.buffer ); - - // data block - heap.set( asmCrypto.hex_to_bytes('00112233445566778899aabbccddeeff'), AES_asm.HEAP_DATA ); - - // - // AES-128 - // - - aes.set_key( 4, 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f ); - - deepEqual( - keys.subarray( 0, 44 ).map( function (x) { return x } ), - [ - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, - 0xd6aa74fd, 0xd2af72fa, 0xdaa678f1, 0xd6ab76fe, - 0xb692cf0b, 0x643dbdf1, 0xbe9bc500, 0x6830b3fe, - 0xb6ff744e, 0xd2c2c9bf, 0x6c590cbf, 0x0469bf41, - 0x47f7f7bc, 0x95353e03, 0xf96c32bc, 0xfd058dfd, - 0x3caaa3e8, 0xa99f9deb, 0x50f3af57, 0xadf622aa, - 0x5e390f7d, 0xf7a69296, 0xa7553dc1, 0x0aa31f6b, - 0x14f9701a, 0xe35fe28c, 0x440adf4d, 0x4ea9c026, - 0x47438735, 0xa41c65b9, 0xe016baf4, 0xaebf7ad2, - 0x549932d1, 0xf0855768, 0x1093ed9c, 0xbe2c974e, - 0x13111d7f, 0xe3944a17, 0xf307a78b, 0x4d2b30c5 - ], - "AES-128: encryption key schedule ok" - ); - - deepEqual( - keys.subarray( 0x100, 0x100+44 ).map( function (x) { return x } ), - [ - 0x13111d7f, 0x4d2b30c5, 0xf307a78b, 0xe3944a17, - 0x13aa29be, 0x00f7bf03, 0xf770f580, 0x9c8faff6, - 0x1362a463, 0xf7874a83, 0x6bff5a76, 0x8f258648, - 0x8d82fc74, 0x9c7810f5, 0xe4dadc3e, 0x9c47222b, - 0x72e3098d, 0x78a2cccb, 0x789dfe15, 0x11c5de5f, - 0x2ec41027, 0x003f32de, 0x6958204a, 0x6326d7d2, - 0xa8a2f504, 0x69671294, 0x0a7ef798, 0x4de2c7f5, - 0xc7c6e391, 0x6319e50c, 0x479c306d, 0xe54032f1, - 0xa0db0299, 0x2485d561, 0xa2dc029c, 0x2286d160, - 0x8c56dff0, 0x8659d7fd, 0x805ad3fc, 0x825dd3f9, - 0x00010203, 0x0c0d0e0f, 0x08090a0b, 0x04050607 - ], - "AES-128: decryption key schedule ok" - ); - - aes.cipher( AES_asm.ENC.ECB, AES_asm.HEAP_DATA, 16 ); - - equal( - asmCrypto.bytes_to_hex( heap.subarray( AES_asm.HEAP_DATA, AES_asm.HEAP_DATA+16 ) ), - '69c4e0d86a7b0430d8cdb78070b4c55a', - "AES-128: encrypt ok" - ); - - aes.cipher( AES_asm.DEC.ECB, AES_asm.HEAP_DATA, 16 ); - - equal( - asmCrypto.bytes_to_hex( heap.subarray( AES_asm.HEAP_DATA, AES_asm.HEAP_DATA+16 ) ), - '00112233445566778899aabbccddeeff', - "AES-128: decrypt ok" - ); - - // - // AES-192 - // - - aes.set_key( 6, 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, 0x10111213, 0x14151617 ); - - deepEqual( - keys.subarray( 0, 52 ).map( function (x) { return x } ), - [ - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, - 0x10111213, 0x14151617, 0x5846f2f9, 0x5c43f4fe, - 0x544afef5, 0x5847f0fa, 0x4856e2e9, 0x5c43f4fe, - 0x40f949b3, 0x1cbabd4d, 0x48f043b8, 0x10b7b342, - 0x58e151ab, 0x04a2a555, 0x7effb541, 0x6245080c, - 0x2ab54bb4, 0x3a02f8f6, 0x62e3a95d, 0x66410c08, - 0xf5018572, 0x97448d7e, 0xbdf1c6ca, 0x87f33e3c, - 0xe5109761, 0x83519b69, 0x34157c9e, 0xa351f1e0, - 0x1ea0372a, 0x99530916, 0x7c439e77, 0xff12051e, - 0xdd7e0e88, 0x7e2fff68, 0x608fc842, 0xf9dcc154, - 0x859f5f23, 0x7a8d5a3d, 0xc0c02952, 0xbeefd63a, - 0xde601e78, 0x27bcdf2c, 0xa223800f, 0xd8aeda32, - 0xa4970a33, 0x1a78dc09, 0xc418c271, 0xe3a41d5d - ], - "AES-192: encryption key schedule ok" - ); - - deepEqual( - keys.subarray( 0x100, 0x100+52 ).map( function (x) { return x } ), - [ - 0xa4970a33, 0xe3a41d5d, 0xc418c271, 0x1a78dc09, - 0xd6bebd0d, 0x3e021bb9, 0x4db07380, 0xc209ea49, - 0x8fb999c9, 0x85c68c72, 0xc7f9d89d, 0x73b26839, - 0xf77d6ec1, 0x14b75744, 0x5378317f, 0x423f54ef, - 0x11476590, 0xfc0bf1f0, 0x9b0ece8d, 0x47cf663b, - 0xdcc1a8b6, 0xb5423a2e, 0xcc5c194a, 0x67053f7d, - 0xc6deb0ab, 0x568803ab, 0xa4055fbe, 0x791e2364, - 0xdd1b7cda, 0xbbc497cb, 0x8a49ab1d, 0xf28d5c15, - 0x78c4f708, 0xbfc093cf, 0x9655b701, 0x318d3cd6, - 0x60dcef10, 0x2f9620cf, 0x62dbef15, 0x299524ce, - 0x4b4ecbdb, 0x4949cbde, 0x5752d7c7, 0x4d4dcfda, - 0x1a1f181d, 0x4949cbde, 0x4742c7d7, 0x1e1b1c19, - 0x00010203, 0x0c0d0e0f, 0x08090a0b, 0x04050607 - ], - "AES-192: decryption key schedule ok" - ); - - aes.cipher( AES_asm.ENC.ECB, AES_asm.HEAP_DATA, 16 ); - - equal( - asmCrypto.bytes_to_hex( heap.subarray( AES_asm.HEAP_DATA, AES_asm.HEAP_DATA+16 ) ), - 'dda97ca4864cdfe06eaf70a0ec0d7191', - "AES-192: encrypt ok" - ); - - aes.cipher( AES_asm.DEC.ECB, AES_asm.HEAP_DATA, 16 ); - - equal( - asmCrypto.bytes_to_hex( heap.subarray( AES_asm.HEAP_DATA, AES_asm.HEAP_DATA+16 ) ), - '00112233445566778899aabbccddeeff', - "AES-192: decrypt ok" - ); - - // - // AES-256 - // - - aes.set_key( 8, 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, 0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f ); - - deepEqual( - keys.subarray( 0, 60 ).map( function (x) { return x } ), - [ - 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, - 0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f, - 0xa573c29f, 0xa176c498, 0xa97fce93, 0xa572c09c, - 0x1651a8cd, 0x0244beda, 0x1a5da4c1, 0x0640bade, - 0xae87dff0, 0x0ff11b68, 0xa68ed5fb, 0x03fc1567, - 0x6de1f148, 0x6fa54f92, 0x75f8eb53, 0x73b8518d, - 0xc656827f, 0xc9a79917, 0x6f294cec, 0x6cd5598b, - 0x3de23a75, 0x524775e7, 0x27bf9eb4, 0x5407cf39, - 0x0bdc905f, 0xc27b0948, 0xad5245a4, 0xc1871c2f, - 0x45f5a660, 0x17b2d387, 0x300d4d33, 0x640a820a, - 0x7ccff71c, 0xbeb4fe54, 0x13e6bbf0, 0xd261a7df, - 0xf01afafe, 0xe7a82979, 0xd7a5644a, 0xb3afe640, - 0x2541fe71, 0x9bf50025, 0x8813bbd5, 0x5a721c0a, - 0x4e5a6699, 0xa9f24fe0, 0x7e572baa, 0xcdf8cdea, - 0x24fc79cc, 0xbf0979e9, 0x371ac23c, 0x6d68de36 - ], - "AES-256: encryption key schedule ok" - ); - - deepEqual( - keys.subarray( 0x100, 0x100+60 ).map( function (x) { return x } ), - [ - 0x24fc79cc, 0x6d68de36, 0x371ac23c, 0xbf0979e9, - 0x34f1d1ff, 0x2558016e, 0xfce9e25f, 0xbfceaa2f, - 0x5e1648eb, 0xdc80e684, 0x7571b746, 0x384c350a, - 0xc8a30580, 0xd9b1e331, 0x43274870, 0x8b3f7bd0, - 0xb5708e13, 0xa9f151c2, 0x4d3d824c, 0x665a7de1, - 0x74da7ba3, 0x9a96ab41, 0xc81833a0, 0x439c7e50, - 0x3ca69715, 0xe4ccd38e, 0x2b67ffad, 0xd32af3f2, - 0xf85fc4f3, 0x528e98e1, 0x8b844df0, 0x374605f3, - 0xde69409a, 0xcfab2c23, 0xf84d0c5f, 0xef8c64e7, - 0xaed55816, 0xd90ad511, 0xbcc24803, 0xcf19c100, - 0x15c668bd, 0x37e6207c, 0x17c168b8, 0x31e5247d, - 0x7fd7850f, 0x65c89d12, 0x73db8903, 0x61cc9916, - 0x2a2840c9, 0x202748c4, 0x26244cc5, 0x24234cc0, - 0x1a1f181d, 0x16131411, 0x12171015, 0x1e1b1c19, - 0x00010203, 0x0c0d0e0f, 0x08090a0b, 0x04050607 - ], - "AES-256: decryption key schedule ok" - ); - - aes.cipher( AES_asm.ENC.ECB, AES_asm.HEAP_DATA, 16 ); - - equal( - asmCrypto.bytes_to_hex( heap.subarray( AES_asm.HEAP_DATA, AES_asm.HEAP_DATA+16 ) ), - '8ea2b7ca516745bfeafc49904b496089', - "AES-256: encrypt ok" - ); - - aes.cipher( AES_asm.DEC.ECB, AES_asm.HEAP_DATA, 16 ); - - equal( - asmCrypto.bytes_to_hex( heap.subarray( AES_asm.HEAP_DATA, AES_asm.HEAP_DATA+16 ) ), - '00112233445566778899aabbccddeeff', - "AES-256: decrypt ok" - ); -}); - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.AES_ECB !== 'undefined' ) -{ - var ecb_aes_vectors = [ - // AES-ECB-128 - [ - '2b7e151628aed2a6abf7158809cf4f3c', // key - '6bc1bee22e409f96e93d7e117393172a', // clear text - '3ad77bb40d7a3660a89ecaf32466ef97' // cipher text - ], - [ - '2b7e151628aed2a6abf7158809cf4f3c', // key - 'ae2d8a571e03ac9c9eb76fac45af8e51', // clear text - 'f5d3d58503b9699de785895a96fdbaaf' // cipher text - ], - [ - '2b7e151628aed2a6abf7158809cf4f3c', // key - '30c81c46a35ce411e5fbc1191a0a52ef', // clear text - '43b1cd7f598ece23881b00e3ed030688' // cipher text - ], - [ - '2b7e151628aed2a6abf7158809cf4f3c', // key - 'f69f2445df4f9b17ad2b417be66c3710', // clear text - '7b0c785e27e8ad3f8223207104725dd4' // cipher text - ], - [ // Two blocks - '2b7e151628aed2a6abf7158809cf4f3c', // key - 'f69f2445df4f9b17ad2b417be66c3710f69f2445df4f9b17ad2b417be66c3710', // clear text - '7b0c785e27e8ad3f8223207104725dd47b0c785e27e8ad3f8223207104725dd4' // cipher text - ], - // AES-ECB-256 - [ - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key - '6bc1bee22e409f96e93d7e117393172a', // clear text - 'f3eed1bdb5d2a03c064b5a7e3db181f8' // cipher text - ], - [ - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key - 'ae2d8a571e03ac9c9eb76fac45af8e51', // clear text - '591ccb10d410ed26dc5ba74a31362870' // cipher text - ], - [ - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key - '30c81c46a35ce411e5fbc1191a0a52ef', // clear text - 'b6ed21b99ca6f4f9f153e7b1beafed1d' // cipher text - ], - [ // Two blocks - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key - '30c81c46a35ce411e5fbc1191a0a52ef30c81c46a35ce411e5fbc1191a0a52ef', // clear text - 'b6ed21b99ca6f4f9f153e7b1beafed1db6ed21b99ca6f4f9f153e7b1beafed1d' // cipher text - ], - [ - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key - 'f69f2445df4f9b17ad2b417be66c3710', // clear text - '23304b7a39f9f3ff067d8d8f9e24ecc7' // cipher text - ] - ]; - - test( "asmCrypto.AES_ECB.encrypt / asmCrypto.AES_ECB.decrypt", function () { - for ( var i = 0; i < ecb_aes_vectors.length; ++i ) { - var key = new Uint8Array( asmCrypto.hex_to_bytes(ecb_aes_vectors[i][0]) ), - clear = new Uint8Array( asmCrypto.hex_to_bytes(ecb_aes_vectors[i][1]) ), - cipher = new Uint8Array( asmCrypto.hex_to_bytes(ecb_aes_vectors[i][2]) ); - - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_ECB.encrypt( clear, key ) ), - asmCrypto.bytes_to_hex(cipher), - "encrypt vector " + i - ); - - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_ECB.decrypt( cipher, key ) ), - asmCrypto.bytes_to_hex(clear), - "decrypt vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.AES_ECB" ); -} - -if ( typeof asmCrypto.AES_CBC !== 'undefined' ) -{ - var cbc_aes_vectors = [ - [ // key - [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c ], - // iv - [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ], - // clear text - [ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ], - // cipher text - [ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, - 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, - 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, - 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ] - ], - [ // key - [ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, - 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ], - // iv - [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ], - // clear text - [ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ], - // cipher text - [ 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, - 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, - 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, - 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ] - ] +import * as asmCrypto from '../asmcrypto.all.es8'; +import chai from 'chai'; +const expect = chai.expect; + +describe('AES', () => { + describe('ECB', () => { + const ecb_aes_vectors = [ + // AES-ECB-128 + [ + '2b7e151628aed2a6abf7158809cf4f3c', // key + '6bc1bee22e409f96e93d7e117393172a', // clear text + '3ad77bb40d7a3660a89ecaf32466ef97', // cipher text + ], + [ + '2b7e151628aed2a6abf7158809cf4f3c', // key + 'ae2d8a571e03ac9c9eb76fac45af8e51', // clear text + 'f5d3d58503b9699de785895a96fdbaaf', // cipher text + ], + [ + '2b7e151628aed2a6abf7158809cf4f3c', // key + '30c81c46a35ce411e5fbc1191a0a52ef', // clear text + '43b1cd7f598ece23881b00e3ed030688', // cipher text + ], + [ + '2b7e151628aed2a6abf7158809cf4f3c', // key + 'f69f2445df4f9b17ad2b417be66c3710', // clear text + '7b0c785e27e8ad3f8223207104725dd4', // cipher text + ], + [ + // Two blocks + '2b7e151628aed2a6abf7158809cf4f3c', // key + 'f69f2445df4f9b17ad2b417be66c3710f69f2445df4f9b17ad2b417be66c3710', // clear text + '7b0c785e27e8ad3f8223207104725dd47b0c785e27e8ad3f8223207104725dd4', // cipher text + ], + // AES-ECB-256 + [ + '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key + '6bc1bee22e409f96e93d7e117393172a', // clear text + 'f3eed1bdb5d2a03c064b5a7e3db181f8', // cipher text + ], + [ + '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key + 'ae2d8a571e03ac9c9eb76fac45af8e51', // clear text + '591ccb10d410ed26dc5ba74a31362870', // cipher text + ], + [ + '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key + '30c81c46a35ce411e5fbc1191a0a52ef', // clear text + 'b6ed21b99ca6f4f9f153e7b1beafed1d', // cipher text + ], + [ + // Two blocks + '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key + '30c81c46a35ce411e5fbc1191a0a52ef30c81c46a35ce411e5fbc1191a0a52ef', // clear text + 'b6ed21b99ca6f4f9f153e7b1beafed1db6ed21b99ca6f4f9f153e7b1beafed1d', // cipher text + ], + [ + '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', // key + 'f69f2445df4f9b17ad2b417be66c3710', // clear text + '23304b7a39f9f3ff067d8d8f9e24ecc7', // cipher text + ], ]; - test( "asmCrypto.AES_CBC.encrypt / asmCrypto.AES_CBC.decrypt", function () { - for ( var i = 0; i < cbc_aes_vectors.length; ++i ) { - var key = new Uint8Array( cbc_aes_vectors[i][0] ), - iv = new Uint8Array( cbc_aes_vectors[i][1] ), - clear = new Uint8Array( cbc_aes_vectors[i][2] ), - cipher = new Uint8Array( cbc_aes_vectors[i][3] ); + it('asmCrypto.AES_ECB.encrypt / asmCrypto.AES_ECB.decrypt', function () { + for (let i = 0; i < ecb_aes_vectors.length; ++i) { + const key = new Uint8Array(asmCrypto.hex_to_bytes(ecb_aes_vectors[i][0])); + const clear = new Uint8Array(asmCrypto.hex_to_bytes(ecb_aes_vectors[i][1])); + const cipher = new Uint8Array(asmCrypto.hex_to_bytes(ecb_aes_vectors[i][2])); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CBC.encrypt( clear, key, false, iv ) ), - asmCrypto.bytes_to_hex(cipher), - "encrypt vector " + i - ); + expect(asmCrypto.AES_ECB.encrypt(clear, key), `encrypt vector ${i}`).to.deep.equal(cipher); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CBC.decrypt( cipher, key, false, iv ) ), - asmCrypto.bytes_to_hex(clear), - "decrypt vector " + i - ); - } + expect(asmCrypto.AES_ECB.decrypt(cipher, key), `decrypt vector ${i}`).to.deep.equal(clear); + } }); -} -else -{ - skip( "asmCrypto.AES_CBC" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.AES_CTR !== 'undefined' ) -{ - var ctr_aes_vectors = [ - [ - // key - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - // nonce - asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), - // input message - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), - // encrypted message - asmCrypto.hex_to_bytes('874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee') - ], - [ - // key - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - // nonce - asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), - // input message - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c'), - // encrypted message - asmCrypto.hex_to_bytes('874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f300') - ], - [ - // key - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - // nonce - asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), - // input message - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e11739317'), - // encrypted message - asmCrypto.hex_to_bytes('874d6191b620e3261bef6864990db6') - ], - [ - // key - asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), - // nonce - asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), - // input message - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), - // encrypted message - asmCrypto.hex_to_bytes('601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6') - ] + }); + + describe('CBC', () => { + const cbc_aes_vectors = [ + [ // key + [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + // iv + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], + // clear text + [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10], + // cipher text + [0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, + 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, + 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7] + ], + [ // key + [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], + // iv + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], + // clear text + [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10], + // cipher text + [0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b] + ] ]; - test( "asmCrypto.AES_CTR.encrypt / asmCrypto.AES_CTR.decrypt", function () { - for ( var i = 0; i < ctr_aes_vectors.length; ++i ) { - var key = new Uint8Array( ctr_aes_vectors[i][0] ), - nonce = new Uint8Array( ctr_aes_vectors[i][1] ), - clear = new Uint8Array( ctr_aes_vectors[i][2] ), - cipher = new Uint8Array( ctr_aes_vectors[i][3] ); + it('asmCrypto.AES_CBC.encrypt / asmCrypto.AES_CBC.decrypt', function () { + for (let i = 0; i < cbc_aes_vectors.length; ++i) { + const key = new Uint8Array(cbc_aes_vectors[i][0]); + const iv = new Uint8Array(cbc_aes_vectors[i][1]); + const clear = new Uint8Array(cbc_aes_vectors[i][2]); + const cipher = new Uint8Array(cbc_aes_vectors[i][3]); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CTR.encrypt( clear, key, nonce ) ), - asmCrypto.bytes_to_hex(cipher), - "encrypt vector " + i - ); + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CBC.encrypt(clear, key, false, iv)), `encrypt vector ${i}`).to.be.equal(asmCrypto.bytes_to_hex(cipher)); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CTR.decrypt( cipher, key, nonce ) ), - asmCrypto.bytes_to_hex(clear), - "decrypt vector " + i - ); - } + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CBC.decrypt(cipher, key, false, iv)), `decrypt vector ${i}`).to.be.equal(asmCrypto.bytes_to_hex(clear)); + } }); -} -else -{ - skip( "asmCrypto.AES_CTR" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.AES_CCM !== 'undefined' ) -{ - var ccm_aes_vectors = [ - [ - // key - new Uint8Array([ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf ]), - // nonce - new Uint8Array([ 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 ]), - // adata - new Uint8Array([ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]), - // tagSize - 8, - // input message - new Uint8Array([ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e ]), - // encrypted message - new Uint8Array([ 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, - 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 ]), - ], - [ - // key - new Uint8Array([ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf ]), - // nonce - new Uint8Array([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]), - // adata - new Uint8Array([ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x61, 0x75, 0x74, 0x68, 0x69, 0x6e, 0x66, 0x6f, 0x6f ]), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('44696420796f75206b6e6f772e2e2e0d0a46726f6d2057696b6970656469612773206e657720616e6420726563656e746c7920696d70726f76656420636f6e74656e743a0d0a5361696e74204c656f6e61726420436174686f6c69632043687572636820284d616469736f6e2c204e65627261736b61290d0a2e2e2e207468617420746865204a61636f62204d2e204e616368746967616c6c2d64657369676e65642053742e204c656f6e61726420436174686f6c696320436875726368202870696374757265642920696e204d616469736f6e2c204e65627261736b612c20636f6e7461696e73206120626f6e652072656c6963206f6620697473206e616d6573616b653f0d0a2e2e2e2074686174207468652043616e61646196536f757468204b6f72656120467265652054726164652041677265656d656e742077696c6c20656c696d696e61746520393825206f6620616c6c20696d706f72742074617269666673206265747765656e207468652074776f20636f756e74726965733f0d0a2e2e2e207468617420526f7373204d634577616e2c2043454f206f66205242532047726f75702c206f6e63652074686520776f726c642773206c6172676573742062616e6b2c207477696365206661696c656420616e206163636f756e74616e6379206578616d3f0d0a2e2e2e2074686174205475726b69736820776f6d656e2773206e6174696f6e616c2069636520686f636b657920706c617965722047697a656d20d67a74617364656c656e2069732061206d656d626572206f662068657220666174686572277320636c7562204d696c656e79756d20506174656e20534b3f0d0a2e2e2e207468617420566572697a6f6e20762e204643432028323031342920776173207265706f7274656420746f20626520746865206465617468206f66206e6574776f726b206e65757472616c6974792c20686176696e6720766163617465642074776f206f662074686520464343204f70656e20496e7465726e6574204f726465722032303130277320746872656520726567756c6174696f6e733f0d0a2e2e2e207468617420746865206d6f737320737065636965732043686f7269736f646f6e7469756d206163697068796c6c756d2063616e207375727669766520666f72206d6f7265207468616e20312c3530302079656172732066726f7a656e3f'), - // encrypted message - asmCrypto.hex_to_bytes('09e3c1f3ba2f40eeca4dd7c27453085c71727d4b452a388dbdafc48a7f1406184b5516ea59d9ece55f347237b440792a4e71d26ee6df2dfcd39aea379080082a67be4d7c1af810181379d3f3a444512468e43494a41e9f968c6fe13f45027a297cc24ba3113a5e1b575fa3e1246004d75264e0960052d4e14b4e1a46b24f644428ef4ad4c50455e7029fa53b4eadbe5934c234043f23296b1c235bc8ffadd28deea7415b4bfd996071179cb361822894ab54078b5ad139a7dea6889a36d1417cbbbb1eb9afa0de88d736bf81e5140df06988f2901c275f63fed880fb6a00e7ebd0d5394360ca67b0680d64cc4ba5f7c69298a265916dc4ef03bb54b5e59c0cc48f83b20cf6ec1180b2423966e78ffd94ad1b74dc6b314802ddea17036d507f44c289effd820cb43d0daac09d3ee20ee41cff1e3f2858dc2643e13fcc481d4b1d36ada547e05f789f0d1067c73949c522fd54dc0240c942cc250af3304173dcbab38f1c8292ce0036c8f0c20ceb3d5cc70cc02e5b07329640dc971a410959e89e24edf15d96a6d2cf81abcb994355051371983533f788c9bd01a8e640b1b733c2b34b7ddf7229cf81d3664d85e0cf14dcfb73f0701939f6929e725de6ea590dc0a4caf5fa6fdacc96590e43b94c6f221a703c1c5073509e6b0700eeafde7ee99e149bdbf34a5acd948a513401ba78c4db7128e1f0aac26767f8a4754ae06a41287a12a7f3059c7a405aceb105b3748264c081240c3aa3f298a0ef5f2ea93151a25a3f746082d352eb3a52fb6f860cdf0f4d2186af5e4aa744893e8a59037daa6c23d8d31d2666c528a4ce4e249a27f7aab2bf14eeb7bf8c617380a34db5b7fade8eca02f1f030a62a2ffc7f2d2b14ec366b2a4269be4c763276195ce4c95b4c77c2cc001aac54dd6496099d7ecfe1f1e316d846ab41c4ef461ae0687588ea45532fe8bf9c91cf0840200a232adaa0b8036eaf3f29e4b2d898e8fb2315c22f4915b5746c7920a0bbc98548076e8f68a2fbf3b84df590d0a3154a66d17a80a115027c066f4d5f6c69769e52268f3cea1ee86150144bc05ba63d526e611a1ef723b0b573b37eb5949dd27875208219a77d5a8f170fcecf452ea1b4c78bc135a6345c853a2621154a664806d9fbb88a61ec7935c3511aa3ede4736ee37027e5f2ef2079447886ed5a30839eee442ff8feb17acfa832a8dedb28cbb52b07a950c5dcb853a32ed2f8c0ff83adea7b060aaf2466d148ad43d8e657') - ], - [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) - // key - asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), - // nonce - asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), - // adata - undefined, - // tagSize - 16, - // plaintext - asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), - // ciphertext - asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), - ], - [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) - // key - asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), - // nonce - asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), - // adata - null, - // tagSize - 16, - // plaintext - asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), - // ciphertext - asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), - ], - [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) - // key - asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), - // nonce - asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // plaintext - asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), - // ciphertext - asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), - ], - [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) - // key - asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), - // nonce - asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), - // adata - new Uint8Array(0), - // tagSize - 16, - // plaintext - asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), - // ciphertext - asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), - ], - [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158797782) - // key - asmCrypto.hex_to_bytes('0f0e0d0c0b0a09080706050403020100'), - // nonce - asmCrypto.hex_to_bytes('000102030405060708090a0b'), - // adata - undefined, - // tagSize - 16, - // plaintext - asmCrypto.string_to_bytes('42'), - // ciphertext - asmCrypto.hex_to_bytes('28be1ac7b43d8868869b9a45d3de436cd0cc'), - ], + }); + + describe('CTR', () => { + const ctr_aes_vectors = [ + [ + // key + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + // nonce + asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), + // input message + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), + // encrypted message + asmCrypto.hex_to_bytes('874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee') + ], + [ + // key + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + // nonce + asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), + // input message + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c'), + // encrypted message + asmCrypto.hex_to_bytes('874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f300') + ], + [ + // key + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + // nonce + asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), + // input message + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e11739317'), + // encrypted message + asmCrypto.hex_to_bytes('874d6191b620e3261bef6864990db6') + ], + [ + // key + asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), + // nonce + asmCrypto.hex_to_bytes('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), + // input message + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), + // encrypted message + asmCrypto.hex_to_bytes('601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6') + ] ]; - test( "asmCrypto.AES_CCM.encrypt / asmCrypto.AES_CCM.decrypt", function () { - for ( var i = 0; i < ccm_aes_vectors.length; ++i ) { - var key = ccm_aes_vectors[i][0], - nonce = ccm_aes_vectors[i][1], - adata = ccm_aes_vectors[i][2], - tagsize = ccm_aes_vectors[i][3], - clear = ccm_aes_vectors[i][4], - cipher = ccm_aes_vectors[i][5]; + it('asmCrypto.AES_CTR.encrypt / asmCrypto.AES_CTR.decrypt', function () { + for (let i = 0; i < ctr_aes_vectors.length; ++i) { + const key = new Uint8Array(ctr_aes_vectors[i][0]); + const nonce = new Uint8Array(ctr_aes_vectors[i][1]); + const clear = new Uint8Array(ctr_aes_vectors[i][2]); + const cipher = new Uint8Array(ctr_aes_vectors[i][3]); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CCM.encrypt( clear, key, nonce, adata, tagsize ) ), - asmCrypto.bytes_to_hex(cipher), - "encrypt vector " + i - ); + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CTR.encrypt(clear, key, nonce)), `encrypt vector ${i}`).to.be.equal(asmCrypto.bytes_to_hex(cipher)); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CCM.decrypt( cipher, key, nonce, adata, tagsize ) ), - asmCrypto.bytes_to_hex(clear), - "decrypt vector " + i - ); - } + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CTR.decrypt(cipher, key, nonce)), `decrypt vector ${i}`).to.be.equal(asmCrypto.bytes_to_hex(clear)); + } }); -} -else -{ - skip( "asmCrypto.AES_CCM" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.AES_GCM !== 'undefined' ) -{ - - var gcm_aes_vectors = [ - [ - // key - asmCrypto.hex_to_bytes('00000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('000000000000000000000000'), - // adata - null, - // tagSize - 16, - // input message - asmCrypto.string_to_bytes(''), - // encrypted message - asmCrypto.hex_to_bytes('58e2fccefa7e3061367f1d57a4e7455a') - ], - [ - // key - asmCrypto.hex_to_bytes('00000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('000000000000000000000000'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('00000000000000000000000000000000'), - // encrypted message - asmCrypto.hex_to_bytes('0388dace60b6a392f328c2b971b2fe78ab6e47d42cec13bdf53a67b21257bddf') - ], - [ - // key - asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), - // nonce - asmCrypto.hex_to_bytes('cafebabefacedbaddecaf888'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255'), - // encrypted message - asmCrypto.hex_to_bytes('42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4') - ], - [ - // key - asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), - // nonce - asmCrypto.hex_to_bytes('cafebabefacedbaddecaf888'), - // adata - asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), - // encrypted message - asmCrypto.hex_to_bytes('42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e0915bc94fbc3221a5db94fae95ae7121a47') - ], - [ - // key - asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), - // nonce - asmCrypto.hex_to_bytes('cafebabefacedbad'), - // adata - asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), - // encrypted message - asmCrypto.hex_to_bytes('61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f45983612d2e79e3b0785561be14aaca2fccb') - ], - [ - // key - asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), - // nonce - asmCrypto.hex_to_bytes('9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b'), - // adata - asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), - // encrypted message - asmCrypto.hex_to_bytes('8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5619cc5aefffe0bfa462af43c1699d050') - ], - [ - // key - asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('000000000000000000000000'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('00000000000000000000000000000000'), - // encrypted message - asmCrypto.hex_to_bytes('cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919') - ], - [ - // key - asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('000000000000000000000000'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes(''), - // encrypted message - asmCrypto.hex_to_bytes('530f8afbc74536b9a963b4f1c4cb738b') - ], - [ - // key - asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('000000000000000000000000'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.string_to_bytes(''), - // encrypted message - asmCrypto.hex_to_bytes('530f8afbc74536b9a963b4f1c4cb738b') - ], - [ - // key - asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('000000000000000000000000'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('00000000000000000000000000000000'), - // encrypted message - asmCrypto.hex_to_bytes('cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919') - ], - [ - // key - asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308'), - // nonce - asmCrypto.hex_to_bytes('9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b'), - // adata - asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), - // encrypted message - asmCrypto.hex_to_bytes('5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3fa44a8266ee1c8eb0c8b5d4cf5ae9f19a') - ], - [ // Test case for issue #70 (https://github.com/vibornoff/asmcrypto.js/issues/70) - // key - asmCrypto.hex_to_bytes('00000000000000000000000000000000'), - // nonce - asmCrypto.hex_to_bytes('00'), - // adata - asmCrypto.string_to_bytes(''), - // tagSize - 16, - // input message - asmCrypto.hex_to_bytes('00'), - // encrypted message - asmCrypto.hex_to_bytes('e9d60634580263ebab909efa6623dafc61') - ], - [ // Test case for issue #70 (https://github.com/vibornoff/asmcrypto.js/issues/92) - // key - asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), - // nonce - asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), - // adata - undefined, - // tagSize - 16, - // input message - asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), - // encrypted message - asmCrypto.base64_to_bytes('L3zqVYAOsRk7zMg2KsNTVShcad8TjIQ7umfsvia21QO0XTj8vaeR') - ], + }); + describe('GCM', () => { + const gcm_aes_vectors = [ + [ + // key + asmCrypto.hex_to_bytes('00000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('000000000000000000000000'), + // adata + undefined, + // tagSize + 16, + // input message + asmCrypto.string_to_bytes(''), + // encrypted message + asmCrypto.hex_to_bytes('58e2fccefa7e3061367f1d57a4e7455a') + ], + [ + // key + asmCrypto.hex_to_bytes('00000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('000000000000000000000000'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('00000000000000000000000000000000'), + // encrypted message + asmCrypto.hex_to_bytes('0388dace60b6a392f328c2b971b2fe78ab6e47d42cec13bdf53a67b21257bddf') + ], + [ + // key + asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), + // nonce + asmCrypto.hex_to_bytes('cafebabefacedbaddecaf888'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255'), + // encrypted message + asmCrypto.hex_to_bytes('42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4') + ], + [ + // key + asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), + // nonce + asmCrypto.hex_to_bytes('cafebabefacedbaddecaf888'), + // adata + asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), + // encrypted message + asmCrypto.hex_to_bytes('42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e0915bc94fbc3221a5db94fae95ae7121a47') + ], + [ + // key + asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), + // nonce + asmCrypto.hex_to_bytes('cafebabefacedbad'), + // adata + asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), + // encrypted message + asmCrypto.hex_to_bytes('61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f45983612d2e79e3b0785561be14aaca2fccb') + ], + [ + // key + asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308'), + // nonce + asmCrypto.hex_to_bytes('9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b'), + // adata + asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), + // encrypted message + asmCrypto.hex_to_bytes('8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5619cc5aefffe0bfa462af43c1699d050') + ], + [ + // key + asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('000000000000000000000000'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('00000000000000000000000000000000'), + // encrypted message + asmCrypto.hex_to_bytes('cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919') + ], + [ + // key + asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('000000000000000000000000'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes(''), + // encrypted message + asmCrypto.hex_to_bytes('530f8afbc74536b9a963b4f1c4cb738b') + ], + [ + // key + asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('000000000000000000000000'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.string_to_bytes(''), + // encrypted message + asmCrypto.hex_to_bytes('530f8afbc74536b9a963b4f1c4cb738b') + ], + [ + // key + asmCrypto.hex_to_bytes('0000000000000000000000000000000000000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('000000000000000000000000'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('00000000000000000000000000000000'), + // encrypted message + asmCrypto.hex_to_bytes('cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919') + ], + [ + // key + asmCrypto.hex_to_bytes('feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308'), + // nonce + asmCrypto.hex_to_bytes('9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b'), + // adata + asmCrypto.hex_to_bytes('feedfacedeadbeeffeedfacedeadbeefabaddad2'), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'), + // encrypted message + asmCrypto.hex_to_bytes('5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3fa44a8266ee1c8eb0c8b5d4cf5ae9f19a') + ], + [ // Test case for issue #70 (https://github.com/vibornoff/asmcrypto.js/issues/70) + // key + asmCrypto.hex_to_bytes('00000000000000000000000000000000'), + // nonce + asmCrypto.hex_to_bytes('00'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('00'), + // encrypted message + asmCrypto.hex_to_bytes('e9d60634580263ebab909efa6623dafc61') + ], + [ // Test case for issue #70 (https://github.com/vibornoff/asmcrypto.js/issues/92) + // key + asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), + // nonce + asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), + // adata + undefined, + // tagSize + 16, + // input message + asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), + // encrypted message + asmCrypto.base64_to_bytes('L3zqVYAOsRk7zMg2KsNTVShcad8TjIQ7umfsvia21QO0XTj8vaeR') + ], ]; - test( "asmCrypto.AES_GCM.encrypt", function () { - for ( var i = 0; i < gcm_aes_vectors.length; ++i ) { - var key = gcm_aes_vectors[i][0], - nonce = gcm_aes_vectors[i][1], - adata = gcm_aes_vectors[i][2], - tagsize = gcm_aes_vectors[i][3], - cleartext = gcm_aes_vectors[i][4], - ciphertext = gcm_aes_vectors[i][5]; + it("asmCrypto.AES_GCM.encrypt", function () { + for (let i = 0; i < gcm_aes_vectors.length; ++i) { + const key = gcm_aes_vectors[i][0]; + const nonce = gcm_aes_vectors[i][1]; + const adata = gcm_aes_vectors[i][2]; + const tagsize = gcm_aes_vectors[i][3]; + const cleartext = gcm_aes_vectors[i][4]; + const ciphertext = gcm_aes_vectors[i][5]; - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_GCM.encrypt( cleartext, key, nonce, adata, tagsize ) ), - asmCrypto.bytes_to_hex( ciphertext ), - "encrypt vector " + i - ); + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_GCM.encrypt(cleartext, key, nonce, adata, tagsize)), 'encrypt vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(ciphertext)); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_GCM.decrypt( ciphertext, key, nonce, adata, tagsize ) ), - asmCrypto.bytes_to_hex( cleartext ), - "decrypt vector " + i - ); - } + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_GCM.decrypt(ciphertext, key, nonce, adata, tagsize)), 'decrypt vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(cleartext)); + } }); -} -else -{ - skip( "asmCrypto.AES_GCM" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.AES_CFB !== 'undefined' ) -{ - var cfb_aes_vectors = [ - [ // key - [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c ], - // iv - [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ], - // clear text - [ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ], - // cipher text - [ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, - 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, - 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, - 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6 ] - ], - [ // key - [ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c ], - // iv - [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ], - // clear text - [ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41 ], - // cipher text - [ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, - 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, - 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, - 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6 ] - ], - [ // key - [ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, - 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ], - // iv - [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ], - // clear text - [ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ], - // cipher text - [ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, - 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, - 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, - 0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71 ] - ], - [ // key - [ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, - 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ], - // iv - [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ], - // clear text - [ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24 ], - // cipher text - [ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, - 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, - 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, - 0x75, 0xa3, 0x85 ] - ] + }); + + describe('CFB', () => { + const cfb_aes_vectors = [ + [ // key + [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + // iv + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], + // clear text + [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10], + // cipher text + [0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, + 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, + 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, + 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6] + ], + [ // key + [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c], + // iv + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], + // clear text + [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41], + // cipher text + [0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, + 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, + 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, + 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6] + ], + [ // key + [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], + // iv + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], + // clear text + [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10], + // cipher text + [0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, + 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, + 0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71] + ], + [ // key + [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], + // iv + [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], + // clear text + [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24], + // cipher text + [0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, + 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, + 0x75, 0xa3, 0x85] + ] ]; - test( "asmCrypto.AES_CFB.encrypt / asmCrypto.AES_CFB.decrypt", function () { - for ( var i = 0; i < cfb_aes_vectors.length; ++i ) { - var key = new Uint8Array( cfb_aes_vectors[i][0] ), - iv = new Uint8Array( cfb_aes_vectors[i][1] ), - clear = new Uint8Array( cfb_aes_vectors[i][2] ), - cipher = new Uint8Array( cfb_aes_vectors[i][3] ); + it('asmCrypto.AES_CFB.encrypt / asmCrypto.AES_CFB.decrypt', function () { + for (let i = 0; i < cfb_aes_vectors.length; ++i) { + const key = new Uint8Array(cfb_aes_vectors[i][0]); + const iv = new Uint8Array(cfb_aes_vectors[i][1]); + const clear = new Uint8Array(cfb_aes_vectors[i][2]); + const cipher = new Uint8Array(cfb_aes_vectors[i][3]); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CFB.encrypt( clear, key, iv ) ), - asmCrypto.bytes_to_hex(cipher), - "encrypt vector " + i - ); + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CFB.encrypt(clear, key, iv)), `encrypt vector ${i}`).to.be.equal(asmCrypto.bytes_to_hex(cipher)); - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CFB.decrypt( cipher, key, iv ) ), - asmCrypto.bytes_to_hex(clear), - "decrypt vector " + i - ); - } + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CFB.decrypt(cipher, key, iv)), `decrypt vector ${i}`).to.be.equal(asmCrypto.bytes_to_hex(clear)); + } }); -} -else -{ - skip( "asmCrypto.AES_CFB" ); -} - -testIf( asmCrypto.AES_OFB !== undefined, "asmCrypto.AES_OFB", function () { + }); + describe('OFB', () => { // key, iv, cleartext, ciphertext - var ofb_vectors = [ - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('000102030405060708090A0B0C0D0E0F'), - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), - asmCrypto.hex_to_bytes('3b3fd92eb72dad20333449f8e83cfb4a'), - ], - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('50FE67CC996D32B6DA0937E99BAFEC60'), - asmCrypto.hex_to_bytes('ae2d8a571e03ac9c9eb76fac45af8e51'), - asmCrypto.hex_to_bytes('7789508d16918f03f53c52dac54ed825'), - ], - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('D9A4DADA0892239F6B8B3D7680E15674'), - asmCrypto.hex_to_bytes('30c81c46a35ce411e5fbc1191a0a52ef'), - asmCrypto.hex_to_bytes('9740051e9c5fecf64344f7a82260edcc'), - ], - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('A78819583F0308E7A6BF36B1386ABF23'), - asmCrypto.hex_to_bytes('f69f2445df4f9b17ad2b417be66c3710'), - asmCrypto.hex_to_bytes('304c6528f659c77866a510d9c1d6ae5e'), - ], - [ - asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), - asmCrypto.hex_to_bytes('000102030405060708090A0B0C0D0E0F'), - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), - asmCrypto.hex_to_bytes('cdc80d6fddf18cab34c25909c99a4174'), - ], - [ - asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), - asmCrypto.hex_to_bytes('A609B38DF3B1133DDDFF2718BA09565E'), - asmCrypto.hex_to_bytes('ae2d8a571e03ac9c9eb76fac45af8e51'), - asmCrypto.hex_to_bytes('fcc28b8d4c63837c09e81700c1100401'), - ], - [ - asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), - asmCrypto.hex_to_bytes('52EF01DA52602FE0975F78AC84BF8A50'), - asmCrypto.hex_to_bytes('30c81c46a35ce411e5fbc1191a0a52ef'), - asmCrypto.hex_to_bytes('8d9a9aeac0f6596f559c6d4daf59a5f2'), - ], - [ - asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), - asmCrypto.hex_to_bytes('BD5286AC63AABD7EB067AC54B553F71D'), - asmCrypto.hex_to_bytes('f69f2445df4f9b17ad2b417be66c3710'), - asmCrypto.hex_to_bytes('6d9f200857ca6c3e9cac524bd9acc92a'), - ], - [ - asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), - asmCrypto.hex_to_bytes('000102030405060708090A0B0C0D0E0F'), - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), - asmCrypto.hex_to_bytes('dc7e84bfda79164b7ecd8486985d3860'), - ], - [ - asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), - asmCrypto.hex_to_bytes('B7BF3A5DF43989DD97F0FA97EBCE2F4A'), - asmCrypto.hex_to_bytes('ae2d8a571e03ac9c9eb76fac45af8e51'), - asmCrypto.hex_to_bytes('4febdc6740d20b3ac88f6ad82a4fb08d'), - ], - [ - asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), - asmCrypto.hex_to_bytes('E1C656305ED1A7A6563805746FE03EDC'), - asmCrypto.hex_to_bytes('30c81c46a35ce411e5fbc1191a0a52ef'), - asmCrypto.hex_to_bytes('71ab47a086e86eedf39d1c5bba97c408'), - ], - [ - asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), - asmCrypto.hex_to_bytes('41635BE625B48AFC1666DD42A09D96E7'), - asmCrypto.hex_to_bytes('f69f2445df4f9b17ad2b417be66c3710'), - asmCrypto.hex_to_bytes('0126141d67f37be8538f5a8be740e484'), - ], + const ofb_vectors = [ + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('000102030405060708090A0B0C0D0E0F'), + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), + asmCrypto.hex_to_bytes('3b3fd92eb72dad20333449f8e83cfb4a'), + ], + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('50FE67CC996D32B6DA0937E99BAFEC60'), + asmCrypto.hex_to_bytes('ae2d8a571e03ac9c9eb76fac45af8e51'), + asmCrypto.hex_to_bytes('7789508d16918f03f53c52dac54ed825'), + ], + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('D9A4DADA0892239F6B8B3D7680E15674'), + asmCrypto.hex_to_bytes('30c81c46a35ce411e5fbc1191a0a52ef'), + asmCrypto.hex_to_bytes('9740051e9c5fecf64344f7a82260edcc'), + ], + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('A78819583F0308E7A6BF36B1386ABF23'), + asmCrypto.hex_to_bytes('f69f2445df4f9b17ad2b417be66c3710'), + asmCrypto.hex_to_bytes('304c6528f659c77866a510d9c1d6ae5e'), + ], + [ + asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), + asmCrypto.hex_to_bytes('000102030405060708090A0B0C0D0E0F'), + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), + asmCrypto.hex_to_bytes('cdc80d6fddf18cab34c25909c99a4174'), + ], + [ + asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), + asmCrypto.hex_to_bytes('A609B38DF3B1133DDDFF2718BA09565E'), + asmCrypto.hex_to_bytes('ae2d8a571e03ac9c9eb76fac45af8e51'), + asmCrypto.hex_to_bytes('fcc28b8d4c63837c09e81700c1100401'), + ], + [ + asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), + asmCrypto.hex_to_bytes('52EF01DA52602FE0975F78AC84BF8A50'), + asmCrypto.hex_to_bytes('30c81c46a35ce411e5fbc1191a0a52ef'), + asmCrypto.hex_to_bytes('8d9a9aeac0f6596f559c6d4daf59a5f2'), + ], + [ + asmCrypto.hex_to_bytes('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'), + asmCrypto.hex_to_bytes('BD5286AC63AABD7EB067AC54B553F71D'), + asmCrypto.hex_to_bytes('f69f2445df4f9b17ad2b417be66c3710'), + asmCrypto.hex_to_bytes('6d9f200857ca6c3e9cac524bd9acc92a'), + ], + [ + asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), + asmCrypto.hex_to_bytes('000102030405060708090A0B0C0D0E0F'), + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), + asmCrypto.hex_to_bytes('dc7e84bfda79164b7ecd8486985d3860'), + ], + [ + asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), + asmCrypto.hex_to_bytes('B7BF3A5DF43989DD97F0FA97EBCE2F4A'), + asmCrypto.hex_to_bytes('ae2d8a571e03ac9c9eb76fac45af8e51'), + asmCrypto.hex_to_bytes('4febdc6740d20b3ac88f6ad82a4fb08d'), + ], + [ + asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), + asmCrypto.hex_to_bytes('E1C656305ED1A7A6563805746FE03EDC'), + asmCrypto.hex_to_bytes('30c81c46a35ce411e5fbc1191a0a52ef'), + asmCrypto.hex_to_bytes('71ab47a086e86eedf39d1c5bba97c408'), + ], + [ + asmCrypto.hex_to_bytes('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'), + asmCrypto.hex_to_bytes('41635BE625B48AFC1666DD42A09D96E7'), + asmCrypto.hex_to_bytes('f69f2445df4f9b17ad2b417be66c3710'), + asmCrypto.hex_to_bytes('0126141d67f37be8538f5a8be740e484'), + ], ]; - - for ( var i = 0; i < ofb_vectors.length; ++i ) { - var key = new Uint8Array( ofb_vectors[i][0] ), - iv = new Uint8Array( ofb_vectors[i][1] ), - clear = new Uint8Array( ofb_vectors[i][2] ), - cipher = new Uint8Array( ofb_vectors[i][3] ); - - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_OFB.encrypt( clear, key, iv ) ), - asmCrypto.bytes_to_hex( cipher ), - "encrypt vector " + i - ); - - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_OFB.decrypt( cipher, key, iv ) ), - asmCrypto.bytes_to_hex( clear ), - "decrypt vector " + i - ); - } -}); - -testIf( asmCrypto.AES_CMAC !== undefined, "asmCrypto.AES_CMAC", function () { + + it('asmCrypto.AES_OFB.encrypt / asmCrypto.AES_OFB.decrypt', () => { + for (let i = 0; i < ofb_vectors.length; ++i) { + const key = new Uint8Array(ofb_vectors[i][0]); + const iv = new Uint8Array(ofb_vectors[i][1]); + const clear = new Uint8Array(ofb_vectors[i][2]); + const cipher = new Uint8Array(ofb_vectors[i][3]); + + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_OFB.encrypt(clear, key, iv)), 'encrypt vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(cipher)); + + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_OFB.decrypt(cipher, key, iv)), 'decrypt vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(clear)); + } + }); + }); + describe('CMAC', () => { // key, data, result - var cmac_vectors = [ - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes(''), - asmCrypto.hex_to_bytes('bb1d6929e95937287fa37d129b756746'), - ], - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), - asmCrypto.hex_to_bytes('070a16b46b4d4144f79bdd9dd04a287c'), - ], - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411'), - asmCrypto.hex_to_bytes('dfa66747de9ae63030ca32611497c827'), - ], - [ - asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), - asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), - asmCrypto.hex_to_bytes('51f0bebf7e3b9d92fc49741779363cfe'), - ], + const cmac_vectors = [ + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes(''), + asmCrypto.hex_to_bytes('bb1d6929e95937287fa37d129b756746'), + ], + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'), + asmCrypto.hex_to_bytes('070a16b46b4d4144f79bdd9dd04a287c'), + ], + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411'), + asmCrypto.hex_to_bytes('dfa66747de9ae63030ca32611497c827'), + ], + [ + asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'), + asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), + asmCrypto.hex_to_bytes('51f0bebf7e3b9d92fc49741779363cfe'), + ], + ]; + + it('asmCrypto.AES_CMAC', function() { + for (let i = 0; i < cmac_vectors.length; ++i) { + const key = new Uint8Array(cmac_vectors[i][0]); + const data = new Uint8Array(cmac_vectors[i][1]); + const result = new Uint8Array(cmac_vectors[i][2]); + + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CMAC.bytes(data, key)), 'cmac vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(result)); + } + }); + }); + describe('CCM', () => { + const ccm_aes_vectors = [ + [ + // key + new Uint8Array([ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf ]), + // nonce + new Uint8Array([ 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 ]), + // adata + new Uint8Array([ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]), + // tagSize + 8, + // input message + new Uint8Array([ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e ]), + // encrypted message + new Uint8Array([ 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 ]), + ], + [ + // key + new Uint8Array([ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf ]), + // nonce + new Uint8Array([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]), + // adata + new Uint8Array([ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x61, 0x75, 0x74, 0x68, 0x69, 0x6e, 0x66, 0x6f, 0x6f ]), + // tagSize + 16, + // input message + asmCrypto.hex_to_bytes('44696420796f75206b6e6f772e2e2e0d0a46726f6d2057696b6970656469612773206e657720616e6420726563656e746c7920696d70726f76656420636f6e74656e743a0d0a5361696e74204c656f6e61726420436174686f6c69632043687572636820284d616469736f6e2c204e65627261736b61290d0a2e2e2e207468617420746865204a61636f62204d2e204e616368746967616c6c2d64657369676e65642053742e204c656f6e61726420436174686f6c696320436875726368202870696374757265642920696e204d616469736f6e2c204e65627261736b612c20636f6e7461696e73206120626f6e652072656c6963206f6620697473206e616d6573616b653f0d0a2e2e2e2074686174207468652043616e61646196536f757468204b6f72656120467265652054726164652041677265656d656e742077696c6c20656c696d696e61746520393825206f6620616c6c20696d706f72742074617269666673206265747765656e207468652074776f20636f756e74726965733f0d0a2e2e2e207468617420526f7373204d634577616e2c2043454f206f66205242532047726f75702c206f6e63652074686520776f726c642773206c6172676573742062616e6b2c207477696365206661696c656420616e206163636f756e74616e6379206578616d3f0d0a2e2e2e2074686174205475726b69736820776f6d656e2773206e6174696f6e616c2069636520686f636b657920706c617965722047697a656d20d67a74617364656c656e2069732061206d656d626572206f662068657220666174686572277320636c7562204d696c656e79756d20506174656e20534b3f0d0a2e2e2e207468617420566572697a6f6e20762e204643432028323031342920776173207265706f7274656420746f20626520746865206465617468206f66206e6574776f726b206e65757472616c6974792c20686176696e6720766163617465642074776f206f662074686520464343204f70656e20496e7465726e6574204f726465722032303130277320746872656520726567756c6174696f6e733f0d0a2e2e2e207468617420746865206d6f737320737065636965732043686f7269736f646f6e7469756d206163697068796c6c756d2063616e207375727669766520666f72206d6f7265207468616e20312c3530302079656172732066726f7a656e3f'), + // encrypted message + asmCrypto.hex_to_bytes('09e3c1f3ba2f40eeca4dd7c27453085c71727d4b452a388dbdafc48a7f1406184b5516ea59d9ece55f347237b440792a4e71d26ee6df2dfcd39aea379080082a67be4d7c1af810181379d3f3a444512468e43494a41e9f968c6fe13f45027a297cc24ba3113a5e1b575fa3e1246004d75264e0960052d4e14b4e1a46b24f644428ef4ad4c50455e7029fa53b4eadbe5934c234043f23296b1c235bc8ffadd28deea7415b4bfd996071179cb361822894ab54078b5ad139a7dea6889a36d1417cbbbb1eb9afa0de88d736bf81e5140df06988f2901c275f63fed880fb6a00e7ebd0d5394360ca67b0680d64cc4ba5f7c69298a265916dc4ef03bb54b5e59c0cc48f83b20cf6ec1180b2423966e78ffd94ad1b74dc6b314802ddea17036d507f44c289effd820cb43d0daac09d3ee20ee41cff1e3f2858dc2643e13fcc481d4b1d36ada547e05f789f0d1067c73949c522fd54dc0240c942cc250af3304173dcbab38f1c8292ce0036c8f0c20ceb3d5cc70cc02e5b07329640dc971a410959e89e24edf15d96a6d2cf81abcb994355051371983533f788c9bd01a8e640b1b733c2b34b7ddf7229cf81d3664d85e0cf14dcfb73f0701939f6929e725de6ea590dc0a4caf5fa6fdacc96590e43b94c6f221a703c1c5073509e6b0700eeafde7ee99e149bdbf34a5acd948a513401ba78c4db7128e1f0aac26767f8a4754ae06a41287a12a7f3059c7a405aceb105b3748264c081240c3aa3f298a0ef5f2ea93151a25a3f746082d352eb3a52fb6f860cdf0f4d2186af5e4aa744893e8a59037daa6c23d8d31d2666c528a4ce4e249a27f7aab2bf14eeb7bf8c617380a34db5b7fade8eca02f1f030a62a2ffc7f2d2b14ec366b2a4269be4c763276195ce4c95b4c77c2cc001aac54dd6496099d7ecfe1f1e316d846ab41c4ef461ae0687588ea45532fe8bf9c91cf0840200a232adaa0b8036eaf3f29e4b2d898e8fb2315c22f4915b5746c7920a0bbc98548076e8f68a2fbf3b84df590d0a3154a66d17a80a115027c066f4d5f6c69769e52268f3cea1ee86150144bc05ba63d526e611a1ef723b0b573b37eb5949dd27875208219a77d5a8f170fcecf452ea1b4c78bc135a6345c853a2621154a664806d9fbb88a61ec7935c3511aa3ede4736ee37027e5f2ef2079447886ed5a30839eee442ff8feb17acfa832a8dedb28cbb52b07a950c5dcb853a32ed2f8c0ff83adea7b060aaf2466d148ad43d8e657') + ], + [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) + // key + asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), + // nonce + asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), + // adata + undefined, + // tagSize + 16, + // plaintext + asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), + // ciphertext + asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), + ], + [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) + // key + asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), + // nonce + asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), + // adata + undefined, + // tagSize + 16, + // plaintext + asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), + // ciphertext + asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), + ], + [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) + // key + asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), + // nonce + asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), + // adata + asmCrypto.string_to_bytes(''), + // tagSize + 16, + // plaintext + asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), + // ciphertext + asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), + ], + [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158269407) + // key + asmCrypto.base64_to_bytes('dGQhii+B7+eLLHRiOA690w=='), + // nonce + asmCrypto.base64_to_bytes('R8q1njARXS7urWv3'), + // adata + new Uint8Array(0), + // tagSize + 16, + // plaintext + asmCrypto.base64_to_bytes('dGQhwoovwoHDr8OnwossdGI4DsK9w5M='), + // ciphertext + asmCrypto.base64_to_bytes('kMrwkAdqy9VuEdkUA75K2hxjjy4kyRfDXMGzg+l4CoHga1/Rh49R'), + ], + [ // Test case for issue #92 (https://github.com/vibornoff/asmcrypto.js/issues/92#issuecomment-158797782) + // key + asmCrypto.hex_to_bytes('0f0e0d0c0b0a09080706050403020100'), + // nonce + asmCrypto.hex_to_bytes('000102030405060708090a0b'), + // adata + undefined, + // tagSize + 16, + // plaintext + asmCrypto.string_to_bytes('42'), + // ciphertext + asmCrypto.hex_to_bytes('28be1ac7b43d8868869b9a45d3de436cd0cc'), + ], ]; - for ( var i = 0; i < cmac_vectors.length; ++i ) { - var key = new Uint8Array( cmac_vectors[i][0] ), - data = new Uint8Array( cmac_vectors[i][1] ), - result = new Uint8Array( cmac_vectors[i][2] ); + it('asmCrypto.AES_CCM.encrypt / asmCrypto.AES_CCM.decrypt', function() { + for (let i = 0; i < ccm_aes_vectors.length; ++i) { + const key = ccm_aes_vectors[i][0]; + const nonce = ccm_aes_vectors[i][1]; + const adata = ccm_aes_vectors[i][2]; + const tagsize = ccm_aes_vectors[i][3]; + const clear = ccm_aes_vectors[i][4]; + const cipher = ccm_aes_vectors[i][5]; - equal( - asmCrypto.bytes_to_hex( asmCrypto.AES_CMAC.bytes( data, key ) ), - asmCrypto.bytes_to_hex(result), - "cmac vector " + i - ); + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CCM.encrypt(clear, key, nonce, adata, tagsize)), 'encrypt vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(cipher)); - } + expect(asmCrypto.bytes_to_hex(asmCrypto.AES_CCM.decrypt(cipher, key, nonce, adata, tagsize)), 'decrypt vector ' + i).to.be.equal(asmCrypto.bytes_to_hex(clear)); + } + }); + }); }); diff --git a/test/bignum.js b/test/bignum.js index 009fe69..be1317d 100644 --- a/test/bignum.js +++ b/test/bignum.js @@ -1,287 +1,460 @@ -module("BigNumber"); - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.BigNumber !== 'undefined' ) -{ - test( "new asmCrypto.BigNumber()", function () { - var zero = new asmCrypto.BigNumber(); - ok( zero, "zero = new 0" ); - equal( zero.limbs.length, 0, "zero.limbs.length" ); - equal( zero.bitLength, 0, "zero.bitLength" ); - equal( zero.valueOf(), 0, "zero.valueOf()" ); - equal( zero.toString(16), '0', "zero.toString(16)" ); - - var one = asmCrypto.BigNumber.fromNumber(1); - ok( one, "one = new 1" ); - equal( one.limbs.length, 1, "one.limbs.length" ); - equal( one.limbs[0], 1, "one.limbs[0]" ); - equal( one.bitLength, 32, "one.bitLength" ); - equal( one.valueOf(), 1, "one.valueOf()" ); - equal( one.toString(16), '1', "one.toString(16)" ); - - var ten = asmCrypto.BigNumber.fromNumber(10); - ok( ten, "ten = new 10" ); - equal( ten.limbs.length, 1, "ten.limbs.length" ); - equal( ten.limbs[0], 10, "ten.limbs[0]" ); - equal( ten.bitLength, 32, "ten.bitLength" ); - equal( ten.valueOf(), 10, "ten.valueOf()" ); - equal( ten.toString(16), 'a', "ten.toString(16)" ); - - var mten = asmCrypto.BigNumber.fromNumber(-10); - ok( mten, "mten = new -10" ); - equal( mten.limbs.length, 1, "mten.limbs.length" ); - equal( mten.limbs[0], 10, "mten.limbs[0]" ); - equal( mten.bitLength, 32, "mten.bitLength" ); - equal( mten.valueOf(), -10, "mten.valueOf()" ); - equal( mten.toString(16), '-a', "mten.toString(16)" ); - - var ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff); - ok( ffffffff, "ffffffff = new 0xfffffff" ); - equal( ffffffff.limbs.length, 1, "ffffffff.limbs.length" ); - equal( ffffffff.limbs[0], 0xffffffff, "ffffffff.limbs[0]" ); - equal( ffffffff.bitLength, 32, "ffffffff.bitLength" ); - equal( ffffffff.valueOf(), 0xffffffff, "ffffffff.valueOf()" ); - equal( ffffffff.toString(16), 'ffffffff', "ffffffff.toString(16)" ); - - var deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); - ok( deadbeefcafe, "deadbeefcafe = new 0xdeadbeefcafe" ); - equal( deadbeefcafe.limbs.length, 2, "deadbeefcafe.limbs.length" ); - equal( deadbeefcafe.limbs[0], 0xbeefcafe, "deadbeefcafe.limbs[0]" ); - equal( deadbeefcafe.limbs[1], 0xdead, "deadbeefcafe.limbs[1]" ); - equal( deadbeefcafe.bitLength, 52, "deadbeefcafe.bitLength" ); - equal( deadbeefcafe.valueOf(), 0xdeadbeefcafe, "deadbeefcafe.valueOf()" ); - equal( deadbeefcafe.toString(16), 'deadbeefcafe', "deadbeefcafe.toString(16)" ); - - var verylarge = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc')); - ok( verylarge, "verylarge = new 3f70f29d…f967b6cc" ); - equal( verylarge.limbs.length, 64, "verylarge.limbs.length" ); - equal( verylarge.limbs[0], 0xf967b6cc, "verylarge.limbs[0]" ); - equal( verylarge.limbs[63], 0x3f70f29d, "verylarge.limbs[63]" ); - equal( verylarge.bitLength, 2048, "verylarge.bitLength" ); - equal( verylarge.valueOf(), Infinity, "verylarge.valueOf()" ); - equal( verylarge.toString(16), '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', "verylarge.toString()" ); - }); - - test( "asmCrypto.BigNumber.slice", function () { - var deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); - equal( deadbeefcafe.slice(0).valueOf(), 0xdeadbeefcafe, "slice(0)" ); - equal( deadbeefcafe.slice(52).valueOf(), 0, "slice(bitLength)" ); - equal( deadbeefcafe.slice(24,16).valueOf(), 0xadbe, "slice(middle)" ); - }); - - test( "asmCrypto.BigNumber.compare", function () { - var deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe), - ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff), - result = null; - - result = ffffffff.compare(asmCrypto.BigNumber.fromNumber(0xffffffff)); - equal( result, 0, "ffffffff == 0xffffffff" ); - - result = deadbeefcafe.compare(ffffffff); - equal( result, 1, "deadbeefcafe > ffffffff" ); - - result = ffffffff.compare(deadbeefcafe); - equal( result, -1, "ffffffff > deadbeefcafe" ); - - result = ffffffff.compare(asmCrypto.BigNumber.fromNumber(-10)); - equal( result, 1, "ffffffff > -10" ); - }); - - test( "asmCrypto.BigNumber.add", function () { - var deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe), - ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff), - result = null; - - result = deadbeefcafe.add(ffffffff); - equal( result.toString(16), 'deaebeefcafd', "deadbeefcafe + ffffffff" ); - - result = ffffffff.add(deadbeefcafe); - equal( result.toString(16), 'deaebeefcafd', "ffffffff + deadbeefcafe" ); - - result = ffffffff.add(asmCrypto.BigNumber.fromNumber(-4294967295)); - equal( result.valueOf(), 0, "ffffffff + (-ffffffff)" ); - - result = (new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'))).add(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'))); - equal( result.toString(16), '10000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', "large fff…fff" ); - }); - - test( "asmCrypto.BigNumber.subtract", function () { - var deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe), - ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff), - result = null; - - result = deadbeefcafe.subtract(ffffffff); - equal( result.toString(16), 'deacbeefcaff', "deadbeefcafe - ffffffff" ); - - result = ffffffff.subtract(deadbeefcafe); - equal( result.toString(16), '-deacbeefcaff', "ffffffff - deadbeefcafe" ); - - result = (new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'))).subtract(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'))); - equal( result.toString(16), 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000', "large fff…fff" ); - }); - - test( "asmCrypto.BigNumber.multiply", function () { - var small = asmCrypto.BigNumber.fromNumber(0xabcdabcd), - large = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd')), - verylarge = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc')), - result = null; - - result = small.multiply(asmCrypto.BigNumber.fromNumber(0x1000)); - equal( result.toString(16), 'abcdabcd000', "small product is ok" ); - - result = large.multiply(large); - equal( result.toString(16), '9d616b569f3248a3e8b0bdcbed25f33122fd4e63f46cdacf664809417b3af1210cfd498deef48381295f067280f14d9ec85fe251e545f5013048853daab3b89', "large product is ok"); - - result = verylarge.multiply(verylarge); - equal( result.toString(16), 'fb8c93e94a3fb8c87d267c2550011118c118f0a8ed6b1f2a611a13d05c363e90514fd4e4b4f8485b9113846168ba5cca86bfb8faadd25a5b978da0e95432a4203ca0c58ad4c34a81acb7065dc182a58e5bbca29b1ab195209a48dd6429aaa29ea2109ba8ea28302108b7b1812dcbbf4221e72e7d1283264bf0a2e2cb180e8687892ba428b88b92bcfdc228b733a02dceec5e0ee501b81b4ee68d66e320e3aae26f63cbd2db9f01e43844b1c40c68dfd2f329925cd1334a5af0f33f8ea509c1bb9c810bed4a4e5d0b91504cf56178027af972130bc3eaaac52868b3b0c554204d55470e05ff5dd70d8b70b8c385277329d0d4d0a5aa7a1c555750eaee4f1e1581ab56e3b1210e14d46393539ccb793e3a6a6f15bcf61b1e8a9acdf36db03457a37a1ae522c0129c18d08345ccc2f44352ed159db24272d4ac2de9e5f6c361477826b9d62be54468a9c9949ba0c772548dd28eabb4e195bb87a01244c3d44462aaa0ab3f22b48693650da8a1ffddde979533709f4dfb2b1a7c6fa98646deeb4b97f29d8c79f74f3f537845b99f8564ff046d35fbe108e13cf17c3f1b9390512fc57cd2f66d6ff94a455ba646a3ebc7464376b63126c869e2b722510243ee579882540e3d02e796c997fe1d43e2364314ba3190bc8ff0ba09855df3ef9cd3277b4f4ffeba6aeafc9513d89c012507cc8a471ea2ab91b24898afd6575e572aeb290', "verylarge product is ok"); - - result = (new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc'))).multiply(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'))); - equal( result.toString(16), '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', "verylarge2 product is ok"); - }); - - test( "asmCrypto.BigNumber.square", function () { - var small = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffff')), - medium = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffff')), - medium2 = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')), - large = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd')), - verylarge = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc')), - result; - - result = small.square(); - equal( result.toString(16), 'fffffffe00000001', "small square is ok" ); - - result = medium.square(); - equal( result.toString(16), 'fffffffffffffffe0000000000000001', "medium square is ok" ); - - result = medium2.square(); - equal( result.toString(16), 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000000000000000000000000000000001', "medium2 square is ok" ); - - result = large.square(); - equal( result.toString(16), '9d616b569f3248a3e8b0bdcbed25f33122fd4e63f46cdacf664809417b3af1210cfd498deef48381295f067280f14d9ec85fe251e545f5013048853daab3b89', "large square is ok"); - - result = verylarge.square(); - equal( result.toString(16), 'fb8c93e94a3fb8c87d267c2550011118c118f0a8ed6b1f2a611a13d05c363e90514fd4e4b4f8485b9113846168ba5cca86bfb8faadd25a5b978da0e95432a4203ca0c58ad4c34a81acb7065dc182a58e5bbca29b1ab195209a48dd6429aaa29ea2109ba8ea28302108b7b1812dcbbf4221e72e7d1283264bf0a2e2cb180e8687892ba428b88b92bcfdc228b733a02dceec5e0ee501b81b4ee68d66e320e3aae26f63cbd2db9f01e43844b1c40c68dfd2f329925cd1334a5af0f33f8ea509c1bb9c810bed4a4e5d0b91504cf56178027af972130bc3eaaac52868b3b0c554204d55470e05ff5dd70d8b70b8c385277329d0d4d0a5aa7a1c555750eaee4f1e1581ab56e3b1210e14d46393539ccb793e3a6a6f15bcf61b1e8a9acdf36db03457a37a1ae522c0129c18d08345ccc2f44352ed159db24272d4ac2de9e5f6c361477826b9d62be54468a9c9949ba0c772548dd28eabb4e195bb87a01244c3d44462aaa0ab3f22b48693650da8a1ffddde979533709f4dfb2b1a7c6fa98646deeb4b97f29d8c79f74f3f537845b99f8564ff046d35fbe108e13cf17c3f1b9390512fc57cd2f66d6ff94a455ba646a3ebc7464376b63126c869e2b722510243ee579882540e3d02e796c997fe1d43e2364314ba3190bc8ff0ba09855df3ef9cd3277b4f4ffeba6aeafc9513d89c012507cc8a471ea2ab91b24898afd6575e572aeb290', "verylarge square is ok"); - }); - - test( "asmCrypto.BigNumber.divide", function () { - var small = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('95705fac129de210')), - small2 = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('fffffffe00000002')), - small3 = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffff')), - large = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('9d616b569f3248a3e8b0bdcbed25f33122fd4e63f46cdacf664809417b3af1210cfd498deef48381295f067280f14d9ec85fe251e545f5013048853daab3b89')), - large2 = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd')), - result = null; - - result = small.divide(asmCrypto.BigNumber.fromNumber(0xabcd)); - equal( result.remainder.toString(16), 'aaaa', "small % 0xabcd" ); - equal( result.quotient.toString(16), 'deadbeefcafe', "floor( small / 0xabcd )" ); - - result = small2.divide(small3); - equal( result.remainder.toString(16), '1', "small2 % small3" ); - equal( result.quotient.toString(16), 'ffffffff', "floor( small2 / small3 )" ); - - result = large.divide(large2); - equal( result.remainder, asmCrypto.BigNumber.ZERO, "large % large2" ); - equal( result.quotient.toString(16), '322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd', "floor( large / large2 )" ); - - result = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')) - .divide(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd'))); - equal( result.quotient.toString(16), '1', "q is ok" ); - equal( result.remainder.toString(16), '380e43e204e417d2dbb510fedd73ebf63e6776b13561debcf0e9964b55c79b360c80c2ae4d4b45e54617f0a62d98025eade1774faee866ce8a1ffbabc391c9eedbd0dbbcd317105c47e0f0099f4b06e3a2ad0daee590c7e7e58406541108d24fa9af7444b114a09a0e9e22d2a4bc69aa2d518f7e0339d0234d7eadf6ee2698ff37a3250ed182e0ea4aa521798dbf8ddbdae672b31c6fe6aaf3b3756de03dce2c16bd689773d288329711702125c748065d8b8fe010dc4b15593e563ea4d2880c89cb6cfc7903df13d6e416a51266a97fe1e3899fe4f63bec526ea00fc4023f494dcc97951a617350ee8af4af654b1a811f6dfddc64511c291c6d2e9bfe7a1e33', "r is ok" ); - - result = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ad399e5f74531e554ab7e7130b8ae864c7ea09621f5fff87e07160b080e89cca0bb74448c9e792b53806bce62a0cedfed2184ea47014988c92fdbafe60771d02d5b5dcf7d4f5ac1dc0a1dd010d7ae5672efdb92b38f56b78ac54797d18a6dd363fdac5e58b68321305983c81cf4d627ed2a59c150458999e23d1d2569beb083c67fab925ae495a97acb4465aa6960d1df08a73d3f5362a53c3db3813f006d7bb7a29028d0547e918f2bb407acf60f6391b7862a1db39f26727771c61747a7766619a42864faa21d8d23317e12abbb13e0ba2ad6f7f0e3d08')) - .divide(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('a736146b621310f6cd645cb2fefeda223aa7ae33a53ac22e019b6ffb7167d9b29be1aebb3e1a7129ee3a5b4fb1a11660932b9be2b36a6dd3226451d7c4dd79619bdb9aa5596cef4e7b6d91f0e227bba2547b004ded1ed0e06182141dc55e183374fe1d93e23c38fcc81cd8eae82647528dde963cf1ef86f470e69436a2ac0d7fa7161d6fbfd32141217df992002320cb575e8de44c446d73bdf116719d61451c474701e153a01771cb8f070f8241d465d3d0124aed70ec459669bfc4927f941ddac97f4772f8d4d55165d1d06eec147749d0b9fee868ddf3'))); - equal( result.quotient.toString(16), '1', "q is ok" ); - equal( result.remainder.toString(16), '60389f412400d5e7d538a600c8c0e428d425b2e7a253d59ded5f0b50f80c3176fd5958d8bcd218b49cc6196786bd79e3eecb2c1bcaa2ab9709969269b99a3a139da42527b88bccf45344b102b5329c4da82b8dd4bd69a984ad2655f5348c502cadca851a92bf9163d7b6396e7271b2c44c705d8126912a9b2eb3e1ff93efabcc0e49bb5ee7639568b364cc8a672ec52992be5efa8f1bce005ea21a252a5929f32e200abb1a7d1a7272c396b4d1f21d347a85056edc90621910d5c9ce1fae34886d0c33edcb14d0380cd4610bbcf9cc6c1d1f37096a55f15', "r is ok" ); - - result = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ad399e5f74531e554ab7e7130b8ae864c7ea09621f5fff87e07160b080e89cca0bb74448c9e792b53806bce62a0cedfed2184ea47014988c92fdbafe60771d02d5b5dcf7d4f5ac1dc0a1dd010d7ae5672efdb92b38f56b78ac54797d18a6dd363fdac5e58b68321305983c81cf4d627ed2a59c150458999e23d1d2569beb083c67fab925ae495a97acb4465aa6960d1df08a73d3f5362a53c3db3813f006d7bb7a29028d0547e918f2bb407acf60f6391b7862a1db39f26727771c61747a7766619a42864faa21d8d23317e12abbb13e0ba2ad6f7f0e3d08')) - .divide(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('a736146b621310f6cd645cb2fefeda223aa7ae33a53ac22e019b6ffb7167d9b29be1aebb3e1a7129ee3a5b4fb1a11660932b9be2b36a6dd3226451d7c4dd79619bdb9aa5596cef4e7b6d91f0e227bba2547b004ded1ed0e06182141dc55e183374fe1d93e23c38fcc81cd8eae82647528dde963cf1ef86f470e69436a2ac0d7fa7161d6fbfd32141217df992002320cb575e8de44c446d73bdf116719d61451c474701e153a01771cb8f070f8241d465d3d0124aed70ec459669bfc4927f941ddac97f4772f8d4d55165d1d06eec147749d0b9fee868ddf3'))); - equal( result.quotient.toString(16), '1', "q is ok" ); - equal( result.remainder.toString(16), '60389f412400d5e7d538a600c8c0e428d425b2e7a253d59ded5f0b50f80c3176fd5958d8bcd218b49cc6196786bd79e3eecb2c1bcaa2ab9709969269b99a3a139da42527b88bccf45344b102b5329c4da82b8dd4bd69a984ad2655f5348c502cadca851a92bf9163d7b6396e7271b2c44c705d8126912a9b2eb3e1ff93efabcc0e49bb5ee7639568b364cc8a672ec52992be5efa8f1bce005ea21a252a5929f32e200abb1a7d1a7272c396b4d1f21d347a85056edc90621910d5c9ce1fae34886d0c33edcb14d0380cd4610bbcf9cc6c1d1f37096a55f15', "r is ok" ); - - result = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('8251a22c009e3e37af0a516bbd73662a462531e4886005cec939265e99f177d7812fd7d5df184c5ea8ced1cace7e6724a4c31b1dbdedcd9636acff51936801df9bdf255850896b4da0aebfbc8944da8385a58f47e335ce94fd53ab1b299335c9e242fd89fc87126c11df2e65efa31fc37ce90e454b72afff5db16c271d476054022227c76c039c30feba1a1bd8d62c11b5c8a9e666b7726c4306c1e84f51c6fbe4485a2826cfacaea58d4a522a48a0164aa45df489944822953f860084d34b3ac537e27af0ed95613ffcb7f775832bf3acc7beff1469ed7a28abbff4dbf08859cafc8b8a7b3a2dc02cdff66095f53897ae74d2ce47e5644ea7ac59398a99b55')) - .divide(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('4128d116004f1f1bd78528b5deb9b315231298f2443002e7649c932f4cf8bbebc097ebeaef8c262f546768e5673f339252618d8edef6e6cb1b567fa8c9b400efcdef92ac2844b5a6d0575fde44a26d41c2d2c7a3f19ae74a7ea9d58d94c99ae4f1217ec4fe43893608ef9732f7d18fe1be748722a5b957ffaed8b6138ea3b02a011113e3b601ce187f5d0d0dec6b1608dae454f3335bb936218360f427a8e37df2242d141367d65752c6a5291524500b25522efa44ca24114a9fc3004269a59d629bf13d7876cab09ffe5bfbbac195f9d663df7f8a34f6bd1455dffa6df8442ce57e45c53d9d16e0166ffb304afa9c4bd73a696723f2b22753d62c9cc54cdab'))); - equal( result.quotient.toString(16), '1', "q is ok" ); - equal( result.remainder.toString(16), '4128d116004f1f1bd78528b5deb9b315231298f2443002e7649c932f4cf8bbebc097ebeaef8c262f546768e5673f339252618d8edef6e6cb1b567fa8c9b400efcdef92ac2844b5a6d0575fde44a26d41c2d2c7a3f19ae74a7ea9d58d94c99ae4f1217ec4fe43893608ef9732f7d18fe1be748722a5b957ffaed8b6138ea3b02a011113e3b601ce187f5d0d0dec6b1608dae454f3335bb936218360f427a8e37df2242d141367d65752c6a5291524500b25522efa44ca24114a9fc3004269a59d629bf13d7876cab09ffe5bfbbac195f9d663df7f8a34f6bd1455dffa6df8442ce57e45c53d9d16e0166ffb304afa9c4bd73a696723f2b22753d62c9cc54cdaa', "r is ok" ); - - result = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('8000000000000000')) - .divide(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('80000000ffff'))); - equal( result.quotient.toString(16), 'ffff', "q is ok" ); - equal( result.remainder.toString(16), '7fff0001ffff', "r is ok" ); - }); - - test( "asmCrypto.BigNumber.extGCD", function () { - var z; - - z = asmCrypto.BigNumber.extGCD(asmCrypto.BigNumber.fromNumber(3), asmCrypto.BigNumber.fromNumber(2)); - equal( z.gcd.valueOf(), 1, "gcd ok" ); - equal( z.x.valueOf(), 1, "x ok" ); - equal( z.y.valueOf(), -1, "y ok" ); - - z = asmCrypto.BigNumber.extGCD(asmCrypto.BigNumber.fromNumber(240), asmCrypto.BigNumber.fromNumber(46)); - equal( z.gcd.valueOf(), 2, "gcd ok" ); - equal( z.x.valueOf(), -9, "x ok" ); - equal( z.y.valueOf(), 47, "y ok" ); - - z = asmCrypto.BigNumber.extGCD( new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('abcdabcdabcd')), new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('20000000000000')) ); - equal( z.gcd.valueOf(), 1, "gcd ok" ); - equal( z.x.toString(16), '9b51de3a73905', "x ok" ); - equal( z.y.toString(16), '-341e3c1e3c1e', "y ok" ); - - z = asmCrypto.BigNumber.extGCD( - new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('00fcbd95956bea867fe1250b179fb2d4e0c59c4a2fe469a01cd90509d7d7c25cdf84f77eea1fbe509269819a828959b39b8f54a38a6f0290e48c0f3c9c45b78123')), - new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('00d5176443bebb2a31a44df711ff7c982395c5477365f3618398fd7d37fad4d2394f9458c39dec561dab0bc6c7ced1c76b29cfd2e14ec793d5d300c70d49ada9f1')), - ); - equal( z.gcd.valueOf(), 1, "gcd ok" ); - - z = asmCrypto.BigNumber.extGCD( - new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')), - new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd')) - ); - equal( z.gcd.valueOf(), 1, "gcd ok" ); - equal( z.x.toString(16), '-210fc146c2f2919c3e9a4372a7221069fa359d7feba4ecaf765c47f29819a82ebb92c5944f921e090c8f0eee5218d243b35eb488fdef6a2f9712ba887625af9599b2a547595528054f079124831d94872243009cec4e3154199893d700c2a64c3fae1e259bd37b4f88e34a6ff0fcb7c221a9b222df4a74f4d381259c641cef4d05bbbc737ac29f06e050139aa823d00c2af2b484720a58eadc39ea10d53c8664289e5495fcb188abecb167c8b81a267a24fa304b447d484c37af38525f5c1c3c7bc9e614b779e21d582c0222fa8bc13bc37673cefbb60a84a70423dcec8850d6c3c80c244e09cee87e7f6dadaf24a2b9410bc31e1afc588f9d20d769a5c3df71', "x ok" ); - equal( z.y.toString(16), '2a54a02a4b2182e2ea06578065a9608f53c45bd34ab2d3c47c18bca20e2bf9d93f6ac1aecc7a4bf18cfbc073db8cd0829b656bcb1f7a52b10bdc463ac246f11a30c0cc4ea00f093fcb0b4809a2b83bfb627789c6daac33d467a2b7bcda403018b344ca065fecccd2922afd53268ea599b17b96f29fe9fa4487cd0df93db31f3197a1973fafdd5f37a9f80f2554947ed63ffa4f12f0c5eefec24e9192ddcbc19ad179f76d95e361250300f18de3f7c9a067b84ccba3b31e1d1cf4379a492aa916882e09fa6836e3524b9bf750cf8f8dddbb48dd2ac0a9cfdfe6409330c0d62f08d13ec220436482bb39db9b1c595c5e0e0b743344620ac8eb0e18b0d3c641f305', "y ok" ); - }); - - test( "asmCrypto.Modulus", function () { - var M = new asmCrypto.Modulus(asmCrypto.BigNumber.fromNumber(123456789)); - - ok( M, "new Modulus" ); - equal( M.reduce(asmCrypto.BigNumber.fromNumber(987654321)).valueOf(), 9, "Modulus.reduce(small)" ); - - var M2 = new asmCrypto.Modulus(asmCrypto.BigNumber.fromNumber(0xabcdabcdabcd)); - equal( M2.comodulus.toString(16), '10000000000000000', "M2 comodulus ok" ); - equal( M2.comodulusRemainder.toString(16), '624f6250624f', "M2 comodulus remainder ok" ); - equal( M2.comodulusRemainderSquare.toString(16), '399f399e399e', "M2 comodulus remainder square ok" ); - equal( M2.coefficient.toString(16), '1c58c6fb', "M2 coefficent ok" ); - - var M3 = new asmCrypto.Modulus(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd'))); - equal( M3.comodulus.toString(16), '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', "M3 comodulus ok" ); - equal( M3.comodulusRemainder.toString(16), '380e43e204e417d2dbb510fedd73ebf63e6776b13561debcf0e9964b55c79b360c80c2ae4d4b45e54617f0a62d98025eade1774faee866ce8a1ffbabc391c9eedbd0dbbcd317105c47e0f0099f4b06e3a2ad0daee590c7e7e58406541108d24fa9af7444b114a09a0e9e22d2a4bc69aa2d518f7e0339d0234d7eadf6ee2698ff37a3250ed182e0ea4aa521798dbf8ddbdae672b31c6fe6aaf3b3756de03dce2c16bd689773d288329711702125c748065d8b8fe010dc4b15593e563ea4d2880c89cb6cfc7903df13d6e416a51266a97fe1e3899fe4f63bec526ea00fc4023f494dcc97951a617350ee8af4af654b1a811f6dfddc64511c291c6d2e9bfe7a1e33', "M3 comodulus remainder ok" ); - equal( M3.comodulusRemainderSquare.toString(16), 'a8d0cc3c0069b1fe694294247f367071deb9b3fdc80824536f04fae0c3df7fccc9f856aeee2033803b371a3c455522fb288c60f326db2fdcaf7452b48b0f0a29cce2dabe844a63f8077be24d2a0db5051e8a1481c16f0b880819cf8d193adaa79c92f11f1e4a2e89f24bc0ef0e2285ff218a5c058908f6feef024b0c8bfe11d37cba38103339f19ba7466f3070588152f1a008dc454cebcc4f70879e94ac1eb26179833049da7b450fbe93d7d802edc5900b3a973d05ff76c6bbb7914c59b27265222501b14497fe0ef99b7fa67777bf9ab89a8b346aacb6dbf606e68da0ba2a5c4ce3b0f85225292cd1acafebae5f553c03e9c3857730c715017550e4e77a53', "M3 comodulus remainder square ok" ); - equal( M3.coefficient.toString(16), "39be0cfb", "M3 coefficent ok" ); - - var M4 = new asmCrypto.Modulus( new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('453b5e276054110d94fd7b413ca54e467543c28168730315dae65c6241c847aa7ca16aa99e84e89249addf73bdb326cb7787a667cce65537cd0be7a3564f40fecace8bd6eac901013d5cd5dc28ec9415defff41e30b495bf269472e66e163493403396b14e27c1c9697e90a6274ea8dfda5bcf94d014ed7fa9c64174c78deb2ca1222521f161eafa0752dddecb31c76968929a42669174c9839b97036a2371b5d1466fe5549e53bcc7f30f7ba676950bd7a751e9e916c6525f49bf3046903ff738c5b0514ffe375ba9fe41bb766daf5973ca1d7782d84628e59b3dfa14d7c86fb3d62a219176e84e17d6fae34faa461094ae0ffd9631dd49c9138f6691a1a854') )); - equal( M4.inverse( new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('145cc156e018b9b8b3599cb8d59a07f69af5cfcbb54f00e84f70edfec80dbab9ac2f79b96adbcbeeca6050c7b043c01db9be7c3ca5ad281f788b07e4bf08404af05addd5cc9578c4211b4df57572c2248ce1de633b806847479512bc3e7f00678b5a779d8f751ae0e2cadf3fed717cf68b846a3ad3c9eb7fe6a3b8e61c93270d2055563728e09067a7cd141459e176e2c4675a8c000ca9e0ea790e4c4c64c7175bab4e16461072fb49de139cd69b59037ba9aeae357f2b456751ecf014c103c12ed0bb6335a51f5731ff7cbeaa5c7ede12ff35d7db308d1b165ad5fe425d954e07b775cda34117260702fe7f176e50d7b34240f03b3bd7ac4a32edf0fda80455') )).toString(16), '11', "M4 inverse OK" ); - - var M5 = new asmCrypto.Modulus( new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('0aabbccddaabbccdd')) ); - equal( M5.reduce( new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('1aabbccddaabbccdd')) ).toString(16), '5544332255443323', "M5 reduce ok" ); - }); - - test( "asmCrypto.Modulus.power", function () { - var base = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc')), - modulus = new asmCrypto.Modulus(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd'))), - exponent = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd')); - - equal( modulus.power( base, exponent ).toString(16), '5b3823974b3eda87286d3f38499de290bd575d8b02f06720acacf3d50950f9ca0ff6b749f3be03913ddca0b291e0b263bdab6c9cb97e4ab47ee9c235ff20931a8ca358726fab93614e2c549594f5c50b1c979b34f840b6d4fc51d6feb2dd072995421d17862cb405e040fc1ed662a3245a1f97bbafa6d1f7f76c7db6a802e3037acdf01ab5053f5da518d6753477193b9c25e1720519dcb9e2f6e70d5786656d356151845a49861dfc40187eff0e85cd18b1f3f3b97c476472edfa090b868b2388edfffecc521c20df8cebb8aacfb3669b020330dd6ea64b2a3067a972b8f249bccc19347eff43893e916f0949bd5789a5cce0f8b7cd87cece909d679345c0d4', "Modulus.power ok" ); - }); - - test( "asmCrypto.isProbablePrime", function () { - var p = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('8844ae66464b4b7db53644be87617124f314a1d8243d347867c8cfd6afb595bdb88ce63538fbd6c3f8461133d77ed4f5ef403f48c65b7340c683839c00bc7874bff3e9ffe7916a3ca085c7096f31871f2d628198f9c1deaeaefa581ebaef834a89afdf663b9570287a257bd6e4f507cede3b31eda6bd7fd4f8ae3c5b8791d89f')); - ok( p.isProbablePrime(), "p is probable prime" ); - }); -} -else -{ - skip( "asmCrypto.BigNumber" ); -} +import * as asmCrypto from '../asmcrypto.all.es8'; +import chai from 'chai'; +const expect = chai.expect; + +describe('Bignum', () => { + it('new asmCrypto.BigNumber()', function() { + const zero = new asmCrypto.BigNumber(); + expect(zero.limbs.length, 'zero.limbs.length').to.equal(0); + expect(zero.bitLength, 'zero.bitLength').to.equal(0); + expect(zero.valueOf(), 'zero.valueOf()').to.equal(0); + expect(zero.toString(16), 'zero.toString(16)').to.equal('0'); + + const one = asmCrypto.BigNumber.fromNumber(1); + expect(one.limbs.length, 'one.limbs.length').to.equal(1); + expect(one.limbs[0], 'one.limbs[0]').to.equal(1); + expect(one.bitLength, 'one.bitLength').to.equal(32); + expect(one.valueOf(), 'one.valueOf()').to.equal(1); + expect(one.toString(16), 'one.toString(16)').to.equal('1'); + + const ten = asmCrypto.BigNumber.fromNumber(10); + expect(ten.limbs.length, 'ten.limbs.length').to.equal(1); + expect(ten.limbs[0], 'ten.limbs[0]').to.equal(10); + expect(ten.bitLength, 'ten.bitLength').to.equal(32); + expect(ten.valueOf(), 'ten.valueOf()').to.equal(10); + expect(ten.toString(16), 'ten.toString(16)').to.equal('a'); + + const mten = asmCrypto.BigNumber.fromNumber(-10); + expect(mten.limbs.length, 'mten.limbs.length').to.equal(1); + expect(mten.limbs[0], 'mten.limbs[0]').to.equal(10); + expect(mten.bitLength, 'mten.bitLength').to.equal(32); + expect(mten.valueOf(), 'mten.valueOf()').to.equal(-10); + expect(mten.toString(16), 'mten.toString(16)').to.equal('-a'); + + const ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff); + expect(ffffffff.limbs.length, 'ffffffff.limbs.length').to.equal(1); + expect(ffffffff.limbs[0], 'ffffffff.limbs[0]').to.equal(0xffffffff); + expect(ffffffff.bitLength, 'ffffffff.bitLength').to.equal(32); + expect(ffffffff.valueOf(), 'ffffffff.valueOf()').to.equal(0xffffffff); + expect(ffffffff.toString(16), 'ffffffff.toString(16)').to.equal('ffffffff'); + + const deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); + expect(deadbeefcafe.limbs.length, 'deadbeefcafe.limbs.length').to.equal(2); + expect(deadbeefcafe.limbs[0], 'deadbeefcafe.limbs[0]').to.equal(0xbeefcafe); + expect(deadbeefcafe.limbs[1], 'deadbeefcafe.limbs[1]').to.equal(0xdead); + expect(deadbeefcafe.bitLength, 'deadbeefcafe.bitLength').to.equal(52); + expect(deadbeefcafe.valueOf(), 'deadbeefcafe.valueOf()').to.equal(0xdeadbeefcafe); + expect(deadbeefcafe.toString(16), 'deadbeefcafe.toString(16)').to.equal('deadbeefcafe'); + + const verylarge = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', + ), + ); + expect(verylarge.limbs.length, 'verylarge.limbs.length').to.equal(64); + expect(verylarge.limbs[0], 'verylarge.limbs[0]').to.equal(0xf967b6cc); + expect(verylarge.limbs[63], 'verylarge.limbs[63]').to.equal(0x3f70f29d); + expect(verylarge.bitLength, 'verylarge.bitLength').to.equal(2048); + expect(verylarge.valueOf(), 'verylarge.valueOf()').to.equal(Infinity); + expect(verylarge.toString(16), 'verylarge.toString()').to.equal( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', + ); + }); + + it('asmCrypto.BigNumber.slice', function() { + const deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); + expect(deadbeefcafe.slice(0).valueOf(), 'slice(0)').to.equal(0xdeadbeefcafe); + expect(deadbeefcafe.slice(52).valueOf(), 'slice(bitLength)').to.equal(0); + expect(deadbeefcafe.slice(24, 16).valueOf(), 'slice(middle)').to.equal(0xadbe); + }); + + it('asmCrypto.BigNumber.compare', function() { + const deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); + const ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff); + let result = null; + + result = ffffffff.compare(asmCrypto.BigNumber.fromNumber(0xffffffff)); + expect(result, 'ffffffff == 0xffffffff').to.equal(0); + + result = deadbeefcafe.compare(ffffffff); + expect(result, 'deadbeefcafe > ffffffff').to.equal(1); + + result = ffffffff.compare(deadbeefcafe); + expect(result, 'ffffffff > deadbeefcafe').to.equal(-1); + + result = ffffffff.compare(asmCrypto.BigNumber.fromNumber(-10)); + expect(result, 'ffffffff > -10').to.equal(1); + }); + + it('asmCrypto.BigNumber.add', function() { + const deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); + const ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff); + let result = null; + + result = deadbeefcafe.add(ffffffff); + expect(result.toString(16), 'deadbeefcafe + ffffffff').to.equal('deaebeefcafd'); + + result = ffffffff.add(deadbeefcafe); + expect(result.toString(16), 'ffffffff + deadbeefcafe').to.equal('deaebeefcafd'); + + result = ffffffff.add(asmCrypto.BigNumber.fromNumber(-4294967295)); + expect(result.valueOf(), 'ffffffff + (-ffffffff)').to.equal(0); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), + ).add( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + ), + ), + ); + expect(result.toString(16), 'large fff…fff').to.equal( + '10000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe', + ); + }); + + it('asmCrypto.BigNumber.subtract', function() { + const deadbeefcafe = asmCrypto.BigNumber.fromNumber(0xdeadbeefcafe); + const ffffffff = asmCrypto.BigNumber.fromNumber(0xffffffff); + let result = null; + + result = deadbeefcafe.subtract(ffffffff); + expect(result.toString(16), 'deadbeefcafe - ffffffff').to.equal('deacbeefcaff'); + + result = ffffffff.subtract(deadbeefcafe); + expect(result.toString(16), 'ffffffff - deadbeefcafe').to.equal('-deacbeefcaff'); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + ), + ).subtract( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), + ), + ); + expect(result.toString(16), 'large fff…fff').to.equal( + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000', + ); + }); + + it('asmCrypto.BigNumber.multiply', function() { + const small = asmCrypto.BigNumber.fromNumber(0xabcdabcd); + const large = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd'), + ); + const verylarge = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', + ), + ); + let result = null; + + result = small.multiply(asmCrypto.BigNumber.fromNumber(0x1000)); + expect(result.toString(16), 'small product is ok').to.equal('abcdabcd000'); + + result = large.multiply(large); + expect(result.toString(16), 'large product is ok').to.equal( + '9d616b569f3248a3e8b0bdcbed25f33122fd4e63f46cdacf664809417b3af1210cfd498deef48381295f067280f14d9ec85fe251e545f5013048853daab3b89', + ); + + result = verylarge.multiply(verylarge); + expect(result.toString(16), 'verylarge product is ok').to.equal( + 'fb8c93e94a3fb8c87d267c2550011118c118f0a8ed6b1f2a611a13d05c363e90514fd4e4b4f8485b9113846168ba5cca86bfb8faadd25a5b978da0e95432a4203ca0c58ad4c34a81acb7065dc182a58e5bbca29b1ab195209a48dd6429aaa29ea2109ba8ea28302108b7b1812dcbbf4221e72e7d1283264bf0a2e2cb180e8687892ba428b88b92bcfdc228b733a02dceec5e0ee501b81b4ee68d66e320e3aae26f63cbd2db9f01e43844b1c40c68dfd2f329925cd1334a5af0f33f8ea509c1bb9c810bed4a4e5d0b91504cf56178027af972130bc3eaaac52868b3b0c554204d55470e05ff5dd70d8b70b8c385277329d0d4d0a5aa7a1c555750eaee4f1e1581ab56e3b1210e14d46393539ccb793e3a6a6f15bcf61b1e8a9acdf36db03457a37a1ae522c0129c18d08345ccc2f44352ed159db24272d4ac2de9e5f6c361477826b9d62be54468a9c9949ba0c772548dd28eabb4e195bb87a01244c3d44462aaa0ab3f22b48693650da8a1ffddde979533709f4dfb2b1a7c6fa98646deeb4b97f29d8c79f74f3f537845b99f8564ff046d35fbe108e13cf17c3f1b9390512fc57cd2f66d6ff94a455ba646a3ebc7464376b63126c869e2b722510243ee579882540e3d02e796c997fe1d43e2364314ba3190bc8ff0ba09855df3ef9cd3277b4f4ffeba6aeafc9513d89c012507cc8a471ea2ab91b24898afd6575e572aeb290', + ); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', + ), + ).multiply( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + ), + ), + ); + expect(result.toString(16), 'verylarge2 product is ok').to.equal( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + ); + }); + + it('asmCrypto.BigNumber.square', function() { + const small = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffff')); + const medium = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffffffffffff')); + const medium2 = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), + ); + const large = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd'), + ); + const verylarge = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', + ), + ); + let result; + + result = small.square(); + expect(result.toString(16), 'small square is ok').to.equal('fffffffe00000001'); + + result = medium.square(); + expect(result.toString(16), 'medium square is ok').to.equal('fffffffffffffffe0000000000000001'); + + result = medium2.square(); + expect(result.toString(16), 'medium2 square is ok').to.equal( + 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000000000000000000000000000000001', + ); + + result = large.square(); + expect(result.toString(16), 'large square is ok').to.equal( + '9d616b569f3248a3e8b0bdcbed25f33122fd4e63f46cdacf664809417b3af1210cfd498deef48381295f067280f14d9ec85fe251e545f5013048853daab3b89', + ); + + result = verylarge.square(); + expect(result.toString(16), 'verylarge square is ok').to.equal( + 'fb8c93e94a3fb8c87d267c2550011118c118f0a8ed6b1f2a611a13d05c363e90514fd4e4b4f8485b9113846168ba5cca86bfb8faadd25a5b978da0e95432a4203ca0c58ad4c34a81acb7065dc182a58e5bbca29b1ab195209a48dd6429aaa29ea2109ba8ea28302108b7b1812dcbbf4221e72e7d1283264bf0a2e2cb180e8687892ba428b88b92bcfdc228b733a02dceec5e0ee501b81b4ee68d66e320e3aae26f63cbd2db9f01e43844b1c40c68dfd2f329925cd1334a5af0f33f8ea509c1bb9c810bed4a4e5d0b91504cf56178027af972130bc3eaaac52868b3b0c554204d55470e05ff5dd70d8b70b8c385277329d0d4d0a5aa7a1c555750eaee4f1e1581ab56e3b1210e14d46393539ccb793e3a6a6f15bcf61b1e8a9acdf36db03457a37a1ae522c0129c18d08345ccc2f44352ed159db24272d4ac2de9e5f6c361477826b9d62be54468a9c9949ba0c772548dd28eabb4e195bb87a01244c3d44462aaa0ab3f22b48693650da8a1ffddde979533709f4dfb2b1a7c6fa98646deeb4b97f29d8c79f74f3f537845b99f8564ff046d35fbe108e13cf17c3f1b9390512fc57cd2f66d6ff94a455ba646a3ebc7464376b63126c869e2b722510243ee579882540e3d02e796c997fe1d43e2364314ba3190bc8ff0ba09855df3ef9cd3277b4f4ffeba6aeafc9513d89c012507cc8a471ea2ab91b24898afd6575e572aeb290', + ); + }); + + it('asmCrypto.BigNumber.divide', function() { + const small = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('95705fac129de210')); + const small2 = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('fffffffe00000002')); + const small3 = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('ffffffff')); + const large = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '9d616b569f3248a3e8b0bdcbed25f33122fd4e63f46cdacf664809417b3af1210cfd498deef48381295f067280f14d9ec85fe251e545f5013048853daab3b89', + ), + ); + const large2 = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd'), + ); + let result = null; + + result = small.divide(asmCrypto.BigNumber.fromNumber(0xabcd)); + expect(result.remainder.toString(16), 'small % 0xabcd').to.equal('aaaa'); + expect(result.quotient.toString(16), 'floor( small / 0xabcd )').to.equal('deadbeefcafe'); + + result = small2.divide(small3); + expect(result.remainder.toString(16), 'small2 % small3').to.equal('1'); + expect(result.quotient.toString(16), 'floor( small2 / small3 )').to.equal('ffffffff'); + + result = large.divide(large2); + expect(result.remainder, 'large % large2').to.deep.equal(asmCrypto.BigNumber.ZERO); + expect(result.quotient.toString(16), 'floor( large / large2 )').to.equal( + '322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd', + ); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + ), + ).divide( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd', + ), + ), + ); + expect(result.quotient.toString(16), 'q is ok').to.equal('1'); + expect(result.remainder.toString(16), 'r is ok').to.equal( + '380e43e204e417d2dbb510fedd73ebf63e6776b13561debcf0e9964b55c79b360c80c2ae4d4b45e54617f0a62d98025eade1774faee866ce8a1ffbabc391c9eedbd0dbbcd317105c47e0f0099f4b06e3a2ad0daee590c7e7e58406541108d24fa9af7444b114a09a0e9e22d2a4bc69aa2d518f7e0339d0234d7eadf6ee2698ff37a3250ed182e0ea4aa521798dbf8ddbdae672b31c6fe6aaf3b3756de03dce2c16bd689773d288329711702125c748065d8b8fe010dc4b15593e563ea4d2880c89cb6cfc7903df13d6e416a51266a97fe1e3899fe4f63bec526ea00fc4023f494dcc97951a617350ee8af4af654b1a811f6dfddc64511c291c6d2e9bfe7a1e33', + ); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'ad399e5f74531e554ab7e7130b8ae864c7ea09621f5fff87e07160b080e89cca0bb74448c9e792b53806bce62a0cedfed2184ea47014988c92fdbafe60771d02d5b5dcf7d4f5ac1dc0a1dd010d7ae5672efdb92b38f56b78ac54797d18a6dd363fdac5e58b68321305983c81cf4d627ed2a59c150458999e23d1d2569beb083c67fab925ae495a97acb4465aa6960d1df08a73d3f5362a53c3db3813f006d7bb7a29028d0547e918f2bb407acf60f6391b7862a1db39f26727771c61747a7766619a42864faa21d8d23317e12abbb13e0ba2ad6f7f0e3d08', + ), + ).divide( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'a736146b621310f6cd645cb2fefeda223aa7ae33a53ac22e019b6ffb7167d9b29be1aebb3e1a7129ee3a5b4fb1a11660932b9be2b36a6dd3226451d7c4dd79619bdb9aa5596cef4e7b6d91f0e227bba2547b004ded1ed0e06182141dc55e183374fe1d93e23c38fcc81cd8eae82647528dde963cf1ef86f470e69436a2ac0d7fa7161d6fbfd32141217df992002320cb575e8de44c446d73bdf116719d61451c474701e153a01771cb8f070f8241d465d3d0124aed70ec459669bfc4927f941ddac97f4772f8d4d55165d1d06eec147749d0b9fee868ddf3', + ), + ), + ); + expect(result.quotient.toString(16), 'q is ok').to.equal('1'); + expect(result.remainder.toString(16), 'r is ok').to.equal( + '60389f412400d5e7d538a600c8c0e428d425b2e7a253d59ded5f0b50f80c3176fd5958d8bcd218b49cc6196786bd79e3eecb2c1bcaa2ab9709969269b99a3a139da42527b88bccf45344b102b5329c4da82b8dd4bd69a984ad2655f5348c502cadca851a92bf9163d7b6396e7271b2c44c705d8126912a9b2eb3e1ff93efabcc0e49bb5ee7639568b364cc8a672ec52992be5efa8f1bce005ea21a252a5929f32e200abb1a7d1a7272c396b4d1f21d347a85056edc90621910d5c9ce1fae34886d0c33edcb14d0380cd4610bbcf9cc6c1d1f37096a55f15', + ); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'ad399e5f74531e554ab7e7130b8ae864c7ea09621f5fff87e07160b080e89cca0bb74448c9e792b53806bce62a0cedfed2184ea47014988c92fdbafe60771d02d5b5dcf7d4f5ac1dc0a1dd010d7ae5672efdb92b38f56b78ac54797d18a6dd363fdac5e58b68321305983c81cf4d627ed2a59c150458999e23d1d2569beb083c67fab925ae495a97acb4465aa6960d1df08a73d3f5362a53c3db3813f006d7bb7a29028d0547e918f2bb407acf60f6391b7862a1db39f26727771c61747a7766619a42864faa21d8d23317e12abbb13e0ba2ad6f7f0e3d08', + ), + ).divide( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'a736146b621310f6cd645cb2fefeda223aa7ae33a53ac22e019b6ffb7167d9b29be1aebb3e1a7129ee3a5b4fb1a11660932b9be2b36a6dd3226451d7c4dd79619bdb9aa5596cef4e7b6d91f0e227bba2547b004ded1ed0e06182141dc55e183374fe1d93e23c38fcc81cd8eae82647528dde963cf1ef86f470e69436a2ac0d7fa7161d6fbfd32141217df992002320cb575e8de44c446d73bdf116719d61451c474701e153a01771cb8f070f8241d465d3d0124aed70ec459669bfc4927f941ddac97f4772f8d4d55165d1d06eec147749d0b9fee868ddf3', + ), + ), + ); + expect(result.quotient.toString(16), 'q is ok').to.equal('1'); + expect(result.remainder.toString(16), 'r is ok').to.equal( + '60389f412400d5e7d538a600c8c0e428d425b2e7a253d59ded5f0b50f80c3176fd5958d8bcd218b49cc6196786bd79e3eecb2c1bcaa2ab9709969269b99a3a139da42527b88bccf45344b102b5329c4da82b8dd4bd69a984ad2655f5348c502cadca851a92bf9163d7b6396e7271b2c44c705d8126912a9b2eb3e1ff93efabcc0e49bb5ee7639568b364cc8a672ec52992be5efa8f1bce005ea21a252a5929f32e200abb1a7d1a7272c396b4d1f21d347a85056edc90621910d5c9ce1fae34886d0c33edcb14d0380cd4610bbcf9cc6c1d1f37096a55f15', + ); + + result = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '8251a22c009e3e37af0a516bbd73662a462531e4886005cec939265e99f177d7812fd7d5df184c5ea8ced1cace7e6724a4c31b1dbdedcd9636acff51936801df9bdf255850896b4da0aebfbc8944da8385a58f47e335ce94fd53ab1b299335c9e242fd89fc87126c11df2e65efa31fc37ce90e454b72afff5db16c271d476054022227c76c039c30feba1a1bd8d62c11b5c8a9e666b7726c4306c1e84f51c6fbe4485a2826cfacaea58d4a522a48a0164aa45df489944822953f860084d34b3ac537e27af0ed95613ffcb7f775832bf3acc7beff1469ed7a28abbff4dbf08859cafc8b8a7b3a2dc02cdff66095f53897ae74d2ce47e5644ea7ac59398a99b55', + ), + ).divide( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '4128d116004f1f1bd78528b5deb9b315231298f2443002e7649c932f4cf8bbebc097ebeaef8c262f546768e5673f339252618d8edef6e6cb1b567fa8c9b400efcdef92ac2844b5a6d0575fde44a26d41c2d2c7a3f19ae74a7ea9d58d94c99ae4f1217ec4fe43893608ef9732f7d18fe1be748722a5b957ffaed8b6138ea3b02a011113e3b601ce187f5d0d0dec6b1608dae454f3335bb936218360f427a8e37df2242d141367d65752c6a5291524500b25522efa44ca24114a9fc3004269a59d629bf13d7876cab09ffe5bfbbac195f9d663df7f8a34f6bd1455dffa6df8442ce57e45c53d9d16e0166ffb304afa9c4bd73a696723f2b22753d62c9cc54cdab', + ), + ), + ); + expect(result.quotient.toString(16), 'q is ok').to.equal('1'); + expect(result.remainder.toString(16), 'r is ok').to.equal( + '4128d116004f1f1bd78528b5deb9b315231298f2443002e7649c932f4cf8bbebc097ebeaef8c262f546768e5673f339252618d8edef6e6cb1b567fa8c9b400efcdef92ac2844b5a6d0575fde44a26d41c2d2c7a3f19ae74a7ea9d58d94c99ae4f1217ec4fe43893608ef9732f7d18fe1be748722a5b957ffaed8b6138ea3b02a011113e3b601ce187f5d0d0dec6b1608dae454f3335bb936218360f427a8e37df2242d141367d65752c6a5291524500b25522efa44ca24114a9fc3004269a59d629bf13d7876cab09ffe5bfbbac195f9d663df7f8a34f6bd1455dffa6df8442ce57e45c53d9d16e0166ffb304afa9c4bd73a696723f2b22753d62c9cc54cdaa', + ); + + result = new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('8000000000000000')).divide( + new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('80000000ffff')), + ); + expect(result.quotient.toString(16), 'q is ok').to.equal('ffff'); + expect(result.remainder.toString(16), 'r is ok').to.equal('7fff0001ffff'); + }); + + it('asmCrypto.BigNumber.extGCD', function() { + let z; + + z = asmCrypto.BigNumber.extGCD(asmCrypto.BigNumber.fromNumber(3), asmCrypto.BigNumber.fromNumber(2)); + expect(z.gcd.valueOf(), 'gcd ok').to.equal(1); + expect(z.x.valueOf(), 'x ok').to.equal(1); + expect(z.y.valueOf(), 'y ok').to.equal(-1); + + z = asmCrypto.BigNumber.extGCD(asmCrypto.BigNumber.fromNumber(240), asmCrypto.BigNumber.fromNumber(46)); + expect(z.gcd.valueOf(), 'gcd ok').to.equal(2); + expect(z.x.valueOf(), 'x ok').to.equal(-9); + expect(z.y.valueOf(), 'y ok').to.equal(47); + + z = asmCrypto.BigNumber.extGCD( + new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('abcdabcdabcd')), + new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('20000000000000')), + ); + expect(z.gcd.valueOf(), 'gcd ok').to.equal(1); + expect(z.x.toString(16), 'x ok').to.equal('9b51de3a73905'); + expect(z.y.toString(16), 'y ok').to.equal('-341e3c1e3c1e'); + + z = asmCrypto.BigNumber.extGCD( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '00fcbd95956bea867fe1250b179fb2d4e0c59c4a2fe469a01cd90509d7d7c25cdf84f77eea1fbe509269819a828959b39b8f54a38a6f0290e48c0f3c9c45b78123', + ), + ), + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '00d5176443bebb2a31a44df711ff7c982395c5477365f3618398fd7d37fad4d2394f9458c39dec561dab0bc6c7ced1c76b29cfd2e14ec793d5d300c70d49ada9f1', + ), + ), + ); + expect(z.gcd.valueOf(), 'gcd ok').to.equal(1); + + z = asmCrypto.BigNumber.extGCD( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + ), + ), + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd', + ), + ), + ); + expect(z.gcd.valueOf(), 'gcd ok').to.equal(1); + expect(z.x.toString(16), 'x ok').to.equal( + '-210fc146c2f2919c3e9a4372a7221069fa359d7feba4ecaf765c47f29819a82ebb92c5944f921e090c8f0eee5218d243b35eb488fdef6a2f9712ba887625af9599b2a547595528054f079124831d94872243009cec4e3154199893d700c2a64c3fae1e259bd37b4f88e34a6ff0fcb7c221a9b222df4a74f4d381259c641cef4d05bbbc737ac29f06e050139aa823d00c2af2b484720a58eadc39ea10d53c8664289e5495fcb188abecb167c8b81a267a24fa304b447d484c37af38525f5c1c3c7bc9e614b779e21d582c0222fa8bc13bc37673cefbb60a84a70423dcec8850d6c3c80c244e09cee87e7f6dadaf24a2b9410bc31e1afc588f9d20d769a5c3df71', + ); + expect(z.y.toString(16), 'y ok').to.equal( + '2a54a02a4b2182e2ea06578065a9608f53c45bd34ab2d3c47c18bca20e2bf9d93f6ac1aecc7a4bf18cfbc073db8cd0829b656bcb1f7a52b10bdc463ac246f11a30c0cc4ea00f093fcb0b4809a2b83bfb627789c6daac33d467a2b7bcda403018b344ca065fecccd2922afd53268ea599b17b96f29fe9fa4487cd0df93db31f3197a1973fafdd5f37a9f80f2554947ed63ffa4f12f0c5eefec24e9192ddcbc19ad179f76d95e361250300f18de3f7c9a067b84ccba3b31e1d1cf4379a492aa916882e09fa6836e3524b9bf750cf8f8dddbb48dd2ac0a9cfdfe6409330c0d62f08d13ec220436482bb39db9b1c595c5e0e0b743344620ac8eb0e18b0d3c641f305', + ); + }); + + it('asmCrypto.Modulus', function() { + const M = new asmCrypto.Modulus(asmCrypto.BigNumber.fromNumber(123456789)); + + expect(M.reduce(asmCrypto.BigNumber.fromNumber(987654321)).valueOf(), 'Modulus.reduce(small)').to.equal(9); + + const M2 = new asmCrypto.Modulus(asmCrypto.BigNumber.fromNumber(0xabcdabcdabcd)); + expect(M2.comodulus.toString(16), 'M2 comodulus ok').to.equal('10000000000000000'); + expect(M2.comodulusRemainder.toString(16), 'M2 comodulus remainder ok').to.equal('624f6250624f'); + expect(M2.comodulusRemainderSquare.toString(16), 'M2 comodulus remainder square ok').to.equal('399f399e399e'); + expect(M2.coefficient.toString(16), 'M2 coefficent ok').to.equal('1c58c6fb'); + + const M3 = new asmCrypto.Modulus( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd', + ), + ), + ); + expect(M3.comodulus.toString(16), 'M3 comodulus ok').to.be.equal( + '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + ); + expect(M3.comodulusRemainder.toString(16), 'M3 comodulus remainder ok').to.equal( + '380e43e204e417d2dbb510fedd73ebf63e6776b13561debcf0e9964b55c79b360c80c2ae4d4b45e54617f0a62d98025eade1774faee866ce8a1ffbabc391c9eedbd0dbbcd317105c47e0f0099f4b06e3a2ad0daee590c7e7e58406541108d24fa9af7444b114a09a0e9e22d2a4bc69aa2d518f7e0339d0234d7eadf6ee2698ff37a3250ed182e0ea4aa521798dbf8ddbdae672b31c6fe6aaf3b3756de03dce2c16bd689773d288329711702125c748065d8b8fe010dc4b15593e563ea4d2880c89cb6cfc7903df13d6e416a51266a97fe1e3899fe4f63bec526ea00fc4023f494dcc97951a617350ee8af4af654b1a811f6dfddc64511c291c6d2e9bfe7a1e33', + ); + expect(M3.comodulusRemainderSquare.toString(16), 'M3 comodulus remainder square ok').to.equal( + 'a8d0cc3c0069b1fe694294247f367071deb9b3fdc80824536f04fae0c3df7fccc9f856aeee2033803b371a3c455522fb288c60f326db2fdcaf7452b48b0f0a29cce2dabe844a63f8077be24d2a0db5051e8a1481c16f0b880819cf8d193adaa79c92f11f1e4a2e89f24bc0ef0e2285ff218a5c058908f6feef024b0c8bfe11d37cba38103339f19ba7466f3070588152f1a008dc454cebcc4f70879e94ac1eb26179833049da7b450fbe93d7d802edc5900b3a973d05ff76c6bbb7914c59b27265222501b14497fe0ef99b7fa67777bf9ab89a8b346aacb6dbf606e68da0ba2a5c4ce3b0f85225292cd1acafebae5f553c03e9c3857730c715017550e4e77a53', + ); + expect(M3.coefficient.toString(16), 'M3 coefficent ok').to.equal('39be0cfb'); + + const M4 = new asmCrypto.Modulus( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '453b5e276054110d94fd7b413ca54e467543c28168730315dae65c6241c847aa7ca16aa99e84e89249addf73bdb326cb7787a667cce65537cd0be7a3564f40fecace8bd6eac901013d5cd5dc28ec9415defff41e30b495bf269472e66e163493403396b14e27c1c9697e90a6274ea8dfda5bcf94d014ed7fa9c64174c78deb2ca1222521f161eafa0752dddecb31c76968929a42669174c9839b97036a2371b5d1466fe5549e53bcc7f30f7ba676950bd7a751e9e916c6525f49bf3046903ff738c5b0514ffe375ba9fe41bb766daf5973ca1d7782d84628e59b3dfa14d7c86fb3d62a219176e84e17d6fae34faa461094ae0ffd9631dd49c9138f6691a1a854', + ), + ), + ); + expect( + M4.inverse( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '145cc156e018b9b8b3599cb8d59a07f69af5cfcbb54f00e84f70edfec80dbab9ac2f79b96adbcbeeca6050c7b043c01db9be7c3ca5ad281f788b07e4bf08404af05addd5cc9578c4211b4df57572c2248ce1de633b806847479512bc3e7f00678b5a779d8f751ae0e2cadf3fed717cf68b846a3ad3c9eb7fe6a3b8e61c93270d2055563728e09067a7cd141459e176e2c4675a8c000ca9e0ea790e4c4c64c7175bab4e16461072fb49de139cd69b59037ba9aeae357f2b456751ecf014c103c12ed0bb6335a51f5731ff7cbeaa5c7ede12ff35d7db308d1b165ad5fe425d954e07b775cda34117260702fe7f176e50d7b34240f03b3bd7ac4a32edf0fda80455', + ), + ), + ).toString(16), + 'M4 inverse OK', + ).to.equal('11'); + + const M5 = new asmCrypto.Modulus(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('0aabbccddaabbccdd'))); + expect( + M5.reduce(new asmCrypto.BigNumber(asmCrypto.hex_to_bytes('1aabbccddaabbccdd'))).toString(16), + 'M5 reduce ok', + ).to.equal('5544332255443323'); + }); + + it('asmCrypto.Modulus.power', function() { + const base = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '3f70f29d3f3ae354a6d2536ceafba83cfc787cd91e7acd2b6bde05e62beb8295ae18e3f786726f8d034bbc15bf8331df959f59d431736d5f306aaba63dacec279484e39d76db9b527738072af15730e8b9956a64e8e4dbe868f77d1414a8a8b8bf65380a1f008d39c5fabe1a9f8343929342ab7b4f635bdc52532d764701ff3d8072c475c012ff0c59373e8bc423928d99f58c3a6d9f6ab21ee20bc8e8818fc147db09f60c81906f2c6f73dc69725f075853a89f0cd02a30a8dd86b660ccdeffc292f398efb54088c822774445a6afde471f7dd327ef9996296898a5747726ccaeeceeb2e459df98b4128cb5ab8c7cd20c563f960a1aa770f3c81f13f967b6cc', + ), + ); + const modulus = new asmCrypto.Modulus( + new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + 'c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd', + ), + ), + ), + exponent = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes('322e393f76a1c22b147e7d193c00c023afb7c1500b006ff1bc1cc8d391fc38bd'), + ); + + expect(modulus.power(base, exponent).toString(16), 'Modulus.power ok').to.equal( + '5b3823974b3eda87286d3f38499de290bd575d8b02f06720acacf3d50950f9ca0ff6b749f3be03913ddca0b291e0b263bdab6c9cb97e4ab47ee9c235ff20931a8ca358726fab93614e2c549594f5c50b1c979b34f840b6d4fc51d6feb2dd072995421d17862cb405e040fc1ed662a3245a1f97bbafa6d1f7f76c7db6a802e3037acdf01ab5053f5da518d6753477193b9c25e1720519dcb9e2f6e70d5786656d356151845a49861dfc40187eff0e85cd18b1f3f3b97c476472edfa090b868b2388edfffecc521c20df8cebb8aacfb3669b020330dd6ea64b2a3067a972b8f249bccc19347eff43893e916f0949bd5789a5cce0f8b7cd87cece909d679345c0d4', + ); + }); + + it('asmCrypto.isProbablePrime', function() { + const p = new asmCrypto.BigNumber( + asmCrypto.hex_to_bytes( + '8844ae66464b4b7db53644be87617124f314a1d8243d347867c8cfd6afb595bdb88ce63538fbd6c3f8461133d77ed4f5ef403f48c65b7340c683839c00bc7874bff3e9ffe7916a3ca085c7096f31871f2d628198f9c1deaeaefa581ebaef834a89afdf663b9570287a257bd6e4f507cede3b31eda6bd7fd4f8ae3c5b8791d89f', + ), + ); + expect(p.isProbablePrime(), 'p is probable prime').to.be.true; + }); +}); diff --git a/test/dummy.js b/test/dummy.js deleted file mode 100644 index ca913bc..0000000 --- a/test/dummy.js +++ /dev/null @@ -1,152 +0,0 @@ -module("dummy"); - -test( "dummy test", function () { - ok( true, "Passed!" ); -}); - -test( "add with carry proparation", function () { - var a = 0xad4e6ae6, b = 0xedfdecc8, c = 1, d = 0x19b4c57af, dc = 1, - r = 0, rc = 0, u = 0, v = 0; - - r = (a + c)|0, rc = (r>>>0) < (a>>>0) ? 1 : 0; - r = (b + r)|0, rc = (r>>>0) < (b>>>0) ? 1 : rc; - equal( r>>>0, d>>>0, "adc32 result ok" ); - equal( rc, dc, "adc32 carry ok" ); - - u = ( (a & 0xffff) + (b & 0xffff)|0 ) + c|0; - v = ( (a >>> 16) + (b >>> 16)|0 ) + (u >>> 16)|0; - r = (u & 0xffff) | (v << 16); - rc = v >>> 16; - equal( r>>>0, d>>>0, "adc16x2 result ok" ); - equal( rc, dc, "adc16x2 carry ok" ); -}); - -if ( Math.imul ) { - test( "multiply and add", function () { - var imul = Math.imul, - x = 0xad4e6ae6, y = 0xedfdecc8, z = 0x9b4c57af, - h = 0xa11d7fc2, l = 0xde69e35f, - u = 0, v = 0, w = 0, - rh = 0, rl = 0; - - u = imul( x & 0xffff, y & 0xffff ) + (z & 0xffff) | 0; - v = imul( x & 0xffff, y >>> 16 ) + (z >>> 16) | 0; - w = ( imul( x >>> 16, y & 0xffff ) + (v & 0xffff) | 0 ) + (u >>> 16) | 0; - rh = ( imul( x >>> 16, y >>> 16 ) + (v >>> 16) | 0 ) + (w >>> 16) | 0; - rl = (w << 16) | (u & 0xffff); - - equal( h>>>0, rh>>>0, "high part is ok" ); - equal( l>>>0, rl>>>0, "low part is ok" ); - }); - - test( "divide with remainder", function () { - var n0 = 0xad4e6ae6, n1 = 0xedfdecc8, d0 = 0xeeddccbb, q0 = 0xff101123, r0 = 0x39b30255; - - var qh, ql, rh, rl, w0, w1, n, dh, dl, c, imul = Math.imul; - - dh = d0 >>> 16, dl = d0 & 0xffff; - - n = n1; - qh = ( n / dh )|0, rh = n % dh; - while ( ( (rh|0) < 0x10000 ) - & ( ( qh == 0x10000 ) | ( (imul(qh,dl)>>>0) > (((rh<<16)|(n0>>>16))>>>0) ) ) ) - { - qh = (qh-1)|0; - rh = (rh+dh)|0; - } - w0 = imul(qh, dl)|0; - w1 = (w0 >>> 16) + imul(qh, dh)|0; - w0 = w0 << 16; - n = (n0-w0)|0, c = ( (n>>>0) > (n0>>>0) )|0, n0 = n; - n = (n1-c)|0, c = ( (n>>>0) > (n1>>>0) )|0, n1 = (n-w1)|0, c = ( (n1>>>0) > (n>>>0) )|c; - if ( c ) { - qh = (qh-1)|0; - n = (n0+(d0<<16))|0, c = ( (n>>>0) < (n0>>>0) )|0, n0 = n; - n = (n1+c)|0, c = !n, n1 = (n+dh)|0, c = ( (n1>>>0) < (n>>>0) )|c; - } - - n = (n1 << 16) | (n0 >>> 16); - ql = ( n / dh )|0, rl = n % dh; - while ( ( (rl|0) < 0x10000 ) - & ( ( ql == 0x10000 ) | ( (imul(ql,dl)>>>0) > (((rl << 16)|(n0 & 0xffff))>>>0) ) ) ) - { - ql = (ql-1)|0; - rl = (rl+dh)|0; - } - w0 = imul(ql, dl)|0; - w1 = (w0 >>> 16) + imul(ql, dh)|0; - w0 = (w1 << 16) | (w0 & 0xffff); - w1 = w1 >>> 16; - n = (n0-w0)|0, c = ( (n>>>0) > (n0>>>0) )|0, n0 = n; - n = (n1-c)|0, c = ( (n>>>0) > (n1>>>0) )|0, n1 = (n-w1)|0, c = ( (n1>>>0) > (n>>>0) )|c; - if ( c ) { - ql = (ql-1)|0; - n = (n0+d0)|0, c = ( (n>>>0) < (n0>>>0) )|0, n0 = n; - n1 = (n1+c)|0; - } - - equal( ((qh<<16)|ql)>>>0, q0, "quotient ok" ); - equal( n0>>>0, r0, "remainder ok" ); - }); - - test( "imul", function () { - equal( Math.imul(-338592732,968756475)|0, 787375948, "imul works fine" ); - }); -} -else { - skip( "multiply and add" ); - skip( "divide with remainder" ); - skip( "imul" ); -} - -test( "Math.random()", function () { - var r = Math.random(); - ok( typeof r === 'number', "r is number" ); - ok( r >= 0 && r < 1, "0 <= r < 1" ); -}); - -testIf( true, "Conditional test should pass", function () { - ok( true, "Passed!" ); -}); - -testIf( false, "Conditional test should skip", function () { - ok( false, "Failed!" ); -}); - -testIf( asmCrypto.string_to_bytes, "asmCrypto.string_to_bytes", function ( ) { - var bytes = asmCrypto.string_to_bytes("String not containing Unicode character"); - ok( bytes, "No exception on non-Unicode string" ); - - try { - var bytes = asmCrypto.string_to_bytes("String containing Unicode character: Ͼ"); - ok( false, "No exception on Unicode string") - } - catch ( e ) { - ok( e instanceof Error, "Exception thrown on Unicode string" ); - ok( e.message.match(/wide character/i), "Exception message is about wide character" ); - } - - var bytes = asmCrypto.string_to_bytes( "\ud83d\ude80\u2665\u03ffa", true ); // Unicode ROCKET + BLACK HEART SUIT + GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL + LATIN SMALL LETTER A - equal( asmCrypto.bytes_to_hex(bytes), "f09f9a80e299a5cfbf61", "Encode into UTF8 byte array" ); -}); - -testIf( asmCrypto.bytes_to_string, "asmCrypto.bytes_to_string", function ( ) { - var bytes = asmCrypto.hex_to_bytes("f09f9a80e299a5cfbf61"); - - var str = asmCrypto.bytes_to_string( bytes, false ); - equal( str.length, 10, "Binary string length is ok" ); - equal( str, "\xf0\x9f\x9a\x80\xe2\x99\xa5\xcf\xbf\x61", "Binary string content is ok" ); - - var str = asmCrypto.bytes_to_string( bytes, true ); - equal( str.length, 5, "Characters string length is ok" ); - equal( str, "\ud83d\ude80\u2665\u03ffa", "Characters string content is ok" ); - - try { - var str = asmCrypto.bytes_to_string( bytes.subarray(0,3), true ); - ok( false, "No exception on malformed UTF8 byte array" ); - } - catch ( e ) { - ok( e instanceof Error, "Exception thrown on malformed UTF8 byte array" ); - ok( e.message.match(/Malformed UTF8 character/i), "Exception message is about malformed UTF8 character" ); - } -}); diff --git a/test/index.html b/test/index.html deleted file mode 100644 index 4174cdc..0000000 --- a/test/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -asmCrypto test suite - - - - - - - - - - - - - - - - - - - - - - - -
-
- diff --git a/test/isaac.js b/test/isaac.js deleted file mode 100644 index f121ece..0000000 --- a/test/isaac.js +++ /dev/null @@ -1,85 +0,0 @@ -/* -module("ISAAC"); - -/////////////////////////////////////////////////////////////////////////////// - -// Taken from http://burtleburtle.net/bob/rand/randvect.txt - -var isaac_vector = [ - 0x7a68710f, 0x6554abda, 0x90c10757, 0x0b5e435f, 0xaf7d1fb8, 0x01913fd3, 0x6a158d10, 0xb8f6fd4a, - 0xc2b9aa36, 0x96da2655, 0xfe1e42d5, 0x56e6cd21, 0xd5b2d750, 0x7229ea81, 0x5de87abb, 0xb6b9d766, - 0x1e16614c, 0x3b708f99, 0x5cf824cd, 0xa4ca0cf1, 0x62d31911, 0x7cdd662f, 0xcb9e1563, 0x79ae4c10, - 0x080c79ec, 0x18080c8e, 0x4a0a283c, 0x3dde9f39, 0x09c36f90, 0xad567643, 0x08294766, 0xb4415f7d, - 0x5597ec0f, 0x78ffa568, 0x8bace62e, 0x4188bfcd, 0xc87c8006, 0xafa92a6d, 0x50fc8194, 0xcae8deba, - 0x33f6d7b1, 0x53245b79, 0x61119a5a, 0x7e315aeb, 0xe75b41c9, 0xd2a93b51, 0xec46b0b6, 0x1ed3ff4e, - 0x5d023e65, 0xadf6bc23, 0xf7f58f7b, 0xe4f3a26a, 0x0c571a7d, 0xed35e5ee, 0xeadebeac, 0x30bcc764, - 0x66f1e0ab, 0x826dfa89, 0x0d9c7e7e, 0xe7e26581, 0xd5990dfb, 0x02c9b944, 0x4112d96c, 0x3ff1e524, - 0xc35e4580, 0xfdfef62d, 0xb83f957a, 0xbfc7f7cc, 0xb510ce0e, 0xcd7411a7, 0x04db4e13, 0x76904b6d, - 0x08607f04, 0x3718d597, 0x46c0a6f5, 0x8406b137, 0x309bfb78, 0xf7d3f39f, 0x8c2f0d55, 0xc613f157, - 0x127dd430, 0x72c9137d, 0x68a39358, 0x07c28cd1, 0x848f520a, 0xdd2dc1d5, 0x9388b13b, 0x28e7cb78, - 0x03fb88f4, 0xb0b84e7b, 0x14c8009b, 0x884d6825, 0x21c171ec, 0x0809e494, 0x6a107589, 0x12595a19, - 0x0bb3263f, 0x4d8fae82, 0x2a98121a, 0xb00960ba, 0x6708a2bc, 0x35a124b5, 0xbccaaeed, 0x294d37e5, - 0xd405ded8, 0x9f39e2d9, 0x21835c4d, 0xe89b1a3b, 0x7364944b, 0xbd2e5024, 0x6a123f57, 0x34105a8c, - 0x5ad0d3b0, 0xcc033ce3, 0xd51f093d, 0x56a001e3, 0x01a9bd70, 0x8891b3db, 0x13add922, 0x3d77d9a2, - 0x0e7e0e67, 0xd73f72d4, 0x917bdec2, 0xa37f63ff, 0x23d74f4e, 0x3a6ce389, 0x0606cf9f, 0xde11ed34, - 0x70cc94ae, 0xcb0eee4a, 0x13edc0cb, 0xfe29661c, 0xdb6dbe96, 0xb388d96c, 0x33bc405d, 0xa6d12101, - 0x2f36fa86, 0x7ded386f, 0xe6344451, 0xcd57c7f7, 0x1b0dcdc1, 0xcd49ebdb, 0x9e8a51da, 0x12a0594b, - 0x60d4d5f8, 0x91c8d925, 0xe43d0fbb, 0x5d2a542f, 0x451e7ec8, 0x2b36505c, 0x37c0ed05, 0x2364a1aa, - 0x814bc24c, 0xe3a662d9, 0xf2b5cc05, 0xb8b0ccfc, 0xb058bafb, 0x3aea3dec, 0x0d028684, 0x64af0fef, - 0x210f3925, 0xb67ec13a, 0x97166d14, 0xf7e1cdd0, 0x5adb60e7, 0xd5295ebc, 0x28833522, 0x60eda8da, - 0x7bc76811, 0xac9fe69d, 0x30ab93ec, 0x03696614, 0x15e3a5b9, 0xecc5dc91, 0x1d3b8e97, 0x7275e277, - 0x538e1f4e, 0x6cb167db, 0xa7a2f402, 0x2db35dfe, 0xa8bcc22d, 0xd8c58a6a, 0x6a529b0b, 0x0fd43963, - 0xafc17a97, 0x943c3c74, 0x95138769, 0x6f4e0772, 0xb143b688, 0x3b18e752, 0x69d2e4ae, 0x8107c9ff, - 0xcdbc62e2, 0x5781414f, 0x8b87437e, 0xa70e1101, 0x91dabc65, 0x4e232cd0, 0x229749b5, 0xd7386806, - 0xb3c3f24b, 0x60dc5207, 0x0bdb9c30, 0x1a70e7e9, 0xf37c71d5, 0x44b89b08, 0xb4d2f976, 0xb40e27bc, - 0xffdf8a80, 0x9c411a2a, 0xd0f7b37d, 0xef53cec4, 0xeca4d58a, 0x0b923200, 0xcf22e064, 0x8ebfa303, - 0xf7cf814c, 0x32ae2a2b, 0xb5e13dae, 0xc998f9ff, 0x349947b0, 0x29cf72ce, 0x17e38f85, 0xf3b26129, - 0xd45d6d81, 0x09b3ce98, 0x860536b8, 0xe5792e1b, 0x12ad6419, 0xf5f71c69, 0xcbc8b7c2, 0x8f651659, - 0xa0cc74f3, 0xd78cb99e, 0x51c08d83, 0x29f55449, 0x002ed713, 0x38a824f3, 0x57161df6, 0x7452e319, - 0x25890e2e, 0xc7442433, 0x4a5f6355, 0x6a83e1e0, 0x823cedb6, 0xf1d444eb, 0x88381097, 0x5de3743e, - 0x46ca4f9a, 0xd8370487, 0xedec154a, 0x433f1afb, 0xf5fad54f, 0x98db2fb4, 0xe448e96d, 0xf650e4c8, - - 0x4bb5af29, 0x9d855e89, 0xc54cd95b, 0x46d95ca5, 0xef73fbf0, 0xf943f672, 0x86ba527f, 0x9d8d1908, - 0xf3310c92, 0x05340e15, 0x07cffad9, 0x21e2547e, 0x8c17eff0, 0xd32be060, 0x8aba3ffb, 0x94d40125, - 0xc5a87748, 0x824c2009, 0x73c0e762, 0xcdfec2af, 0x0e6c51b3, 0xa86f875e, 0xbc6172c7, 0xf7f395f1, - 0x3f7579b3, 0x7aa114ed, 0x165b1015, 0xd531161a, 0xe36ef5bb, 0xdc153e5f, 0x1d0cb81b, 0xceffc147, - 0x6079e4ce, 0xc3142d8f, 0xa617a083, 0xb54fed6f, 0xc3c7be2c, 0x02614abf, 0x6fb5ce56, 0xd21e796c, - 0x2d0985de, 0xe9f84163, 0xc1a71e3c, 0x2887d96f, 0x57c4c925, 0x05efe294, 0x88157153, 0x9a30c4e8, - 0x8854a0a1, 0x02503f7d, 0x0cd6ef81, 0x1da4f25a, 0xe8fa3860, 0x32e39273, 0x4c8652d6, 0x9ab3a42f, - 0x9ead7f70, 0x836d8003, 0x6cbe7935, 0x721502dd, 0x5a48755c, 0x07497cae, 0xde462f4d, 0x92f57ea7, - 0x1fe26ce0, 0x27c82282, 0xd6ec2f2b, 0x80c6e402, 0xce86fdfc, 0x52649d6c, 0xc798f047, 0x45bae606, - 0x891aec49, 0x66c97340, 0x9ca45e1c, 0x4286619c, 0xf5f9cc3b, 0x4e823ad3, 0xc0d5d42a, 0xaee19096, - 0x3d469303, 0xfe4cb380, 0xc9cd808c, 0x37a97df6, 0x308f751f, 0x276df0b4, 0xe5fbb9c7, 0x97ca2070, - 0x88412761, 0x2ce5d3d5, 0xd7b43abe, 0xa30519ad, 0x26414ff3, 0xc5bde908, 0x275ead3a, 0x26ceb003, - 0xbf1bd691, 0x037464c0, 0xe24124c0, 0x81d4cc5f, 0x484525e4, 0x1c3a4524, 0x9e7e4f04, 0xe1279bff, - 0x6dd1943a, 0x403dae08, 0x82846526, 0xd5683858, 0x29322d0d, 0xa949bea2, 0x74096ae7, 0x85a13f85, - 0x68235b9d, 0x8ef4bce6, 0x142a6e85, 0xdad1b22a, 0xb7546681, 0x959e234e, 0xfd8650d8, 0x3e730fa8, - 0x56f55a71, 0xd20adf03, 0x7cdc78a2, 0x19047c79, 0x253b1d7a, 0x4389a84a, 0x0aeb8165, 0x9c15db3b, - 0xaafef5a7, 0xbe8b06b2, 0xb5fe87c0, 0xe2a4ef71, 0xd9d711f9, 0xecfcf20b, 0x80fac4c2, 0xbbb8abc4, - 0x239e3b0a, 0x858129a6, 0xd97cd348, 0x8a30738a, 0xc5b71937, 0xd649a428, 0x18c1ef9a, 0x75c08a36, - 0xc921f94e, 0xdf9afa29, 0x040f7074, 0x72f5972f, 0x84ef01da, 0x2cb7b77f, 0x867027d7, 0x9ce0199d, - 0x71865c4c, 0x7a36af93, 0x6c48ddd8, 0x19b48fd0, 0x75f4e9e2, 0x0084cfe5, 0x63bfd4d8, 0x9783cdee, - 0x64f2632c, 0xf1b20eaf, 0xcc8bfa2d, 0x39ddf25a, 0x740e0066, 0x9ddb477f, 0x12b2cfb6, 0xd067fce5, - 0x1a4b6a53, 0x001cdb95, 0x12c06908, 0x531ac6bf, 0x513c1764, 0xf7476978, 0x1be79937, 0x8a8dfaa3, - 0x70a1660e, 0xfb737b1a, 0x3f28ee63, 0xc1a51375, 0x84bd6dd6, 0xe4a51d21, 0xeafed133, 0x22ae0582, - 0x4d678f26, 0xf854b522, 0x31907d62, 0x4b55dd99, 0x04d3658a, 0x19c1e69c, 0xc6112fdd, 0xc66699fd, - 0xa0eabe6b, 0x3724d4dc, 0x0d28fe52, 0x46819e2e, 0x96f703ac, 0x21182ca3, 0x2e7b022f, 0x31860f13, - 0x1956b1e5, 0xe1322228, 0x08063a85, 0x1d964589, 0x94d90481, 0x53c078f3, 0x5afb43ae, 0x1e3437f7, - 0x877eb7b4, 0x5d67133c, 0xa385cb2c, 0xb82f2703, 0xef05ee06, 0x931dd7e2, 0x10d210aa, 0xe21339cc, - 0x479c3a22, 0x613b67b2, 0x33c5321c, 0xa5f48ac4, 0xba5590c8, 0xeb244925, 0xd0ef3cc9, 0xd8c423fb, - 0x15cfcc5c, 0x1feb2e4f, 0x36ec0ea3, 0xdbef7d9f, 0xd5ec6bf4, 0x3d3dff8a, 0x1e04a7f7, 0x8766bb54, - 0x9a1d7745, 0xc79a1749, 0xb8d2486d, 0x582e3014, 0xa82427f5, 0x65dfa427, 0xbc5654c1, 0xbd086f26, - 0x0451516d, 0xff4cfc35, 0x81f2864d, 0x31860f05, 0xd0638e1a, 0xb059261d, 0x3d1e9150, 0x21e2a51c, - 0x82d53d12, 0x1010b275, 0x786b2908, 0x4d3cfbda, 0x94a302f4, 0x95c85eaa, 0xd7e1c7be, 0x82ac484f -]; - -test( "prng", function () { - asmCrypto.ISAAC.seed(0); - ok( "reset done" ); - - asmCrypto.ISAAC.prng(); - for ( var i = 0; i < isaac_vector.length; i++ ) { - equal( asmCrypto.ISAAC.rand(), isaac_vector[i], "isaac_vector["+i+"] is correct" ); - } -}); -*/ diff --git a/test/rsa.js b/test/rsa.js index 50e84b9..574a270 100644 --- a/test/rsa.js +++ b/test/rsa.js @@ -1,112 +1,107 @@ -module("RSA"); - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.RSA !== 'undefined' ) -{ - var pubkey = [ - asmCrypto.hex_to_bytes('c13f894819c136381a94c193e619851ddfcde5eca770003ec354f3142e0f61f0676d7d4215cc7a13b06e0744aa8316c9c3766cbefa30b2346fba8f1236d7e6548cf87d9578e6904fc4291e096a2737fcd96624f72e762793505f9dfc5fa17b44611add54f5c00bf54373d720cb6f4e5cabae36c4442b39dbf49158414547f453'), - asmCrypto.hex_to_bytes('10001') - ]; - - var privkey = [ - asmCrypto.hex_to_bytes('c13f894819c136381a94c193e619851ddfcde5eca770003ec354f3142e0f61f0676d7d4215cc7a13b06e0744aa8316c9c3766cbefa30b2346fba8f1236d7e6548cf87d9578e6904fc4291e096a2737fcd96624f72e762793505f9dfc5fa17b44611add54f5c00bf54373d720cb6f4e5cabae36c4442b39dbf49158414547f453'), - asmCrypto.hex_to_bytes('10001'), - asmCrypto.hex_to_bytes('75497aa8a7f8fc4f50d2b82a6b9d518db027e7449adaff4b18829685c8eecd227ba3984263b896df1c55ab53a1a9ae4b06b6f9896f8fde98b4b725de882ac13fc11b614cb2cc81bcc69b9ad167dda093c5c6637754acd0ec9e9845b1b2244d597c9f63d7ea076bda19feadcdb3bd1ba9018915fec981657fb7a4301cb87a3e1'), - asmCrypto.hex_to_bytes('ef2f8d91d7cd96710d6b3b5ea1b6762b4214efe329e7d0609ab8419744ef8620391e423d5890c864aebb36c0daf5035d27f3427e6a84fde36466a14b56ad1cfb'), - asmCrypto.hex_to_bytes('ced5477e0acb9c836c3c54e33268e064ce8cdfd40452c8b87ab838b36b498ae22fdbdb331f59f61dd3ca1512143e77a68f8f2400dbe9e576a000084e6fcbb689'), - asmCrypto.hex_to_bytes('227882f9a2d5513a27c9ed7b7ce8d3ecf61018666fb2a5f85633f9d7f82a60f521e6377ba9d8ebd87eca2260f6ed5ab7c13b30b91156eb542b331349cd4b13a3'), - asmCrypto.hex_to_bytes('4dea2a3460fcb2c90f4ceaed6b5ff6a802e72eaa3fb6afc64ef476e79fd2e46eb078b1ea60351371c906a7495836effbdeb89d67757076f068f59a2b7211db81'), - asmCrypto.hex_to_bytes('261a93613a93e438fa62858758d1db3b3db8366319517c039acfcc0ce04cd0d7349d7e8d8cb0e8a05ac966d04c18c81c49025de2b50bb87f78facccd19cd8602') - ]; - - test( "asmCrypto.RSA", function () { - equal( typeof asmCrypto.RSA, 'object', "RSA exported" ); - }); - - test( "asmCrypto.RSA.generateKey", function () { - var key = asmCrypto.RSA.generateKey( 1024, 3 ); - ok( key, "generateKey" ); - - var m = new asmCrypto.Modulus( new asmCrypto.BigNumber(key[0]) ), - e = new asmCrypto.BigNumber( key[1] ), - d = new asmCrypto.BigNumber( key[2] ), - p = new asmCrypto.BigNumber( key[3] ), - q = new asmCrypto.BigNumber( key[4] ), - dp = new asmCrypto.BigNumber( key[5] ), - dq = new asmCrypto.BigNumber( key[6] ), - qi = new asmCrypto.BigNumber( key[7] ); - - equal( p.multiply(q).toString(16), m.toString(16), "m == p*q" ); - equal( e.multiply(d).divide(p.subtract(asmCrypto.BigNumber.fromNumber(1)).multiply(q.subtract(asmCrypto.BigNumber.fromNumber(1)))).remainder.toString(16), '1', "e*d == 1 mod (p-1)(q-1)" ); - equal( d.divide(p.subtract(asmCrypto.BigNumber.fromNumber(1))).remainder.toString(16), dp.toString(16), "dp == d mod (p-1)" ); - equal( d.divide(q.subtract(asmCrypto.BigNumber.fromNumber(1))).remainder.toString(16), dq.toString(16), "dq == d mod (q-1)" ); - equal( qi.multiply(q).divide(p).remainder.toString(16), '1', "qi*q == 1 mod p" ); - equal( m.slice(m.bitLength-1).valueOf(), 1, "m highest bit is 1" ); - }); -} -else -{ - skip( "asmCrypto.RSA" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.RSA_RAW !== 'undefined' ) -{ - test( "asmCrypto.RSA_RAW.encrypt", function () { - var text = String.fromCharCode(1); - - var ciphertext = asmCrypto.RSA_RAW.encrypt( text, pubkey ); - equal( asmCrypto.bytes_to_hex(ciphertext).replace(/^0+/,''), '1', "ident encrypt" ); - - var result = asmCrypto.RSA_RAW.decrypt( ciphertext, privkey ); - equal( asmCrypto.bytes_to_hex(result).replace(/^0+/,''), '1', "ident decrypt" ); - }); -} -else -{ - skip( "asmCrypto.RSA_RAW" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.RSA_OAEP_SHA256 !== 'undefined' ) -{ - test( "asmCrypto.RSA_OAEP_SHA256 encrypt/decrypt", function () { - var cleartext = asmCrypto.string_to_bytes('HelloWorld!'); - - var ciphertext = asmCrypto.RSA_OAEP_SHA256.encrypt( cleartext, pubkey, 'test' ); - ok( ciphertext, "encrypt" ); - - var result = asmCrypto.RSA_OAEP_SHA256.decrypt( ciphertext, privkey, 'test' ); - equal( asmCrypto.bytes_to_string(result), 'HelloWorld!', "decrypt" ); - }); -} -else -{ - skip( "asmCrypto.RSA_OAEP_SHA256" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.RSA_PSS_SHA256 !== 'undefined' ) -{ - test( "asmCrypto.RSA_PSS_SHA256 sign/verify", function () { - var text = 'HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!'; - - var signature = asmCrypto.RSA_PSS_SHA256.sign( text, privkey ); - ok( signature, "sign" ); - - var result = asmCrypto.RSA_PSS_SHA256.verify( signature, text, pubkey ); - ok( result, "verify" ); - }); - - test( "asmCrypto.RSA_PSS_SHA256 verify OpenSSL-signed-data", function () { - var key = [ - asmCrypto.hex_to_bytes('f30be5ce8941c8e6e764c78d12f3ce6e02a0dea03577bc0c16029de258321b74ceb43ea94f768aec900011c78eb247ab0e94b4477ea8f086ba7b5ce4b03c0ad7e0bf2f54ed509a536a0f179e27db539f729b38a279873f7b3a360690c8390e289dedca6da1ba232d8edc3c1eb229e1072716ddf3ef88caf4a824c152d6ad38f1'), - asmCrypto.hex_to_bytes('10001'), -/* +import * as asmCrypto from '../asmcrypto.all.es8'; +import chai from 'chai'; +const expect = chai.expect; + +const pubKey = [ + asmCrypto.hex_to_bytes( + 'c13f894819c136381a94c193e619851ddfcde5eca770003ec354f3142e0f61f0676d7d4215cc7a13b06e0744aa8316c9c3766cbefa30b2346fba8f1236d7e6548cf87d9578e6904fc4291e096a2737fcd96624f72e762793505f9dfc5fa17b44611add54f5c00bf54373d720cb6f4e5cabae36c4442b39dbf49158414547f453', + ), + asmCrypto.hex_to_bytes('10001'), +]; + +const privkey = [ + asmCrypto.hex_to_bytes( + 'c13f894819c136381a94c193e619851ddfcde5eca770003ec354f3142e0f61f0676d7d4215cc7a13b06e0744aa8316c9c3766cbefa30b2346fba8f1236d7e6548cf87d9578e6904fc4291e096a2737fcd96624f72e762793505f9dfc5fa17b44611add54f5c00bf54373d720cb6f4e5cabae36c4442b39dbf49158414547f453', + ), + asmCrypto.hex_to_bytes('10001'), + asmCrypto.hex_to_bytes( + '75497aa8a7f8fc4f50d2b82a6b9d518db027e7449adaff4b18829685c8eecd227ba3984263b896df1c55ab53a1a9ae4b06b6f9896f8fde98b4b725de882ac13fc11b614cb2cc81bcc69b9ad167dda093c5c6637754acd0ec9e9845b1b2244d597c9f63d7ea076bda19feadcdb3bd1ba9018915fec981657fb7a4301cb87a3e1', + ), + asmCrypto.hex_to_bytes( + 'ef2f8d91d7cd96710d6b3b5ea1b6762b4214efe329e7d0609ab8419744ef8620391e423d5890c864aebb36c0daf5035d27f3427e6a84fde36466a14b56ad1cfb', + ), + asmCrypto.hex_to_bytes( + 'ced5477e0acb9c836c3c54e33268e064ce8cdfd40452c8b87ab838b36b498ae22fdbdb331f59f61dd3ca1512143e77a68f8f2400dbe9e576a000084e6fcbb689', + ), + asmCrypto.hex_to_bytes( + '227882f9a2d5513a27c9ed7b7ce8d3ecf61018666fb2a5f85633f9d7f82a60f521e6377ba9d8ebd87eca2260f6ed5ab7c13b30b91156eb542b331349cd4b13a3', + ), + asmCrypto.hex_to_bytes( + '4dea2a3460fcb2c90f4ceaed6b5ff6a802e72eaa3fb6afc64ef476e79fd2e46eb078b1ea60351371c906a7495836effbdeb89d67757076f068f59a2b7211db81', + ), + asmCrypto.hex_to_bytes( + '261a93613a93e438fa62858758d1db3b3db8366319517c039acfcc0ce04cd0d7349d7e8d8cb0e8a05ac966d04c18c81c49025de2b50bb87f78facccd19cd8602', + ), +]; + +describe('RSA', () => { + it('asmCrypto.RSA.privateKey', function() { + const m = new asmCrypto.Modulus(new asmCrypto.BigNumber(privkey[0])); + const e = new asmCrypto.BigNumber(privkey[1]); + const d = new asmCrypto.BigNumber(privkey[2]); + const p = new asmCrypto.BigNumber(privkey[3]); + const q = new asmCrypto.BigNumber(privkey[4]); + const dp = new asmCrypto.BigNumber(privkey[5]); + const dq = new asmCrypto.BigNumber(privkey[6]); + const qi = new asmCrypto.BigNumber(privkey[7]); + + expect(p.multiply(q).toString(16), 'm == p*q').to.equal(m.toString(16)); + expect( + e + .multiply(d) + .divide(p.subtract(asmCrypto.BigNumber.fromNumber(1)).multiply(q.subtract(asmCrypto.BigNumber.fromNumber(1)))) + .remainder.toString(16), + 'e*d == 1 mod (p-1)(q-1)', + ).to.equal('1'); + expect( + d.divide(p.subtract(asmCrypto.BigNumber.fromNumber(1))).remainder.toString(16), + 'dp == d mod (p-1)', + ).to.equal(dp.toString(16)); + expect( + d.divide(q.subtract(asmCrypto.BigNumber.fromNumber(1))).remainder.toString(16), + 'dq == d mod (q-1)', + ).to.equal(dq.toString(16)); + expect( + qi + .multiply(q) + .divide(p) + .remainder.toString(16), + 'qi*q == 1 mod p', + ).to.equal('1'); + expect(m.slice(m.bitLength - 1).valueOf(), 'm highest bit is 1').to.equal(1); + }); +}); + +describe('RSA-OAEP', () => { + it('asmCrypto.RSA_OAEP_SHA256 encrypt/decrypt', function() { + const cleartext = asmCrypto.string_to_bytes('HelloWorld!'); + const rsaOaepEnc = new asmCrypto.RSA_OAEP(pubKey, new asmCrypto.Sha256(), asmCrypto.string_to_bytes('test')); + const rsaOaepDec = new asmCrypto.RSA_OAEP(privkey, new asmCrypto.Sha256(), asmCrypto.string_to_bytes('test')); + + const ciphertext = rsaOaepEnc.encrypt(cleartext); + + const result = rsaOaepDec.decrypt(ciphertext); + expect(asmCrypto.bytes_to_string(result), 'decrypt').to.equal('HelloWorld!'); + }); +}); + +describe('RSA-PSS-SHA256', () => { + it('asmCrypto.RSA_PSS_SHA256 sign/verify', function() { + const text = 'HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!HelloWorld!'; + const rsaPssSign = new asmCrypto.RSA_PSS(privkey, new asmCrypto.Sha256()); + const rsaPssVerify = new asmCrypto.RSA_PSS(pubKey, new asmCrypto.Sha256()); + + const signature = rsaPssSign.sign(asmCrypto.string_to_bytes(text)); + rsaPssVerify.verify(signature, asmCrypto.string_to_bytes(text)); + }); + + it('asmCrypto.RSA_PSS_SHA256 verify OpenSSL-signed-data', function() { + const key = [ + asmCrypto.hex_to_bytes( + 'f30be5ce8941c8e6e764c78d12f3ce6e02a0dea03577bc0c16029de258321b74ceb43ea94f768aec900011c78eb247ab0e94b4477ea8f086ba7b5ce4b03c0ad7e0bf2f54ed509a536a0f179e27db539f729b38a279873f7b3a360690c8390e289dedca6da1ba232d8edc3c1eb229e1072716ddf3ef88caf4a824c152d6ad38f1', + ), + asmCrypto.hex_to_bytes('10001'), + /* asmCrypto.hex_to_bytes('a2f4032c2ad2b4843bf851e2c0263eed7b4da875f9e3416d4904901ec5cb32a56a416711d5794143c278897326b5595fd2f2d8bc66ab96387ea75f6ce4cc1ce7ba0269a49ce03eb4aea16ca914938e88e5398b10b314276ba9f3f2e448a5f643515ee591cb4c4c5270edccacf7e5b88f86a0c08dc05311513a4ed01802de2511'), asmCrypto.hex_to_bytes('fc592285e370d57900bfd2f8c66b15274b3381ca7ec485091d5aa0092ca8f2b97f8796e608a2fc6aa1df3647b10198c49801e3201fefa72ef9d7ccafcdae5d37'), asmCrypto.hex_to_bytes('f6904d99d7cf9f1237c6798e5343fe730149be31e0363bf33039af84a09b5e9d0dd71239384b6cf6421e4ad41097b2cd09fd0114eb29a4339c433f37d7286f17'), @@ -114,19 +109,17 @@ if ( typeof asmCrypto.RSA_PSS_SHA256 !== 'undefined' ) asmCrypto.hex_to_bytes('9f036da89c10208cc53fd14142de0509f278b69abff8fa2cda9b3961159b5e2777b78edf2c3928aaa0f59c58abe2c9c3867f8ee508ccb04340b1f5e17377763d'), asmCrypto.hex_to_bytes('c07e9ca15c2cc38cc4faab0729403e02b33982b7d1219e15cd74614f3485437d2c800d66a0c368b3cf36513e4b1e05d31d7e0186f00cf036433e35f13b5cfda8') */ - ]; + ]; - var text = 'Hello There!'; + const text = 'Hello There!'; - var signature = asmCrypto.hex_to_bytes('A68BE713861409B4E536C12066B3D30650C7578F9B7AB61C1A302B42ECA14D58AE11899BC55FCB838F0AE06B99381DE26CE8D6318BD59BBFC4FFF56A995E9EFB0306FF105766F508297D1E74F22648B6BD66C18E06F4748BD258358ECB5BB722AC4AFFA146C04EE7BE84AD77ED2A84B5458D6CA4A7DA4D86DAB3F2B39FD647F4'); + const signature = asmCrypto.hex_to_bytes( + 'A68BE713861409B4E536C12066B3D30650C7578F9B7AB61C1A302B42ECA14D58AE11899BC55FCB838F0AE06B99381DE26CE8D6318BD59BBFC4FFF56A995E9EFB0306FF105766F508297D1E74F22648B6BD66C18E06F4748BD258358ECB5BB722AC4AFFA146C04EE7BE84AD77ED2A84B5458D6CA4A7DA4D86DAB3F2B39FD647F4', + ); - var saltlen = 32; + const saltlen = 32; - var result = asmCrypto.RSA_PSS_SHA256.verify( signature, text, key, saltlen ); - ok( result, "verify" ); - }); -} -else -{ - skip( "asmCrypto.RSA_PSS_SHA256" ); -} + const rsaPss = new asmCrypto.RSA_PSS(key, new asmCrypto.Sha256(), saltlen); + rsaPss.verify(signature, asmCrypto.string_to_bytes(text)); + }); +}); diff --git a/test/sha1.js b/test/sha1.js index edae9f7..757ff9c 100644 --- a/test/sha1.js +++ b/test/sha1.js @@ -1,98 +1,139 @@ -module("SHA1"); +import * as asmCrypto from '../asmcrypto.all.es8'; +import chai from 'chai'; +const expect = chai.expect; -/////////////////////////////////////////////////////////////////////////////// +describe('SHA1', () => { + const sha1_vectors = [ + ['a9993e364706816aba3e25717850c26c9cd0d89d', asmCrypto.string_to_bytes('abc')], + ['84983e441c3bd26ebaae4aa1f95129e5e54670f1', asmCrypto.string_to_bytes('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')], + [ + 'a49b2446a02c645bf419f995b67091253a04a259', + asmCrypto.string_to_bytes('abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), + ], + ['2fd4e1c67a2d28fced849ee1bb76e7391b93eb12', asmCrypto.string_to_bytes('The quick brown fox jumps over the lazy dog')], + ['de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3', asmCrypto.string_to_bytes('The quick brown fox jumps over the lazy cog')], + ]; -if ( typeof asmCrypto.SHA1 !== 'undefined' ) -{ - var sha1_vectors = [ - [ 'a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'], - [ '84983e441c3bd26ebaae4aa1f95129e5e54670f1', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'], - [ 'a49b2446a02c645bf419f995b67091253a04a259', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'], - [ '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12', 'The quick brown fox jumps over the lazy dog' ], - [ 'de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3', 'The quick brown fox jumps over the lazy cog' ] - ]; + it('asmCrypto.SHA1.hex', function() { + for (let i = 0; i < sha1_vectors.length; ++i) { + const sha1 = new asmCrypto.Sha1(); + expect(asmCrypto.bytes_to_hex(sha1.process(sha1_vectors[i][1]).finish().result), 'vector ' + i).to.equal( + sha1_vectors[i][0], + ); + } + }); +}); - test( "asmCrypto.SHA1.hex", function () { - for ( var i = 0; i < sha1_vectors.length; ++i ) { - equal( - asmCrypto.SHA1.hex( sha1_vectors[i][1] ), - sha1_vectors[i][0], - "vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.SHA1" ); -} +describe('HMAC-SHA1', () => { + const hmac_sha1_vectors = [ + [ + '5fd596ee78d5553c8ff4e72d266dfd192366da29', + asmCrypto.hex_to_bytes( + '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f', + ), + asmCrypto.hex_to_bytes('53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e'), + ], + ['fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', asmCrypto.string_to_bytes(''), asmCrypto.string_to_bytes('')], + [ + 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', + asmCrypto.string_to_bytes('key'), + asmCrypto.string_to_bytes('The quick brown fox jumps over the lazy dog'), + ], + [ + 'b617318655057264e28bc0b6fb378c8ef146be00', + asmCrypto.hex_to_bytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'), + asmCrypto.string_to_bytes('Hi There'), + ], + [ + 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79', + asmCrypto.string_to_bytes('Jefe'), + asmCrypto.string_to_bytes('what do ya want for nothing?'), + ], + ]; -/////////////////////////////////////////////////////////////////////////////// + it('asmCrypto.HMAC_SHA1.hex', function() { + for (let i = 0; i < hmac_sha1_vectors.length; ++i) { + const hmacSha1 = new asmCrypto.HmacSha1(hmac_sha1_vectors[i][1]); -if ( typeof asmCrypto.HMAC_SHA1 !== 'undefined' ) -{ - var hmac_sha1_vectors = [ - [ '5fd596ee78d5553c8ff4e72d266dfd192366da29', asmCrypto.hex_to_bytes('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f'), asmCrypto.hex_to_bytes('53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e') ], - [ 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', '', '' ], - [ 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', 'key', 'The quick brown fox jumps over the lazy dog' ], - [ 'b617318655057264e28bc0b6fb378c8ef146be00', asmCrypto.hex_to_bytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'), 'Hi There' ], - [ 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79', 'Jefe', 'what do ya want for nothing?'] - ]; + expect(asmCrypto.bytes_to_hex(hmacSha1.process(hmac_sha1_vectors[i][2]).finish().result), 'vector ' + i).to.equal( + hmac_sha1_vectors[i][0], + ); + } + }); +}); - test( "asmCrypto.HMAC_SHA1.hex", function () { - for ( var i = 0; i < hmac_sha1_vectors.length; ++i ) { - equal( - asmCrypto.HMAC_SHA1.hex( hmac_sha1_vectors[i][2], hmac_sha1_vectors[i][1] ), - hmac_sha1_vectors[i][0], - "vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.HMAC_SHA1" ); -} +describe('PBKDF2-HMAC-SHA1', function () { + this.timeout(30000); + const pbkdf2_hmac_sha1_vectors = [ + [ + '0c60c80f961f0e71f3a9b524af6012062fe037a6', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 1, + 20, + ], + [ + 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 2, + 20, + ], + [ + '4b007901b765489abead49d926f721d065a429c1', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 4096, + 20, + ], + [ + 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 16777216, + 20, + ], + [ + '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038', + asmCrypto.string_to_bytes('passwordPASSWORDpassword'), + asmCrypto.string_to_bytes('saltSALTsaltSALTsaltSALTsaltSALTsalt'), + 4096, + 25, + ], + [ + '56fa6aa75548099dcc37d7f03425e0c3', + asmCrypto.string_to_bytes('pass\0word'), + asmCrypto.string_to_bytes('sa\0lt'), + 4096, + 16, + ], + ]; -/////////////////////////////////////////////////////////////////////////////// + it('asmCrypto.PBKDF2_HMAC_SHA1.hex', function() { + for (let i = 0; i < pbkdf2_hmac_sha1_vectors.length; ++i) { + expect( + // got + asmCrypto.bytes_to_hex( + asmCrypto.Pbkdf2HmacSha1( + pbkdf2_hmac_sha1_vectors[i][1], // password + pbkdf2_hmac_sha1_vectors[i][2], // salt + pbkdf2_hmac_sha1_vectors[i][3], // count + pbkdf2_hmac_sha1_vectors[i][4], // dklen + ), + ), -if ( typeof asmCrypto.PBKDF2_HMAC_SHA1 !== 'undefined' ) -{ - var pbkdf2_hmac_sha1_vectors = [ - [ '0c60c80f961f0e71f3a9b524af6012062fe037a6', 'password', 'salt', 1, 20 ], - [ 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957', 'password', 'salt', 2, 20 ], - [ '4b007901b765489abead49d926f721d065a429c1', 'password', 'salt', 4096, 20 ], - //[ 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984', 'password', 'salt', 16777216, 20 ], - [ '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038', 'passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, 25 ], - [ '56fa6aa75548099dcc37d7f03425e0c3', "pass\0word", "sa\0lt", 4096, 16 ] - ]; - - test( "asmCrypto.PBKDF2_HMAC_SHA1.hex", function () { - for ( var i = 0; i < pbkdf2_hmac_sha1_vectors.length; ++i ) { - equal( - // got - asmCrypto.PBKDF2_HMAC_SHA1.hex( - pbkdf2_hmac_sha1_vectors[i][1], // password - pbkdf2_hmac_sha1_vectors[i][2], // salt - pbkdf2_hmac_sha1_vectors[i][3], // count - pbkdf2_hmac_sha1_vectors[i][4] // dklen - ), - - // expect - pbkdf2_hmac_sha1_vectors[i][0], - - // comment - "asmCrypto.PBKDF2_HMAC_SHA1.hex('" - +pbkdf2_hmac_sha1_vectors[i][1]+"', '" - +pbkdf2_hmac_sha1_vectors[i][2]+"', '" - +pbkdf2_hmac_sha1_vectors[i][3]+"', '" - +pbkdf2_hmac_sha1_vectors[i][4] - +"') is equal to '"+pbkdf2_hmac_sha1_vectors[i][0]+"'" - ); - } - }); -} -else -{ - skip( "asmCrypto.PBKDF2_HMAC_SHA1" ); -} + "asmCrypto.PBKDF2_HMAC_SHA1.hex('" + + pbkdf2_hmac_sha1_vectors[i][1] + + "', '" + + pbkdf2_hmac_sha1_vectors[i][2] + + "', '" + + pbkdf2_hmac_sha1_vectors[i][3] + + "', '" + + pbkdf2_hmac_sha1_vectors[i][4] + + "') is equal to '" + + pbkdf2_hmac_sha1_vectors[i][0] + + "'", + ).to.equal(pbkdf2_hmac_sha1_vectors[i][0]); + } + }); +}); diff --git a/test/sha256.js b/test/sha256.js index 917a666..be1fc80 100644 --- a/test/sha256.js +++ b/test/sha256.js @@ -1,99 +1,140 @@ -module("SHA256"); +import * as asmCrypto from '../asmcrypto.all.es8'; +import chai from 'chai'; +const expect = chai.expect; -/////////////////////////////////////////////////////////////////////////////// +describe('SHA256', () => { + const sha256_vectors = [ + ['e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', asmCrypto.string_to_bytes('')], + ['ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', asmCrypto.string_to_bytes('abc')], + ['f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650', asmCrypto.string_to_bytes('message digest')], + [ + 'f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d', + asmCrypto.string_to_bytes('secure hash algorithm'), + ], + [ + '6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630', + asmCrypto.string_to_bytes('SHA256 is considered to be safe'), + ], + [ + '248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1', + asmCrypto.string_to_bytes('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), + ], + [ + 'f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342', + asmCrypto.string_to_bytes('For this sample, this 63-byte string will be used as input data'), + ], + [ + 'ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8', + asmCrypto.string_to_bytes('This is exactly 64 bytes long, not counting the terminating byte'), + ], + ]; -if ( typeof asmCrypto.SHA256 !== 'undefined' ) -{ - var sha256_vectors = [ - [ 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', '' ], - [ 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', 'abc' ], - [ 'f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650', 'message digest' ], - [ 'f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d', 'secure hash algorithm' ], - [ '6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630', 'SHA256 is considered to be safe' ], - [ '248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq' ], - [ 'f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342', 'For this sample, this 63-byte string will be used as input data' ], - [ 'ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8', 'This is exactly 64 bytes long, not counting the terminating byte' ] - ]; + it('asmCrypto.SHA256.hex', function() { + for (let i = 0; i < sha256_vectors.length; ++i) { + const sha256 = new asmCrypto.Sha256(); + expect(asmCrypto.bytes_to_hex(sha256.process(sha256_vectors[i][1]).finish().result), 'vector ' + i).to.equal( + sha256_vectors[i][0], + ); + } + }); +}); +describe('HMAC-SHA256', () => { + const hmac_sha256_vectors = [ + [ + 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad', + asmCrypto.string_to_bytes(''), + asmCrypto.string_to_bytes(''), + ], + [ + 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8', + asmCrypto.string_to_bytes('key'), + asmCrypto.string_to_bytes('The quick brown fox jumps over the lazy dog'), + ], + [ + 'b54d57e9b21940b6496b58d5ac120eda9f1637788b5df058928637f2eca40cd9', + asmCrypto.string_to_bytes('MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword'), + asmCrypto.string_to_bytes('Lorem ipsum dolor sit amet, consectetur adipiscing elit.'), + ], + ]; - test( "asmCrypto.SHA256.hex", function () { - for ( var i = 0; i < sha256_vectors.length; ++i ) { - equal( - asmCrypto.SHA256.hex( sha256_vectors[i][1] ), - sha256_vectors[i][0], - "vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.SHA256" ); -} + it('asmCrypto.HMAC_SHA256.hex', function() { + for (let i = 0; i < hmac_sha256_vectors.length; ++i) { + const hmacSha256 = new asmCrypto.HmacSha256(hmac_sha256_vectors[i][1]); + expect( + asmCrypto.bytes_to_hex(hmacSha256.process(hmac_sha256_vectors[i][2]).finish().result), + 'vector ' + i, + ).to.equal(hmac_sha256_vectors[i][0]); + } + }); +}); +describe('PBKDF2-HMAC-SHA256', () => { + const pbkdf2_hmac_sha256_vectors = [ + [ + '120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 1, + 32, + ], + [ + 'ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 2, + 32, + ], + [ + 'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 4096, + 32, + ], + [ + '348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9', + asmCrypto.string_to_bytes('passwordPASSWORDpassword'), + asmCrypto.string_to_bytes('saltSALTsaltSALTsaltSALTsaltSALTsalt'), + 4096, + 40, + ], + [ + '89b69d0516f829893c696226650a8687', + asmCrypto.string_to_bytes('pass\0word'), + asmCrypto.string_to_bytes('sa\0lt'), + 4096, + 16, + ], + [ + 'cdc8b1780ca68aba97f1f729c9d281719702eb4b308d7d87409817e60188be0d', + asmCrypto.string_to_bytes('MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword'), + asmCrypto.string_to_bytes('MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword'), + 4096, + 32, + ], + ]; -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.HMAC_SHA256 !== 'undefined' ) -{ - var hmac_sha256_vectors = [ - [ 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad', '', '' ], - [ 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8', 'key', 'The quick brown fox jumps over the lazy dog' ], - [ 'b54d57e9b21940b6496b58d5ac120eda9f1637788b5df058928637f2eca40cd9', 'MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' ] - ]; - - test( "asmCrypto.HMAC_SHA256.hex", function () { - for ( var i = 0; i < hmac_sha256_vectors.length; ++i ) { - equal( - asmCrypto.HMAC_SHA256.hex( hmac_sha256_vectors[i][2], hmac_sha256_vectors[i][1] ), - hmac_sha256_vectors[i][0], - "vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.HMAC_SHA256" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.PBKDF2_HMAC_SHA256 !== 'undefined' ) -{ - var pbkdf2_hmac_sha256_vectors = [ - [ '120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b', 'password', 'salt', 1, 32 ], - [ 'ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43', 'password', 'salt', 2, 32 ], - [ 'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a', 'password', 'salt', 4096, 32 ], - [ '348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9', 'passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, 40 ], - [ '89b69d0516f829893c696226650a8687', "pass\0word", "sa\0lt", 4096, 16 ], - [ 'cdc8b1780ca68aba97f1f729c9d281719702eb4b308d7d87409817e60188be0d', 'MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword', 'MyVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryVeeeeeeeeeeeeeryLoooooooooongPassword', 4096, 32 ] - ]; - - test( "asmCrypto.PBKDF2_HMAC_SHA256.hex", function () { - for ( var i = 0; i < pbkdf2_hmac_sha256_vectors.length; ++i ) { - equal( - // got - asmCrypto.PBKDF2_HMAC_SHA256.hex( - pbkdf2_hmac_sha256_vectors[i][1], // password - pbkdf2_hmac_sha256_vectors[i][2], // salt - pbkdf2_hmac_sha256_vectors[i][3], // count - pbkdf2_hmac_sha256_vectors[i][4] // dklen - ), - - // expect - pbkdf2_hmac_sha256_vectors[i][0], - - // comment - "asmCrypto.PBKDF2_HMAC_SHA256.hex('" - +pbkdf2_hmac_sha256_vectors[i][1]+"', '" - +pbkdf2_hmac_sha256_vectors[i][2]+"', '" - +pbkdf2_hmac_sha256_vectors[i][3]+"', '" - +pbkdf2_hmac_sha256_vectors[i][4] - +"') is equal to '"+pbkdf2_hmac_sha256_vectors[i][0]+"'" - ); - } - }); -} -else -{ - skip( "asmCrypto.PBKDF2_HMAC_SHA256" ); -} + it('asmCrypto.PBKDF2_HMAC_SHA256.hex', function() { + for (let i = 0; i < pbkdf2_hmac_sha256_vectors.length; ++i) { + expect( + // got + asmCrypto.bytes_to_hex(asmCrypto.Pbkdf2HmacSha256( + pbkdf2_hmac_sha256_vectors[i][1], // password + pbkdf2_hmac_sha256_vectors[i][2], // salt + pbkdf2_hmac_sha256_vectors[i][3], // count + pbkdf2_hmac_sha256_vectors[i][4], // dklen + )), + "asmCrypto.PBKDF2_HMAC_SHA256.hex('" + + pbkdf2_hmac_sha256_vectors[i][1] + + "', '" + + pbkdf2_hmac_sha256_vectors[i][2] + + "', '" + + pbkdf2_hmac_sha256_vectors[i][3] + + "', '" + + pbkdf2_hmac_sha256_vectors[i][4] + + "') is equal to '" + + pbkdf2_hmac_sha256_vectors[i][0] + + "'", + ).to.equal(pbkdf2_hmac_sha256_vectors[i][0]); + } + }); +}); diff --git a/test/sha512.js b/test/sha512.js index 973663d..c84ca69 100644 --- a/test/sha512.js +++ b/test/sha512.js @@ -1,95 +1,136 @@ -module("SHA512"); +import * as asmCrypto from '../asmcrypto.all.es8'; +import chai from 'chai'; +const expect = chai.expect; -/////////////////////////////////////////////////////////////////////////////// +describe('SHA512', () => { + const sha512_vectors = [ + [ + 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', + asmCrypto.string_to_bytes(''), + ], + [ + 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', + asmCrypto.string_to_bytes('abc'), + ], + [ + '8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', + asmCrypto.string_to_bytes( + 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu', + ), + ], + [ + '07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6', + asmCrypto.string_to_bytes('The quick brown fox jumps over the lazy dog'), + ], + [ + '91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed', + asmCrypto.string_to_bytes('The quick brown fox jumps over the lazy dog.'), + ], + ]; -if ( typeof asmCrypto.SHA512 !== 'undefined' ) -{ - var sha512_vectors = [ - [ 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', '' ], - [ 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'abc' ], - [ '8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu' ], - [ '07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6', 'The quick brown fox jumps over the lazy dog' ], - [ '91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed', 'The quick brown fox jumps over the lazy dog.' ] - ]; + it('asmCrypto.SHA512.hex', function() { + for (let i = 0; i < sha512_vectors.length; ++i) { + const sha512 = new asmCrypto.Sha512(); + expect(asmCrypto.bytes_to_hex(sha512.process(sha512_vectors[i][1]).finish().result), 'vector ' + i).to.equal( + sha512_vectors[i][0], + ); + } + }); +}); +describe('HMAC-SHA512', () => { + const hmac_sha512_vectors = [ + [ + '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854', + asmCrypto.hex_to_bytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'), + asmCrypto.string_to_bytes('Hi There'), + ], + [ + '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737', + asmCrypto.string_to_bytes('Jefe'), + asmCrypto.string_to_bytes('what do ya want for nothing?'), + ], + [ + '80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598', + asmCrypto.hex_to_bytes( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + ), + asmCrypto.string_to_bytes('Test Using Larger Than Block-Size Key - Hash Key First'), + ], + ]; - test( "asmCrypto.SHA512.hex", function () { - for ( var i = 0; i < sha512_vectors.length; ++i ) { - equal( - asmCrypto.SHA512.hex( sha512_vectors[i][1] ), - sha512_vectors[i][0], - "vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.SHA512" ); -} + it('asmCrypto.HMAC_SHA512.hex', function() { + for (let i = 0; i < hmac_sha512_vectors.length; ++i) { + const hmacSha512 = new asmCrypto.HmacSha512(hmac_sha512_vectors[i][1]); + expect( + asmCrypto.bytes_to_hex(hmacSha512.process(hmac_sha512_vectors[i][2]).finish().result), + 'vector ' + i, + ).to.equal(hmac_sha512_vectors[i][0]); + } + }); +}); +describe('PBKDF2-HMAC-SHA512', () => { + const pbkdf2_hmac_sha512_vectors = [ + [ + '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 1, + 64, + ], + [ + '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 1, + 64, + ], + [ + 'e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 2, + 64, + ], + [ + 'd197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5', + asmCrypto.string_to_bytes('password'), + asmCrypto.string_to_bytes('salt'), + 4096, + 64, + ], + [ + '8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8', + asmCrypto.string_to_bytes('passwordPASSWORDpassword'), + asmCrypto.string_to_bytes('saltSALTsaltSALTsaltSALTsaltSALTsalt'), + 4096, + 64, + ], + ]; -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.HMAC_SHA512 !== 'undefined' ) -{ - var hmac_sha512_vectors = [ - [ '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854', asmCrypto.hex_to_bytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'), 'Hi There'], - [ '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737', 'Jefe', 'what do ya want for nothing?' ], - [ '80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598', asmCrypto.hex_to_bytes('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), 'Test Using Larger Than Block-Size Key - Hash Key First'] - ]; - - test( "asmCrypto.HMAC_SHA512.hex", function () { - for ( var i = 0; i < hmac_sha512_vectors.length; ++i ) { - equal( - asmCrypto.HMAC_SHA512.hex( hmac_sha512_vectors[i][2], hmac_sha512_vectors[i][1] ), - hmac_sha512_vectors[i][0], - "vector " + i - ); - } - }); -} -else -{ - skip( "asmCrypto.HMAC_SHA512" ); -} - -/////////////////////////////////////////////////////////////////////////////// - -if ( typeof asmCrypto.PBKDF2_HMAC_SHA512 !== 'undefined' ) -{ - var pbkdf2_hmac_sha512_vectors = [ - [ '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce', 'password', 'salt', 1, 64 ], - [ '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce', asmCrypto.string_to_bytes('password'), asmCrypto.string_to_bytes('salt'), 1, 64 ], - [ 'e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e', 'password', 'salt', 2, 64 ], - [ 'd197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5', 'password', 'salt', 4096, 64 ], - [ '8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8', 'passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 4096, 64 ] - ]; - - test( "asmCrypto.PBKDF2_HMAC_SHA512.hex", function () { - for ( var i = 0; i < pbkdf2_hmac_sha512_vectors.length; ++i ) { - equal( - // got - asmCrypto.PBKDF2_HMAC_SHA512.hex( - pbkdf2_hmac_sha512_vectors[i][1], // password - pbkdf2_hmac_sha512_vectors[i][2], // salt - pbkdf2_hmac_sha512_vectors[i][3], // count - pbkdf2_hmac_sha512_vectors[i][4] // dklen - ), - - // expect - pbkdf2_hmac_sha512_vectors[i][0], - - // comment - "asmCrypto.PBKDF2_HMAC_SHA512.hex('" - +pbkdf2_hmac_sha512_vectors[i][1]+"', '" - +pbkdf2_hmac_sha512_vectors[i][2]+"', '" - +pbkdf2_hmac_sha512_vectors[i][3]+"', '" - +pbkdf2_hmac_sha512_vectors[i][4] - +"') is equal to '"+pbkdf2_hmac_sha512_vectors[i][0]+"'" - ); - } - }); -} -else -{ - skip( "asmCrypto.PBKDF2_HMAC_SHA512" ); -} + it('asmCrypto.PBKDF2_HMAC_SHA512.hex', function() { + for (let i = 0; i < pbkdf2_hmac_sha512_vectors.length; ++i) { + expect( + // got + asmCrypto.bytes_to_hex( + asmCrypto.Pbkdf2HmacSha512( + pbkdf2_hmac_sha512_vectors[i][1], // password + pbkdf2_hmac_sha512_vectors[i][2], // salt + pbkdf2_hmac_sha512_vectors[i][3], // count + pbkdf2_hmac_sha512_vectors[i][4], // dklen + ), + ), + "asmCrypto.PBKDF2_HMAC_SHA512.hex('" + + pbkdf2_hmac_sha512_vectors[i][1] + + "', '" + + pbkdf2_hmac_sha512_vectors[i][2] + + "', '" + + pbkdf2_hmac_sha512_vectors[i][3] + + "', '" + + pbkdf2_hmac_sha512_vectors[i][4] + + "') is expect to '" + + pbkdf2_hmac_sha512_vectors[i][0] + + "'", + ).to.equal(pbkdf2_hmac_sha512_vectors[i][0]); + } + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 953eb19..4b6424b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,23 @@ { "compilerOptions": { - "module": "es6", + "module": "ES6", "target": "es2017", - "noEmit": true, - "allowJs": true, - "checkJs": true, - "sourceMap": false + "lib": ["es5", "dom", "dom.iterable", "es6"], + "noEmit": false, + "strict": true, + "sourceMap": false, + "declaration": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist_es8" }, + "include": [ + "src/**/*.ts" + ], "exclude": [ "node_modules" ], - "include": [ - "src" + "files": [ + "src/entry-export_all.ts" ] } diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..d6b2aa2 --- /dev/null +++ b/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": ["tslint-plugin-prettier"], + "rules": { + "prettier": true + } +}