pax_global_header00006660000000000000000000000064133002240720014503gustar00rootroot0000000000000052 comment=a2d92b81a707201122df753fe514ea425eaa7f3d webcrypto-0.9.2/000077500000000000000000000000001330022407200135315ustar00rootroot00000000000000webcrypto-0.9.2/.editorconfig000066400000000000000000000004161330022407200162070ustar00rootroot00000000000000# top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file and trim whitespace [*] end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.{js,json,yml}] charset = utf-8 indent_style = space indent_size = 2 webcrypto-0.9.2/.gitignore000066400000000000000000000016171330022407200155260ustar00rootroot00000000000000# Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Typescript v1 declaration files typings/ # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # Jsdoc build output docs webcrypto-0.9.2/.travis.yml000066400000000000000000000002461330022407200156440ustar00rootroot00000000000000sudo: false language: node_js node_js: "8.6.0" before_install: npm i -g npm install: npm i script: npm run coverage # after_script: ./node_modules/.bin/codecov webcrypto-0.9.2/LICENSE000066400000000000000000000021171330022407200145370ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Anvil Research, Inc. http://anvil.io 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. webcrypto-0.9.2/README.md000066400000000000000000000146741330022407200150240ustar00rootroot00000000000000# W3C Web Cryptography API _(@trust/webcrypto)_ [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) [![Build Status](https://travis-ci.org/anvilresearch/webcrypto.svg?branch=master)](https://travis-ci.org/anvilresearch/webcrypto) > W3C Web Cryptography API for Node.js W3C's [Web Cryptography API][webcrypto] defines a standard interface for performing cryptographic operations in JavaScript, such as key generation, hashing, signing, and encryption. This package implements the API for Node.js, in order to support universal crypto-dependent code required by protocols such as [JOSE][jose] and [OpenID Connect][oidc]. [webcrypto]: https://www.w3.org/TR/WebCryptoAPI/ [jose]: https://datatracker.ietf.org/wg/jose/documents/ [oidc]: http://openid.net/connect/ ## Table of Contents * [Security](#security) * [Background](#background) * [Install](#install) * [Usage](#usage) * [Develop](#develop) * [Supported Algorithms](#supported-algorithms) * [API](#api) * [Contribute](#contribute) * [MIT License](#mit-license) ## Security TBD ## Background The purpose of this package is to enable development of universal JavaScript libraries that depend on the availability of cryptographic primitives in order to implement cryptographic protocols. The long term goal of the project is to encourage or provide a [native, if not core][wtf] Web Cryptography module. [wtf]: https://github.com/nodejs/node/issues/2833 ## Install `@trust/webcrypto` requires recent versions of [node][node] and [npm][npm] to run. For key generation operations, it also requires [OpenSSL][openssl] to be installed on the system. [node]: https://nodejs.org [npm]: https://www.npmjs.com/ [openssl]: https://www.openssl.org/ ```bash $ npm install @trust/webcrypto --save ``` ## Usage ```javascript const crypto = require('@trust/webcrypto') ``` ## Develop ### Install ```bash $ git clone git@github.com:anvilresearch/webcrypto.git $ cd webcrypto $ npm install ``` ### Test ```bash $ npm test ``` ## Supported Algorithms | Algorithm name | encrypt | decrypt | sign | verify | digest | generateKey | deriveKey | deriveBits | importKey | exportKey | wrapKey | unwrapKey | |------------------|---|---|---|---|---|---|---|---|---|---|---|---| |RSASSA-PKCS1-v1_5 | | | ✔ | ✔ | | ✔ | | | ✔ | ✔ | | | |RSA-PSS | | | ✔ | ✔ | | ✔ | | | ✔ | ✔ | | | |RSA-OAEP | ✔ | ✔ | | | | ✔ | | | ✔ | ✔ | ✔ | ✔ | |ECDSA | | | ⚐ | ⚐ | | ⚐ | | | ✔ | ✔ | | | |EDDSA | | | ⚐ | ⚐ | | ⚐ | | | ✔ | ✔ | | | |ECDH | | | | | | _ | _ | _ | _ | _ | | | |AES-CTR | ⚐ | ⚐ | | | | ✔ | | | ✔ | ✔ | ✔ | ✔ | |AES-CBC | ✔ | ✔ | | | | ✔ | | | ✔ | ✔ | ✔ | ✔ | |AES-GCM | ✔ | ✔ | | | | ✔ | | | ✔ | ✔ | ✔ | ✔ | |AES-KW | | | | | | ✔ | | | ✔ | ✔ | ✔ | ✔ | |HMAC | | | ✔ | ✔ | | ✔ | | | ✔ | ✔ | | | |SHA-1 | | | | | ✔ | | | | | | | | |SHA-256 | | | | | ✔ | | | | | | | | |SHA-384 | | | | | ✔ | | | | | | | | |SHA-512 | | | | | ✔ | | | | | | | | |HKDF | | | | | | | _ | _ | _ | | | | |PBKDF2 | | | | | | | _ | _ | _ | | | | Key: ` ✔ ` Implemented ` _ ` Currently not implemented ` ⚐ ` Partially implemented, only certain paramaters supported. ## Partial Support Only the following paramaters are supported for the corresponding algorithm. | Algorithm name | Supported paramater | | -------------- | ------------------- | | ECDSA | `K-256 (secp256k1)`, `P-256`, `P-384`, `P-512` | | EDDSA | `ed25519` | | AES-CTR | `sha-1` | ## API See [W3C Web Cryptography API][webcrypto] specification and diafygi's [webcrypto-examples][examples]. [examples]: https://github.com/diafygi/webcrypto-examples ## Contribute ### Issues * Please file [issues](https://github.com/anvilresearch/webcrypto/issues) :) * When writing a bug report, include relevant details such as platform, version, relevant data, and stack traces * Ensure to check for existing issues before opening new ones * Read the documentation before asking questions * It is strongly recommended to open an issue before hacking and submitting a PR * We reserve the right to close an issue for excessive bikeshedding ### Pull requests #### Policy * We're not presently accepting *unsolicited* pull requests * Create an issue to discuss proposed features before submitting a pull request * Create an issue to propose changes of code style or introduce new tooling * Ensure your work is harmonious with the overall direction of the project * Ensure your work does not duplicate existing effort * Keep the scope compact; avoid PRs with more than one feature or fix * Code review with maintainers is required before any merging of pull requests * New code must respect the style guide and overall architecture of the project * Be prepared to defend your work #### Style guide * ES6 * Standard JavaScript * jsdocs #### Code reviews * required before merging PRs * reviewers MUST run and test the code under review ### Collaborating #### Weekly project meeting * Thursdays from 1:00 PM to 2:00 Eastern US time at [TBD] * Join remotely with Google Hangouts #### Pair programming * Required for new contributors * Work directly with one or more members of the core development team ### Code of conduct * @trust/webcrypto follows the [Contributor Covenant](http://contributor-covenant.org/version/1/3/0/) Code of Conduct. ### Contributors * Christian Smith [@christiansmith](https://github.com/christiansmith) * Dmitri Zagidulin [@dmitrizagidulin](https://github.com/dmitrizagidulin) * Greg Linklater [@EternalDeiwos](https://github.com/EternalDeiwos) * JC Bailey [@thelunararmy](https://github.com/thelunararmy) * Ioan Budea [@johnny90](https://github.com/johnny90) * Abdulrahman Alotaibi [@adminq80](https://github.com/adminq80) * Linus Unnebäck [@LinusU](https://github.com/LinusU) * Len Boyette [@kevlened](https://github.com/kevlened) * Tom Bonner [@Glitch0011](https://github.com/Glitch0011) ## MIT License Copyright (c) 2016 Anvil Research, Inc. webcrypto-0.9.2/index.d.ts000066400000000000000000000000541330022407200154310ustar00rootroot00000000000000declare var crypto: Crypto export = crypto; webcrypto-0.9.2/jsdoc.json000066400000000000000000000002661330022407200155320ustar00rootroot00000000000000{ "source": { "include": [ "./src" ] }, "opts": { "destination": "./docs/build", "readme": "./README.md" }, "plugins": [ "plugins/markdown" ] } webcrypto-0.9.2/package-lock.json000066400000000000000000004366031330022407200167610ustar00rootroot00000000000000{ "name": "@trust/webcrypto", "version": "0.9.2", "lockfileVersion": 1, "requires": true, "dependencies": { "@trust/keyto": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/@trust/keyto/-/keyto-0.3.4.tgz", "integrity": "sha512-OAqKvuSEPIu2zCnIHzBthvGnV8nKmpv7cBlRMngLzJZzZI9CanyuSfnEI1xC4sH4TwqA0XJR7Mb0oX4bwymXIw==", "requires": { "asn1.js": "^4.9.1", "base64url": "^3.0.0", "elliptic": "^6.4.0" } }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.3.0" } }, "argv": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", "dev": true }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "integrity": "sha512-6i37w/+EhlWlGUJff3T/Q8u1RGmP5wgbiwYnOnbOqvtrPxT63/sYFyP9RcpxtxGymtfA075IvmOnL7ycNOWl3w==" }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "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 }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, "aws4": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", "dev": true }, "babylon": { "version": "7.0.0-beta.19", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", "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 }, "base64url": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.0.tgz", "integrity": "sha512-LIVmqIrIWuiqTvn4RzcrwCOuHo2DD6tKmKBPXXlr4p4n4l6BZBkwFTIa3zu1XkX5MbZgro4a6BvPi+n2Mns5Gg==" }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, "optional": true, "requires": { "tweetnacl": "^0.14.3" } }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", "dev": true }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "dev": true, "requires": { "hoek": "4.x.x" } }, "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" } }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "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 }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, "catharsis": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", "integrity": "sha512-2qrVMmSPlNNmcUytNiGJaiA218fj7wDAijSSWaqrP2Cyy2pzAxXAymAXl4J5TWOSGlHpiqjRZKLVhsTB1e2l6A==", "dev": true, "requires": { "underscore-contrib": "~0.3.0" } }, "chai": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { "assertion-error": "^1.0.1", "deep-eql": "^0.1.3", "type-detect": "^1.0.0" } }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, "codecov": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.0.2.tgz", "integrity": "sha512-9ljtIROIjPIUmMRqO+XuDITDoV8xRrZmA0jcEq6p2hg2+wY9wGmLfreAZGIL72IzUfdEDZaU8+Vjidg1fBQ8GQ==", "dev": true, "requires": { "argv": "0.0.2", "request": "^2.81.0", "urlgrey": "0.4.4" } }, "combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "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 }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "dev": true, "requires": { "boom": "5.x.x" }, "dependencies": { "boom": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", "dev": true, "requires": { "hoek": "4.x.x" } } } }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "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": "0.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", "integrity": "sha512-6sEotTRGBFiNcqVoeHwnfopbSpi5NbH1VWJmYCVkmxMmaVTT0bUTrNaGyBwhgP4MZL012W/mkzIn3Da+iDYweg==", "dev": true, "requires": { "type-detect": "0.1.1" }, "dependencies": { "type-detect": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", "dev": true } } }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "dev": true, "optional": true, "requires": { "jsbn": "~0.1.0" } }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.0" } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, "form-data": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", "mime-types": "^2.1.12" } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "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 }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", "dev": true }, "har-validator": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { "ajv": "^5.1.0", "har-schema": "^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 }, "hash.js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.0" } }, "hawk": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "dev": true, "requires": { "boom": "4.x.x", "cryptiles": "3.x.x", "hoek": "4.x.x", "sntp": "2.x.x" } }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", "dev": true }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "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": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, "js2xmlparser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", "integrity": "sha512-CSOkdn0/GhRFwxnipmhXfqJ+FG6+wkWBi46kKSsPx6+j65176ZiQcrCYpg6K8x3iLbO4k3zScBnZ7I/L80dAtw==", "dev": true, "requires": { "xmlcreate": "^1.0.1" } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true, "optional": true }, "jsdoc": { "version": "3.5.5", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", "dev": true, "requires": { "babylon": "7.0.0-beta.19", "bluebird": "~3.5.0", "catharsis": "~0.8.9", "escape-string-regexp": "~1.0.5", "js2xmlparser": "~3.0.0", "klaw": "~2.0.0", "marked": "~0.3.6", "mkdirp": "~0.5.1", "requizzle": "~0.2.1", "strip-json-comments": "~2.0.1", "taffydb": "2.6.2", "underscore": "~1.8.3" } }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" } }, "klaw": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", "integrity": "sha512-Hx5PvgJKTWpMkNJCYrBUNBLlxYIkxN4FVU/BnZP4CFh5BpiHOgujAPx7iFVz/phD0bP8rsqD48gtqcvNlUt0lQ==", "dev": true, "requires": { "graceful-fs": "^4.1.9" } }, "marked": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "dev": true }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { "mime-db": "~1.33.0" } }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "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": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", "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 }, "node-rsa": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-0.4.2.tgz", "integrity": "sha1-1jkXKewWqDDtWjgEKzFX0tXXJTA=", "requires": { "asn1": "0.2.3" } }, "nyc": { "version": "11.8.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.8.0.tgz", "integrity": "sha512-PUFq1PSsx5OinSk5g5aaZygcDdI3QQT5XUlbR9QRMihtMS6w0Gm8xj4BxmKeeAlpQXC5M2DIhH16Y+KejceivQ==", "dev": true, "requires": { "archy": "^1.0.0", "arrify": "^1.0.1", "caching-transform": "^1.0.0", "convert-source-map": "^1.5.1", "debug-log": "^1.0.1", "default-require-extensions": "^1.0.0", "find-cache-dir": "^0.1.1", "find-up": "^2.1.0", "foreground-child": "^1.5.3", "glob": "^7.0.6", "istanbul-lib-coverage": "^1.1.2", "istanbul-lib-hook": "^1.1.0", "istanbul-lib-instrument": "^1.10.0", "istanbul-lib-report": "^1.1.3", "istanbul-lib-source-maps": "^1.2.3", "istanbul-reports": "^1.4.0", "md5-hex": "^1.2.0", "merge-source-map": "^1.1.0", "micromatch": "^3.1.10", "mkdirp": "^0.5.0", "resolve-from": "^2.0.0", "rimraf": "^2.6.2", "signal-exit": "^3.0.1", "spawn-wrap": "^1.4.2", "test-exclude": "^4.2.0", "yargs": "11.1.0", "yargs-parser": "^8.0.0" }, "dependencies": { "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" } }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "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": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "append-transform": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { "default-require-extensions": "^1.0.0" } }, "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", "dev": true }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, "atob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", "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" } }, "babel-generator": { "version": "6.26.1", "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "dev": true, "requires": { "babel-messages": "^6.23.0", "babel-runtime": "^6.26.0", "babel-types": "^6.26.0", "detect-indent": "^4.0.0", "jsesc": "^1.3.0", "lodash": "^4.17.4", "source-map": "^0.5.7", "trim-right": "^1.0.1" } }, "babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { "babel-runtime": "^6.22.0" } }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" } }, "babel-template": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { "babel-runtime": "^6.26.0", "babel-traverse": "^6.26.0", "babel-types": "^6.26.0", "babylon": "^6.18.0", "lodash": "^4.17.4" } }, "babel-traverse": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { "babel-code-frame": "^6.26.0", "babel-messages": "^6.23.0", "babel-runtime": "^6.26.0", "babel-types": "^6.26.0", "babylon": "^6.18.0", "debug": "^2.6.8", "globals": "^9.18.0", "invariant": "^2.2.2", "lodash": "^4.17.4" } }, "babel-types": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { "babel-runtime": "^6.26.0", "esutils": "^2.0.2", "lodash": "^4.17.4", "to-fast-properties": "^1.0.3" } }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "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 }, "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", "component-emitter": "^1.2.1", "define-property": "^1.0.0", "isobject": "^3.0.1", "mixin-deep": "^1.2.0", "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "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" } }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "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 }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", "get-value": "^2.0.6", "has-value": "^1.0.0", "isobject": "^3.0.1", "set-value": "^2.0.0", "to-object-path": "^0.3.0", "union-value": "^1.0.0", "unset-value": "^1.0.0" }, "dependencies": { "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true } } }, "caching-transform": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { "md5-hex": "^1.2.0", "mkdirp": "^0.5.1", "write-file-atomic": "^1.1.4" } }, "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true, "optional": true }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "optional": true, "requires": { "align-text": "^0.1.3", "lazy-cache": "^1.0.3" } }, "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" } }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", "isobject": "^3.0.0", "static-extend": "^0.1.1" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true } } }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "optional": true, "requires": { "center-align": "^0.1.1", "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "dev": true, "optional": true } } }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" } }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "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 }, "convert-source-map": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", "dev": true }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, "core-js": { "version": "2.5.6", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==", "dev": true }, "cross-spawn": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { "lru-cache": "^4.0.1", "which": "^1.2.9" } }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "debug-log": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, "default-require-extensions": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { "strip-bom": "^2.0.0" } }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, "detect-indent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { "repeating": "^2.0.0" } }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "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 }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "execa": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" }, "dependencies": { "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", "which": "^1.2.9" } } } }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "posix-character-classes": "^0.1.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" } } } }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", "expand-brackets": "^2.1.4", "extend-shallow": "^2.0.1", "fragment-cache": "^0.2.1", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "find-cache-dir": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", "dev": true, "requires": { "commondir": "^1.0.1", "mkdirp": "^0.5.1", "pkg-dir": "^1.0.0" } }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { "locate-path": "^2.0.0" } }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { "cross-spawn": "^4", "signal-exit": "^3.0.0" } }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { "map-cache": "^0.2.2" } }, "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-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "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" } }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "handlebars": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { "async": "^1.4.0", "optimist": "^0.6.1", "source-map": "^0.4.4", "uglify-js": "^2.6" }, "dependencies": { "source-map": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { "amdefine": ">=0.0.4" } } } }, "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": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", "isobject": "^3.0.0" }, "dependencies": { "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true } } }, "has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" }, "dependencies": { "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "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 }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { "loose-envify": "^1.0.0" } }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { "kind-of": "^3.0.2" } }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { "builtin-modules": "^1.0.0" } }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { "kind-of": "^3.0.2" } }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true }, "is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "^3.0.2" } }, "is-odd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", "dev": true, "requires": { "is-number": "^4.0.0" }, "dependencies": { "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" }, "dependencies": { "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true } } }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "istanbul-lib-coverage": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", "dev": true }, "istanbul-lib-hook": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", "dev": true, "requires": { "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", "dev": true, "requires": { "babel-generator": "^6.18.0", "babel-template": "^6.16.0", "babel-traverse": "^6.18.0", "babel-types": "^6.18.0", "babylon": "^6.18.0", "istanbul-lib-coverage": "^1.2.0", "semver": "^5.3.0" } }, "istanbul-lib-report": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.3.tgz", "integrity": "sha512-D4jVbMDtT2dPmloPJS/rmeP626N5Pr3Rp+SovrPn1+zPChGHcggd/0sL29jnbm4oK9W0wHjCRsdch9oLd7cm6g==", "dev": true, "requires": { "istanbul-lib-coverage": "^1.1.2", "mkdirp": "^0.5.1", "path-parse": "^1.0.5", "supports-color": "^3.1.2" }, "dependencies": { "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { "has-flag": "^1.0.0" } } } }, "istanbul-lib-source-maps": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz", "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==", "dev": true, "requires": { "debug": "^3.1.0", "istanbul-lib-coverage": "^1.1.2", "mkdirp": "^0.5.1", "rimraf": "^2.6.1", "source-map": "^0.5.3" }, "dependencies": { "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" } } } }, "istanbul-reports": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.4.0.tgz", "integrity": "sha512-OPzVo1fPZ2H+owr8q/LYKLD+vquv9Pj4F+dj808MdHbuQLD7S4ACRjcX+0Tne5Vxt2lxXvdZaL7v+FOOAV281w==", "dev": true, "requires": { "handlebars": "^4.0.3" } }, "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 }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true, "optional": true }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { "invert-kv": "^1.0.0" } }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", "pinkie-promise": "^2.0.0", "strip-bom": "^2.0.0" } }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } } }, "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", "dev": true }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { "js-tokens": "^3.0.0" } }, "lru-cache": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { "object-visit": "^1.0.0" } }, "md5-hex": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { "md5-o-matic": "^0.1.1" } }, "md5-o-matic": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", "dev": true }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { "mimic-fn": "^1.0.0" } }, "merge-source-map": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { "source-map": "^0.6.1" }, "dependencies": { "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 } } }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" }, "dependencies": { "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "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 }, "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" } } } }, "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" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "nanomatch": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", "is-odd": "^2.0.0", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", "is-builtin-module": "^1.0.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { "path-key": "^2.0.0" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } } } }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { "isobject": "^3.0.0" }, "dependencies": { "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true } } }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { "isobject": "^3.0.1" }, "dependencies": { "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "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" } }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" } }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { "execa": "^0.7.0", "lcid": "^1.0.0", "mem": "^1.1.0" } }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", "dev": true, "requires": { "p-try": "^1.0.0" } }, "p-locate": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { "p-limit": "^1.1.0" } }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { "error-ex": "^1.2.0" } }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { "pinkie-promise": "^2.0.0" } }, "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-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "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 }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" } }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { "pinkie": "^2.0.0" } }, "pkg-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { "find-up": "^1.0.0" }, "dependencies": { "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" } } } }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", "path-type": "^1.0.0" } }, "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" } } } }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" } }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { "is-finite": "^1.0.0" } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", "dev": true }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "optional": true, "requires": { "align-text": "^0.1.1" } }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "^7.0.5" } }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { "ret": "~0.1.10" } }, "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "map-cache": "^0.2.2", "source-map": "^0.5.6", "source-map-resolve": "^0.5.0", "use": "^3.1.0" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { "kind-of": "^3.2.0" } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, "source-map-resolve": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", "dev": true, "requires": { "atob": "^2.0.0", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", "urix": "^0.1.0" } }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, "spawn-wrap": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { "foreground-child": "^1.5.6", "mkdirp": "^0.5.0", "os-homedir": "^1.0.1", "rimraf": "^2.6.2", "signal-exit": "^3.0.2", "which": "^1.3.0" } }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { "extend-shallow": "^3.0.0" } }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } } } }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" } } } }, "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" } }, "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { "is-utf8": "^0.2.0" } }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "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 }, "test-exclude": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==", "dev": true, "requires": { "arrify": "^1.0.1", "micromatch": "^3.1.8", "object-assign": "^4.1.0", "read-pkg-up": "^1.0.1", "require-main-filename": "^1.0.1" }, "dependencies": { "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "posix-character-classes": "^0.1.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { "is-descriptor": "^0.1.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" } }, "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", "expand-brackets": "^2.1.4", "extend-shallow": "^2.0.1", "fragment-cache": "^0.2.1", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "dependencies": { "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { "is-descriptor": "^1.0.0" } }, "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } } } }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" } }, "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } } } }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } } } }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { "kind-of": "^3.0.2" } }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" } }, "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" }, "dependencies": { "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "^3.0.2" } } } }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, "requires": { "source-map": "~0.5.1", "uglify-to-browserify": "~1.0.0", "yargs": "~3.10.0" }, "dependencies": { "yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "optional": true, "requires": { "camelcase": "^1.0.2", "cliui": "^2.1.0", "decamelize": "^1.0.0", "window-size": "0.1.0" } } } }, "uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { "is-extendable": "^0.1.0" } }, "set-value": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.1", "to-object-path": "^0.3.0" } } } }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" }, "dependencies": { "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", "isobject": "^2.0.0" }, "dependencies": { "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "requires": { "isarray": "1.0.0" } } } }, "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true } } }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", "dev": true, "requires": { "kind-of": "^6.0.2" }, "dependencies": { "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, "optional": true }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" }, "dependencies": { "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-file-atomic": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", "slide": "^1.1.5" } }, "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { "cliui": "^4.0.0", "decamelize": "^1.1.1", "find-up": "^2.1.0", "get-caller-file": "^1.0.1", "os-locale": "^2.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", "y18n": "^3.2.1", "yargs-parser": "^9.0.2" }, "dependencies": { "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { "string-width": "^2.1.1", "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" } }, "yargs-parser": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { "camelcase": "^4.1.0" } } } }, "yargs-parser": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", "dev": true, "requires": { "camelcase": "^4.1.0" }, "dependencies": { "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } } } } }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", "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 }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, "request": { "version": "2.86.0", "resolved": "https://registry.npmjs.org/request/-/request-2.86.0.tgz", "integrity": "sha512-BQZih67o9r+Ys94tcIW4S7Uu8pthjrQVxhsZ/weOwHbDfACxvIyvnAbzFQxjy1jMtvFSzv5zf4my6cZsJBbVzw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.6.0", "caseless": "~0.12.0", "combined-stream": "~1.0.5", "extend": "~3.0.1", "forever-agent": "~0.6.1", "form-data": "~2.3.1", "har-validator": "~5.0.3", "hawk": "~6.0.2", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.17", "oauth-sign": "~0.8.2", "performance-now": "^2.1.0", "qs": "~6.5.1", "safe-buffer": "^5.1.1", "tough-cookie": "~2.3.3", "tunnel-agent": "^0.6.0", "uuid": "^3.1.0" } }, "requizzle": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", "integrity": "sha512-Lk39CGyJafiW6ZM+1jPiCpcqZTUKVtft5QdvGw/5DylN5SplowmUU9Uf7hCdiKxoESF0JfaLM/plZlsXawnBFQ==", "dev": true, "requires": { "underscore": "~1.6.0" }, "dependencies": { "underscore": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", "dev": true } } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "sntp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "dev": true, "requires": { "hoek": "4.x.x" } }, "sshpk": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "tweetnacl": "~0.14.0" } }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true }, "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" } }, "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", "dev": true }, "text-encoding": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { "punycode": "^1.4.1" } }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true, "optional": true }, "type-detect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", "integrity": "sha512-f9Uv6ezcpvCQjJU0Zqbg+65qdcszv3qUQsZfjdRbWiZ7AMenrX1u0lNk9EoWWX6e1F+NULyg27mtdeZ5WhpljA==", "dev": true }, "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha512-5WsVTFcH1ut/kkhAaHf4PVgI8c7++GiVcpCGxPouI6ZVjsqPnSDf8h/8HtVqc0t4fzRXwnMK70EcZeAs3PIddg==", "dev": true }, "underscore-contrib": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", "dev": true, "requires": { "underscore": "1.6.0" }, "dependencies": { "underscore": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", "dev": true } } }, "urlgrey": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=", "dev": true }, "uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", "dev": true }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "xmlcreate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", "dev": true } } } webcrypto-0.9.2/package.json000066400000000000000000000017351330022407200160250ustar00rootroot00000000000000{ "name": "@trust/webcrypto", "version": "0.9.2", "description": "WebCrypto API for Node.js", "main": "src/index.js", "types": "index.d.ts", "directories": { "test": "test" }, "scripts": { "test": "nyc _mocha test", "jsdoc": "jsdoc -c jsdoc.json -r", "coverage": "nyc --reporter=lcov _mocha test" }, "repository": { "type": "git", "url": "git+ssh://git@github.com/anvilresearch/webcrypto.git" }, "keywords": [ "WebCrypto" ], "author": "Anvil Research, Inc.", "license": "MIT", "bugs": { "url": "https://github.com/anvilresearch/webcrypto/issues" }, "homepage": "https://github.com/anvilresearch/webcrypto#README", "dependencies": { "@trust/keyto": "^0.3.4", "base64url": "^3.0.0", "elliptic": "^6.4.0", "node-rsa": "^0.4.0", "text-encoding": "^0.6.1" }, "devDependencies": { "chai": "^3.5.0", "codecov": "^3.0.2", "jsdoc": "^3.4.3", "mocha": "^5.2.0", "nyc": "^11.2.1" } } webcrypto-0.9.2/src/000077500000000000000000000000001330022407200143205ustar00rootroot00000000000000webcrypto-0.9.2/src/Crypto.js000066400000000000000000000030301330022407200161320ustar00rootroot00000000000000/** * Module dependencies */ const legacyCrypto = require('crypto') const SubtleCrypto = require('./SubtleCrypto') const {QuotaExceededError, TypeMismatchError} = require('./errors') /** * integerTypes */ const integerTypes = [ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array ] /** * integerGetByConstructor */ const integerGetByConstructor = { 'Int8Array': 'getInt8', 'Uint8Array': 'getUint8', 'Int16Array': 'getInt16', 'Uint16Array': 'getUint16', 'Int32Array': 'getInt32', 'Uint32Array': 'getUint32' } /** * Crypto interface */ class Crypto { /** * getRandomValues */ getRandomValues (typedArray) { if (!integerTypes.some(type => typedArray instanceof type)) { throw new TypeMismatchError() } let byteLength = typedArray.byteLength if (byteLength > 65536) { throw new QuotaExceededError() } let type = typedArray.constructor let method = integerGetByConstructor[type.name] let totalBytes = byteLength * typedArray.length let buffer = legacyCrypto.randomBytes(totalBytes) let arrayBuffer = new Uint8Array(buffer) let dataView = new DataView(arrayBuffer.buffer) for (let byteIndex = 0; byteIndex < totalBytes; byteIndex += byteLength) { let integer = dataView[method](byteIndex) let arrayIndex = byteIndex / byteLength typedArray[arrayIndex] = integer } return typedArray } /** * subtle */ get subtle () { return new SubtleCrypto() } } /** * Export */ module.exports = Crypto webcrypto-0.9.2/src/SubtleCrypto.js000066400000000000000000000363361330022407200173300ustar00rootroot00000000000000/** * Local dependencies */ const CryptoKey = require('./keys/CryptoKey') const CryptoKeyPair = require('./keys/CryptoKeyPair') const JsonWebKey = require('./keys/JsonWebKey') const recognizedKeyUsages = require('./keys/recognizedKeyUsages') const supportedAlgorithms = require('./algorithms') const {InvalidAccessError, NotSupportedError} = require('./errors') const {TextEncoder,TextDecoder} = require('text-encoding') /** * SubtleCrypto */ class SubtleCrypto { /** * encrypt * * @description * * @param {AlgorithmIdentifier} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Promise} */ encrypt (algorithm, key, data) { data = data.slice() let normalizedAlgorithm = supportedAlgorithms.normalize('encrypt', algorithm) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } return new Promise((resolve, reject) => { if (normalizedAlgorithm.name !== key.algorithm.name) { throw new InvalidAccessError('Algorithm does not match key') } if (!key.usages.includes('encrypt')) { throw new InvalidAccessError('Key usages must include "encrypt"') } let ciphertext = normalizedAlgorithm.encrypt(algorithm,key, data) resolve(ciphertext) }) } /** * decrypt * * @description * * @param {AlgorithmIdentifier} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Promise} */ decrypt (algorithm, key, data) { let normalizedAlgorithm = supportedAlgorithms.normalize('decrypt', algorithm) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } data = data.slice() return new Promise((resolve, reject) => { if (normalizedAlgorithm.name !== key.algorithm.name) { throw new InvalidAccessError('Algorithm does not match key') } if (!key.usages.includes('decrypt')) { throw new InvalidAccessError('Key usages must include "decrypt"') } let plaintext = normalizedAlgorithm.decrypt(algorithm, key, data) resolve(plaintext) }) } /** * sign * * @description * * @param {AlgorithmIdentifier} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Promise} */ sign (algorithm, key, data) { data = data.slice() let normalizedAlgorithm = supportedAlgorithms.normalize('sign', algorithm) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } return new Promise((resolve, reject) => { if (normalizedAlgorithm.name !== key.algorithm.name) { throw new InvalidAccessError('Algorithm does not match key') } if (!key.usages.includes('sign')) { throw new InvalidAccessError('Key usages must include "sign"') } let result = normalizedAlgorithm.sign(key, data) resolve(result) }) } /** * verify * * @description * * @param {AlgorithmIdentifier} algorithm * @param {CryptoKey} key * @param {BufferSource} signature * @param {BufferSource} data * * @returns {Promise} */ verify (alg, key, signature, data) { signature = signature.slice() let normalizedAlgorithm = supportedAlgorithms.normalize('verify', alg) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } data = data.slice() return new Promise((resolve, reject) => { if (normalizedAlgorithm.name !== key.algorithm.name) { throw new InvalidAccessError('Algorithm does not match key') } if (!key.usages.includes('verify')) { throw new InvalidAccessError('Key usages must include "verify"') } let result = normalizedAlgorithm.verify(key, signature, data) resolve(result) }) } /** * digest * * @description * * @param {AlgorithmIdentifier} algorithm * @param {BufferSource} data * * @returns {Promise.} */ digest (algorithm, data) { data = data.slice() let normalizedAlgorithm = supportedAlgorithms.normalize('digest', algorithm) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } return new Promise((resolve, reject) => { try { let result = normalizedAlgorithm.digest(algorithm, data) return resolve(result) } catch (error) { return reject(error) } }) } /** * generateKey * * @description * * @param {AlgorithmIdentifier} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {Promise} */ generateKey (algorithm, extractable, keyUsages) { let normalizedAlgorithm = supportedAlgorithms.normalize('generateKey', algorithm) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } return new Promise((resolve, reject) => { try { let result = normalizedAlgorithm.generateKey(algorithm, extractable, keyUsages) if (result instanceof CryptoKey) { let {type,usages} = result let restricted = (type === 'secret' || type === 'private') let emptyUsages = (!usages || usages.length === 0) if (restricted && emptyUsages) { throw new SyntaxError() } } if (result instanceof CryptoKeyPair) { let {privateKey:{usages}} = result if (!usages || usages.length === 0) { throw new SyntaxError() } } resolve(result) } catch (error) { return reject(error) } }) } /** * deriveKey * * @description * * @param {AlgorithmIdentifier} algorithm * @param {CryptoKey} baseKey * @param {AlgorithmIdentifier} derivedKeyType * @param {Boolean} extractable * @param {Array} keyUsages * @returns {Promise} */ deriveKey (algorithm, baseKey, derivedKeyType, extractable, keyUsages) { return new Promise() } /** * deriveBits * * @description * * @param {AlgorithmIdentifier} algorithm * @param {CryptoKey} baseKey * @param {number} length * * @returns {Promise} */ deriveBits (algorithm, baseKey, length) { return new Promise() } /** * importKey * * @description * * @param {KeyFormat} format * @param {BufferSource|JWK} keyData * @param {AlgorithmIdentifier} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {Promise} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let normalizedAlgorithm = supportedAlgorithms.normalize('importKey', algorithm) if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } return new Promise((resolve, reject) => { if (format === 'raw' || format === 'pkcs8' || format === 'spki') { if (keyData instanceof JsonWebKey) { throw new TypeError() } keyData = keyData.slice() } if (format === 'jwk') { keyData = new JsonWebKey(keyData) if (!(keyData instanceof JsonWebKey)) { throw new TypeError('key is not a JSON Web Key') } } try { let result = normalizedAlgorithm .importKey(format, keyData, algorithm, extractable, keyUsages) if (result.type === 'secret' || result.type === 'private') { if (!result.usages || result.usages.length === 0) { throw new SyntaxError() } } result.extractable = extractable result.usages = recognizedKeyUsages.normalize(keyUsages) resolve(result) } catch (error) { return reject(error) } }) } /** * exportKey * * @description * * @param {KeyFormat} format * @param {CryptoKey} key * * @returns {Promise} */ exportKey (format, key) { return new Promise((resolve, reject) => { try { let registeredAlgorithms = supportedAlgorithms['exportKey'] if (!registeredAlgorithms[key.algorithm.name]) { throw new NotSupportedError(key.algorithm.name) } if (key.extractable === false) { throw new InvalidAccessError('Key is not extractable') } let result = key.algorithm.exportKey(format, key) resolve(result) } catch (error) { return reject(error) } }) } /** * wrapKey * * @description * * @param {KeyFormat} format * @param {CryptoKey} key * @param {CryptoKey} wrappingKey * @param {AlgorithmIdentifier} wrapAlgorithm * * @returns {Promise} */ wrapKey (format, key, wrappingKey, wrapAlgorithm) { // 1. Parameters // 2. Setup normalizedAlgorithm with op as 'unwrap' let normalizedAlgorithm = supportedAlgorithms.normalize('wrapKey', wrapAlgorithm) if (normalizedAlgorithm instanceof Error) { // 3. If failed, then try again with op as 'encrypt' normalizedAlgorithm = supportedAlgorithms.normalize('encrypt', wrapAlgorithm) } // 4. Otherwise reject outright if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } // 5-6. Setup and asynchronously return a new promise return new Promise((resolve, reject) => { // 7. Try catch the following step... // if anything goes wrong then reject the promise outright try { // 8. Validate normalizedAlgorithm name property if (normalizedAlgorithm.name !== wrappingKey.algorithm.name) { throw new InvalidAccessError('NormalizedAlgorthm name must be same as wrappingKey algorithm name') } // 9. Validate usages property contains wrap if (!wrappingKey.usages.includes('wrapKey')) { throw new InvalidAccessError('Wrapping key usages must include "wrapKey"') } // 10. Validate algorithm contains exportKey let exportKeyAlgorithms = supportedAlgorithms['exportKey'] if (!exportKeyAlgorithms[key.algorithm.name]) { throw new NotSupportedError(key.algorithm.name) } // 11. Validate extractable property if (key.extractable === false) { throw new InvalidAccessError('Key is not extractable') } // 12. Generate extracted key return this.exportKey(format,key) .then(exportedKey => { let bytes // 13.1. If format is "raw", "pkcs8", or "spki": if (["raw", "pkcs8","spki"].includes(format)) { bytes = exportedKey } // 13.2. If format is "jwk" else if (format === "jwk"){ let json = JSON.stringify(exportedKey) bytes = new TextEncoder().encode(json) } // 14.1. If the normalizedAlgorithm supports wrapKey then use it if (normalizedAlgorithm['wrapKey']){ return normalizedAlgorithm.wrapKey(format,bytes,wrappingKey,wrapAlgorithm) } // 14.2. Otherwise try with encrypt else if (normalizedAlgorithm['encrypt']){ return normalizedAlgorithm.encrypt(wrapAlgorithm,wrappingKey,new Uint8Array(bytes)) } // 14.3. Otherwise throw error else { return reject (new NotSupportedError(normalizedAlgorithm.name)) } }) // 15. Return the resulting promise .then(resolve) } catch (error) { return reject(error) } }) } /** * unwrapKey * * @description * * @param {KeyFormat} format * @param {BufferSource} wrappedKey * @param {CryptoKey} unwrappingKey * @param {AlgorithmIdentifier} unwrapAlgorithm * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {Promise} */ unwrapKey (format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) { // 1. Parameters // 2. Ommited due to redundancy // 3. Setup normalizedAlgorithm with op as 'unwrap' let normalizedAlgorithm = supportedAlgorithms.normalize('unwrapKey', unwrapAlgorithm) if (normalizedAlgorithm instanceof Error) { // 4. If failed, then try again with op as 'encrypt' normalizedAlgorithm = supportedAlgorithms.normalize('decrypt', unwrapAlgorithm) } // 5. Otherwise reject outright if (normalizedAlgorithm instanceof Error) { return Promise.reject(normalizedAlgorithm) } // 6. Setup normalizedKeyAlgorithm let normalizedKeyAlgorithm = supportedAlgorithms.normalize('importKey', unwrappedKeyAlgorithm) if (normalizedKeyAlgorithm instanceof Error) { // 7. If failed, then try again with op as 'encrypt' return Promise.reject(normalizedKeyAlgorithm) } // 8-9. Setup and asynchronously return a new promise return new Promise((resolve, reject) => { // 10. Try catch the following step... // if anything goes wrong then reject the promise outright try { // 11. Validate normalizedAlgorithm name property if (normalizedAlgorithm.name !== unwrappingKey.algorithm.name) { throw new InvalidAccessError('NormalizedAlgorthm name must be same as unwrappingKey algorithm name') } // 12. Validate usages property contains unwrap if (!unwrappingKey.usages.includes('unwrapKey')) { throw new InvalidAccessError('Unwrapping key usages must include "unwrapKey"') } let key // 13.1. If the normalizedAlgorithm supports unwrapKey then use it if (normalizedAlgorithm['unwrapKey']){ key = normalizedAlgorithm.unwrapKey(format,wrappedKey,unwrappingKey,unwrapAlgorithm,unwrappedKeyAlgorithm,extractable,keyUsages) } // 13.2. Otherwise try with decrypt else if (normalizedAlgorithm['decrypt']){ key = normalizedAlgorithm.decrypt(unwrapAlgorithm,unwrappingKey,wrappedKey) } // 13.3. Otherwise throw error else { return reject (new NotSupportedError(normalizedAlgorithm.name)) } let bytes // 14.1. If format is "raw", "pkcs8", or "spki": if (["raw", "pkcs8","spki"].includes(format)) { bytes = key } // 14.2. If format is "jwk" else if (format === "jwk"){ bytes = JSON.parse(new TextDecoder().decode(key)) } // 15. Import the resulting unwrapped content // 16-18. Ommitted because it is handled by importKey interface let result = normalizedKeyAlgorithm.importKey(format, bytes, unwrappedKeyAlgorithm, extractable, keyUsages) // 19. Resolve the result return resolve(result) } catch (error) { return reject(error) } }) } } /** * Export */ module.exports = SubtleCryptowebcrypto-0.9.2/src/algorithms/000077500000000000000000000000001330022407200164715ustar00rootroot00000000000000webcrypto-0.9.2/src/algorithms/AES-CBC.js000066400000000000000000000235061330022407200200320ustar00rootroot00000000000000/** * Package dependencies */ const crypto = require('crypto') const base64url = require('base64url') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../dictionaries/AesKeyAlgorithm') const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const JsonWebKey = require('../keys/JsonWebKey') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError } = require('../errors') /** * AES-CBC */ class AES_CBC extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, AesKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource' } } /** * encrypt * * @description * Encrypts an AES-CBC digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ encrypt (algorithm, key, data) { // 1. Ensure correct iv length if (algorithm.iv.byteLength !== 16) { throw new OperationError('IV Length must be exactly 16 bytes') } // 2. Add padding to erronuous length text as described here: // https://tools.ietf.org/html/rfc2315#section-10.3 let paddedPlaintext = data // 3. Do the encryption let cipherName if (key.algorithm.name === 'AES-CBC' && [128,192,256].includes(key.algorithm.length)){ cipherName = 'AES-' + key.algorithm.length + '-CBC' } else { throw new DataError('Invalid AES-CBC and length pair.') } let cipher = crypto.createCipheriv(cipherName,key.handle,Buffer.from(algorithm.iv)) let ciphertext = cipher.update(Buffer.from(data)) // 4. Return result return Uint8Array.from(Buffer.concat([ciphertext,cipher.final()])).buffer } /** * decrypt * * @description * Decrypts an AES-CBC digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ decrypt (algorithm, key, data) { // 1. Ensure correct iv length if (algorithm.iv.byteLength !== 16){ throw new OperationError('IV Length must be exactly 16 bytes') } // 2. Perform the decryption let cipherName if (key.algorithm.name === 'AES-CBC' && [128,192,256].includes(key.algorithm.length)){ cipherName = 'AES-' + key.algorithm.length + '-CBC' } else { throw new DataError('Invalid AES-CBC and length pair.') } let decipher = crypto.createDecipheriv(cipherName,key.handle,Buffer.from(algorithm.iv)) let ciphertext = decipher.update(Buffer.from(data)) let plaintext = Array.from(Buffer.concat([ciphertext,decipher.final()])) // 3-5. Text de-padding performed by crypto.decipher // 6. Return resulting ArrayBuffer return Uint8Array.from(plaintext).buffer } /** * generateKey * * @description * Generate an AES-CBC key pair * * @param {AesCbcParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Validate usages usages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2. Validate length if (![128,192,256].includes(params.length)) { throw new OperationError('Member length must be 128, 192, or 256.') } // 3. Generate AES Key let symmetricKey try { symmetricKey = crypto.randomBytes(params.length/8) // 4. Validate key generation } catch (error) { throw new OperationError(error.message) } // 6. Set new AesKeyAlgorithm let algorithm = new AES_CBC(params) // 5. Define new CryptoKey names key let key = new CryptoKey({ type: 'secret', algorithm, extractable, usages, handle: symmetricKey }) // 12. Return Key return key } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let data, jwk // 1. Validate keyUsages keyUsages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the octet string contained in keyData data = Buffer.from(keyData) // 2.1.2 Ensure data length is 128, 192 or 256 if (![16,24,32].includes(data.length)){ throw new DataError('Length of data bits must be 128, 192 or 256.') } } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Ensure data is JsonWebKey dictionary if (typeof keyData === 'object' && !Array.isArray(keyData)){ jwk = new JsonWebKey(keyData) } else { throw new DataError('Invalid jwk format') } // 2.2.2 Validate "kty" field heuristic if (jwk.kty !== "oct"){ throw new DataError('kty property must be "oct"') } // 2.2.3 Ensure jwk meets these requirements: // https://tools.ietf.org/html/rfc7518#section-6.4 if (!jwk.k){ throw new DataError('k property must not be empty') } // 2.2.4 Assign data data = base64url.toBuffer(jwk.k) // 2.2.5 Validate data lengths if (data.length === 16) { if (jwk.alg && jwk.alg !== 'A128CBC'){ throw new DataError('Algorithm "A128CBC" must be 128 bits in length') } } else if (data.length === 24) { if (jwk.alg && jwk.alg !== 'A192CBC'){ throw new DataError('Algorithm "A192CBC" must be 192 bits in length') } } else if (data.length === 32) { if (jwk.alg && jwk.alg !== 'A256CBC'){ throw new DataError('Algorithm "A256CBC" must be 256 bits in length') } } else { throw new DataError('Algorithm and data length mismatch') } // 2.2.6 Validate "use" field if (keyUsages && jwk.use && jwk.use !== 'enc'){ throw new DataError('Key use must be "enc"') } // 2.2.7 Validate "key_ops" field if (jwk.key_ops){ jwk.key_ops.forEach(op => { if (op !== 'encrypt' && op !== 'decrypt' && op !== 'wrapKey' && op !== 'unwrapKey') { throw new DataError('Key operation can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) } // 2.2.8 validate "ext" field if (jwk.ext === false && extractable === true){ throw new DataError('Cannot be extractable when "ext" is set to false') } } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Generate new key let key = new CryptoKey({ type: 'secret', extractable, usages: keyUsages, handle: data }) // 4-6. Generate algorithm let aesAlgorithm = new AES_CBC( { name: 'AES-CBC', length: data.length * 8 }) // 7. Set algorithm to internal algorithm property of key key.algorithm = aesAlgorithm // 8. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { let result, data // 1. Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the raw octets of the key data = key.handle // 2.1.2 Let result be containing data result = Buffer.from(data) } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Validate JsonWebKey let jwk = new JsonWebKey() // 2.2.2 Set kty property jwk.kty = 'oct' // 2.2.3 Set k property jwk.k = base64url(key.handle) data = key.handle // 2.2.4 Validate length if (data.length === 16) { jwk.alg = 'A128CBC' } else if (data.length === 24) { jwk.alg = 'A192CBC' } else if (data.length === 32) { jwk.alg = 'A256CBC' } // 2.2.5 Set keyops property jwk.key_ops = key.usages // 2.2.6 Set ext property jwk.ext = key.extractable // 2.2.7 Set result to the result of converting jwk to an ECMAScript object result = jwk } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Return result return result } } /** * Export */ module.exports = AES_CBCwebcrypto-0.9.2/src/algorithms/AES-CTR.js000066400000000000000000000241131330022407200200660ustar00rootroot00000000000000/** * Package dependencies */ const crypto = require('crypto') const base64url = require('base64url') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../dictionaries/AesKeyAlgorithm') const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const JsonWebKey = require('../keys/JsonWebKey') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError } = require('../errors') /** * AES-CTR */ class AES_CTR extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, AesKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource' } } /** * encrypt * * @description * Encrypts an AES-CTR digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ encrypt (algorithm, key, data) { // 1. Ensure correct counter length if (algorithm.counter === undefined || algorithm.counter.byteLength !== 16){ throw new OperationError('Counter must be exactly 16 bytes') } // 2. Ensure correct length size if (algorithm.length === undefined || algorithm.length === 0 || algorithm.length > 128){ throw new OperationError('Length must be non zero and less than or equal to 128') } // 3. Do the encryption let cipherName if (key.algorithm.name === 'AES-CTR' && [128,192,256].includes(key.algorithm.length)){ cipherName = 'AES-' + key.algorithm.length + '-CTR' } else { throw new DataError('Invalid AES-CTR and length pair.') } let cipher = crypto.createCipheriv(cipherName,key.handle,Buffer.from(algorithm.counter)) // 4. Return result return Uint8Array.from(Buffer.concat([cipher.update(data),cipher.final()])).buffer } /** * decrypt * * @description * Decrypts an AES-CTR digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ decrypt (algorithm, key, data) { // 1. Ensure correct counter length if (algorithm.counter === undefined || algorithm.counter.byteLength !== 16) { throw new OperationError('Counter must be exactly 16 bytes') } // 2. Ensure correct length size if (algorithm.length === undefined || algorithm.length === 0 || algorithm.length > 128){ throw new OperationError('Length must be non zero and less than or equal to 128') } // 3. Perform the decryption let cipherName if (key.algorithm.name === 'AES-CTR' && [128,192,256].includes(key.algorithm.length)){ cipherName = 'AES-' + key.algorithm.length + '-CTR' } else { throw new DataError('Invalid AES-CTR and length pair.') } let decipher = crypto.createDecipheriv(cipherName,key.handle,algorithm.counter) let plaintext = Array.from(Buffer.concat([decipher.update(Buffer.from(data)),decipher.final()])) // 4. Return resulting ArrayBuffer return Uint8Array.from(plaintext).buffer } /** * generateKey * * @description * Generate an AES-CTR key pair * * @param {AesCtrParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Validate usages usages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2. Validate length if (![128,192,256].includes(params.length)) { throw new OperationError('Member length must be 128, 192, or 256.') } // 3. Generate AES Key let symmetricKey try { symmetricKey = crypto.randomBytes(params.length/8) // 4. Validate key generation } catch (error) { throw new OperationError(error.message) } // Set new AesKeyAlgorithm let algorithm = new AES_CTR(params) // 5-11. Define new CryptoKey names key let key = new CryptoKey({ type: 'secret', algorithm, extractable, usages, handle: symmetricKey }) // 12. Return Key return key } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let data, jwk // 1. Validate keyUsages keyUsages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the octet string contained in keyData data = Buffer.from(keyData) // 2.1.2 Ensure data length is 128, 192 or 256 if (![16,24,32].includes(data.length)){ throw new DataError('Length of data bits must be 128, 192 or 256.') } } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Ensure data is JsonWebKey dictionary if (typeof keyData === 'object' && !Array.isArray(keyData)){ jwk = new JsonWebKey(keyData) } else { throw new DataError('Invalid jwk format') } // 2.2.2 Validate "kty" field heuristic if (jwk.kty !== "oct"){ throw new DataError('kty property must be "oct"') } // 2.2.3 Ensure jwk meets these requirements: // https://tools.ietf.org/html/rfc7518#section-6.4 if (!jwk.k){ throw new DataError('k property must not be empty') } // 2.2.4 Assign data data = base64url.toBuffer(jwk.k) // 2.2.5 Validate data lengths if (data.length === 16) { if (jwk.alg && jwk.alg !== 'A128CTR'){ throw new DataError('Algorithm "A128CTR" must be 128 bits in length') } } else if (data.length === 24) { if (jwk.alg && jwk.alg !== 'A192CTR'){ throw new DataError('Algorithm "A192CTR" must be 192 bits in length') } } else if (data.length === 32) { if (jwk.alg && jwk.alg !== 'A256CTR'){ throw new DataError('Algorithm "A256CTR" must be 256 bits in length') } } else { throw new DataError('Algorithm and data length mismatch') } // 2.2.6 Validate "use" field if (keyUsages && jwk.use && jwk.use !== 'enc'){ throw new DataError('Key use must be "enc"') } // 2.2.7 Validate "key_ops" field if (jwk.key_ops){ jwk.key_ops.forEach(op => { if (op !== 'encrypt' && op !== 'decrypt' && op !== 'wrapKey' && op !== 'unwrapKey') { throw new DataError('Key operation can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) } // 2.2.8 validate "ext" field if (jwk.ext === false && extractable === true){ throw new DataError('Cannot be extractable when "ext" is set to false') } } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Generate new key let key = new CryptoKey({ type: 'secret', extractable, usages: keyUsages, handle: data }) // 4-6. Generate algorithm let aesAlgorithm = new AES_CTR({ name: 'AES-CTR', length: data.length * 8 }) // 7. Set algorithm to internal algorithm property of key key.algorithm = aesAlgorithm // 8. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { let result, data // 1. Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the raw octets of the key data = key.handle // 2.1.2 Let result be containing data result = Buffer.from(data) } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Validate JsonWebKey let jwk = new JsonWebKey(key) // 2.2.2 Set kty property jwk.kty = 'oct' // 2.2.3 Set k property jwk.k = base64url(key.handle) data = key.handle // 2.2.4 Validate length if (data.length === 16) { jwk.alg = 'A128CTR' } else if (data.length === 24) { jwk.alg = 'A192CTR' } else if (data.length === 32) { jwk.alg = 'A256CTR' } // 2.2.5 Set keyops property jwk.key_ops = key.usages // 2.2.6 Set ext property jwk.ext = key.extractable // 2.2.7 Set result to the result of converting jwk to an ECMAScript object result = jwk } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Return result return result } } /** * Export */ module.exports = AES_CTR webcrypto-0.9.2/src/algorithms/AES-GCM.js000066400000000000000000000312361330022407200200500ustar00rootroot00000000000000/** * Package dependencies */ const crypto = require('crypto') const base64url = require('base64url') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../dictionaries/AesKeyAlgorithm') const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const JsonWebKey = require('../keys/JsonWebKey') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * AES-GCM */ class AES_GCM extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, AesKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource' } } /** * encrypt * * @description * Encrypts an AES-GCM digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ encrypt (algorithm, key, data) { // 1. Ensure correct data length if (data.byteLength === undefined || data.byteLength > 549755813632) { // 2^39-256 throw new OperationError('Data must have a length less than 549755813632.') } // 2. Ensure correct iv length if (algorithm.iv.byteLength === undefined || algorithm.iv.byteLength > 18446744073709551615) { // 2^64-1 throw new OperationError('IV Length must be less than 18446744073709551615 in length.') } // 3. Ensure correct additionalData if (algorithm.additionalData !== undefined && (algorithm.additionalData.length === undefined || algorithm.additionalData.length > 18446744073709551615)) { // 2^64-1 throw new OperationError('AdditionalData must be less than 18446744073709551615 in length.') } // 4. Verify tagLength // Note: node only support tag length up to 128, so there is some discrepancy between // this, and the spec outline: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm let tagLength if (algorithm.tagLength === undefined){ tagLength = 128 } else if ([32,64,96,104,112,120].includes(algorithm.tagLength)) { throw new CurrentlyNotSupportedError('Node currently only supports 128 tagLength.', '128') } else if (algorithm.tagLength !== 128) { throw new OperationError('TagLength is an invalid size.') } else { tagLength = algorithm.tagLength } // 5. Assign additionalData let additionalData if (algorithm.additionalData !== undefined){ additionalData = Buffer.from(algorithm.additionalData) } else { additionalData = Buffer.from('') } // 6. Do the encryption let cipherName if (key.algorithm.name === 'AES-GCM' && [128,192,256].includes(key.algorithm.length)){ cipherName = 'aes-' + key.algorithm.length + '-gcm' } else { throw new DataError('Invalid AES-GCM and length pair.') } let cipher = crypto.createCipheriv(cipherName,key.handle,Buffer.from(algorithm.iv)) cipher.setAAD(additionalData) let ciphertext = cipher.update(Buffer.from(data)) ciphertext = Buffer.concat([ciphertext,cipher.final()]) // 7. Concat C and T let authTag = cipher.getAuthTag() ciphertext = Buffer.concat([ciphertext,authTag]) // 8. Return result return Uint8Array.from(ciphertext).buffer } /** * decrypt * * @description * Decrypts an AES-GCM digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ decrypt (algorithm, key, data) { // 1. Verify tagLength let tagLength if (algorithm.tagLength === undefined){ tagLength = 128 } else if ([32,64,96,104,112,120].includes(algorithm.tagLength)) { throw new CurrentlyNotSupportedError('Node currently only supports 128 tagLength.', '128') } else if (algorithm.tagLength !== 128) { throw new OperationError('TagLength is an invalid size.') } else { tagLength = algorithm.tagLength } // 2. Verify data length if ((data.length * 8) < tagLength){ throw new OperationError('Data length cannot be less than tagLength.') } // 3. Ensure correct iv length if (algorithm.iv.byteLength === undefined || algorithm.iv.byteLength > 18446744073709551615) { // 2^64-1 throw new OperationError('IV Length must be less than 18446744073709551615 in length.') } // 4 & 7. Ensure correct additionalData let additionalData if (algorithm.additionalData !== undefined){ if (algorithm.additionalData.length === undefined || algorithm.additionalData.length > 18446744073709551615) { // 2^64-1 throw new OperationError('AdditionalData must be less than 18446744073709551615 in length.') } else { additionalData = Buffer.from(algorithm.additionalData) } } else{ additionalData = Buffer.from('') } // 5. Get the AuthTag data = Buffer.from(data) let tagLengthBytes = tagLength/8 let tag = data.slice(-tagLengthBytes) // 6. Get the actualCiphertext let actualCiphertext = data.slice(0,-tagLengthBytes) // 8. Perform the decryption let cipherName if (key.algorithm.name === 'AES-GCM' && [128,192,256].includes(key.algorithm.length)){ cipherName = 'aes-' + key.algorithm.length + '-gcm' } else { throw new DataError('Invalid AES-GCM and length pair.') } let decipher = crypto.createDecipheriv(cipherName,key.handle,Buffer.from(algorithm.iv)) decipher.setAAD(additionalData) decipher.setAuthTag(tag) let plaintext = decipher.update(Buffer.from(actualCiphertext)) plaintext = Buffer.concat([plaintext,decipher.final()]) // 9. Return resulting ArrayBuffer return Uint8Array.from(plaintext).buffer } /** * generateKey * * @description * Generate an AES-GCM key pair * * @param {AesGcmParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Validate usages usages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2. Validate length if (![128,192,256].includes(params.length)) { throw new OperationError('Member length must be 128, 192, or 256.') } // 3. Generate AES Key let symmetricKey try { symmetricKey = crypto.randomBytes(params.length/8) // 4. Validate key generation } catch (error) { throw new OperationError(error.message) } // 6. Set new AesKeyAlgorithm let algorithm = new AES_GCM(params) // 5. Define new CryptoKey names key let key = new CryptoKey({ type: 'secret', algorithm, extractable, usages, handle: symmetricKey }) // 12. Return Key return key } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let data, jwk // 1. Validate keyUsages keyUsages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the octet string contained in keyData data = Buffer.from(keyData) // 2.1.2 Ensure data length is 128, 192 or 256 if (![16,24,32].includes(data.length)){ throw new DataError('Length of data bits must be 128, 192 or 256.') } } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Ensure data is JsonWebKey dictionary if (typeof keyData === 'object' && !Array.isArray(keyData)){ jwk = new JsonWebKey(keyData) } else { throw new DataError('Invalid jwk format') } // 2.2.2 Validate "kty" field heuristic if (jwk.kty !== "oct"){ throw new DataError('kty property must be "oct"') } // 2.2.3 Ensure jwk meets these requirements: // https://tools.ietf.org/html/rfc7518#section-6.4 if (!jwk.k){ throw new DataError('k property must not be empty') } // 2.2.4 Assign data data = base64url.toBuffer(jwk.k) // 2.2.5 Validate data lengths if (data.length === 16) { if (jwk.alg && jwk.alg !== 'A128GCM'){ throw new DataError('Algorithm "A128GCM" must be 128 bits in length') } } else if (data.length === 24) { if (jwk.alg && jwk.alg !== 'A192GCM'){ throw new DataError('Algorithm "A192GCM" must be 192 bits in length') } } else if (data.length === 32) { if (jwk.alg && jwk.alg !== 'A256GCM'){ throw new DataError('Algorithm "A256GCM" must be 256 bits in length') } } else { throw new DataError('Algorithm and data length mismatch') } // 2.2.6 Validate "use" field if (keyUsages && jwk.use && jwk.use !== 'enc'){ throw new DataError('Key use must be "enc"') } // 2.2.7 Validate "key_ops" field if (jwk.key_ops){ jwk.key_ops.forEach(op => { if (op !== 'encrypt' && op !== 'decrypt' && op !== 'wrapKey' && op !== 'unwrapKey') { throw new DataError('Key operation can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) } // 2.2.8 validate "ext" field if (jwk.ext === false && extractable === true){ throw new DataError('Cannot be extractable when "ext" is set to false') } } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Generate new key let key = new CryptoKey({ type: 'secret', extractable, usages: keyUsages, handle: data }) // 4-6. Generate algorithm let aesAlgorithm = new AES_GCM( { name: 'AES-GCM', length: data.length * 8 }) // 7. Set algorithm to internal algorithm property of key key.algorithm = aesAlgorithm // 8. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { let result, data // 1. Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the raw octets of the key data = key.handle // 2.1.2 Let result be containing data result = Buffer.from(data) } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Validate JsonWebKey let jwk = new JsonWebKey() // 2.2.2 Set kty property jwk.kty = 'oct' // 2.2.3 Set k property jwk.k = base64url(key.handle) data = key.handle // 2.2.4 Validate length if (data.length === 16) { jwk.alg = 'A128GCM' } else if (data.length === 24) { jwk.alg = 'A192GCM' } else if (data.length === 32) { jwk.alg = 'A256GCM' } // 2.2.5 Set keyops property jwk.key_ops = key.usages // 2.2.6 Set ext property jwk.ext = key.extractable // 2.2.7 Set result to the result of converting jwk to an ECMAScript object result = jwk } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Return result return result } } /** * Export */ module.exports = AES_GCM webcrypto-0.9.2/src/algorithms/AES-KW.js000066400000000000000000000251671330022407200177710ustar00rootroot00000000000000/** * Package dependencies */ const crypto = require('crypto') const base64url = require('base64url') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../dictionaries/AesKeyAlgorithm') const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const JsonWebKey = require('../keys/JsonWebKey') const supportedAlgorithms = require('../algorithms') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * AES-KW */ class AES_KW extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, AesKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource' } } /** * wrapKey * * @description * * @param {string} format * @param {Any} key * @param {CryptoKey} wrappingKey * @param {KeyAlgorithm} wrappingAlgorithm * * @returns {Array} */ wrapKey (format, key, wrappingKey, wrappingAlgorithm) { // Currently only raw is supported if (format.toLowerCase() !== 'raw'){ throw new CurrentlyNotSupportedError(format,'raw') } // Determine what format the key is a jwk or simple a handle let data if (key instanceof CryptoKey){ data = key.algorithm.exportKey("raw",key) } else if (Buffer.isBuffer(key)){ data = key } else { throw new OperationError('Key must be a CryptoKey or BufferSource') } // 1. Ensure the data is a multiple of 8 (not just 64) if (!data.length || data.length % 8 !== 0){ throw new OperationError('Invalid key length. Must be multiple of 8.') } // 2. Do the wrap let ciphertext, cipher try { let cipherName if (wrappingKey.algorithm.name === 'AES-KW' && [128,192,256].includes(wrappingKey.algorithm.length)){ cipherName = 'id-aes' + wrappingKey.algorithm.length + '-wrap' } else { throw new DataError('Invalid AES-KW and length pair.') } let iv = Buffer.from('A6A6A6A6A6A6A6A6', 'hex') cipher = crypto.createCipheriv(cipherName,wrappingKey.handle,iv) ciphertext = cipher.update(data) } catch (error) { throw new OperationError(error.message) } // 3. Return result return Uint8Array.from(Buffer.concat([ciphertext,cipher.final()])).buffer } /** * unwrapKey * * @description * * @param {KeyFormat} format * @param {BufferSource} wrappedKey * @param {CryptoKey} unwrappingKey * @param {AlgorithmIdentifier} unwrapAlgorithm * @param {AlgorithmIdentifier} unwrappedKeyAlgorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {Array} */ unwrapKey (format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) { // Currently only raw is supported if (format.toLowerCase() !== 'raw'){ throw new CurrentlyNotSupportedError(format,'raw') } // 1-2. Do the unwrap operation let plaintext try { let cipherName if (unwrappingKey.algorithm.name === 'AES-KW' && [128,192,256].includes(unwrappingKey.algorithm.length)){ cipherName = 'id-aes' + unwrappingKey.algorithm.length + '-wrap' } else { throw new DataError('Invalid AES-KW and length pair.') } let iv = Buffer.from('A6A6A6A6A6A6A6A6', 'hex') let decipher = crypto.createDecipheriv(cipherName,unwrappingKey.handle,iv) let deciphertext = decipher.update(Buffer.from(wrappedKey)) plaintext = Array.from(Buffer.concat([deciphertext,decipher.final()])) } catch (error) { throw new OperationError(error.message) } // 3. Return the resulting CryptoKey object return plaintext } /** * generateKey * * @description * Generate an AES-KW key pair * * @param {AesKwParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Validate usages usages.forEach(usage => { if (usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "wrapKey" or "unwrapKey"') } }) // 2. Validate length if (![128,192,256].includes(params.length)) { throw new OperationError('Member length must be 128, 192, or 256.') } // 3. Generate AES Key let symmetricKey try { symmetricKey = crypto.randomBytes(params.length/8) // 4. Validate key generation } catch (error) { throw new OperationError(error.message) } // 6. Set new AesKeyAlgorithm let algorithm = new AES_KW(params) // 5. Define new CryptoKey names key let key = new CryptoKey({ type: 'secret', algorithm, extractable, usages, handle: symmetricKey }) // 12. Return Key return key } /** * importKey *} * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let data, jwk // 1. Validate keyUsages keyUsages.forEach(usage => { if (usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "wrapKey" or "unwrapKey"') } }) // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the octet string contained in keyData data = Buffer.from(keyData) // 2.1.2 Ensure data length is 128, 192 or 256 if (![16,24,32].includes(data.length)){ throw new DataError('Length of data bits must be 128, 192 or 256.') } } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Ensure data is JsonWebKey dictionary if (typeof keyData === 'object' && !Array.isArray(keyData)){ jwk = new JsonWebKey(keyData) } else { throw new DataError('Invalid jwk format') } // 2.2.2 Validate "kty" field heuristic if (jwk.kty !== "oct"){ throw new DataError('kty property must be "oct"') } // 2.2.3 Ensure jwk meets these requirements: // https://tools.ietf.org/html/rfc7518#section-6.4 if (!jwk.k){ throw new DataError('k property must not be empty') } // 2.2.4 Assign data data = base64url.toBuffer(jwk.k) // 2.2.5 Validate data lengths if (data.length === 16) { if (jwk.alg && jwk.alg !== 'A128KW'){ throw new DataError('Algorithm "A128KW" must be 128 bits in length') } } else if (data.length === 24) { if (jwk.alg && jwk.alg !== 'A192KW'){ throw new DataError('Algorithm "A192KW" must be 192 bits in length') } } else if (data.length === 32) { if (jwk.alg && jwk.alg !== 'A256KW'){ throw new DataError('Algorithm "A256KW" must be 256 bits in length') } } else { throw new DataError('Algorithm and data length mismatch') } // 2.2.6 Validate "use" field if (keyUsages && jwk.use && jwk.use !== 'enc'){ throw new DataError('Key use must be "enc"') } // 2.2.7 Validate "key_ops" field if (jwk.key_ops){ jwk.key_ops.forEach(op => { if (op !== 'encrypt' && op !== 'decrypt' && op !== 'wrapKey' && op !== 'unwrapKey') { throw new DataError('Key operation can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) } // 2.2.8 validate "ext" field if (jwk.ext === false && extractable === true){ throw new DataError('Cannot be extractable when "ext" is set to false') } } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Generate new key let key = new CryptoKey({ type: 'secret', extractable, usages: keyUsages, handle: data }) // 4-6. Generate algorithm let aesAlgorithm = new AES_KW( { name: 'AES-KW', length: data.length * 8 }) // 7. Set algorithm to internal algorithm property of key key.algorithm = aesAlgorithm // 8. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { let result, data // 1. Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // 2.1 "raw" format if (format === 'raw'){ // 2.1.1 Let data be the raw octets of the key data = key.handle // 2.1.2 Let result be containing data result = Buffer.from(data) } // 2.2 "jwk" format else if (format === 'jwk'){ // 2.2.1 Validate JsonWebKey let jwk = new JsonWebKey() // 2.2.2 Set kty property jwk.kty = 'oct' // 2.2.3 Set k property jwk.k = base64url(key.handle) data = key.handle // 2.2.4 Validate length if (data.length === 16) { jwk.alg = 'A128KW' } else if (data.length === 24) { jwk.alg = 'A192KW' } else if (data.length === 32) { jwk.alg = 'A256KW' } // 2.2.5 Set keyops property jwk.key_ops = key.usages // 2.2.6 Set ext property jwk.ext = key.extractable // 2.2.7 Set result to the result of converting jwk to an ECMAScript object result = jwk } // 2.3 Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3. Return result return result } } /** * Export */ module.exports = AES_KWwebcrypto-0.9.2/src/algorithms/Algorithm.js000066400000000000000000000011731330022407200207570ustar00rootroot00000000000000/** * Algorithm */ class Algorithm { /** * constructor * * @description * The Algorithm object is a dictionary object [WebIDL] which is used * to specify an algorithm and any additional parameters required to * fully specify the desired operation. * * @param {string|Object} algorithm */ constructor (algorithm) { if (typeof algorithm === 'string') { this.name = algorithm } else { Object.assign(this, algorithm) if (typeof this.name !== 'string') { throw new Error('Algorithm name must be a string') } } } } /** * Export */ module.exports = Algorithm webcrypto-0.9.2/src/algorithms/ECDSA.js000066400000000000000000000244411330022407200176530ustar00rootroot00000000000000/** * Package dependencies */ const base64url = require('base64url') const crypto = require('crypto') const {spawnSync} = require('child_process') const {TextEncoder, TextDecoder} = require('text-encoding') const keyto = require('@trust/keyto') /** * Local dependencies */ const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const CryptoKeyPair = require('../keys/CryptoKeyPair') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const EcKeyAlgorithm = require('../dictionaries/EcKeyAlgorithm') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * ECDSA */ class ECDSA extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, EcKeyAlgorithm ] } /** * members */ static get members () { return { name: String, namedCurve: String, hash: 'HashAlgorithmIdentifier' } } /** * sign * * @description * Create a digital signature * * @param {CryptoKey} key * @param {BufferSource} data * * @returns {ArrayBuffer} */ sign (key, data) { let result // 1. Ensure the key is a private type only if (key.type !== 'private') { throw new InvalidAccessError('Signing requires a private key') } // 2-5. Ommitted due to support by Crypto // 6. Attempt to sign using Crypto lib try { let osslCurveName = EcKeyAlgorithm.mapping.find(alg => alg.namedCurve === key.algorithm.namedCurve) data = Buffer.from(data) let signer = crypto.createSign(osslCurveName.hash) signer.update(data) result = signer.sign(key.handle) } catch (error) { throw new OperationError(error.message) } // 7. Return resulting buffer return result.buffer }//sign /** * verify * * @description * Verifies a digital signature * * @param {CryptoKey} key * @param {BufferSource} signature * @param {BufferSource} data * * @returns {Boolean} */ verify (key, signature, data) { let result // 1. Ensure the key is a public type only if (key.type !== 'public') { throw new InvalidAccessError('Verifying requires a public key') } // 2-5. Ommitted due to support by Crypto // 6. Attempt to verify using Crypto lib try { let osslCurveName = EcKeyAlgorithm.mapping.find(alg => alg.namedCurve === key.algorithm.namedCurve) data = Buffer.from(data) signature = Buffer.from(signature) let verifier = crypto.createVerify(osslCurveName.hash) verifier.update(data) result = verifier.verify(key.handle, signature) } catch (error) { throw new OperationError(error.message) } return result }//verify /** * generateKey * * @description * Generate an ECDSA key pair * * @param {EcKeyGenParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Validate usages usages.forEach(usage => { if (usage !== 'sign' && usage !== 'verify') { throw new SyntaxError('Key usages can only include "sign", or "verify"') } }) // 2. Generate a keypair let keypair = {} let { namedCurve } = params if (!namedCurve) { throw new DataError('namedCurve is a required parameter for ECDSA') } if (!EcKeyAlgorithm.mapping.map(alg => alg.namedCurve).includes(namedCurve)) { throw new DataError('namedCurve is not valid') } let osslCurveName = EcKeyAlgorithm.mapping.find(alg => alg.namedCurve === namedCurve) try { // TODO may need to remove -noout if ec params is needed let privateKey = spawnSync('openssl', ['ecparam','-name',osslCurveName.name,'-genkey','-noout']).stdout let publicKey = spawnSync('openssl', ['ec', '-pubout'], { input: privateKey }).stdout try { keypair.privateKey = privateKey.toString('ascii').trim() keypair.publicKey = publicKey.toString('ascii').trim() } catch(error){ throw new OperationError(error.message) } } catch (error) { // 3. If any operation fails then throw error throw new OperationError(error.message) } // 4. Set algorithm be a new ECDSA let algorithm = new ECDSA(params) // 5-6. Set name to ECDSA // Defined in class header so it will be passed down via params // 7-11. Create publicKey object let publicKey = new CryptoKey({ type: 'public', algorithm, extractable: true, usages: ['verify'], handle: keypair.publicKey }) // 12-16. Create privateKey object let privateKey = new CryptoKey({ type: 'private', algorithm, extractable, usages: ['sign'], handle: keypair.privateKey }) // 17-20. Create and return a new CryptoKeyPair return new CryptoKeyPair({publicKey,privateKey}) }//generateKey /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let key, hash, normalizedHash, jwk, privateKeyInfo // 1-2. Check formatting // 2.1. "spki" format if (format === 'spki') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.2. "pkcs8" format else if (format === 'pkcs8') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.3. "jwk" format else if (format === 'jwk') { // 2.3.1 Ensure data is JsonWebKey dictionary if (typeof keyData === 'object' && !Array.isArray(keyData)){ jwk = new JsonWebKey(keyData) } else { throw new DataError('Invalid jwk format') } // 2.3.2. Ensure 'd' field and keyUsages match up if (jwk.d !== undefined && keyUsages.some(usage => usage !== 'sign')) { throw new SyntaxError('Key usages must include "sign"') } if (jwk.d === undefined && !keyUsages.some(usage => usage === 'verify')) { throw new SyntaxError('Key usages must include "verify"') } // 2.3.3 Validate 'kty' field if (jwk.kty !== 'EC'){ throw new DataError('Key type must be "EC".') } // 2.3.4. Validate 'use' field if (keyUsages !== undefined && jwk.use !== undefined && jwk.use !== 'sig'){ throw new DataError('Key use must be "sig".') } // 2.3.5. Validate 'key_ops' field if (jwk.key_ops !== undefined) { jwk.key_ops.forEach(op => { if (op !== 'sign' && op !== 'verify' ) { throw new DataError('Key operation can only include "sign", or "verify".') } }) } // 2.3.6. Validate 'ext' field if (jwk.ext !== undefined && jwk.ext === false && extractable === true){ throw new DataError('Cannot be extractable when "ext" is set to false') } // 2.3.7. Set namedCurve let namedCurve = jwk.crv // 2.3.8. Ommitted due to redundancy // 2.3.9.1. If namedCurve is equal to 'secp256k1' then... if (EcKeyAlgorithm.mapping.map(alg => alg.namedCurve).includes(namedCurve)){ // 2.3.9.1.1-3 Ommited due to redundancy // 2.3.9.1.4.1. Validate 'd' property if (jwk.d) { // 2.3.9.1.4.1.1. TODO jwk validation here... // 2.3.9.1.4.1.2-3 Generate new private CryptoKeyObject key = new CryptoKey({ type: 'private', extractable, usages: ['sign'], handle: keyto.from(jwk, 'jwk').toString('pem', 'private_pkcs1') }) } // 2.3.9.1.4.2. Otherwise... else { // 2.3.9.1.4.2.1. TODO jwk validation here... // 2.3.9.1.4.2.2-3 Generate new public CryptoKeyObject key = new CryptoKey({ type: 'public', extractable: true, usages: ['verify'], handle: keyto.from(jwk, 'jwk').toString('pem', 'public_pkcs8') }) } } // 2.3.9.2. Otherwise... else { // 2.3.9.2.1. TODO Implement further key import steps from other specs // 2.3.9.2.1. Throw error because there are currently no further specs throw new DataError ('Not a valid jwk specification') } // 2.3.10. Ommitted due to redudancy // 2.3.11-14 Set new alg object key.algorithm = new ECDSA(algorithm) } // 2.4. "raw" format else if (format === 'raw') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.5. Otherwise bad format else { throw new KeyFormatNotSupportedError(format) } // 3. Return key return key }//importKey /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { // 1. Setup resulting var let result // 2. Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // 3.1. "spki" format if (format === 'spki') { throw new CurrentlyNotSupportedError(format,"jwk' or 'raw") } // 3.2. "pkcs8" format else if (format === 'pkcs8') { throw new CurrentlyNotSupportedError(format,"jwk' or 'raw") } // 2.3. "jwk" format else if (format === 'jwk') { // 2.3.1-3 Create new jwk let jwk = keyto.from(key.handle, 'pem').toJwk(key.type) // 2.3.4. Set "key_ops" field jwk.key_ops = key.usages // 2.3.5. Set "ext" field jwk.ext = key.extractable // 2.3.6. Set result to jwk object result = jwk } // 3.4. "raw" format else if (format === 'raw') { // 3.4.1. Validate that the internal use is public if (key.type !== 'public'){ throw new InvalidAccessError('Can only access public key data.') } // 3.4.2. Omitted due to redundancy // 3.4.3. Let resulting data be Buffer containing data result = Buffer.from(key.handle) } // 3.5. Otherwise bad format else { throw new KeyFormatNotSupportedError(format) } // 4. Result result return result } }//ECDSA /** * Export */ module.exports = ECDSA webcrypto-0.9.2/src/algorithms/EDDSA.js000066400000000000000000000332141330022407200176520ustar00rootroot00000000000000/** * Package dependencies */ const base64url = require('base64url') const crypto = require('crypto') const {spawnSync} = require('child_process') const {TextEncoder, TextDecoder} = require('text-encoding') const keyto = require('@trust/keyto') const elEdDSA = require('elliptic').eddsa; const elliptic = require('elliptic') /** * Local dependencies */ const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const CryptoKeyPair = require('../keys/CryptoKeyPair') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const EcKeyAlgorithm = require('../dictionaries/EcKeyAlgorithm') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * Key Mappings */ const EddsaCurves = [ {namedCurve: 'Ed25519', name: 'ed25519', alg: 'Ed25519'} ] /** * EDDSA */ class EDDSA extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, EcKeyAlgorithm ] } /** * members */ static get members () { return { name: String, namedCurve: String } } /** * sign * * @description * Create a digital signature * * @param {CryptoKey} key * @param {BufferSource} data * * @returns {ArrayBuffer} */ sign (key, data) { let result // Ensure the key is a private type only if (key.type !== 'private'){ throw new InvalidAccessError('Signing requires a private key') } // Ensure data is hex string, array or Buffer if (!Array.isArray(data) && !Buffer.isBuffer(data) && typeof data !== 'string'){ throw new DataError('Data must be an Array, Buffer or hex string') } // Ensure key.handle is hex string, array or Buffer if (!Array.isArray(key.handle) && !Buffer.isBuffer(key.handle) && typeof key.handle !== 'string' ){ throw new DataError('Key handle must be an Array, Buffer or hex string') } try { // Normalize curve let curveName = EddsaCurves.find(alg => alg.namedCurve === key.algorithm.namedCurve) // Create curve via elliptic let ec = new elEdDSA(curveName.name) // Generate keypair from private key let ecKey if (typeof key.handle === 'string'){ ecKey = ec.keyFromSecret(key.handle, 'hex') } else { ecKey = ec.keyFromSecret(key.handle) } // Perform the signing result = ecKey.sign(data).toHex() } catch (error) { throw new OperationError(error.message) } // Return resulting buffer return Uint8Array.from(Buffer.from(result,'hex')).buffer }//sign /** * verify * * @description * Verifies a digital signature * * @param {CryptoKey} key * @param {BufferSource} signature * @param {BufferSource} data * * @returns {Boolean} */ verify (key, signature, data) { let result // Ensure the key is a public if (key.type !== 'public') { throw new InvalidAccessError('Verifying requires a public key') } // Ensure data is hex string, array or Buffer if (!Array.isArray(data) && !Buffer.isBuffer(data) && typeof data !== 'string'){ throw new DataError('Data must be an Array, Buffer or hex string') } // Ensure key.handle is hex string, array or Buffer if (!Array.isArray(key.handle) && !Buffer.isBuffer(key.handle) && typeof key.handle !== 'string' ){ throw DataError('Key handle must be an Array, Buffer or hex string') } // Ensure signature is ArrayBuffer or hex string if (!signature instanceof ArrayBuffer && typeof signature !== 'string'){ throw DataError('Signature must be an ArrayBuffer or hex string') } try { // Normalize curve let curveName = EddsaCurves.find(alg => alg.namedCurve === key.algorithm.namedCurve) // Create curve via elliptic let ec = new elEdDSA(curveName.name) // Generate keypair from key let ecKey if (key.type === 'public'){ if (typeof key.handle === 'string'){ ecKey = ec.keyFromPublic(key.handle, 'hex') } else { ecKey = ec.keyFromPublic(key.handle.toString('hex'),'hex') } } else { throw new OperationError("Invalid key type") } // Convert ArrayBuffer back to hex if (signature instanceof ArrayBuffer){ signature = Buffer.from(signature).toString('hex') } // Perform the verification result = ecKey.verify(data,signature) } catch (error) { throw new OperationError(error.message) } // Return boolean result return result }//verify /** * generateKey * * @description * Generate an EDDSA key pair * * @param {EcKeyGenParams} params * @returns {CryptoKey} */ generateKey (params, extractable, usages) { // Validate usages usages.forEach(usage => { if (usage !== 'sign' && usage !== 'verify') { throw new SyntaxError('Key usages can only include "sign", or "verify"') } }) // Normalize Curve Name let { namedCurve } = params if (!namedCurve) { throw new DataError('namedCurve is a required parameter for EDDSA') } if (!EddsaCurves.map(alg => alg.namedCurve).includes(namedCurve)) { throw new DataError('namedCurve is not valid') } // Generate random key for scret portion let secretBytes = crypto.randomBytes(32) // Normalize curve let curveName = EddsaCurves.find(alg => alg.namedCurve === namedCurve) // Create curve via elliptic let ec = new elEdDSA(curveName.name) let ecKey = ec.keyFromSecret(secretBytes) let pubKey = Buffer.from(ecKey.pubBytes()) // Set algorithm be a new EDDSA let algorithm = new EDDSA(params) // Create private key object let privateKey = new CryptoKey({ type: 'private', algorithm, extractable, usages: ['sign'], handle: secretBytes }) // Create public key object let publicKey = new CryptoKey({ type: 'public', algorithm, extractable: true, usages: ['verify'], handle: pubKey }) // Return the generated Key return new CryptoKeyPair({publicKey,privateKey}) }//generateKey /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsage * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let key, hash, normalizedHash, jwk, privateKeyInfo // Check formatting // "spki" format if (format === 'spki') { throw new CurrentlyNotSupportedError(format,'jwk') } // "pkcs8" format else if (format === 'pkcs8') { throw new CurrentlyNotSupportedError(format,'jwk') } // "jwk" format else if (format === 'jwk') { // Ensure data is JsonWebKey dictionary if (typeof keyData === 'object' && !Array.isArray(keyData)){ jwk = new JsonWebKey(keyData) } else { throw new DataError('Invalid jwk format') } // Ensure 'd' field and keyUsages match up if (jwk.d !== undefined && keyUsages.some(usage => usage !== 'sign')) { throw new SyntaxError('Key usages must include "sign"') } if (jwk.d === undefined && !keyUsages.some(usage => usage === 'verify')) { throw new SyntaxError('Key usages must include "verify"') } // Validate 'kty' field if (jwk.kty !== 'OKP'){ throw new DataError('Key type must be "OKP".') } // Validate 'crv' field let namedCurve = jwk.crv if (!EddsaCurves.map(alg => alg.namedCurve).includes(namedCurve)){ throw new DataError('Invalid curve type for EDDSA.') } // Validate 'key_ops' field if (jwk.key_ops !== undefined){ jwk.key_ops.forEach(op => { if (op !== 'sign' && op !== 'verify' ) { throw new DataError('Key operation can only include "sign", or "verify".') } }) } // Validate 'd' property if (jwk.d && jwk.x){ try { // Generate new private CryptoKeyObject key = new CryptoKey({ type: 'private', extractable, usages: ['sign'], handle: base64url.toBuffer(jwk.d) }) } catch (error) { throw new DataError('Invalid "d" field value.') } } // Validate 'x' property else if(jwk.x){ // Generate new public CryptoKeyObject try { key = new CryptoKey({ type: 'public', extractable: true, usages: ['verify'], handle: base64url.toBuffer(jwk.x) }) } catch (error) { throw new DataError('Invalid "x" field value.') } } else { throw new DataError('Unknown jwk format, missing "x" and "d" fields.') } // Ensure the key length if (key.handle.length !== 32){ throw new DataError('Key handle must be 32 bytes in length.') } // Set new alg object key.algorithm = new EDDSA(algorithm) } // "raw" format else if (format === 'raw') { throw new CurrentlyNotSupportedError(format,'jwk') } // "hex" format else if (format === 'hex'){ // Ensure data is object if (typeof keyData !== 'object'){ throw new DataError('Invalid hex format') } // Determine if the type is valid if (!['private','public'].includes(keyData.type)){ throw new DataError(`Key type can only be "private" or "public".`) } // Determine if the size of the hex is valid if ( typeof keyData.hex !== 'string' || keyData.hex.length !== 64 ){ throw new DataError(`Hex value must be a 64 byte string.`) } // Generate private key from hex if (keyData.type === 'private'){ // Ensure keyUsages match up if (keyUsages.some(usage => usage !== 'sign')) { throw new SyntaxError('Key usages must include "sign"') } // Generate new private CryptoKeyObject try { key = new CryptoKey({ type: 'private', extractable, usages: ['sign'], handle: Buffer.from(keyData.hex,'hex') }) } catch (error) { throw new DataError('Invalid private key hex.') } } // Generate public key from hex else if(keyData.type === 'public'){ // Ensure keyUsages match up if (!keyUsages.some(usage => usage === 'verify')) { throw new SyntaxError('Key usages must include "verify"') } // Generate new public CryptoKeyObject try { key = new CryptoKey({ type: 'public', extractable: true, usages: ['verify'], handle: Buffer.from(keyData.hex,'hex') }) } catch (error) { throw new DataError('Invalid public key hex.') } } else { throw new DataError('Unknown key type.') } // Ensure the key length if (key.handle.length !== 32){ throw new DataError('Key handle must be 32 bytes in length.') } // Set new alg object key.algorithm = new EDDSA(algorithm) } // Otherwise bad format else { throw new KeyFormatNotSupportedError(format) } // Return key return key }//importKey /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { // Setup resulting var let result // Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // Ensure data is accessible if (key.extractable !== true){ throw new InvalidAccessError('Key handle is not extractable.') } // "spki" format if (format === 'spki'){ throw new CurrentlyNotSupportedError(format,"jwk' or 'raw") } // "pkcs8" format else if (format === 'pkcs8'){ throw new CurrentlyNotSupportedError(format,"jwk' or 'raw") } // "jwk" format else if (format === 'jwk'){ // Create new jwk let jwk = new JsonWebKey({ "kty": "OKP", }) // Assign 'crv' to jwk jwk.crv = EddsaCurves.find(alg => alg.namedCurve === key.algorithm.namedCurve).namedCurve // If the key is Private then derive 'd' and 'x' let ec = new elEdDSA('ed25519') if (key.type === 'private'){ let ecKey = ec.keyFromSecret(key.handle) jwk.d = base64url(key.handle) jwk.x = base64url(ecKey.pubBytes()) } // If the key is Public then derive 'x' else if (key.type === 'public'){ let ecKey = ec.keyFromPublic(key.handle) jwk.x = base64url(ecKey.pubBytes()) } // Otherwise throw error else { throw new DataError ("Unknown key type.") } // Set "key_ops" field jwk.key_ops = key.usages // Set "ext" field jwk.ext = key.extractable // Set result to jwk object result = jwk } // "raw" format else if (format === 'raw'){ // Let resulting data be Buffer containing data result = Buffer.from(key.handle) } // "hex" format else if (format === 'hex'){ // Let resulting data be hex string containing data result = base64url(key.handle) } // Otherwise throw bad format else { throw new KeyFormatNotSupportedError(format) } // Result result return result } }//EDDSA /** * Export */ module.exports = EDDSAwebcrypto-0.9.2/src/algorithms/HMAC.js000066400000000000000000000161311330022407200175410ustar00rootroot00000000000000/** * Package dependencies */ const base64url = require('base64url') const crypto = require('crypto') /** * Local dependencies */ const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const HmacKeyAlgorithm = require('../dictionaries/HmacKeyAlgorithm') /** * Errors */ const { DataError, OperationError, NotSupportedError, KeyFormatNotSupportedError } = require('../errors') /** * HMAC */ class HMAC extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, HmacKeyAlgorithm ] } /** * members */ static get members () { return {} } /** * sign * * @description * Create a MAC * * @param {CryptoKey} key * @param {BufferSource} data * * @return {string} */ sign (key, data) { let alg = key.algorithm.hash.name.replace('-', '').toLowerCase() let hmac = crypto.createHmac(alg, key.handle) hmac.update(Buffer.from(data)) return new Uint8Array(hmac.digest()).buffer } /** * verify * * @description * Verify a MAC * * @param {CryptoKey} key * @param {BufferSource} signature * @param {BufferSource} data * * @returns {Boolean} */ verify (key, signature, data) { let mac = Buffer.from(this.sign(key, data)) return mac.equals(Buffer.from(signature)) } /** * generateKey * * @description * Generate HMAC key * * @param {HmacKeyGenParams} params * @param {Boolean} extractable * @param {Array} usages * * @returns {CryptoKey} */ generateKey (params, extractable, usages) { usages.forEach(usage => { if (usage !== 'sign' && usage !== 'verify') { throw new SyntaxError( 'Key usages can only include "sign" and "verify"' ) } }) let length if (params.length === undefined) { length = params.hash.name.match(/[0-9]+/)[0] } else if (params.length > 0) { length = params.length } else { throw new OperationError('Invalid HMAC length') } let generatedKey try { generatedKey = crypto.randomBytes(parseInt(length)) } catch (e) { throw new OperationError('Failed to generate HMAC key') } let key = new CryptoKey({ type: 'secret', algorithm: new HMAC({ name: 'HMAC', hash: new KeyAlgorithm({ name: params.hash.name }) }), extractable, usages, handle: generatedKey }) return key } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { keyUsages.forEach(usage => { if (usage !== 'sign' && usage !== 'verify') { throw new SyntaxError( 'Key usages can only include "sign" and "verify"' ) } }) let hash = new KeyAlgorithm({ name: 'HMAC' }) let data if (format === 'raw') { data = new Buffer(keyData) if (algorithm.hash) { hash = algorithm.hash } else { throw new TypeError('HmacKeyGenParams: hash: Missing or not an AlgorithmIdentifier') } } else if (format === 'jwk') { let jwk = new JsonWebKey(keyData) if (jwk.kty !== 'oct') { throw new DataError() } data = base64url.toBuffer(jwk.k) if (algorithm.hash !== undefined) { hash = algorithm.hash if (hash.name === 'SHA-1') { if (jwk.alg && jwk.alg !== 'HS1') { throw new DataError() } } else if (hash.name === 'SHA-256') { if (jwk.alg && jwk.alg !== 'HS256') { throw new DataError() } } else if (hash.name === 'SHA-384') { if (jwk.alg && jwk.alg !== 'HS384') { throw new DataError() } } else if (hash.name === 'SHA-512') { if (jwk.alg && jwk.alg !== 'HS512') { throw new DataError() } // TODO // "another applicable specification" //} else if () { // ... } else { throw new DataError() } } else { if (jwk.alg === undefined) { throw new DataError() } if (jwk.alg === 'HS1') { hash.name = 'SHA-1' } else if (jwk.alg === 'HS256') { hash.name = 'SHA-256' } else if (jwk.alg === 'HS384') { hash.name = 'SHA-384' } else if (jwk.alg === 'HS512') { hash.name = 'SHA-512' } else { // TODO // "other applicable specifications" } } if (jwk.use !== undefined && jwk.use !== 'sign') { throw new DataError() } if (jwk.key_ops !== undefined) { //if (jwk.key_ops ...?) { // throw new DataError() //} keyUsages.forEach(usage => { if (!jwk.key_ops.includes(usage)) { throw new DataError() } }) } if (jwk.ext === false && extractable === true) { throw new DataError() } } else { throw new KeyFormatNotSupportedError(format) } let length = data.length * 8 if (length === 0) { throw new DataError('HMAC key data must not be empty') } if (algorithm.length !== undefined) { if (algorithm.length > length) { throw new DataError() } else if (algorithm.length <= length - 8) { throw new DataError() } else { length = algorithm.length } } let key = new CryptoKey({ type: 'secret', algorithm: new HMAC({ name: 'HMAC', length, hash }), extractable, usages: keyUsages, handle: data }) return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { if (!(key instanceof CryptoKey) || key.handle === undefined) { throw new OperationError('argument must be CryptoKey') } let result if (format === 'raw') { let data = key.handle result = Buffer.from(data) } else if (format === 'jwk') { let jwk = new JsonWebKey({ kty: 'oct', k: base64url(key.handle) }) let algorithm = key.algorithm let hash = algorithm.hash if (hash.name === 'SHA-1') { jwk.alg = 'HS1' } else if (hash.name === 'SHA-256') { jwk.alg = 'HS256' } else if (hash.name === 'SHA-384') { jwk.alg = 'HS384' } else if (hash.name === 'SHA-512') { jwk.alg = 'HS512' } else { // TODO // "other applicable specifications" } jwk.key_ops = key.usages jwk.ext = key.extractable result = jwk } else { throw new KeyFormatNotSupportedError(format) } return result } } /** * Export */ module.exports = HMAC webcrypto-0.9.2/src/algorithms/RSA-OAEP.js000066400000000000000000000320101330022407200201720ustar00rootroot00000000000000/** * Package dependencies */ const crypto = require('crypto') const base64url = require('base64url') const keyto = require('@trust/keyto') const {spawnSync} = require('child_process') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../dictionaries/AesKeyAlgorithm') const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const CryptoKeyPair = require('../keys/CryptoKeyPair') const JsonWebKey = require('../keys/JsonWebKey') const RsaKeyAlgorithm = require('../dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../dictionaries/RsaHashedKeyAlgorithm') const supportedAlgorithms = require('../algorithms') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * RSA-OAEP */ class RSA_OAEP extends Algorithm { /** * Constructor */ constructor (algorithm) { super(algorithm) if (typeof algorithm === "object" && algorithm !== null ){ if (!algorithm.hash || !algorithm.hash.name){ throw new Error('Algorithm requires a valid hash object.') } } else { throw new Error('Algorithm must be an object with a name and hash.') } } /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, AesKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource' } } /** * encrypt * * @description * Encrypts an RSA-OAEP digital signature * * @param {RsaOaepParams} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ encrypt (algorithm, key, data) { let result // 1. Ensure the key is a public type only if (key.type !== 'public') { throw new InvalidAccessError('Encrypt requires a public key') } // 2. Assign label // TODO Investigate use for label within context let label if (algorithm.label !== undefined){ label = algorithm.label } else { label = "" } // TODO Remove this error once additional Node support is available. if (key.algorithm.hash.name !== 'SHA-1'){ throw new CurrentlyNotSupportedError(key.algorithm.hash.name,'SHA-1') } // 3-5. Attempt to encrypt using crypto lib try { data = Buffer.from(data) result = crypto.publicEncrypt( { key: key.handle, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }, data) } catch (error) { throw new OperationError(error.message) } // 7. Return resulting buffer return result.buffer } /** * decrypt * * @description * Decrypts an RSA-OAEP digital signature * * @param {AesKeyAlgorithm} algorithm * @param {CryptoKey} key * @param {BufferSource} data * * @returns {Array} */ decrypt (algorithm, key, data) { let result // 1. Ensure the key is a private type only if (key.type !== 'private') { throw new InvalidAccessError('Decrypt requires a private key') } // 2. Assign label let label if (algorithm.label !== undefined){ label = algorithm.label } else { label = "" } // TODO Remove this error once additional Node support is available. if (key.algorithm.hash.name !== 'SHA-1'){ throw new CurrentlyNotSupportedError(key.algorithm.hash.name,'SHA-1') } // 3-5. Attempt to decrypt using crypto lib try { data = Buffer.from(data) result = crypto.privateDecrypt({ key: key.handle, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }, data) } catch (error) { throw new OperationError(error.message) } // 7. Return resulting buffer return result.buffer } /** * generateKey * * @description * Generate an RSA-OAEP key pair * * @param {RsaOaepParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Validate usages usages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'decrypt' && usage !== 'wrapKey' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') } }) // 2. Generate RSA key pair let keypair = {} try { let {modulusLength,publicExponent} = params // Get the keypairs from openssl spawns let privateKey = spawnSync('openssl', ['genrsa', modulusLength || 4096]).stdout let publicKey = spawnSync('openssl', ['rsa', '-pubout'], { input: privateKey }).stdout // Convert to ascii strings keypair.privateKey = privateKey.toString('ascii') keypair.publicKey = publicKey.toString('ascii') } catch (error) { throw new OperationError(error.message) } // 4-8. Set new RSA-OAEP object with params carried over let algorithm = new RSA_OAEP(params) // 9-13. Create publicKey object let publicKey = new CryptoKey({ type: 'public', algorithm, extractable: true, usages: ['encrypt','wrapKey'], handle: keypair.publicKey }) // 14-18. Create privateKey object let privateKey = new CryptoKey({ type: 'private', algorithm, extractable: extractable, usages: ['decrypt','unwrapKey'], handle: keypair.privateKey }) // 19-22. Return Key CryptoKeyPair return new CryptoKeyPair({publicKey,privateKey}) } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let data, key, jwk, hash, normalizedHash // 1. Assignment of keyData is done in function param // 2.1. "spki" format if (format === 'spki') { // TODO Add support for spki throw new CurrentlyNotSupportedError(format,'jwk') } // 2.2. "pkcs8" format else if (format === 'pkcs8') { // TODO Add support for pkcs8 throw new CurrentlyNotSupportedError(format,'jwk') } // 2.3. "jwk" format else if (format === 'jwk') { // 2.3.1. Create new JWK using data jwk = new JsonWebKey(keyData) // 2.3.2. Validate present 'd' field and allowed usages if (jwk.d) { keyUsages.forEach(usage => { if (usage !== 'decrypt' && usage !== 'unwrapKey') { throw new SyntaxError('Key usages can only include "decrypt" or "unwrapKey"') } }) } // 2.3.3. Validate absent 'd' field and allowed usages if (jwk.d === undefined) { keyUsages.forEach(usage => { if (usage !== 'encrypt' && usage !== 'wrapKey') { throw new SyntaxError('Key usages can only include "encrypt" or "wrapKey"') } }) } // 2.3.4. Validate 'kty' field and allowed string match if (jwk.kty !== 'RSA') { throw new DataError('Key type must be RSA') } // 2.3.5. Validate present 'use' field and allowed string match if (jwk.use !== undefined && jwk.use !== 'sig') { throw new DataError('Key use must be "sig"') } // 2.3.6. Validate present 'key_ops' field if (jwk.key_ops !== undefined) { jwk.key_ops.forEach(op => { if (op !== 'encrypt' && op !== 'decrypt' && op !== 'wrapKey' && op !== 'unwrapKey' ) { throw new DataError('Key operation can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey".') } }) } // 2.3.7. Validate present 'ext' field if (jwk.ext !== undefined && jwk.ext === false && extractable === true){ throw new DataError('Cannot be extractable when "ext" is set to false') } // 2.3.8.1. 'alg' field is not present if (jwk.alg === undefined){ // Leave undefined } // 2.3.8.2. 'alg' field is "RSA-OAEP" else if (jwk.alg === 'RSA-OAEP'){ hash = 'SHA-1' } // 2.3.8.3. 'alg' field is "RSA-OAEP-256" else if (jwk.alg === 'RSA-OAEP-256'){ hash = 'SHA-256' } // 2.3.8.4. 'alg' field is "RSA-OAEP-384" else if (jwk.alg === 'RSA-OAEP-384'){ hash = 'SHA-384' } // 2.3.8.5. 'alg' field is "RSA-OAEP-512" else if (jwk.alg === 'RSA-OAEP-512'){ hash = 'SHA-512' } // 2.3.8.6. Otherwise... else { // TODO Perform alternative key import steps defined by other applicable specifications throw new CurrentlyNotSupportedError(jwk.alg,'RSA-OAEP') } // 2.3.9. If hash not undefined then... if (hash !== undefined){ // 2.3.9.1. Normalize the hash with alg set to 'hash', and op to 'digest' normalizedHash = supportedAlgorithms.normalize('digest', hash) // 2.3.9.2. Validate hash member of normalizedAlgorithm if (!normalizedHash || normalizedHash.name !== this.hash.name) { throw new DataError("Unknown hash or mismatched hash name.") } } // 2.3.10. Validate 'd' field... if (jwk.d) { // 2.3.10.1.1. TODO jwk validation here... // 2.3.10.1.2-5 Generate new private CryptoKeyObject key = new CryptoKey({ type: 'private', extractable, usages: ['decrypt'], handle: keyto.from(jwk, 'jwk').toString('pem', 'private_pkcs1') }) } // 2.3.10.2. Otherwise... else { // 2.3.10.2.1 TODO jwk validation here... // 2.3.10.2.2-5 Generate new public CryptoKeyObject key = new CryptoKey({ type: 'public', extractable: true, usages: ['encrypt'], handle: keyto.from(jwk, 'jwk').toString('pem', 'public_pkcs8') }) } } // 2.4. Otherwise... else { throw new KeyFormatNotSupportedError(format) } // 3-7. Create RsaHashedKeyAlgorithm let alg = new RSA_OAEP({ name: 'RSA-OAEP', modulusLength: (new Buffer(jwk.n, 'base64').length / 2) * 8, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: normalizedHash }) // 8. Set key.algorthm to alg key.algorithm = alg // 9. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { // 1. Setup resulting var let result // 2. Validate handle slot if (!key.handle) { throw new OperationError('Missing key material') } // 3.1. "spki" format if (format === 'spki') { throw new CurrentlyNotSupportedError(format,"jwk") } // 3.2. "pkcs8" format else if (format === 'pkcs8') { throw new CurrentlyNotSupportedError(format,"jwk") } // 2.3. "jwk" format else if (format === 'jwk') { // 2.3.1. Create new jwk let jwk = keyto.from(key.handle, 'pem').toJwk(key.type) // 2.3.2. Setting 'kty' value jwk.kty = "RSA" // 2.3.3. Determine alg from hash let hash = key.algorithm.hash.name // 2.3.3.1. Hash is "SHA-1" if (hash === 'SHA-1') { jwk.alg = 'RSA-OAEP' } // 2.3.3.2. Hash is "SHA-256" else if (hash === 'SHA-256') { jwk.alg = 'RSA-OAEP-256' } // 2.3.3.3. Hash is "SHA-384" else if (hash === 'SHA-384') { jwk.alg = 'RSA-OAEP-384' } // 2.3.3.4. Hash is "SHA-512" else if (hash === 'SHA-512') { jwk.alg = 'RSA-OAEP-512' } // 2.3.3.5. Hash is other value else { // TODO other applicable specifications throw new CurrentlyNotSupportedError(format,"SHA-1") } // 2.3.4-5. Assign corresponding field from JWA specification Object.assign(jwk, keyto.from(key.handle, 'pem').toJwk(key.type)) // 2.3.6. Set "key_ops" field jwk.key_ops = key.usages // 2.3.7. Set "ext" field jwk.ext = key.extractable // 2.3.8. Set result to jwk object result = jwk } // 3.4. Otherwise bad format else { throw new KeyFormatNotSupportedError(format) } // 4. Result result return result } } /** * Export */ module.exports = RSA_OAEPwebcrypto-0.9.2/src/algorithms/RSA-PSS.js000066400000000000000000000242401330022407200201210ustar00rootroot00000000000000/** * Package dependencies */ const crypto = require('crypto') const base64url = require('base64url').default const keyto = require('@trust/keyto') const {spawnSync} = require('child_process') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const CryptoKeyPair = require('../keys/CryptoKeyPair') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const RsaKeyAlgorithm = require('../dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../dictionaries/RsaHashedKeyAlgorithm') const supportedAlgorithms = require('../algorithms') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * RSA_PSS */ class RSA_PSS extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, RsaKeyAlgorithm, RsaHashedKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource', hash: 'HashAlgorithmIdentifier', } } /** * sign * * @description * Create an RSA-PSS digital signature * * @param {CryptoKey} key * @param {BufferSource} data * * @returns {ArrayBuffer} */ sign (key, data) { // 1. Ensure key type is 'private' only if (key.type !== 'private') { throw new InvalidAccessError('Signing requires a private key') } // Ensure saltLength exists if (this.saltLength === undefined){ throw new OperationError('saltLength must be a valid integer') } // Parametrize hash let hashName if (this.hash.name === 'SHA-1'){ hashName = 'sha1' } else if (this.hash.name === 'SHA-256'){ hashName = 'sha256' } else if (this.hash.name === 'SHA-384'){ hashName = 'sha384' } else if (this.hash.name === 'SHA-512'){ hashName = 'sha512' } else { throw new OperationError('Algorithm hash is an unknown format.') } // 2-5. Perform key signing and return result try { let pem = key.handle data = new TextDecoder().decode(data) let signer = crypto.createSign(hashName) signer.update(data) return signer.sign({ key: pem, saltLength: this.saltLength, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }).buffer } catch (error) { throw new OperationError(error.message) } } /** * verify * * @description * * @param {CryptoKey} key * @param {BufferSource} signature * @param {BufferSource} data * * @returns {Boolean} */ verify (key, signature, data) { // 1. Ensure key type is 'public' only if (key.type !== 'public') { throw new InvalidAccessError('Verifying requires a public key') } // Ensure saltLength exists if (this.saltLength === undefined){ throw new OperationError('saltLength must be a valid integer') } // Parametrize hash let hashName if (this.hash.name === 'SHA-1'){ hashName = 'sha1' } else if (this.hash.name === 'SHA-256'){ hashName = 'sha256' } else if (this.hash.name === 'SHA-384'){ hashName = 'sha384' } else if (this.hash.name === 'SHA-512'){ hashName = 'sha512' } else { throw new OperationError('Algorithm hash is an unknown format.') } // 2-4. Perform verification and return result try { let pem = key.handle data = Buffer.from(data) signature = Buffer.from(signature) let verifier = crypto.createVerify(hashName) verifier.update(data) return verifier.verify({ key: pem, saltLength: this.saltLength, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }, signature) } catch (error) { throw new OperationError(error.message) } } /** * generateKey * * @description * Generate an RSA key pair * * @param {RsaHashedKeyGenParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Verify usages usages.forEach(usage => { if (usage !== 'sign' && usage !== 'verify') { throw new SyntaxError('Key usages can only include "sign" and "verify"') } }) let keypair = {} // 2. Generate RSA keypair try { let {modulusLength,publicExponent} = params // TODO // - fallback on node-rsa if OpenSSL is not available on the system let privateKey = spawnSync('openssl', ['genrsa', modulusLength || 4096]).stdout let publicKey = spawnSync('openssl', ['rsa', '-pubout'], { input: privateKey }).stdout try { keypair.privateKey = privateKey.toString('ascii') keypair.publicKey = publicKey.toString('ascii') } catch (error){ throw new OperationError(error.message) } // 3. Throw operation error if anything fails } catch (error) { throw new OperationError(error.message) } // 4-9. Create and assign algorithm object let algorithm = new RSA_PSS(params) // 10-13. Instantiate publicKey let publicKey = new CryptoKey({ type: 'public', algorithm, extractable: true, usages: ['verify'], handle: keypair.publicKey }) // 14-18. Instantiate privateKey let privateKey = new CryptoKey({ type: 'private', algorithm, extractable: extractable, usages: ['sign'], handle: keypair.privateKey }) // 19-22. Create and return a new keypair return new CryptoKeyPair({publicKey,privateKey}) } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let key, hash, normalizedHash, jwk // 1. Performed in function parameters // 2.1. "spki" format if (format === 'spki') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.2. "pkcs8" format else if (format === 'pkcs8') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.3. "jwk" format else if (format === 'jwk') { // 2.3.1. Cast keyData to JWK object jwk = new JsonWebKey(keyData) // 2.3.2. Verify 'd' field if (jwk.d && keyUsages.some(usage => usage !== 'sign')) { throw new SyntaxError('Key usages must include "sign"') } if (jwk.d === undefined && !keyUsages.some(usage => usage === 'verify')) { throw new SyntaxError('Key usages must include "verify"') } // 2.3.3. Verify 'kty' field if (jwk.kty !== 'RSA') { throw new DataError('Key type must be RSA') } // 2.3.4. Verify 'use' field if (jwk.use !== undefined && jwk.use !== 'sig') { throw new DataError('Key use must be "sig"') } // 2.3.5. Validate present 'use' field and allowed string match if (jwk.use !== undefined && jwk.use !== 'sig') { throw new DataError('Key use must be "sig"') } // 2.3.6. Validate present 'key_ops' field if (jwk.key_ops !== undefined) { jwk.key_ops.forEach(op => { if (op !== 'sign' && op !== 'verify') { throw new DataError('Key operation can only include "sign", and "verify".') } }) } // 2.3.7-8. Determine hash name if (jwk.alg === undefined) { // keep undefined } else if (jwk.alg === 'PS1') { hash = 'SHA-1' } else if (jwk.alg === 'PS256') { hash = 'SHA-256' } else if (jwk.alg === 'PS384') { hash = 'SHA-384' } else if (jwk.alg === 'PS512') { hash = 'SHA-512' } else { throw new DataError( 'Key alg must be "PS1", "PS256", "PS384", or "PS512"' ) } // 2.3.9. Ommited due to redundancy if (hash !== undefined) { normalizedHash = supportedAlgorithms.normalize('digest', hash) } // 2.3.10. Verify 'd' field if (jwk.d) { key = new CryptoKey({ type: 'private', extractable: extractable, usages: ['sign'], handle: keyto.from(jwk, 'jwk').toString('pem', 'private_pkcs1') }) } else { key = new CryptoKey({ type: 'public', extractable: true, usages: ['verify'], handle: keyto.from(jwk, 'jwk').toString('pem', 'public_pkcs8') }) } } else { throw new KeyFormatNotSupportedError(format) } // 3-7. Setup RSA PSS object let alg = new RSA_PSS({ name: 'RSA-PSS', modulusLength: base64url.toBuffer(jwk.n).length * 8, publicExponent: new Uint8Array(base64url.toBuffer(jwk.e)), hash: normalizedHash }) // 8. Set algorithm of key to alg key.algorithm = alg // 9. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { let result if (!key.handle) { throw new OperationError('Missing key material') } if (format === 'spki') { // TODO } else if (format === 'pkcs8') { // TODO } else if (format === 'jwk') { let jwk = new JsonWebKey({ kty: 'RSA' }) let hash = key.algorithm.hash.name if (hash === 'SHA-1') { jwk.alg = 'PS1' } else if (hash === 'SHA-256') { jwk.alg = 'PS256' } else if (hash === 'SHA-384') { jwk.alg = 'PS384' } else if (hash === 'SHA-512') { jwk.alg = 'PS512' } else { // TODO other applicable specifications } Object.assign(jwk, keyto.from(key.handle, 'pem').toJwk(key.type)) jwk.key_ops = key.usages jwk.ext = key.extractable // conversion to ECMAScript Object is implicit result = jwk } else { throw new KeyFormatNotSupportedError(format) } return result } } /** * Export */ module.exports = RSA_PSSwebcrypto-0.9.2/src/algorithms/RSASSA-PKCS1-v1_5.js000066400000000000000000000236631330022407200214240ustar00rootroot00000000000000/** * Package dependencies */ const RSA = require('node-rsa') const crypto = require('crypto') const {spawnSync} = require('child_process') const keyto = require('@trust/keyto') const {TextEncoder, TextDecoder} = require('text-encoding') const base64url = require('base64url').default /** * Local dependencies */ const Algorithm = require ('../algorithms/Algorithm') const CryptoKey = require('../keys/CryptoKey') const CryptoKeyPair = require('../keys/CryptoKeyPair') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const RsaKeyAlgorithm = require('../dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../dictionaries/RsaHashedKeyAlgorithm') const supportedAlgorithms = require('../algorithms') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError, CurrentlyNotSupportedError } = require('../errors') /** * RSASSA_PKCS1_v1_5 */ class RSASSA_PKCS1_v1_5 extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, RsaKeyAlgorithm, RsaHashedKeyAlgorithm ] } /** * members */ static get members () { return { name: String, modulusLength: Number, publicExponent: 'BufferSource', hash: 'HashAlgorithmIdentifier' } } /** * sign * * @description * Create an RSA digital signature * * @param {CryptoKey} key * @param {BufferSource} data * * @returns {ArrayBuffer} */ sign (key, data) { // 1. Ensure key type is 'private' only if (key.type !== 'private') { throw new InvalidAccessError('Signing requires a private key') } // Parametrize hash let hashName if (this.hash.name === 'SHA-1'){ hashName = 'RSA-SHA1' } else if (this.hash.name === 'SHA-256'){ hashName = 'RSA-SHA256' } else if (this.hash.name === 'SHA-384'){ hashName = 'RSA-SHA384' } else if (this.hash.name === 'SHA-512'){ hashName = 'RSA-SHA512' } else { throw new OperationError('Algorithm hash is an unknown format.') } // 2-5. Perform key signing and return result try { let pem = key.handle data = new TextDecoder().decode(data) let signer = crypto.createSign(hashName) signer.update(data) return signer.sign(pem).buffer } catch (error) { throw new OperationError(error.message) } } /** * verify * * @description * * @param {CryptoKey} key * @param {BufferSource} signature * @param {BufferSource} data * * @returns {Boolean} */ verify (key, signature, data) { // 1. Ensure key type is 'public' only if (key.type !== 'public') { throw new InvalidAccessError('Verifying requires a public key') } // Parametrize hash let hashName if (this.hash.name === 'SHA-1'){ hashName = 'RSA-SHA1' } else if (this.hash.name === 'SHA-256'){ hashName = 'RSA-SHA256' } else if (this.hash.name === 'SHA-384'){ hashName = 'RSA-SHA384' } else if (this.hash.name === 'SHA-512'){ hashName = 'RSA-SHA512' } else { throw new OperationError('Algorithm hash is an unknown format.') } // 2-4. Perform verification and return result try { let pem = key.handle data = Buffer.from(data) signature = Buffer.from(signature) let verifier = crypto.createVerify(hashName) verifier.update(data) return verifier.verify(pem, signature) } catch (error) { throw new OperationError(error.message) } } /** * generateKey * * @description * Generate an RSA key pair * * @param {RsaHashedKeyGenParams} params * @returns {CryptoKeyPair} */ generateKey (params, extractable, usages) { // 1. Verify usages usages.forEach(usage => { if (usage !== 'sign' && usage !== 'verify') { throw new SyntaxError('Key usages can only include "sign" and "verify"') } }) let keypair = {} // 2. Generate RSA keypair try { let {modulusLength,publicExponent} = params // TODO // - fallback on node-rsa if OpenSSL is not available on the system let privateKey = spawnSync('openssl', ['genrsa', modulusLength || 4096]).stdout let publicKey = spawnSync('openssl', ['rsa', '-pubout'], { input: privateKey }).stdout try { keypair.privateKey = privateKey.toString('ascii') keypair.publicKey = publicKey.toString('ascii') } catch (error){ throw new OperationError(error.message) } // 3. Throw operation error if anything fails } catch (error) { throw new OperationError(error.message) } // 4-9. Create and assign algorithm object let algorithm = new RSASSA_PKCS1_v1_5(params) // 10-13. Instantiate publicKey let publicKey = new CryptoKey({ type: 'public', algorithm, extractable: true, usages: ['verify'], handle: keypair.publicKey }) // 14-18. Instantiate privateKey let privateKey = new CryptoKey({ type: 'private', algorithm, extractable: extractable, usages: ['sign'], handle: keypair.privateKey }) // 19-22. Create and return a new keypair return new CryptoKeyPair({publicKey,privateKey}) } /** * importKey * * @description * * @param {string} format * @param {string|JsonWebKey} keyData * @param {KeyAlgorithm} algorithm * @param {Boolean} extractable * @param {Array} keyUsages * * @returns {CryptoKey} */ importKey (format, keyData, algorithm, extractable, keyUsages) { let key, hash, normalizedHash, jwk // 1. Performed in function parameters // 2.1. "spki" format if (format === 'spki') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.2. "pkcs8" format else if (format === 'pkcs8') { throw new CurrentlyNotSupportedError(format,'jwk') } // 2.3. "jwk" format else if (format === 'jwk') { // 2.3.1. Cast keyData to JWK object jwk = new JsonWebKey(keyData) // 2.3.2. Verify 'd' field if (jwk.d && keyUsages.some(usage => usage !== 'sign')) { throw new SyntaxError('Key usages must include "sign"') } if (jwk.d === undefined && !keyUsages.some(usage => usage === 'verify')) { throw new SyntaxError('Key usages must include "verify"') } // 2.3.3. Verify 'kty' field if (jwk.kty !== 'RSA') { throw new DataError('Key type must be RSA') } // 2.3.4. Verify 'use' field if (jwk.use !== undefined && jwk.use !== 'sig') { throw new DataError('Key use must be "sig"') } // 2.3.5. Validate present 'use' field and allowed string match if (jwk.use !== undefined && jwk.use !== 'sig') { throw new DataError('Key use must be "sig"') } // 2.3.6. Validate present 'key_ops' field if (jwk.key_ops !== undefined) { jwk.key_ops.forEach(op => { if (op !== 'sign' && op !== 'verify') { throw new DataError('Key operation can only include "sign", and "verify".') } }) } // 2.3.7-8. Determine hash name if (jwk.alg === undefined) { // keep undefined } else if (jwk.alg === 'RS1') { hash = 'SHA-1' } else if (jwk.alg === 'RS256') { hash = 'SHA-256' } else if (jwk.alg === 'RS384') { hash = 'SHA-384' } else if (jwk.alg === 'RS512') { hash = 'SHA-512' } else { throw new DataError( 'Key alg must be "RS1", "RS256", "RS384", or "RS512"' ) } // 2.3.9. Ommited due to redundancy, uncomment if needed if (hash !== undefined) { normalizedHash = supportedAlgorithms.normalize('digest', hash) //if (normalizedHash !== normalizedAlgorithm.hash) { // throw new DataError() //} } // 2.3.10. Verify 'd' field if (jwk.d) { key = new CryptoKey({ type: 'private', extractable: extractable, usages: ['sign'], handle: keyto.from(jwk, 'jwk').toString('pem', 'private_pkcs1') }) } else { key = new CryptoKey({ type: 'public', extractable: true, usages: ['verify'], handle: keyto.from(jwk, 'jwk').toString('pem', 'public_pkcs8') }) } } else { throw new KeyFormatNotSupportedError(format) } // 3-7. Setup RSSASSA object let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', modulusLength: base64url.toBuffer(jwk.n).length * 8, publicExponent: new Uint8Array(base64url.toBuffer(jwk.e)), hash: normalizedHash }) // 8. Set algorithm of key to alg key.algorithm = alg // 9. Return key return key } /** * exportKey * * @description * * @param {string} format * @param {CryptoKey} key * * @returns {*} */ exportKey (format, key) { let result // TODO // - should we type check key here? if (!key.handle) { throw new OperationError('Missing key material') } if (format === 'spki') { // TODO } else if (format === 'pkcs8') { // TODO } else if (format === 'jwk') { let jwk = new JsonWebKey({ kty: 'RSA' }) let hash = key.algorithm.hash.name if (hash === 'SHA-1') { jwk.alg = 'RS1' } else if (hash === 'SHA-256') { jwk.alg = 'RS256' } else if (hash === 'SHA-384') { jwk.alg = 'RS384' } else if (hash === 'SHA-512') { jwk.alg = 'RS512' } else { // TODO other applicable specifications } Object.assign(jwk, keyto.from(key.handle, 'pem').toJwk(key.type)) jwk.key_ops = key.usages jwk.ext = key.extractable // conversion to ECMAScript Object is implicit result = jwk } else { throw new KeyFormatNotSupportedError(format) } return result } } /** * Export */ module.exports = RSASSA_PKCS1_v1_5 webcrypto-0.9.2/src/algorithms/RegisteredAlgorithms.js000066400000000000000000000007571330022407200231670ustar00rootroot00000000000000/** * RegisteredAlgorithms */ class RegisteredAlgorithms { /** * Constructor * * @param {Object} mapping */ constructor (mapping) { Object.assign(this, mapping) } /** * getCaseInsensitive * * @param {string} algName * @returns {string} */ getCaseInsensitive (algName) { for (let key in this) { if (key.match(new RegExp(`^${algName}$`, 'i'))) { return key } } } } /** * Export */ module.exports = RegisteredAlgorithms webcrypto-0.9.2/src/algorithms/SHA.js000066400000000000000000000027461330022407200174530ustar00rootroot00000000000000/** * Module dependencies */ const Algorithm = require ('../algorithms/Algorithm') const crypto = require('crypto') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const ShaKeyAlgorithm = require('../dictionaries/ShaKeyAlgorithm') const {OperationError} = require('../errors') /** * SHA */ class SHA extends Algorithm { /** * dictionaries */ static get dictionaries () { return [ KeyAlgorithm, ShaKeyAlgorithm ] } /** * members */ static get members () { return {} } /** * digest * * @description * * @param {AlgorithmIdentifier} algorithm * @param {BufferSource} data * * @returns {Uint8Array} */ digest (algorithm, data) { let result let {name} = algorithm data = Buffer.from(data) if (name === 'SHA-1') { let hash = crypto.createHash('sha1') hash.update(data) result = hash.digest() } else if (name === 'SHA-256') { let hash = crypto.createHash('sha256') hash.update(data) result = hash.digest() } else if (name === 'SHA-384') { let hash = crypto.createHash('sha384') hash.update(data) result = hash.digest() } else if (name === 'SHA-512') { let hash = crypto.createHash('sha512') hash.update(data) result = hash.digest() } else { throw new OperationError(`${name} is not a supported algorithm`) } return Uint8Array.from(result).buffer } } /** * Export */ module.exports = SHA webcrypto-0.9.2/src/algorithms/SupportedAlgorithms.js000066400000000000000000000054551330022407200230570ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('../dictionaries/Algorithm') const KeyAlgorithm = require('../dictionaries/KeyAlgorithm') const RegisteredAlgorithms = require('./RegisteredAlgorithms') const {NotSupportedError} = require('../errors') /** * Supported Operations */ const operations = [ 'encrypt', 'decrypt', 'sign', 'verify', 'deriveBits', 'digest', // THIS WASN'T IN THE LIST. PROBABLY GETTING SOMETHING WRONG HERE 'wrapKey', 'unwrapKey', 'generateKey', 'importKey', 'exportKey', 'getLength' ] /** * SupportedAlgorithms */ class SupportedAlgorithms { /** * Constructor */ constructor () { operations.forEach(op => { this[op] = new RegisteredAlgorithms() }) } /** * Supported Operations */ static get operations () { return operations } /** * Define Algorithm */ define (alg, op, type) { let registeredAlgorithms = this[op] registeredAlgorithms[alg] = type } /** * Normalize */ normalize (op, alg) { if (typeof alg === 'string') { return this.normalize(op, new KeyAlgorithm({ name: alg })) } if (typeof alg === 'object') { let registeredAlgorithms = this[op] let initialAlg try { initialAlg = new Algorithm(alg) } catch (error) { return error } let algName = initialAlg.name algName = registeredAlgorithms.getCaseInsensitive(algName) if (algName === undefined) { return new NotSupportedError(alg.name) } let desiredType, normalizedAlgorithm try { desiredType = require(registeredAlgorithms[algName]) normalizedAlgorithm = new desiredType(alg) normalizedAlgorithm.name = algName } catch (error) { return error } let dictionaries = desiredType.dictionaries for (let i = 0; i < dictionaries.length; i++) { let dictionary = dictionaries[i] let members = dictionary.members for (let key in members) { let member = members[key] let idlValue = normalizedAlgorithm[key] try { if (member === 'BufferSource' && idlValue !== undefined) { normalizedAlgorithm[key] = idlValue.slice() } if (member === 'HashAlgorithmIdentifier') { let hashAlgorithm = this.normalize('digest', idlValue) if (hashAlgorithm instanceof Error) { return hashAlgorithm } normalizedAlgorithm[key] = hashAlgorithm } if (member === 'AlgorithmIdentifier') { normalizedAlgorithm[key] = this.normalize(WTF, idlValue) } } catch (error) { return error } } } return normalizedAlgorithm } } } /** * Export */ module.exports = SupportedAlgorithms webcrypto-0.9.2/src/algorithms/index.js000066400000000000000000000153431330022407200201440ustar00rootroot00000000000000/** * Local dependencies */ const SupportedAlgorithms = require('./SupportedAlgorithms') /** * Register Supported Algorithms */ const supportedAlgorithms = new SupportedAlgorithms() /** * encrypt */ supportedAlgorithms.define('RSA-OAEP', 'encrypt', '../algorithms/RSA-OAEP') supportedAlgorithms.define('AES-CTR', 'encrypt', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'encrypt', '../algorithms/AES-CBC') supportedAlgorithms.define('AES-GCM', 'encrypt', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'encrypt', ) /** * decrypt */ supportedAlgorithms.define('RSA-OAEP', 'decrypt', '../algorithms/RSA-OAEP') supportedAlgorithms.define('AES-CTR', 'decrypt', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'decrypt', '../algorithms/AES-CBC') supportedAlgorithms.define('AES-GCM', 'decrypt', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'decrypt', ) /** * sign */ supportedAlgorithms.define('RSASSA-PKCS1-v1_5', 'sign', '../algorithms/RSASSA-PKCS1-v1_5') supportedAlgorithms.define('RSA-PSS', 'sign', '../algorithms/RSA-PSS') supportedAlgorithms.define('ECDSA', 'sign', '../algorithms/ECDSA') supportedAlgorithms.define('EDDSA', 'sign', '../algorithms/EDDSA') //supportedAlgorithms.define('AES-CMAC', 'sign', ) supportedAlgorithms.define('HMAC', 'sign', '../algorithms/HMAC') /** * verify */ supportedAlgorithms.define('RSASSA-PKCS1-v1_5', 'verify', '../algorithms/RSASSA-PKCS1-v1_5') supportedAlgorithms.define('RSA-PSS', 'verify', '../algorithms/RSA-PSS') supportedAlgorithms.define('ECDSA', 'verify', '../algorithms/ECDSA') supportedAlgorithms.define('EDDSA', 'verify', '../algorithms/EDDSA') //supportedAlgorithms.define('AES-CMAC', 'verify', ) supportedAlgorithms.define('HMAC', 'verify', '../algorithms/HMAC') /** * digest */ supportedAlgorithms.define('SHA-1', 'digest', '../algorithms/SHA') supportedAlgorithms.define('SHA-256', 'digest', '../algorithms/SHA') supportedAlgorithms.define('SHA-384', 'digest', '../algorithms/SHA') supportedAlgorithms.define('SHA-512', 'digest', '../algorithms/SHA') /** * deriveKey */ //supportedAlgorithms.define('ECDH', 'deriveKey', ) //supportedAlgorithms.define('DH', 'deriveKey', ) //supportedAlgorithms.define('CONCAT', 'deriveKey', ) //supportedAlgorithms.define('HKDF-CTR', 'deriveKey', ) //supportedAlgorithms.define('PBKDF2', 'deriveKey', ) /** * deriveBits */ //supportedAlgorithms.define('ECDH', 'deriveBits', ) //supportedAlgorithms.define('DH', 'deriveBits', ) //supportedAlgorithms.define('CONCAT', 'deriveBits', ) //supportedAlgorithms.define('HKDF-CTR', 'deriveBits', ) //supportedAlgorithms.define('PBKDF2', 'deriveBits', ) /** * generateKey */ supportedAlgorithms.define('RSASSA-PKCS1-v1_5', 'generateKey', '../algorithms/RSASSA-PKCS1-v1_5') supportedAlgorithms.define('RSA-PSS', 'generateKey', '../algorithms/RSA-PSS') supportedAlgorithms.define('RSA-OAEP', 'generateKey', '../algorithms/RSA-OAEP') supportedAlgorithms.define('ECDSA', 'generateKey', '../algorithms/ECDSA') supportedAlgorithms.define('EDDSA', 'generateKey', '../algorithms/EDDSA') //supportedAlgorithms.define('ECDH', 'generateKey', ) supportedAlgorithms.define('AES-CTR', 'generateKey', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'generateKey', '../algorithms/AES-CBC') //supportedAlgorithms.define('AES-CMAC', 'generateKey', ) supportedAlgorithms.define('AES-GCM', 'generateKey', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'generateKey', ) supportedAlgorithms.define('AES-KW', 'generateKey', '../algorithms/AES-KW') supportedAlgorithms.define('HMAC', 'generateKey', '../algorithms/HMAC') //supportedAlgorithms.define('DH', 'generateKey', ) //supportedAlgorithms.define('PBKDF2', 'generateKey', ) /** * importKey */ supportedAlgorithms.define('RSASSA-PKCS1-v1_5', 'importKey', '../algorithms/RSASSA-PKCS1-v1_5') supportedAlgorithms.define('RSA-PSS', 'importKey', '../algorithms/RSA-PSS') supportedAlgorithms.define('RSA-OAEP', 'importKey', '../algorithms/RSA-OAEP') supportedAlgorithms.define('ECDSA', 'importKey', '../algorithms/ECDSA') supportedAlgorithms.define('EDDSA', 'importKey', '../algorithms/EDDSA') //supportedAlgorithms.define('ECDH', 'importKey', ) supportedAlgorithms.define('AES-CTR', 'importKey', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'importKey', '../algorithms/AES-CBC') //supportedAlgorithms.define('AES-CMAC', 'importKey', ) supportedAlgorithms.define('AES-GCM', 'importKey', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'importKey', ) supportedAlgorithms.define('AES-KW', 'importKey', '../algorithms/AES-KW') supportedAlgorithms.define('HMAC', 'importKey', '../algorithms/HMAC') //supportedAlgorithms.define('DH', 'importKey', ) //supportedAlgorithms.define('CONCAT', 'importKey', ) //supportedAlgorithms.define('HKDF-CTR', 'importKey', ) //supportedAlgorithms.define('PBKDF2', 'importey', ) /** * exportKey */ supportedAlgorithms.define('RSASSA-PKCS1-v1_5', 'exportKey', '../algorithms/RSASSA-PKCS1-v1_5') supportedAlgorithms.define('RSA-PSS', 'exportKey', '../algorithms/RSA-PSS') supportedAlgorithms.define('RSA-OAEP', 'exportKey', '../algorithms/RSA-OAEP') supportedAlgorithms.define('EDDSA', 'exportKey', '../algorithms/EDDSA') supportedAlgorithms.define('ECDSA', 'exportKey', '../algorithms/ECDSA') //supportedAlgorithms.define('ECDH', 'exportKey', ) supportedAlgorithms.define('AES-CTR', 'exportKey', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'exportKey', '../algorithms/AES-CBC') //supportedAlgorithms.define('AES-CMAC', 'exportKey', ) supportedAlgorithms.define('AES-GCM', 'exportKey', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'exportKey', ) supportedAlgorithms.define('AES-KW', 'exportKey', '../algorithms/AES-KW') supportedAlgorithms.define('HMAC', 'exportKey', '../algorithms/HMAC') //supportedAlgorithms.define('DH', 'exportKey', ) /** * wrapKey */ supportedAlgorithms.define('RSA-OAEP', 'wrapKey', '../algorithms/RSA-OAEP') supportedAlgorithms.define('AES-CTR', 'wrapKey', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'wrapKey', '../algorithms/AES-CBC') supportedAlgorithms.define('AES-GCM', 'wrapKey', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'wrapKey', ) supportedAlgorithms.define('AES-KW', 'wrapKey', '../algorithms/AES-KW') /** * unwrapKey */ supportedAlgorithms.define('RSA-OAEP', 'unwrapKey', '../algorithms/RSA-OAEP') supportedAlgorithms.define('AES-CTR', 'unwrapKey', '../algorithms/AES-CTR') supportedAlgorithms.define('AES-CBC', 'unwrapKey', '../algorithms/AES-CBC') supportedAlgorithms.define('AES-GCM', 'unwrapKey', '../algorithms/AES-GCM') //supportedAlgorithms.define('AES-CFB', 'unwrapKey', ) supportedAlgorithms.define('AES-KW', 'unwrapKey', '../algorithms/AES-KW') /** * Export */ module.exports = supportedAlgorithmswebcrypto-0.9.2/src/dictionaries/000077500000000000000000000000001330022407200167755ustar00rootroot00000000000000webcrypto-0.9.2/src/dictionaries/AES-KW.js000066400000000000000000000000001330022407200202500ustar00rootroot00000000000000webcrypto-0.9.2/src/dictionaries/AesCbcParams.js000066400000000000000000000003541330022407200216210ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesCbcParams */ class AesCbcParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesCbcParams webcrypto-0.9.2/src/dictionaries/AesCfbParams.js000066400000000000000000000003551330022407200216250ustar00rootroot00000000000000 /** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesCfbParams */ class AesCfbParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesCfbParams webcrypto-0.9.2/src/dictionaries/AesCmacParams.js000066400000000000000000000003571330022407200220000ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesCmacParams */ class AesCmacParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesCmacParams webcrypto-0.9.2/src/dictionaries/AesCtrParams.js000066400000000000000000000003541330022407200216620ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesCtrParams */ class AesCtrParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesCtrParams webcrypto-0.9.2/src/dictionaries/AesDerivedKeyParams.js000066400000000000000000000004011330022407200231560ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesDerivedKeyParams */ class AesDerivedKeyParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesDerivedKeyParams webcrypto-0.9.2/src/dictionaries/AesGcmParams.js000066400000000000000000000003541330022407200216400ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesGcmParams */ class AesGcmParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesGcmParams webcrypto-0.9.2/src/dictionaries/AesKeyAlgorithm.js000066400000000000000000000004701330022407200223640ustar00rootroot00000000000000/** * Local dependencies */ const KeyAlgorithm = require('./KeyAlgorithm') /** * AesKeyAlgorithm */ class AesKeyAlgorithm extends KeyAlgorithm { /** * Constructor */ constructor (algorithm) { super(algorithm) //TODO Do more here. } } /** * Export */ module.exports = AesKeyAlgorithm webcrypto-0.9.2/src/dictionaries/AesKeyGenParams.js000066400000000000000000000003651330022407200223160ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * AesKeyGenParams */ class AesKeyGenParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = AesKeyGenParams webcrypto-0.9.2/src/dictionaries/Algorithm.js000066400000000000000000000011731330022407200212630ustar00rootroot00000000000000/** * Algorithm */ class Algorithm { /** * constructor * * @description * The Algorithm object is a dictionary object [WebIDL] which is used * to specify an algorithm and any additional parameters required to * fully specify the desired operation. * * @param {string|Object} algorithm */ constructor (algorithm) { if (typeof algorithm === 'string') { this.name = algorithm } else { Object.assign(this, algorithm) if (typeof this.name !== 'string') { throw new Error('Algorithm name must be a string') } } } } /** * Export */ module.exports = Algorithm webcrypto-0.9.2/src/dictionaries/ConcatParams.js000066400000000000000000000003541330022407200217100ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * ConcatParams */ class ConcatParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = ConcatParams webcrypto-0.9.2/src/dictionaries/DhImportKeyParams.js000066400000000000000000000003731330022407200227010ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * DhImportKeyParams */ class DhImportKeyParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = DhImportKeyParams webcrypto-0.9.2/src/dictionaries/DhKeyAlgorithm.js000066400000000000000000000003731330022407200222110ustar00rootroot00000000000000/** * Local dependencies */ const KeyAlgorithm = require('./KeyAlgorithm') /** * DhKeyAlgorithm */ class DhKeyAlgorithm extends KeyAlgorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = DhKeyAlgorithm webcrypto-0.9.2/src/dictionaries/DhKeyDeriveParams.js000066400000000000000000000003731330022407200226450ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * DhKeyDeriveParams */ class DhKeyDeriveParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = DhKeyDeriveParams webcrypto-0.9.2/src/dictionaries/DhKeyGenParams.js000066400000000000000000000003621330022407200221360ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * DhKeyGenParams */ class DhKeyGenParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = DhKeyGenParams webcrypto-0.9.2/src/dictionaries/EcKeyAlgorithm.js000066400000000000000000000012471330022407200222060ustar00rootroot00000000000000/** * Local dependencies */ const KeyAlgorithm = require('./KeyAlgorithm') /** * Mapping */ const mapping = [ { namedCurve: 'P-256', name: 'prime256v1', alg: 'ES256', hash: 'sha256' }, { namedCurve: 'P-384', name: 'secp384r1', alg: 'ES384', hash: 'sha384' }, { namedCurve: 'P-521', name: 'secp521r1', alg: 'ES512', hash: 'sha512' }, { namedCurve: 'K-256', name: 'secp256k1', alg: 'KS256', hash: 'sha256' }, ] /** * EcKeyAlgorithm */ class EcKeyAlgorithm extends KeyAlgorithm { /** * Constructor */ constructor (algorithm) { super(algorithm) } static get mapping () { return mapping } } /** * Export */ module.exports = EcKeyAlgorithm webcrypto-0.9.2/src/dictionaries/EcKeyGenParams.js000066400000000000000000000004551330022407200221350ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * EcKeyGenParams */ class EcKeyGenParams extends Algorithm { /** * Constructor */ constructor (params) { super(params) } static get mapping () { } } /** * Export */ module.exports = EcKeyGenParams webcrypto-0.9.2/src/dictionaries/EcKeyImportParams.js000066400000000000000000000004261330022407200226740ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * EcKeyImportParams */ class EcKeyImportParams extends Algorithm { /** * Constructor */ constructor (params) { super(params) } } /** * Export */ module.exports = EcKeyImportParams webcrypto-0.9.2/src/dictionaries/EcdhKeyDeriveParams.js000066400000000000000000000004011330022407200231450ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * EcdhKeyDeriveParams */ class EcdhKeyDeriveParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = EcdhKeyDeriveParams webcrypto-0.9.2/src/dictionaries/EcdsaParams.js000066400000000000000000000003511330022407200215150ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * EcdsaParams */ class EcdsaParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = EcdsaParams webcrypto-0.9.2/src/dictionaries/HkdfCtrParams.js000066400000000000000000000003571330022407200220310ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * HkdfCtrParams */ class HkdfCtrParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = HkdfCtrParams webcrypto-0.9.2/src/dictionaries/HmacImportParams.js000066400000000000000000000003701330022407200225420ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * HmacImportParams */ class HmacImportParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = HmacImportParams webcrypto-0.9.2/src/dictionaries/HmacKeyAlgorithm.js000066400000000000000000000010351330022407200225220ustar00rootroot00000000000000/** * Package dependencies */ const base64url = require('base64url') const crypto = require('crypto') /** * Local dependencies */ const CryptoKey = require('../keys/CryptoKey') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('./KeyAlgorithm') /** * Errors */ const { DataError, OperationError, NotSupportedError, KeyFormatNotSupportedError } = require('../errors') /** * HmacKeyAlgorithm */ class HmacKeyAlgorithm extends KeyAlgorithm { } /** * Export */ module.exports = HmacKeyAlgorithm webcrypto-0.9.2/src/dictionaries/HmacKeyGenParams.js000066400000000000000000000003701330022407200224520ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * HmacKeyGenParams */ class HmacKeyGenParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = HmacKeyGenParams webcrypto-0.9.2/src/dictionaries/KeyAlgorithm.js000066400000000000000000000006701330022407200217350ustar00rootroot00000000000000/** * Local dependencies */ const {NotSupportedError} = require('../errors') /** * KeyAlgorithm dictionary */ class KeyAlgorithm { /** * constructor * * @param {object} algorithm */ constructor (algorithm) { Object.assign(this, algorithm) // validate name if (this.name === undefined) { throw new Error('KeyAlgorithm must have a name') } } } /** * Export */ module.exports = KeyAlgorithm webcrypto-0.9.2/src/dictionaries/Pbkdf2Params.js000066400000000000000000000003541330022407200216110ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * Pbkdf2Params */ class Pbkdf2Params extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = Pbkdf2Params webcrypto-0.9.2/src/dictionaries/RsaHashedImportParams.js000066400000000000000000000004241330022407200235340ustar00rootroot00000000000000/** * RsaHashedImportParams */ class RsaHashedImportParams { constructor (hash) { // validate and set hash //if (!(hash instanceof HashAlgorithmIdentifier)) { throw new Error() } this.hash = hash } } /** * Export */ module.exports = RsaHashedImportParams webcrypto-0.9.2/src/dictionaries/RsaHashedKeyAlgorithm.js000066400000000000000000000014641330022407200235220ustar00rootroot00000000000000/** * Package dependencies */ const RSA = require('node-rsa') const crypto = require('crypto') const {spawnSync} = require('child_process') const {TextEncoder, TextDecoder} = require('text-encoding') /** * Local dependencies */ const CryptoKey = require('../keys/CryptoKey') const CryptoKeyPair = require('../keys/CryptoKeyPair') const JsonWebKey = require('../keys/JsonWebKey') const KeyAlgorithm = require('./KeyAlgorithm') const RsaKeyAlgorithm = require('./RsaKeyAlgorithm') const supportedAlgorithms = require('../algorithms') /** * Errors */ const { DataError, OperationError, InvalidAccessError, KeyFormatNotSupportedError } = require('../errors') /** * RsaHashedKeyAlgorithm */ class RsaHashedKeyAlgorithm extends RsaKeyAlgorithm { } /** * Export */ module.exports = RsaHashedKeyAlgorithm webcrypto-0.9.2/src/dictionaries/RsaHashedKeyGenParams.js000066400000000000000000000011021330022407200234360ustar00rootroot00000000000000/** * Local dependencies */ const KeyAlgorithm = require('./KeyAlgorithm') const RsaKeyGenParams = require('./RsaKeyGenParams') /** * RsaHashedKeyGenParams */ class RsaHashedKeyGenParams extends RsaKeyGenParams { /** * constructor */ constructor (algorithm) { super(algorithm) } /** * validate */ validate () { // validate hash is an object if (typeof this.hash !== 'object') { throw new Error( 'hash of RsaHashedKeyGenParams must be an object' ) } } } /** * Export */ module.exports = RsaHashedKeyGenParams webcrypto-0.9.2/src/dictionaries/RsaKeyAlgorithm.js000066400000000000000000000017161330022407200224050ustar00rootroot00000000000000/** * Local dependencies */ const KeyAlgorithm = require('./KeyAlgorithm') /** * RsaKeyAlgorithm */ class RsaKeyAlgorithm extends KeyAlgorithm { /** * constructor * * @param {object} algorithm */ constructor (algorithm) { // Call parent constructor then validate sundry tests super(algorithm) /* FIXME Implement to pass tests // validate type of modulusLength if (typeof this.modulusLength !== 'number') { throw new Error( 'modulusLength of RsaKeyAlgorithm must be a number' ) } // validate range of modulusLength if (this.modulusLength < 1024) { throw new Error( 'modulusLength of RsaKeyAlgorithm must be at least 1024' ) } // validate publicExponent if (!(this.publicExponent instanceof Uint8Array)) { throw new Error( 'publicExponent of RsaKeyAlgorithm must be a BigInteger' ) }*/ } } /** * Export */ module.exports = RsaKeyAlgorithm webcrypto-0.9.2/src/dictionaries/RsaKeyGenParams.js000066400000000000000000000012751330022407200223340ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * RsaKeyGenParams */ class RsaKeyGenParams extends Algorithm { /** * Constructor * * @param {number} modulusLength * @param {BigInteger} publicExponent */ constructor (algorithm) { super(algorithm) } /** * validate */ validate () { // validate modulusLength if (typeof this.modulusLength !== 'number') { throw new Error() } if (this.modulusLength < 1024) { throw new Error() } // validate publicExponent if (!(this.publicExponent instanceof Uint8Array)) { throw new Error() } } } /** * Export */ module.exports = RsaKeyGenParams webcrypto-0.9.2/src/dictionaries/RsaOaepParams.js000066400000000000000000000003571330022407200220360ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * RsaOaepParams */ class RsaOaepParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = RsaOaepParams webcrypto-0.9.2/src/dictionaries/RsaPssParams.js000066400000000000000000000003541330022407200217140ustar00rootroot00000000000000/** * Local dependencies */ const Algorithm = require('./Algorithm') /** * RsaPssParams */ class RsaPssParams extends Algorithm { /** * Constructor */ constructor () {} } /** * Export */ module.exports = RsaPssParams webcrypto-0.9.2/src/dictionaries/ShaKeyAlgorithm.js000066400000000000000000000004341330022407200223670ustar00rootroot00000000000000/** * Module dependencies */ const crypto = require('crypto') const KeyAlgorithm = require('./KeyAlgorithm') const {OperationError} = require('../errors') /** * ShaKeyAlgorithm */ class ShaKeyAlgorithm extends KeyAlgorithm { } /** * Export */ module.exports = ShaKeyAlgorithm webcrypto-0.9.2/src/errors/000077500000000000000000000000001330022407200156345ustar00rootroot00000000000000webcrypto-0.9.2/src/errors/CurrentlyNotSupportedError.js000066400000000000000000000006371330022407200235700ustar00rootroot00000000000000/** * Local dependencies */ const NotSupportedError = require('./NotSupportedError') /** * CurrentlyNotSupportedError */ class CurrentlyNotSupportedError extends NotSupportedError { constructor (format,available) { super() this.message = `Currently '${format}' is not a supported format. Please use '${available}' in the interim.` } } /** * Export */ module.exports = CurrentlyNotSupportedError webcrypto-0.9.2/src/errors/DataError.js000066400000000000000000000002261330022407200200550ustar00rootroot00000000000000/** * DataError */ class DataError extends Error { constructor (message) { super(message) } } /** * Export */ module.exports = DataError webcrypto-0.9.2/src/errors/InvalidAccessError.js000066400000000000000000000002611330022407200217130ustar00rootroot00000000000000/** * InvalidAccessError */ class InvalidAccessError extends Error { constructor (message) { super(message) } } /** * Export */ module.exports = InvalidAccessError webcrypto-0.9.2/src/errors/KeyFormatNotSupportedError.js000066400000000000000000000005421330022407200234750ustar00rootroot00000000000000/** * Local dependencies */ const NotSupportedError = require('./NotSupportedError') /** * KeyFormatNotSupportedError */ class KeyFormatNotSupportedError extends NotSupportedError { constructor (format) { super() this.message = `${format} is not a supported key format` } } /** * Export */ module.exports = KeyFormatNotSupportedError webcrypto-0.9.2/src/errors/NotSupportedError.js000066400000000000000000000003341330022407200216520ustar00rootroot00000000000000/** * NotSupportedError */ class NotSupportedError extends Error { constructor (alg) { super() this.message = `${alg} is not a supported algorithm` } } /** * Export */ module.exports = NotSupportedError webcrypto-0.9.2/src/errors/OperationError.js000066400000000000000000000002451330022407200211450ustar00rootroot00000000000000/** * OperationError */ class OperationError extends Error { constructor (message) { super(message) } } /** * Export */ module.exports = OperationError webcrypto-0.9.2/src/errors/QuotaExceededError.js000066400000000000000000000002611330022407200217230ustar00rootroot00000000000000/** * QuotaExceededError */ class QuotaExceededError extends Error { constructor (message) { super(message) } } /** * Export */ module.exports = QuotaExceededError webcrypto-0.9.2/src/errors/TypeMismatchError.js000066400000000000000000000002561330022407200216160ustar00rootroot00000000000000/** * TypeMismatchError */ class TypeMismatchError extends Error { constructor (message) { super(message) } } /** * Export */ module.exports = TypeMismatchError webcrypto-0.9.2/src/errors/index.js000066400000000000000000000007161330022407200173050ustar00rootroot00000000000000module.exports = { DataError: require('./DataError'), InvalidAccessError: require('./InvalidAccessError'), KeyFormatNotSupportedError: require('./KeyFormatNotSupportedError'), CurrentlyNotSupportedError: require('./CurrentlyNotSupportedError'), NotSupportedError: require('./NotSupportedError'), OperationError: require('./OperationError'), QuotaExceededError: require('./QuotaExceededError'), TypeMismatchError: require('./TypeMismatchError') } webcrypto-0.9.2/src/index.js000066400000000000000000000001011330022407200157550ustar00rootroot00000000000000const Crypto = require('./Crypto') module.exports = new Crypto() webcrypto-0.9.2/src/keys/000077500000000000000000000000001330022407200152735ustar00rootroot00000000000000webcrypto-0.9.2/src/keys/CryptoKey.js000066400000000000000000000040421330022407200175620ustar00rootroot00000000000000/** * CryptoKey interface */ class CryptoKey { /** * Constructor */ constructor ({type, extractable, algorithm, usages, handle}) { this.type = type this.extractable = extractable this.algorithm = algorithm this.usages = usages // ensure values are not writeable Object.defineProperties(this, { // TODO // These properties can't be fixed immediately on creation of the // object because the implementation may build it up in stages. // At some point in the operations before returning a key we should // freeze the object to prevent further manipulation. //type: { // enumerable: true, // writeable: false, // value: type //}, //extractable: { // enumerable: true, // writeable: true, // value: extractable //}, //algorithm: { // enumerable: true, // writeable: false, // value: algorithm //}, //usages: { // enumerable: true, // writeable: true, // value: usages //}, // this is the "key material" used internally // it is not enumerable, but we need it to be // accessible by algorithm implementations handle: { enumerable: false, writeable: false, value: handle } }) //if (!Array.isArray(type) || KeyType.indexOf(type) === -1) { throw new Error('Invalid CryptoKey type') } // verify type of algorithm // verify type/enum of usages } /** * Structured clone algorithm * https://www.w3.org/TR/WebCryptoAPI/#cryptokey-interface-clone * * TODO * This requires review and consideration with respect to the * internal structured cloning algorithm. * https://www.w3.org/TR/WebCryptoAPI/#dfn-structured-clone * * @param {Object} input * @param {Object} memory * * @returns {CryptoKey} */ clone ({type,extractable,algorithm,usages,handle}, memory) { return new CryptoKey({type,extractable,algorithm,usages,handle}) } } /** * Export */ module.exports = CryptoKey webcrypto-0.9.2/src/keys/CryptoKeyPair.js000066400000000000000000000003341330022407200203760ustar00rootroot00000000000000/** * CryptoKeyPair dictionary */ class CryptoKeyPair { constructor ({publicKey,privateKey}) { this.publicKey = publicKey this.privateKey = privateKey } } /** * Export */ module.exports = CryptoKeyPair webcrypto-0.9.2/src/keys/JsonWebKey.js000066400000000000000000000002611330022407200176500ustar00rootroot00000000000000/** * JsonWebKey */ class JsonWebKey { /** * Constructor */ constructor (data) { Object.assign(this, data) } } /** * Export */ module.exports = JsonWebKey webcrypto-0.9.2/src/keys/recognizedKeyUsages.js000066400000000000000000000010641330022407200216040ustar00rootroot00000000000000/** * KeyUsage */ class KeyUsage extends Array { /** * constructor */ constructor (collection) { super() collection.forEach(item => this.push(item)) } /** * normalize */ normalize (usages) { let result = [] for (let i = 0; i < this.length; i++) { let usage = this[i] if (usages.includes(usage)) { result.push(usage) } } return result } } /** * Export */ module.exports = new KeyUsage([ 'encrypt', 'decrypt', 'sign', 'verify', 'deriveBits', 'wrapKey', 'unwrapKey' ]) webcrypto-0.9.2/test/000077500000000000000000000000001330022407200145105ustar00rootroot00000000000000webcrypto-0.9.2/test/CryptoSpec.js000066400000000000000000000014521330022407200171430ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() /** * Code under test */ const crypto = require('../src') const SubtleCrypto = require('../src/SubtleCrypto') /** * Tests */ describe('Crypto', () => { describe('getRandomValues', () => { it('should return the typed array argument', () => { let array = new Uint8Array(16) crypto.getRandomValues(array).should.equal(array) }) it('should write random values to the typed array', () => { let array = new Uint8Array(16) crypto.getRandomValues(array) array.forEach(value => value.should.not.equal(0)) }) }) describe('subtle', () => { it('should return a SubtleCrypto instance', () => { crypto.subtle.should.be.instanceof(SubtleCrypto) }) }) }) webcrypto-0.9.2/test/EcdsaKeyPairsForTesting.js000066400000000000000000000164221330022407200215470ustar00rootroot00000000000000/** * Dependencies */ const ECDSA = require('../src/algorithms/ECDSA') /** * ECDSAObjects */ const ECDSA_K256 = new ECDSA({ name: 'ECDSA', namedCurve: 'K-256', hash: { name: 'SHA-256' } }) const ECDSA_P256 = new ECDSA({ name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-256' } }) const ECDSA_P384 = new ECDSA({ name: 'ECDSA', namedCurve: 'P-384', hash: { name: 'SHA-256' } }) const ECDSA_P521 = new ECDSA({ name: 'ECDSA', namedCurve: 'P-521', hash: { name: 'SHA-256' } }) /** * ECDSA_K256_PublicKey */ const ECDSA_K256_PublicKey = ECDSA_K256.importKey( 'jwk', { kty: 'EC', crv: 'K-256', x: 'v-7l4HaEJwSkQwx0uzm0qZmHavW2Gpjm5D2tKifeIeo', y: 'JGGVfZjuI_25bBbEuwI5PA4M2DMyoS5d07BlA5dWr0E' }, { name: 'ECDSA', namedCurve: 'K-256', hash: { name: 'SHA-256' } }, true, ['verify']) /** * ECDSA_K256_PublicPem */ ECDSA_K256_PublicPem = `-----BEGIN PUBLIC KEY----- MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEL/yAQbK4Kg95AknFkfVO8V5rWkN1shsz 7jrEyDZ3McDY1rv9hRIcMyfrxeycgY5+jdPCIip9tpNe9q9QrNPqqg== -----END PUBLIC KEY-----` /** * ECDSA_K256_PrivateKey */ const ECDSA_K256_PrivateKey = ECDSA_K256.importKey( 'jwk', { kty: 'EC', crv: 'K-256', d: '-2luTboUHmtHxZUDNOyq1MY2JzHnVDd8xyhfaol8Mec', x: 'v-7l4HaEJwSkQwx0uzm0qZmHavW2Gpjm5D2tKifeIeo', y: 'JGGVfZjuI_25bBbEuwI5PA4M2DMyoS5d07BlA5dWr0E' }, { name: 'ECDSA', namedCurve: 'K-256', hash: { name: 'SHA-256' } }, true, ['sign']) /** * ECDSA_K256_PrivatePem */ ECDSA_K256_PrivatePem = `-----BEGIN EC PRIVATE KEY----- MHQCAQEEID0efOySYrkhN2hbYWqJ2H91SbQfVl2mXDe1YtDpgVLcoAcGBSuBBAAK oUQDQgAEL/yAQbK4Kg95AknFkfVO8V5rWkN1shsz7jrEyDZ3McDY1rv9hRIcMyfr xeycgY5+jdPCIip9tpNe9q9QrNPqqg== -----END EC PRIVATE KEY-----` /** * ECDSA_P256_PublicKey */ const ECDSA_P256_PublicKey = ECDSA_P256.importKey( 'jwk', { "kty": "EC", "crv": "P-256", "x": "bag3R0FTUvlLJGEM7zEhY2IGJgoEN4Q4UA7eR5Uh7BE", "y": "CM1wRrk_90vXDVymupli0yyHAcRBVS3MdQFUCSq5BV0" }, { name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-256' } }, true, ['verify']) /** * ECDSA_P256_PublicPem */ ECDSA_P256_PublicPem = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbag3R0FTUvlLJGEM7zEhY2IGJgoE N4Q4UA7eR5Uh7BEIzXBGuT/3S9cNXKa6mWLTLIcBxEFVLcx1AVQJKrkFXQ== -----END PUBLIC KEY-----` /** * ECDSA_P256_PrivateKey */ const ECDSA_P256_PrivateKey = ECDSA_P256.importKey( 'jwk', { "kty": "EC", "crv": "P-256", "d": "3t2jGdosjga1Un35fmweoWMkgDmNYsHeYpkTY707WYE", "x": "bag3R0FTUvlLJGEM7zEhY2IGJgoEN4Q4UA7eR5Uh7BE", "y": "CM1wRrk_90vXDVymupli0yyHAcRBVS3MdQFUCSq5BV0" }, { name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-256' } }, true, ['sign']) /** * ECDSA_P256_PrivatePem */ ECDSA_P256_PrivatePem = `-----BEGIN EC PRIVATE KEY----- MHcCAQEEIN7doxnaLI4GtVJ9+X5sHqFjJIA5jWLB3mKZE2O9O1mBoAoGCCqGSM49 AwEHoUQDQgAEbag3R0FTUvlLJGEM7zEhY2IGJgoEN4Q4UA7eR5Uh7BEIzXBGuT/3 S9cNXKa6mWLTLIcBxEFVLcx1AVQJKrkFXQ== -----END EC PRIVATE KEY-----` /** * ECDSA_P384_PublicKey */ const ECDSA_P384_PublicKey = ECDSA_P384.importKey( 'jwk', { "kty": "EC", "crv": "P-384", "x": "XN3ga623z2mu5BdxWXIVeGhznGbDHsqEKaIqTK9RlpCxKwrcdoRqaC3qlIPygcN7", "y": "NVey0D8e2Kjx1iqge8-KTCCd7VMs3o6mSPnVjdC6ls6ntN7-0M7yFNUNqh_LPCKz" }, { name: 'ECDSA', namedCurve: 'P-384', hash: { name: 'SHA-384' } }, true, ['verify']) /** * ECDSA_P384_PublicPem */ ECDSA_P384_PublicPem = `-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEXN3ga623z2mu5BdxWXIVeGhznGbDHsqE KaIqTK9RlpCxKwrcdoRqaC3qlIPygcN7NVey0D8e2Kjx1iqge8+KTCCd7VMs3o6m SPnVjdC6ls6ntN7+0M7yFNUNqh/LPCKz -----END PUBLIC KEY-----` /** * ECDSA_P384_PrivateKey */ const ECDSA_P384_PrivateKey = ECDSA_P384.importKey( 'jwk', { "kty": "EC", "crv": "P-384", "d": "WH7_8esDPbqChcrIj5M0espufGuwWMM1lv_EVI9iJw3dh3QLrLl0MiA8JoyPdp51", "x": "XN3ga623z2mu5BdxWXIVeGhznGbDHsqEKaIqTK9RlpCxKwrcdoRqaC3qlIPygcN7", "y": "NVey0D8e2Kjx1iqge8-KTCCd7VMs3o6mSPnVjdC6ls6ntN7-0M7yFNUNqh_LPCKz" }, { name: 'ECDSA', namedCurve: 'P-384', hash: { name: 'SHA-384' } }, true, ['sign']) /** * ECDSA_P384_PrivatePem */ ECDSA_P384_PrivatePem = `-----BEGIN EC PRIVATE KEY----- MIGkAgEBBDBYfv/x6wM9uoKFysiPkzR6ym58a7BYwzWW/8RUj2InDd2HdAusuXQy IDwmjI92nnWgBwYFK4EEACKhZANiAARc3eBrrbfPaa7kF3FZchV4aHOcZsMeyoQp oipMr1GWkLErCtx2hGpoLeqUg/KBw3s1V7LQPx7YqPHWKqB7z4pMIJ3tUyzejqZI +dWN0LqWzqe03v7QzvIU1Q2qH8s8IrM= -----END EC PRIVATE KEY-----` /** * ECDSA_P521_PublicKey */ const ECDSA_P521_PublicKey = ECDSA_P521.importKey( 'jwk', { "kty": "EC", "crv": "P-521", "x": "AUfN5-iTkxajWZGoNe-jzNCpSydvol5MrKf-QPS0k_3ZxgW62YdOrespAXYrK--G_ff2IoGrXWOw2kuM0JWiioOn", "y": "AQc6m4W2GVAfWKxf3qhCtKj6nGCQxCNTHF54AX-Yh4g271LYf8VgW8bshT877SJOJjkYabKJc8NOG_lp1cwffOfq" }, { name: 'ECDSA', namedCurve: 'P-521', hash: { name: 'SHA-512' } }, true, ['verify']) /** * ECDSA_P521_PublicPem */ ECDSA_P521_PublicPem = `-----BEGIN PUBLIC KEY----- MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBR83n6JOTFqNZkag176PM0KlLJ2+i Xkysp/5A9LST/dnGBbrZh06t6ykBdisr74b99/YigatdY7DaS4zQlaKKg6cBBzqb hbYZUB9YrF/eqEK0qPqcYJDEI1McXngBf5iHiDbvUth/xWBbxuyFPzvtIk4mORhp solzw04b+WnVzB985+o= -----END PUBLIC KEY-----` /** * ECDSA_P521_PrivateKey */ const ECDSA_P521_PrivateKey = ECDSA_P521.importKey( 'jwk', { "kty": "EC", "crv": "P-521", "d": "Aae3gDHukB0OAL-LRH3lWBUFJ951hxRRAH8qjnI0lB8zxZjUKR9pDMBaWbulz8WrgU1U5xVvEALQ9aL9S-le2h6W", "x": "AUfN5-iTkxajWZGoNe-jzNCpSydvol5MrKf-QPS0k_3ZxgW62YdOrespAXYrK--G_ff2IoGrXWOw2kuM0JWiioOn", "y": "AQc6m4W2GVAfWKxf3qhCtKj6nGCQxCNTHF54AX-Yh4g271LYf8VgW8bshT877SJOJjkYabKJc8NOG_lp1cwffOfq" }, { name: 'ECDSA', namedCurve: 'P-521', hash: { name: 'SHA-512' } }, true, ['sign']) /** * ECDSA_P521_PrivatePem */ ECDSA_P521_PrivatePem = `-----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIBp7eAMe6QHQ4Av4tEfeVYFQUn3nWHFFEAfyqOcjSUHzPFmNQpH2kM wFpZu6XPxauBTVTnFW8QAtD1ov1L6V7aHpagBwYFK4EEACOhgYkDgYYABAFHzefo k5MWo1mRqDXvo8zQqUsnb6JeTKyn/kD0tJP92cYFutmHTq3rKQF2Kyvvhv339iKB q11jsNpLjNCVooqDpwEHOpuFthlQH1isX96oQrSo+pxgkMQjUxxeeAF/mIeINu9S 2H/FYFvG7IU/O+0iTiY5GGmyiXPDThv5adXMH3zn6g== -----END EC PRIVATE KEY-----` /** * Export */ module.exports = { ECDSA_K256_PrivateKey, ECDSA_K256_PublicKey, ECDSA_K256_PrivatePem, ECDSA_K256_PublicPem, ECDSA_P256_PrivateKey, ECDSA_P256_PublicKey, ECDSA_P256_PrivatePem, ECDSA_P256_PublicPem, ECDSA_P384_PrivateKey, ECDSA_P384_PublicKey, ECDSA_P384_PrivatePem, ECDSA_P384_PublicPem, ECDSA_P521_PrivateKey, ECDSA_P521_PublicKey, ECDSA_P521_PrivatePem, ECDSA_P521_PublicPem, } webcrypto-0.9.2/test/RsaKeyPairForPSSTesting.js000066400000000000000000000110161330022407200214520ustar00rootroot00000000000000/** * Dependencies */ const CryptoKey = require('../src/keys/CryptoKey') const keyto = require('@trust/keyto') /** * RsaPrivateKey */ const RsaPrivateKey = `-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAtK1GWlnRWt35Nb1J3NUz7SBKP5Ui/r5g8xcqPIdUklKreZdn xzMLBGf8RV1woo+EudIrLanN5kiReX5e29bm/LKagasBnYn1sb+uLVeFJVahsslS IY9vKUtIfJlI2svGzrygD2LHLNzrMgQs+Nk7kil+KliFepeaCyEiSuGE+/zb9MUD K47Jj2YBlhugrqSvCTkfCmIFD98asQsJQpU8oMOKtyDZMHpSaVgNO0MH1/hiH2W4 tC7R0e3/5qpCoD73LOgh0c0EIM03tle7il60cI+9vRleuie7BSqoPiokiQvQLwWi PLZq3u9hUfLLexHmlPe+JWn9GGi9UNh1eV7OJQIDAQABAoIBAGX9hkBMgWy87wfR 8ZcSVzydRKx9wIJy74Fp6zK95hSvTBLYUAHXo3l6RaLWa1WolHDc3fjp6Mv83Pnr RxrsRfoRzDw0TzYiAaq0HFuGEygPrjmhgZZmRIbX83Q6hzDTZUegnO3ygaKmlrHm P4i9/+2zNIAs9jRMze1IZ/ZDNfGUSZsRyJG69k9hnRpFVoJ/WkPn0zJrkDXmiWyw vVpK06NBMF0fnnXRPs+XN/NDhhB6arg7PQZlU2hk4xubtPDQiwaBkeSzj1PFP5y5 GkocW/bBha6wHpUxzy2Sx7Yte9jmEY3QoZy6KCGvWdkQQYRQ17JN0RyhDc828cL5 rfonpoECgYEA3g9/IyYuQUf+sCnbsEBsd1ni87CvXAxG3NDQXrioZjNIuu32T5r/ I2481gtwfUieyYfg4ZFwXA9m2wWC1qWLz82oZBhedGMO5Uw4IY6glzGHmFZDeFt+ Jrfi0xcmPuBulJTHMkcNHgE/OLMXCpUsr4C96IL7ktGB3OmQagDqE+ECgYEA0EqR 63vQSabgmVd5KvsGlwgjcjN5ajFA7oDrvrP4DFp/8SFjMzia3XylUXqaHU8tyPwe uq8OMSF1l4KoYiD00waPXXeguvCGNo4vTXSJvMMLoXPVGGXs8QZ4UzKlacplwpiI jY2oU1ZOBIKHHqMoZmHSVNUI+VYO3BJ5vlfNwsUCgYAUkgzt/aB1Ta0LNqVyO1WQ 7NO4TVrBRSXfWLykuahn50JKhra1gx81cgXSsjaWdH65How3eRiWfprBmU4Ygjdk ZaG+u/8r+u0rUpc0jJjVyLHN69fOM3OJNKmfclqJopK70thtEOXnLKhloTl2MoF0 NJHjExco751/EGffWfxVIQKBgCqpS0/O8S9UpaXim6eo+IWQninyzwhoBCOVdjN+ Cu0E0DWkH/xKuLVqpTWWBeDA6eDDesvDtQVtE/evRCutElfyfQSoztvbDbI41wln OBrYXBZ6cgfoQGpxZ82qjuSnFsaPlVBg1jwTbjFQRrqIsmqd2IWViJwA+1Qp2JOa ykL9AoGAXMgvAWE9jJcoluljAcUhVMp837FTdhY1m1rv6BNzjaG0iQ8qV7OI/MnJ SHpGrbNh4k/6bUyuozHV9nkWD6vYJL5stEsP3SIv2FqoytyoeGoLpPg4BPD5ye57 QQ6nQ+YQJWuvl63/GPKN3AzB9uMNkcnp4A/ezighFir0KZpwrlw= -----END RSA PRIVATE KEY-----` /** * RsaPrivateJwk */ const RsaPrivateJwk = keyto.from(RsaPrivateKey,'pem').toJwk('private') /** * RsaPrivateCryptoKey */ const RsaPrivateCryptoKeySHA1 = new CryptoKey({ type: 'private', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-1'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) const RsaPrivateCryptoKeySHA256 = new CryptoKey({ type: 'private', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-256'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) const RsaPrivateCryptoKeySHA384 = new CryptoKey({ type: 'private', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-384'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) const RsaPrivateCryptoKeySHA512 = new CryptoKey({ type: 'private', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-512'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) /** * RsaPublicKey */ const RsaPublicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtK1GWlnRWt35Nb1J3NUz 7SBKP5Ui/r5g8xcqPIdUklKreZdnxzMLBGf8RV1woo+EudIrLanN5kiReX5e29bm /LKagasBnYn1sb+uLVeFJVahsslSIY9vKUtIfJlI2svGzrygD2LHLNzrMgQs+Nk7 kil+KliFepeaCyEiSuGE+/zb9MUDK47Jj2YBlhugrqSvCTkfCmIFD98asQsJQpU8 oMOKtyDZMHpSaVgNO0MH1/hiH2W4tC7R0e3/5qpCoD73LOgh0c0EIM03tle7il60 cI+9vRleuie7BSqoPiokiQvQLwWiPLZq3u9hUfLLexHmlPe+JWn9GGi9UNh1eV7O JQIDAQAB -----END PUBLIC KEY-----` /** * RsaPublicJwk */ const RsaPublicJwk = keyto.from(RsaPublicKey,'pem').toJwk('public') /** * RsaPrivateCryptoKey */ const RsaPublicCryptoKeySHA1 = new CryptoKey({ type: 'public', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-1'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) const RsaPublicCryptoKeySHA256 = new CryptoKey({ type: 'public', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-256'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) const RsaPublicCryptoKeySHA384 = new CryptoKey({ type: 'public', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-384'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) const RsaPublicCryptoKeySHA512 = new CryptoKey({ type: 'public', algorithm: { name: 'RSA-PSS', saltLength: 128, hash: {name: 'SHA-512'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) /** * Export */ module.exports = { RsaPrivateKey, RsaPrivateJwk, RsaPrivateCryptoKeySHA1, RsaPrivateCryptoKeySHA256, RsaPrivateCryptoKeySHA384, RsaPrivateCryptoKeySHA512, RsaPublicKey, RsaPublicJwk, RsaPublicCryptoKeySHA1, RsaPublicCryptoKeySHA256, RsaPublicCryptoKeySHA384, RsaPublicCryptoKeySHA512 } webcrypto-0.9.2/test/RsaKeyPairForTesting.js000066400000000000000000000107261330022407200210730ustar00rootroot00000000000000/** * Dependencies */ const CryptoKey = require('../src/keys/CryptoKey') const keyto = require('@trust/keyto') /** * RsaPrivateKey */ const RsaPrivateKey = `-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAiEJoO1tBT1Yc9jdYWI5JUkMnOlFD+weoi1rkxsWvZoBRJJGi fjrdmIn/5xOaaW38Cg535lo6NEorsVsq7V6zGan2QCT1TRCb7vJq4UIEq6tL5uB0 BZMyByKBYDKVGAinXYd502nJ1T7sbZQnSjZFC3HgDvrqb/4bDIbO0+sAiaTumt+2 uyIYcGYBuIfTi8vmElz2ngUFh+8K/uQyH7YjrOrg6ThOldh8IVzaOSA7LAb/DjyC +H44F/J24qMRLGuWK53gz+2RazSBotiNUsGoxdZv30Sud3Yfbz9ZjSXxPWpRnG6m ZAZW76oSbn8FvTSTWrf0iU6MyNkv/QuAjF+1BQIDAQABAoIBAHb3G8/vDad59NFX Yu/2Urfa363/882BUztQQXv2bvycPbwi1u9E7+JVYjLbH667ExmopjBdSIIM2/b+ NQ2H5/EZPmGkovME9E/8ISrInBFR/nP2NfYEHOKz0qctopSYQZ/cP5ZAv7JKPNwz RNZ7aW7jno8VrYfYIL+gF4ZYoGCLdIdw2rFaobZFGtUQ1ASpuBIS3NAQjxQLTdlz jUXCqqE02VKVW6Chr/ZPDnsjDmVxZjY5+vLoZRyS4jWBR64fgVrA+FoCFqtbKh5X ZCGUSRhGYs06XLlnjLn91ftgO6Di3FbQ2d4nrMRkD8ciOPv1iao429wKThiChTge 0DRF5SECgYEAvblqHOYDjdRTPV2rumoWKPzREhebi0ljKeMBFPvqVBM/IvOhqpVa cBsDCNGHwkOo3lX+M+c8y381ZR66pJb5QpF7qfIjlOQEYQfLc31HErYcHiPtKSNj L4HP5kAoZT4ILFZlfnVJP8oZ/S+BKO27juMwDVUk/wlI2CiN0a1oPWkCgYEAt9vB +yjoWydrBXy5q4m0pMcTm9FZum9kahCXx/0QjYPLjxwX6+d8Tc1Y1/VROtQDAIxu yMZxkboQ0L8uXtVQCjVz8hG1UDeqzISxLyTVP+JtD6yijhyrtQdgtokgAFzBHpYa MKgr8tARtojF5EyWPTQJpBSI2+tl0GgwEOa3Gz0CgYB65SQLXCNpN+RDl+2pbxaz rjBvm8Mx0nPdqiIFSblchKsdJNvP97cBbz3j9HYQLGuyudlUHbGPz/LycZlNDE6i BEMqrqLFy33arIXpZXkocbZ8/6CcSUPyfhABggWoryn0LnLIG4k7PNrg2mi77mLU B+4UdNbmLUl2W66h58XiIQKBgDG6kMccE2zERqAfUiDhiCihZ95XS4uvoVtGzabb /eQo55/3m0jFPcvVZNhUk/nzajR1x2kqs4EU8INlkmc4DwQT3R52R7JAvEPBCCOW NM+osJLywKzreE3ohvIYOL2gWOOq+b57Xhe4y3GxoMTVKjW3o3vryfChxNIPvCB2 JsSJAoGBAJV3gcwgFgAA6t8m7g4YStDKANJngttdfHZC1IhGFOtKPc/rneobgDCt 48gw9bQD8gy87laRb/hjm/0Az4bjtDDOkKY5yhCUtipnpx4FR12nGRmMfRGedLJh rrdlkni8537vUl2rwiG3U3LTi9vHMIbBQek5rxlbc8jS8ejGUFdc -----END RSA PRIVATE KEY-----` /** * RsaPrivateJwk */ const RsaPrivateJwk = keyto.from(RsaPrivateKey,'pem').toJwk('private') /** * RsaPrivateCryptoKey */ const RsaPrivateCryptoKeySHA1 = new CryptoKey({ type: 'private', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-1'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) const RsaPrivateCryptoKeySHA256 = new CryptoKey({ type: 'private', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-256'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) const RsaPrivateCryptoKeySHA384 = new CryptoKey({ type: 'private', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-384'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) const RsaPrivateCryptoKeySHA512 = new CryptoKey({ type: 'private', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-512'} }, extractable: false, usages: ['sign'], handle: RsaPrivateKey }) /** * RsaPublicKey */ const RsaPublicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiEJoO1tBT1Yc9jdYWI5J UkMnOlFD+weoi1rkxsWvZoBRJJGifjrdmIn/5xOaaW38Cg535lo6NEorsVsq7V6z Gan2QCT1TRCb7vJq4UIEq6tL5uB0BZMyByKBYDKVGAinXYd502nJ1T7sbZQnSjZF C3HgDvrqb/4bDIbO0+sAiaTumt+2uyIYcGYBuIfTi8vmElz2ngUFh+8K/uQyH7Yj rOrg6ThOldh8IVzaOSA7LAb/DjyC+H44F/J24qMRLGuWK53gz+2RazSBotiNUsGo xdZv30Sud3Yfbz9ZjSXxPWpRnG6mZAZW76oSbn8FvTSTWrf0iU6MyNkv/QuAjF+1 BQIDAQAB -----END PUBLIC KEY-----` /** * RsaPublicJwk */ const RsaPublicJwk = keyto.from(RsaPublicKey,'pem').toJwk('public') /** * RsaPrivateCryptoKey */ const RsaPublicCryptoKeySHA1 = new CryptoKey({ type: 'public', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-1'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) const RsaPublicCryptoKeySHA256 = new CryptoKey({ type: 'public', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-256'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) const RsaPublicCryptoKeySHA384 = new CryptoKey({ type: 'public', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-384'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) const RsaPublicCryptoKeySHA512 = new CryptoKey({ type: 'public', algorithm: { name: 'RSASSA-PKCS1-v1_5', hash: {name: 'SHA-512'} }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) /** * Export */ module.exports = { RsaPrivateKey, RsaPrivateJwk, RsaPrivateCryptoKeySHA1, RsaPrivateCryptoKeySHA256, RsaPrivateCryptoKeySHA384, RsaPrivateCryptoKeySHA512, RsaPublicKey, RsaPublicJwk, RsaPublicCryptoKeySHA1, RsaPublicCryptoKeySHA256, RsaPublicCryptoKeySHA384, RsaPublicCryptoKeySHA512 } webcrypto-0.9.2/test/SubtleCryptoSpec.js000066400000000000000000001126261330022407200203300ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() /** * Code under test */ const crypto = require('../src') const CryptoKey = require('../src/keys/CryptoKey') const CryptoKeyPair = require('../src/keys/CryptoKeyPair') const JsonWebKey = require('../src/keys/JsonWebKey') const RSASSA_PKCS1_v1_5 = require('../src/algorithms/RSASSA-PKCS1-v1_5') const AES_CBC = require('../src/algorithms/AES-CBC') const AES_GCM = require('../src/algorithms/AES-GCM') const {TextEncoder,TextDecoder} = require('text-encoding') /** * RSA Key Pair for testing */ const { RsaPrivateKey, RsaPrivateJwk, RsaPrivateCryptoKeySHA256, RsaPublicKey, RsaPublicJwk, RsaPublicCryptoKeySHA256 } = require('./RsaKeyPairForTesting') /** * Test code for AES-GCM */ const good_iv = Buffer.from([ 220, 29, 37, 164, 41, 84, 153, 197, 157, 122, 156, 254, 196, 161, 114, 74 ]) /** * Tests */ describe('SubtleCrypto', () => { /** * encrypt */ describe('encrypt', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let algorithm = { name: 'BAD-ALGORITHM' } let key = new CryptoKey({}) let data = new ArrayBuffer() promise = crypto.subtle.encrypt(algorithm, key, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with mismatched algorithm name', () => { let promise, error beforeEach(() => { let algorithm = { name: 'AES-CBC' } let key = new CryptoKey({ algorithm: { name: 'AES-CCC' } }) let data = new ArrayBuffer() promise = crypto.subtle.encrypt(algorithm, key, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Algorithm does not match key') }) }) describe('with invalid usages', () => { let promise, error beforeEach(() => { let algorithm = { name: 'AES-CBC' } let key = new CryptoKey({ algorithm: { name: 'AES-CBC', length: 128 }, usages: ['decrypt'] }) let data = new ArrayBuffer() promise = crypto.subtle.encrypt(algorithm, key, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Key usages must include "encrypt"') }) }) describe('with valid arguments', () => { let algorithm,aes, key, iv, promise, result, signature, error beforeEach((done) => { aes = new AES_CBC({ name: 'AES-CBC', length: 256}) i = Buffer.from([ 220, 29, 37, 164, 41, 84, 153, 197, 157, 122, 156, 254, 196, 161, 114, 74 ]) algorithm = { name: 'AES-CBC', iv:i } key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, }, { name: "AES-CBC", }, true, ["encrypt","decrypt"] ) let data = new TextEncoder().encode('signed with Chrome Webcrypto') signature = new Uint8Array([ 76, 82, 211, 155, 13, 154, 24, 6, 156, 203, 50, 171, 210, 17, 88, 145, 32, 225, 125, 119, 179, 197, 224, 210, 122, 43, 255, 159, 59, 195, 206, 210]) promise = crypto.subtle .encrypt(algorithm, key, data) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve an ArrayBuffer', () => { result.should.be.instanceof(ArrayBuffer) }) it('should resolve a correct encryption for the data and key', () => { Buffer.from(result).should.eql(Buffer.from(signature.buffer)) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * decrypt */ describe('decrypt', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let algorithm = { name: 'BAD-ALGORITHM' } let key = new CryptoKey({algorithm}) let data = new ArrayBuffer() promise = crypto.subtle.decrypt(algorithm, key, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with mismatched algorithm name', () => { let promise, error beforeEach(() => { let algorithm = { name: 'AES-CBC' } let key = new CryptoKey({ algorithm: { name: 'AES-CCC' } }) let data = new ArrayBuffer() promise = crypto.subtle.decrypt(algorithm, key, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Algorithm does not match key') }) }) describe('with invalid usages', () => { let promise, error beforeEach(() => { let algorithm = { name: 'AES-CBC' } let key = new CryptoKey({ algorithm: { name: 'AES-CBC', length: 128 }, usages: ['encrypt'] }) let data = new ArrayBuffer() promise = crypto.subtle.decrypt(algorithm, key, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Key usages must include "decrypt"') }) }) describe('with valid arguments', () => { let algorithm,aes, key, iv, promise, result, signature, error beforeEach((done) => { aes = new AES_CBC({ name: 'AES-CBC', length: 256}) i = Buffer.from([ 220, 29, 37, 164, 41, 84, 153, 197, 157, 122, 156, 254, 196, 161, 114, 74 ]) algorithm = { name: 'AES-CBC', iv:i } key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, }, { name: "AES-CBC", }, true, ["encrypt","decrypt"] ) let data = new Uint8Array([ 76, 82, 211, 155, 13, 154, 24, 6, 156, 203, 50, 171, 210, 17, 88, 145, 32, 225, 125, 119, 179, 197, 224, 210, 122, 43, 255, 159, 59, 195, 206, 210]) signature = new TextEncoder().encode('signed with Chrome Webcrypto') promise = crypto.subtle .decrypt(algorithm, key, data) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve a correct decryption for the data and key', () => { Buffer.from(result).should.eql(Buffer.from(signature.buffer)) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * sign */ describe('sign', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let algorithm = { name: 'BAD-ALGORITHM' } let privateKey = new CryptoKey({}) let data = new ArrayBuffer() promise = crypto.subtle.sign(algorithm, privateKey, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with mismatched algorithm name', () => { let promise, error beforeEach(() => { let algorithm = { name: 'RSASSA-PKCS1-v1_5' } let privateKey = new CryptoKey({ algorithm: { name: 'RSA-PSS' } }) let data = new ArrayBuffer() promise = crypto.subtle.sign(algorithm, privateKey, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Algorithm does not match key') }) }) describe('with invalid usages', () => { let promise, error beforeEach(() => { let algorithm = { name: 'RSASSA-PKCS1-v1_5' } let privateKey = new CryptoKey({ algorithm: { name: 'RSASSA-PKCS1-v1_5' }, usages: ['verify'] }) let data = new ArrayBuffer() promise = crypto.subtle.sign(algorithm, privateKey, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Key usages must include "sign"') }) }) describe('with valid arguments', () => { let promise, result, signature, error beforeEach((done) => { let algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' }} let data = new TextEncoder().encode('signed with Chrome webcrypto') signature = new Uint8Array([ 84, 181, 186, 121, 235, 76, 199, 102, 174, 125, 176, 216, 94, 190, 243, 201, 219, 114, 227, 61, 54, 194, 237, 14, 248, 204, 120, 109, 249, 220, 229, 80, 44, 48, 86, 133, 96, 129, 85, 213, 70, 19, 126, 0, 160, 91, 18, 185, 200, 102, 180, 181, 69, 27, 162, 181, 189, 110, 188, 112, 124, 93, 57, 208, 91, 142, 182, 192, 87, 167, 193, 111, 88, 5, 244, 108, 200, 150, 133, 68, 144, 208, 27, 155, 222, 213, 189, 224, 156, 226, 124, 65, 178, 69, 71, 63, 243, 141, 3, 126, 209, 237, 45, 179, 240, 255, 194, 245, 43, 148, 123, 97, 172, 239, 168, 221, 44, 186, 72, 194, 29, 9, 171, 103, 125, 182, 39, 95, 163, 80, 3, 208, 184, 184, 48, 114, 135, 7, 111, 114, 38, 25, 28, 234, 82, 18, 49, 113, 20, 251, 59, 147, 206, 7, 134, 15, 189, 201, 253, 241, 120, 236, 58, 235, 148, 27, 204, 233, 165, 31, 27, 223, 28, 10, 214, 159, 109, 186, 239, 71, 126, 18, 63, 111, 198, 115, 226, 237, 145, 26, 12, 120, 56, 166, 13, 195, 65, 11, 114, 149, 145, 255, 242, 97, 190, 255, 202, 219, 144, 83, 238, 240, 182, 82, 165, 229, 118, 146, 29, 95, 127, 76, 188, 247, 138, 254, 72, 18, 251, 42, 118, 156, 229, 66, 8, 106, 55, 106, 83, 232, 234, 23, 195, 160, 167, 133, 14, 181, 126, 5, 36, 157, 2, 81, 144, 83 ]) promise = crypto.subtle .sign(algorithm, RsaPrivateCryptoKeySHA256, data) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve an ArrayBuffer', () => { result.should.be.instanceof(ArrayBuffer) }) it('should resolve a correct signature for the data and key', () => { Buffer.from(result).should.eql(Buffer.from(signature.buffer)) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * verify */ describe('verify', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let algorithm = { name: 'BAD-ALGORITHM' } let publicKey = new CryptoKey({algorithm}) let signature = new ArrayBuffer() let data = new ArrayBuffer() promise = crypto.subtle.verify(algorithm, publicKey, signature, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with mismatched algorithm name', () => { let promise, error beforeEach(() => { let algorithm = { name: 'RSASSA-PKCS1-v1_5' } let publicKey = new CryptoKey({ algorithm: { name: 'RSA-PSS' } }) let signature = new ArrayBuffer() let data = new ArrayBuffer() promise = crypto.subtle.verify(algorithm, publicKey, signature, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Algorithm does not match key') }) }) describe('with invalid usages', () => { let promise, error beforeEach(() => { let algorithm = { name: 'RSASSA-PKCS1-v1_5' } let publicKey = new CryptoKey({ algorithm: { name: 'RSASSA-PKCS1-v1_5' }, usages: ['sign'] }) let signature = new ArrayBuffer() let data = new ArrayBuffer() promise = crypto.subtle.verify(algorithm, publicKey, signature, data) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Key usages must include "verify"') }) }) describe('with valid arguments', () => { let promise, result, signature, error beforeEach((done) => { let algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' }} let data = new TextEncoder().encode('signed with Chrome webcrypto') signature = new Uint8Array([ 84, 181, 186, 121, 235, 76, 199, 102, 174, 125, 176, 216, 94, 190, 243, 201, 219, 114, 227, 61, 54, 194, 237, 14, 248, 204, 120, 109, 249, 220, 229, 80, 44, 48, 86, 133, 96, 129, 85, 213, 70, 19, 126, 0, 160, 91, 18, 185, 200, 102, 180, 181, 69, 27, 162, 181, 189, 110, 188, 112, 124, 93, 57, 208, 91, 142, 182, 192, 87, 167, 193, 111, 88, 5, 244, 108, 200, 150, 133, 68, 144, 208, 27, 155, 222, 213, 189, 224, 156, 226, 124, 65, 178, 69, 71, 63, 243, 141, 3, 126, 209, 237, 45, 179, 240, 255, 194, 245, 43, 148, 123, 97, 172, 239, 168, 221, 44, 186, 72, 194, 29, 9, 171, 103, 125, 182, 39, 95, 163, 80, 3, 208, 184, 184, 48, 114, 135, 7, 111, 114, 38, 25, 28, 234, 82, 18, 49, 113, 20, 251, 59, 147, 206, 7, 134, 15, 189, 201, 253, 241, 120, 236, 58, 235, 148, 27, 204, 233, 165, 31, 27, 223, 28, 10, 214, 159, 109, 186, 239, 71, 126, 18, 63, 111, 198, 115, 226, 237, 145, 26, 12, 120, 56, 166, 13, 195, 65, 11, 114, 149, 145, 255, 242, 97, 190, 255, 202, 219, 144, 83, 238, 240, 182, 82, 165, 229, 118, 146, 29, 95, 127, 76, 188, 247, 138, 254, 72, 18, 251, 42, 118, 156, 229, 66, 8, 106, 55, 106, 83, 232, 234, 23, 195, 160, 167, 133, 14, 181, 126, 5, 36, 157, 2, 81, 144, 83 ]) promise = crypto.subtle .verify(algorithm, RsaPublicCryptoKeySHA256, signature, data) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve the promise', () => { result.should.equal(true) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * digest */ describe('digest', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let algorithm = { name: 'BAD-ALGORITHM' } promise = crypto.subtle.digest(algorithm, new Uint8Array('whatever')) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with valid arguments', () => { let promise, error beforeEach(() => { let algorithm = { name: 'SHA-256' } promise = crypto.subtle.digest(algorithm, new Buffer('whatever')) promise.then(digest => result = digest) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve an ArrayBuffer', () => { result.should.be.instanceof(ArrayBuffer) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * generateKey */ describe('generateKey', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let algorithm = { name: 'BAD-ALGORITHM' } promise = crypto.subtle.generateKey(algorithm, false, ['sign', 'verify']) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) // IS THERE ANY WAY TO TEST THIS WITHOUT SPIES/STUBS? // IF THE UNDERLYING ALGORITHMS ARE DOING THE RIGHT THING // IT WILL ERROR BEFORE EVER GETTING HERE describe('with invalid CryptoKey usages', () => { it('should return a promise') it('should reject the promise') }) describe('with invalid CryptoKeyPair usages', () => { it('should return a promise') it('should reject the promise') }) describe('with valid arguments', () => { let promise, result, error beforeEach((done) => { let algorithm = { name: 'RSASSA-PKCS1-v1_5', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } } let extractable = false let usages = ['sign', 'verify'] promise = crypto.subtle .generateKey(algorithm, extractable, usages) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve the promise', () => { result.should.be.instanceof(CryptoKeyPair) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * deriveKey */ describe('deriveKey', () => { it('should return a Promise') }) /** * deriveBits */ describe('deriveBits', () => { it('should return a Promise') }) /** * importKey */ describe('importKey', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let format = 'jwk' let key = {} let algorithm = { name: 'BAD-ALGORITHM' } let extractable = false let usages = ['verify'] promise = crypto.subtle.importKey('jwk', key, algorithm, extractable, usages) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with raw format', () => {}) describe('with pkcs8 format', () => {}) describe('with spki format', () => {}) describe('with jwk format', () => {}) describe('with invalid resulting usages', () => {}) describe('with valid arguments', () => { let promise, result, error beforeEach((done) => { let key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true } let algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } } let extractable = true let usages = ['sign', 'verify', 'nope'] promise = crypto.subtle .importKey('jwk', key, algorithm, extractable, usages) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve the promise', () => { result.should.be.instanceof(CryptoKey) }) it('should set extractable', () => { result.extractable.should.equal(true) }) it('should normalize key usages', () => { result.usages.should.eql(['sign', 'verify']) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * exportKey */ describe('exportKey', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let format = 'jwk' let key = new CryptoKey({ algorithm: { name: 'BAD-ALGORITHM' } }) promise = crypto.subtle.exportKey('jwk', key) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with unextractable key', () => { let promise, error beforeEach(() => { let format = 'jwk' let key = new CryptoKey({ type: 'public', algorithm: new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', }), extractable: false, handle: RsaPrivateKey }) promise = crypto.subtle.exportKey('jwk', key) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('Key is not extractable') }) }) describe('with valid arguments', () => { let promise, result, error beforeEach((done) => { let format = 'jwk' let key = new CryptoKey({ type: 'public', algorithm: new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }), extractable: true, handle: RsaPrivateKey }) promise = crypto.subtle .exportKey('jwk', key) .then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve the promise', () => { result.should.be.instanceof(JsonWebKey) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * wrapKey */ describe('wrapKey', () => { describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt","wrapKey","unwrapKey"] ) promise = crypto.subtle.wrapKey('jwk',key,key,{name: "AES-NONESENSE"}) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with invalid name property', () => { let promise, error beforeEach( done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt","wrapKey","unwrapKey"] ) let alg = {name: "AES-CBC",iv:good_iv} // Not GCM promise = crypto.subtle.wrapKey('jwk',key,key,alg) promise.catch(err => { error = err done() }) }) it('should reject the promise', () => { promise.should.be.rejected error.should.be.instanceof(Error) error.message.should.include('NormalizedAlgorthm name must be same as wrappingKey algorithm name') }) }) describe('with invalid key ops', () => { let promise, error beforeEach(done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt"] ) let alg = {name: "AES-GCM",iv:good_iv} promise = crypto.subtle.wrapKey('jwk',key,key,alg) promise.catch(err => { error = err done() }) }) it('should reject the promise', () => { promise.should.be.rejected error.should.be.instanceof(Error) error.message.should.include('Wrapping key usages must include "wrapKey"') }) }) describe('with invalid extractable property', () => { let promise, error beforeEach(done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, false, // Incorrect ["encrypt", "decrypt","wrapKey"] ) let alg = {name: "AES-GCM",iv:good_iv} promise = crypto.subtle.wrapKey('jwk',key,key,alg) promise.catch(err => { error = err done() }) }) it('should reject the promise', () => { promise.should.be.rejected error.should.be.instanceof(Error) error.message.should.include('Key is not extractable') }) }) describe('with valid arguments', () => { let promise, result, error beforeEach(done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt","wrapKey"] ) let alg = {name: "AES-GCM",iv:good_iv} promise = crypto.subtle.wrapKey('jwk',key,key,alg) promise.then(res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve the promise', () => { result.should.be.instanceof(ArrayBuffer) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) /** * unwrapKey */ describe('unwrapKey', () => { let wrappedKey before (() => { wrappedKey = new Uint8Array([ 34,105,32,16,166,133,127,43,31,27,51,61,224,43,87,63,222, 207,113,84,80,101,73,170,5,67,147,1,16,76,204,98,165,66, 25,48,219,41,143,247,79,136,187,202,198,2,176,61,50,127, 32,227,5,15,115,49,174,204,21,201,34,37,45,36,68,51,55, 138,56,65,242,121,247,165,89,74,183,157,112,42,245,233, 236,138,177,94,14,151,55,134,166,103,181,77,59,234,225, 115,127,249,108,64,97,144,99,41,205,18,8,123,16,203,141, 104,145,133,96,15,25,97,109,66,16,32,120,207,212,230,175, 31,202,237,230,158,207,35,145,82,87,110,67,159,36,146,148, 147,222,172,81,162,70,16,152,136,228,100,27,111,138,171]) }) describe('with invalid algorithm', () => { let promise, error beforeEach(() => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt","wrapKey","unwrapKey"] ) promise = crypto.subtle.unwrapKey( 'jwk', wrappedKey, key, { name:"AES-NONSENSE", iv: good_iv, tagLength: 128 }, { name: "AES-NONSENSE", length: 256 }, true, ["encrypt","decrypt","wrapKey","unwrapKey"] ) promise.catch(err => error = err) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should reject the promise', () => { error.should.be.instanceof(Error) error.message.should.include('is not a supported algorithm') }) }) describe('with invalid name property', () => { let promise, result, error before( done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt","wrapKey","unwrapKey"] ) promise = crypto.subtle.unwrapKey( 'jwk', wrappedKey, key, { name:"AES-CBC", // Incorrect iv: good_iv, tagLength: 128 }, { name: "AES-CBC", // Incorrect length: 256 }, true, ["encrypt","decrypt","wrapKey","unwrapKey"] ) promise .then ( res => { result = res done() }) .catch(err => { error = err done() }) }) it('should reject the promise', () => { promise.should.be.rejected error.should.be.instanceof(Error) error.message.should.include('NormalizedAlgorthm name must be same as unwrappingKey algorithm name') }) }) describe('with invalid key ops', () => { let promise, error before(done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt"] ) promise = crypto.subtle.unwrapKey( 'jwk', wrappedKey, key, { name:"AES-GCM", iv: good_iv, tagLength: 128 }, { name: "AES-GCM", length: 256 }, true, ["encrypt","decrypt"] ) promise.catch(err => { error = err done() }) }) it('should reject the promise', () => { promise.should.be.rejected error.should.be.instanceof(Error) error.message.should.include('Unwrapping key usages must include "unwrapKey"') }) }) describe('with different key arguments', async () => { let unwrappedSymmetric; before(async () => { let cryptoAlgorithm = { name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "SHA-1" } }; let cryptoSymmetricAlgorithm = { name: "AES-GCM", length: 256, //can be 128, 192, or 256 }; let wrappingAlgorithm = { name: "RSA-OAEP", hash: {name: "SHA-1"}, }; let asymmetricKey = await crypto.subtle.generateKey( cryptoAlgorithm, true, ["encrypt", "decrypt", "wrapKey"] ); let symmetric = await crypto.subtle.generateKey( cryptoSymmetricAlgorithm, true, ["encrypt", "decrypt"] ); let wrappedSymmetric = await crypto.subtle.wrapKey( "raw", symmetric, asymmetricKey.publicKey, wrappingAlgorithm ); unwrappedSymmetric = await crypto.subtle.unwrapKey( "raw", wrappedSymmetric, asymmetricKey.privateKey, wrappingAlgorithm, cryptoSymmetricAlgorithm, false, ["encrypt", "decrypt"] ); }); it('should resolve the promise', () => { unwrappedSymmetric.should.be.instanceof(CryptoKey) }) }) describe('with valid arguments', () => { let promise, result, error before(done => { let aes = new AES_GCM({ name: "AES-GCM", length: 256 }) let key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt","wrapKey","unwrapKey"] ) promise = crypto.subtle.unwrapKey( 'jwk', wrappedKey, key, { name:"AES-GCM", iv: good_iv, tagLength: 128 }, { name: "AES-GCM", length: 256 }, true, ["encrypt","decrypt","wrapKey","unwrapKey"] ) promise .then ( res => { result = res done() }) .catch(err => { error = err done() }) }) it('should return a promise', () => { promise.should.be.instanceof(Promise) }) it('should resolve the promise', () => { result.should.be.instanceof(CryptoKey) }) it('should not reject the promise', () => { expect(error).to.be.undefined }) }) }) }) webcrypto-0.9.2/test/algorithms/000077500000000000000000000000001330022407200166615ustar00rootroot00000000000000webcrypto-0.9.2/test/algorithms/AES-CBCSpec.js000066400000000000000000000374511330022407200210410ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../../src/dictionaries/AesKeyAlgorithm') const AES_CBC = require('../../src/algorithms/AES-CBC') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Test code */ const good_iv = Buffer.from([ 220, 29, 37, 164, 41, 84, 153, 197, 157, 122, 156, 254, 196, 161, 114, 74 ]) const bad_iv = Buffer.from([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ]) // too short /** * Tests */ describe('AES_CBC', () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { AES_CBC.dictionaries.should.eql([ KeyAlgorithm, AesKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { AES_CBC.members.publicExponent.should.equal('BufferSource') }) }) /** * encrypt */ describe('encrypt', () => { let aes, key, data, signature before(() => { aes = new AES_CBC({ name: "AES-CBC", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, }, { name: "AES-CBC", }, true, ["encrypt", "decrypt"] ) data = new TextEncoder().encode('signed with Chrome Webcrypto') signature = new Uint8Array([ 76, 82, 211, 155, 13, 154, 24, 6, 156, 203, 50, 171, 210, 17, 88, 145, 32, 225, 125, 119, 179, 197, 224, 210, 122, 43, 255, 159, 59, 195, 206, 210]) }) it("should throw with invalid iv length", () => { expect(() => { aes.encrypt({name: "AES-CBC", iv: bad_iv},key,new Uint8Array()) }).to.throw('IV Length must be exactly 16 bytes') }) it('should return an ArrayBuffer', () => { aes.encrypt({name: "AES-CBC", iv: good_iv},key,data).should.be.instanceof(ArrayBuffer) }) it('should return a valid encryption', () => { Buffer.from(aes.encrypt({name: "AES-CBC", iv: good_iv},key,data)) .should.eql(Buffer.from(signature.buffer)) }) }) // encrypt /** * decrypt */ describe('decrypt', () => { let aes, key, data, signature before(() => { aes = new AES_CBC({ name: "AES-CBC", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, }, { name: "AES-CBC", }, true, ["encrypt", "decrypt"] ) data = new Uint8Array([ 76, 82, 211, 155, 13, 154, 24, 6, 156, 203, 50, 171, 210, 17, 88, 145, 32, 225, 125, 119, 179, 197, 224, 210, 122, 43, 255, 159, 59, 195, 206, 210]) signature = new TextEncoder().encode('signed with Chrome Webcrypto') }) it("should throw with invalid iv length", () => { expect(() => { aes.decrypt({name: "AES-CBC", iv: bad_iv},key,new Uint8Array()) }).to.throw('IV Length must be exactly 16 bytes') }) it('should return an ArrayBuffer', () => { aes.decrypt({name: "AES-CBC", iv: good_iv},key,data).should.be.instanceof(ArrayBuffer) }) it('should return a valid encryption', () => { Buffer.from(aes.decrypt({name: "AES-CBC", iv: good_iv},key,data)) .should.eql(Buffer.from(signature.buffer)) }) }) // decrypt /** * generateKey */ describe('generateKey', () => { let alg, aes, cryptoKey before(() => { alg = { name: "AES-CBC", length: 256, } aes = new AES_CBC(alg) return Promise.resolve() .then(() => cryptoKey = aes.generateKey(alg,true,["encrypt", "decrypt"])) }) it('should throw with invalid usages', () => { expect(() => { aes.generateKey(alg, true, ['encrypt', 'decrypt', 'wrong']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should throw with invalid paramater length', () => { expect(() => { aes.generateKey({name:"AES-CBC",length:100}, true, ['encrypt', 'decrypt']) }).to.throw('Member length must be 128, 192, or 256.') }) it('should return CryptoKey', () => { cryptoKey.should.be.instanceof(CryptoKey) }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_CBC type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_CBC) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-CBC') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length/8) }) it('should generate a random handle each time', () => { cryptoKey.handle.should.not.equal( aes.generateKey(alg, true, ['encrypt', 'decrypt']).handle ) }) })//generateKey /** * importKey */ describe('importKey', () => { let aes before(() => { aes = new AES_CBC({ name: "AES-CBC", length: 256 }) }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.importKey('WRONG',{},{},true,[]) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, raw, cryptoKey before(() => { alg = { name: "AES-CBC", length: 256, } aes = new AES_CBC(alg) raw = new Uint8Array([99, 76, 237, 223, 177, 224, 59, 31, 129, 99, 180, 144, 141, 133, 102, 174, 168, 79, 144, 238, 56, 34, 45, 137, 113, 191, 114, 201, 213, 3, 61, 241]) return Promise.resolve() .then(() => cryptoKey = aes.importKey("raw",raw,{name:"AES-CBC"},true,["encrypt", "decrypt"]) ) }) it('should expect a suitable raw length', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-CBC"} , true, ['encrypt','decrypt']) }).to.throw('Length of data bits must be 128, 192 or 256.') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_CBC type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_CBC) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-CBC') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length/8) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, cryptoKey before(() => { alg = { name: "AES-CBC", length: 256, } aes = new AES_CBC(alg) key = { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, } return Promise.resolve() .then(() => cryptoKey = aes.importKey("jwk",key,{name:"AES-CBC"},true,["encrypt", "decrypt"])) }) it('should expect a suitable jwk format', () => { expect(() => { aes.importKey('jwk', "Incorrect", {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('Invalid jwk format') }) it('should expect correct kty format', () => { expect(() => { aes.importKey('jwk',{ kty: "WRONG", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('kty property must be "oct"') }) it('should expect data in k property', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", alg: "A256CBC", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('k property must not be empty') }) it('should expect A128CBC when data length is 16', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A256CBC", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A128CBC" must be 128 bits in length') }) it('should expect A192CBC when data length is 24', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A256CBC", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A192CBC" must be 192 bits in length') }) it('should expect A256CBC when data length is 32', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A192CBC", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A256CBC" must be 256 bits in length') }) it('should expect mismatched length when k is not appropriate base64url', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37", alg: "A256CBC", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm and data length mismatch') }) it('should expect correct value when "use" field is used', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", use: "WRONG", ext: true, }, {name:"AES-CBC"} , false, ['encrypt','decrypt']) }).to.throw('Key use must be "enc"') }) it('should expect valid key operations', () => { expect(() => { aes.importKey('jwk',key, {name:"AES-CBC"} , false, ['encrypt','decrypt','WRONG']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should expect non extractable to not be extractable', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: false, }, {name:"AES-CBC"} , true, ['encrypt','decrypt']) }).to.throw('Cannot be extractable when "ext" is set to false') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_CBC type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_CBC) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-CBC') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length/8) }) })//jwk })//importKey /** * exportKey */ describe('exportKey', () => { let aes before(() => { aes = new AES_CBC({ name: "AES-CBC", length: 256 }) }) it('should have a valid handle in the key', () => { expect(() => { aes.exportKey('raw',{}) }).to.throw('Missing key material') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.exportKey('WRONG',{handle:"Something"}) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, key, raw before(() => { alg = { name: "AES-CBC", length: 256, } aes = new AES_CBC(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true },{name:"AES-CBC"},true,["encrypt", "decrypt"]) raw = aes.exportKey("raw",key) }) it('should return a valid object', () => { raw.should.instanceof(Object) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, jwk before(() => { alg = { name: "AES-CBC", length: 256, } aes = new AES_CBC(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true },{name:"AES-CBC"},true,["encrypt", "decrypt"]) jwk = aes.exportKey("jwk",key) }) it('should return a valid object', () => { jwk.should.instanceof(Object) }) it('should expect correct kty field', () => { jwk.kty.should.eql("oct") }) it('should expect A128CBC when data length is 16', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A128CBC", ext: true },{name:"AES-CBC"},true,["encrypt", "decrypt"])).alg.should.eql("A128CBC") }) it('should expect A192CBC when data length is 24', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A192CBC", ext: true },{name:"AES-CBC"},true,["encrypt", "decrypt"])).alg.should.eql("A192CBC") }) it('should expect A256CBC when data length is 32', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true },{name:"AES-CBC"},true,["encrypt", "decrypt"])).alg.should.eql("A256CBC") }) })//jwk })//exportKey }) webcrypto-0.9.2/test/algorithms/AES-CTRSpec.js000066400000000000000000000436021330022407200210750ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../../src/dictionaries/AesKeyAlgorithm') const AES_CTR = require('../../src/algorithms/AES-CTR') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') const CurrentlyNotSupportedError = require('../../src/errors/CurrentlyNotSupportedError') /** * Test code */ const good_iv = Buffer.from([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ]) const good_iv2 = Buffer.from([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3, 7 ]) const bad_iv = new Array() /** * Tests */ describe('AES_CTR', () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { AES_CTR.dictionaries.should.eql([ KeyAlgorithm, AesKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { AES_CTR.members.publicExponent.should.equal('BufferSource') }) }) /** * encrypt */ describe('encrypt', () => { let aes, key, data, signature before(() => { aes = new AES_CTR({ name: "AES-CTR", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true, }, { name: "AES-CTR", }, true, ["encrypt", "decrypt"] ) data = new TextEncoder().encode('Encoded with WebCrypto') signature = new Uint8Array([ 105, 17, 182, 253, 106, 236, 160, 39, 22, 23, 4, 230, 196, 158, 208, 79, 149, 225, 178, 37, 160, 63]) }) it("should throw with empty counter", () => { expect(() => { aes.encrypt({name: "AES-CTR", length: 128}, key, data) // No counter }).to.throw('Counter must be exactly 16 bytes') }) it("should throw with invalid counter", () => { expect(() => { aes.encrypt({name: "AES-CTR", counter: bad_iv, length: 128}, key, new Uint8Array()) }).to.throw('Counter must be exactly 16 bytes') }) it("should throw with length value", () => { expect(() => { aes.encrypt({name: "AES-CTR", counter: good_iv, length: 0}, key, new Uint8Array()) }).to.throw('Length must be non zero and less than or equal to 128') }) it('should return an ArrayBuffer', () => { aes.encrypt({name: "AES-CTR", counter: good_iv, length: 128}, key, data).should.be.instanceof(ArrayBuffer) }) it('should return a valid encryption', () => { Buffer.from(aes.encrypt({name: "AES-CTR", counter: good_iv, length: 128}, key, data)) .should.eql(Buffer.from(signature.buffer)) }) }) // encrypt /** * decrypt */ describe('decrypt', () => { let aes, key, data, signature before(() => { aes = new AES_CTR({ name: "AES-CTR", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true, }, { name: "AES-CTR", }, true, ["encrypt", "decrypt"] ) data = new Uint8Array([ 105, 17, 182, 253, 106, 236, 160, 39, 22, 23, 4, 230, 196, 158, 208, 79, 149, 225, 178, 37, 160, 63]) signature = new TextEncoder().encode('Encoded with WebCrypto') }) it("should throw with empty counter", () => { expect(() => { aes.decrypt({name: "AES-CTR", length: 128}, key, new Uint8Array()) // No counter }).to.throw('Counter must be exactly 16 bytes') }) it("should throw with invalid counter", () => { expect(() => { aes.decrypt({name: "AES-CTR", counter: bad_iv, length: 128}, key, new Uint8Array()) }).to.throw('Counter must be exactly 16 bytes') }) it("should throw with invalid length value", () => { expect(() => { aes.decrypt({name: "AES-CTR", counter: good_iv, length: 1000}, key, new Uint8Array()) }).to.throw('Length must be non zero and less than or equal to 128') }) it('should return an ArrayBuffer', () => { aes.decrypt({name: "AES-CTR", counter: good_iv, length: 128}, key, data).should.be.instanceof(ArrayBuffer) }) it('should return a valid decryption', () => { Buffer.from(aes.decrypt({name: "AES-CTR", counter: good_iv, length: 128}, key, data)) .should.eql(Buffer.from(signature.buffer)) }) }) // decrypt /** * generateKey */ describe('generateKey', () => { let alg, aes, cryptoKey before(() => { alg = { name: "AES-CTR", length: 256, } aes = new AES_CTR(alg) return Promise.resolve() .then(() => cryptoKey = aes.generateKey(alg, true, ["encrypt", "decrypt"])) }) it('should throw with invalid usages', () => { expect(() => { aes.generateKey(alg, true, ['encrypt', 'decrypt', 'wrong']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should throw with invalid parameter length', () => { expect(() => { aes.generateKey({name:"AES-CTR", length:100}, true, ['encrypt', 'decrypt']) }).to.throw('Member length must be 128, 192, or 256.') }) it('should return CryptoKey', () => { cryptoKey.should.be.instanceof(CryptoKey) }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_CTR type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_CTR) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-CTR') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) it('should generate a random handle each time', () => { cryptoKey.handle.should.not.equal( aes.generateKey(alg, true, ['encrypt', 'decrypt']).handle ) }) })//generateKey /** * importKey */ describe('importKey', () => { let aes before(() => { aes = new AES_CTR({ name: "AES-CTR", length: 256 }) }) it('should throw with invalid usages', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-CTR"} , true, ['encrypt', 'decrypt', 'wrong']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.importKey('WRONG',{},{},true,[]) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, raw, cryptoKey before(() => { alg = { name: "AES-CTR", length: 256, } aes = new AES_CTR(alg) raw = new Uint8Array([ 99, 76, 237, 223, 177, 224, 59, 31, 129, 99, 180, 144, 141, 133, 102, 174, 168, 79, 144, 238, 56, 34, 45, 137, 113, 191, 114, 201, 213, 3, 61, 241]) return Promise.resolve() .then(() => cryptoKey = aes.importKey("raw", raw, {name:"AES-CTR"}, true, ["encrypt", "decrypt"])) }) it('should expect a suitable raw length', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-CTR"} , true, ['encrypt','decrypt']) }).to.throw('Length of data bits must be 128, 192 or 256.') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_CTR type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_CTR) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-CTR') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, cryptoKey before(() => { alg = { name: "AES-CTR", length: 256, } aes = new AES_CTR(alg) key = { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true, } return Promise.resolve() .then(() => cryptoKey = aes.importKey("jwk", key, {name:"AES-CTR"}, true, ["encrypt", "decrypt"])) }) it('should expect a suitable jwk format', () => { expect(() => { aes.importKey('jwk', "Incorrect", {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('Invalid jwk format') }) it('should expect correct kty format', () => { expect(() => { aes.importKey('jwk',{ kty: "WRONG", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('kty property must be "oct"') }) it('should expect data in k property', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", alg: "A256CTR", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('k property must not be empty') }) it('should expect A128CTR when data length is 16', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A256CTR", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A128CTR" must be 128 bits in length') }) it('should expect A192CTR when data length is 24', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A256CTR", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A192CTR" must be 192 bits in length') }) it('should expect A256CTR when data length is 32', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A192CTR", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A256CTR" must be 256 bits in length') }) it('should expect mismatched length when k is not appropriate base64url', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37", alg: "A256CTR", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm and data length mismatch') }) it('should expect correct value when "use" field is used', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", use: "WRONG", ext: true, }, {name:"AES-CTR"} , false, ['encrypt','decrypt']) }).to.throw('Key use must be "enc"') }) it('should expect valid key operations', () => { expect(() => { aes.importKey('jwk', key, {name:"AES-CTR"} , false, ['encrypt','decrypt','WRONG']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should expect non extractable to not be extractable', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: false, }, {name:"AES-CTR"} , true, ['encrypt','decrypt']) }).to.throw('Cannot be extractable when "ext" is set to false') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_CTR type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_CTR) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-CTR') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) })//jwk })//importKey /** * exportKey */ describe('exportKey', () => { let aes before(() => { aes = new AES_CTR({ name: "AES-CTR", length: 256 }) }) it('should have a valid handle in the key', () => { expect(() => { aes.exportKey('raw', {}) }).to.throw('Missing key material') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.exportKey('WRONG',{handle:"Something"}) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, key, raw, exportedFromChrome before(() => { alg = { name: "AES-CTR", length: 256, } aes = new AES_CTR(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true }, {name:"AES-CTR"}, true, ["encrypt", "decrypt"]) raw = aes.exportKey("raw",key) exportedFromChrome = new Uint8Array([ 99, 76, 237, 223, 177, 224, 59, 31, 129, 99, 180, 144, 141, 133, 102, 174, 168, 79, 144, 238, 56, 34, 45, 137, 113, 191, 114, 201, 213, 3, 61, 241]) }) it('should return a valid object', () => { raw.should.instanceof(Object) }) it('should be the same as the Chrome exported key' , () => { Buffer.from(aes.exportKey("raw",key)) .should.eql(Buffer.from(exportedFromChrome)) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, jwk before(() => { alg = { name: "AES-CTR", length: 256, } aes = new AES_CTR(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true }, {name:"AES-CTR"}, true, ["encrypt", "decrypt"]) jwk = aes.exportKey("jwk",key) }) it('should return a valid object', () => { jwk.should.instanceof(Object) }) it('should expect correct kty field', () => { jwk.kty.should.eql("oct") }) it('should expect A128CTR when data length is 16', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A128CTR", ext: true }, {name:"AES-CTR"}, true,["encrypt", "decrypt"])).alg.should.eql("A128CTR") }) it('should expect A192CTR when data length is 24', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A192CTR", ext: true }, {name:"AES-CTR"}, true, ["encrypt", "decrypt"])).alg.should.eql("A192CTR") }) it('should expect A256CTR when data length is 32', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true }, {name:"AES-CTR"}, true, ["encrypt", "decrypt"])).alg.should.eql("A256CTR") }) })//jwk })//exportKey }) webcrypto-0.9.2/test/algorithms/AES-GCMSpec.js000066400000000000000000000456511330022407200210610ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../../src/dictionaries/AesKeyAlgorithm') const AES_GCM = require('../../src/algorithms/AES-GCM') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') const CurrentlyNotSupportedError = require('../../src/errors/CurrentlyNotSupportedError') /** * Test code */ const good_iv = Buffer.from([ 220, 29, 37, 164, 41, 84, 153, 197, 157, 122, 156, 254, 196, 161, 114, 74 ]) const bad_iv = new Array() // (2^64 - 1) max size can never occur, as length of array is bounded by 2^32 /** * Tests */ describe('AES_GCM', () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { AES_GCM.dictionaries.should.eql([ KeyAlgorithm, AesKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { AES_GCM.members.publicExponent.should.equal('BufferSource') }) }) /** * encrypt */ describe('encrypt', () => { let aes, key, data, signature before(() => { aes = new AES_GCM({ name: "AES-GCM", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt"] ) data = new TextEncoder().encode('Encoded with WebCrypto') signature = new Uint8Array([ 28, 37, 34, 19, 165, 194, 33, 41, 41, 64, 114, 99, 135, 63, 127, 127, 177, 159, 109, 92, 80, 40, 168, 117, 38, 124, 35, 180, 244, 74, 59, 140, 210, 236, 134, 182, 126, 180]) }) it("should throw invalid data length", () => { expect(() => { let bad_data = {} aes.encrypt({name: "AES-GCM", iv: bad_iv}, key, bad_data) }).to.throw('Data must have a length less than 549755813632.') expect(() => { let bad_data = {} bad_data.byteLength = 549755813633 // > 2^39 - 256 aes.encrypt({name: "AES-GCM", iv: bad_iv}, key, bad_data) }).to.throw('Data must have a length less than 549755813632.') }) it("should throw with invalid iv length", () => { expect(() => { aes.encrypt({name: "AES-GCM", iv: bad_iv}, key, new Uint8Array()) }).to.throw('IV Length must be less than 18446744073709551615 in length.') }) it("should throw with invalid additionalData", () => { expect(() => { aes.encrypt({name: "AES-GCM", iv: good_iv, additionalData: {}}, key, new Uint8Array()) }).to.throw('AdditionalData must be less than 18446744073709551615 in length.') }) it('should accept an ArrayBuffer', () => { let data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]).buffer aes.encrypt({name: "AES-GCM", iv: good_iv}, key, data).should.be.instanceof(ArrayBuffer) }) it('should return an ArrayBuffer', () => { aes.encrypt({name: "AES-GCM", iv: good_iv}, key, data).should.be.instanceof(ArrayBuffer) }) it('should return a valid encryption', () => { Buffer.from(aes.encrypt({name: "AES-GCM", iv: good_iv}, key, data)) .should.eql(Buffer.from(signature.buffer)) }) }) // encrypt /** * decrypt */ describe('decrypt', () => { let aes, key, data, signature before(() => { aes = new AES_GCM({ name: "AES-GCM", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { name: "AES-GCM", }, true, ["encrypt", "decrypt"] ) data = new Uint8Array([ 28, 37, 34, 19, 165, 194, 33, 41, 41, 64, 114, 99, 135, 63, 127, 127, 177, 159, 109, 92, 80, 40, 168, 117, 38, 124, 35, 180, 244, 74, 59, 140, 210, 236, 134, 182, 126, 180]) signature = new TextEncoder().encode('Encoded with WebCrypto') }) it("should throw with invalid tagLength", () => { expect(() => { aes.decrypt({name: "AES-GCM", iv: good_iv, tagLength: 127}, key, new Uint8Array()) }).to.throw('TagLength is an invalid size.') }) it("should throw with unsupported tagLength", () => { expect(() => { aes.decrypt({name: "AES-GCM", iv: good_iv, tagLength: 64}, key, new Uint8Array()) }).to.throw('Node currently only supports 128 tagLength.') }) it("should throw with invalid data length", () => { expect(() => { aes.decrypt({name: "AES-GCM", iv: good_iv}, key, new Uint8Array()) }).to.throw('Data length cannot be less than tagLength.') }) it("should throw with invalid data length", () => { expect(() => { let data = new Uint8Array(1) data[0] = 1 aes.decrypt({name: "AES-GCM", iv: good_iv, tagLength: 128}, key, data) }).to.throw('Data length cannot be less than tagLength.') }) it("should throw with invalid iv length", () => { expect(() => { aes.encrypt({name: "AES-GCM", iv: bad_iv}, key, new Uint8Array()) }).to.throw('IV Length must be less than 18446744073709551615 in length.') }) it("should throw with invalid additionalData", () => { expect(() => { aes.encrypt({name: "AES-GCM", iv: good_iv, additionalData: {}}, key, new Uint8Array()) }).to.throw('AdditionalData must be less than 18446744073709551615 in length.') }) it('should return an ArrayBuffer', () => { aes.decrypt({name: "AES-GCM", iv: good_iv, tagLength: 128}, key, data).should.be.instanceof(ArrayBuffer) }) it('should return a valid decryption', () => { Buffer.from(aes.decrypt({name: "AES-GCM", iv: good_iv, tagLength: 128}, key, data)) .should.eql(Buffer.from(signature.buffer)) }) }) // decrypt /** * generateKey */ describe('generateKey', () => { let alg, aes, cryptoKey before(() => { alg = { name: "AES-GCM", length: 256, } aes = new AES_GCM(alg) return Promise.resolve() .then(() => cryptoKey = aes.generateKey(alg, true, ["encrypt", "decrypt"])) }) it('should throw with invalid usages', () => { expect(() => { aes.generateKey(alg, true, ['encrypt', 'decrypt', 'wrong']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should throw with invalid parameter length', () => { expect(() => { aes.generateKey({name:"AES-GCM", length:100}, true, ['encrypt', 'decrypt']) }).to.throw('Member length must be 128, 192, or 256.') }) it('should return CryptoKey', () => { cryptoKey.should.be.instanceof(CryptoKey) }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_GCM type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_GCM) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-GCM') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) it('should generate a random handle each time', () => { cryptoKey.handle.should.not.equal( aes.generateKey(alg, true, ['encrypt', 'decrypt']).handle ) }) })//generateKey /** * importKey */ describe('importKey', () => { let aes before(() => { aes = new AES_GCM({ name: "AES-GCM", length: 256 }) }) it('should throw with invalid usages', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-GCM"} , true, ['encrypt', 'decrypt', 'wrong']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.importKey('WRONG',{},{},true,[]) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, raw, cryptoKey before(() => { alg = { name: "AES-GCM", length: 256, } aes = new AES_GCM(alg) raw = new Uint8Array([ 99, 76, 237, 223, 177, 224, 59, 31, 129, 99, 180, 144, 141, 133, 102, 174, 168, 79, 144, 238, 56, 34, 45, 137, 113, 191, 114, 201, 213, 3, 61, 241]) return Promise.resolve() .then(() => cryptoKey = aes.importKey("raw", raw, {name:"AES-GCM"}, true, ["encrypt", "decrypt"])) }) it('should expect a suitable raw length', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-GCM"} , true, ['encrypt','decrypt']) }).to.throw('Length of data bits must be 128, 192 or 256.') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_GCM type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_GCM) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-GCM') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, cryptoKey before(() => { alg = { name: "AES-GCM", length: 256, } aes = new AES_GCM(alg) key = { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, } return Promise.resolve() .then(() => cryptoKey = aes.importKey("jwk", key, {name:"AES-GCM"}, true, ["encrypt", "decrypt"])) }) it('should expect a suitable jwk format', () => { expect(() => { aes.importKey('jwk', "Incorrect", {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('Invalid jwk format') }) it('should expect correct kty format', () => { expect(() => { aes.importKey('jwk',{ kty: "WRONG", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('kty property must be "oct"') }) it('should expect data in k property', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", alg: "A256GCM", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('k property must not be empty') }) it('should expect A128GCM when data length is 16', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A256GCM", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A128GCM" must be 128 bits in length') }) it('should expect A192GCM when data length is 24', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A256GCM", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A192GCM" must be 192 bits in length') }) it('should expect A256GCM when data length is 32', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A192GCM", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm "A256GCM" must be 256 bits in length') }) it('should expect mismatched length when k is not appropriate base64url', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37", alg: "A256GCM", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('Algorithm and data length mismatch') }) it('should expect correct value when "use" field is used', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", use: "WRONG", ext: true, }, {name:"AES-GCM"} , false, ['encrypt','decrypt']) }).to.throw('Key use must be "enc"') }) it('should expect valid key operations', () => { expect(() => { aes.importKey('jwk', key, {name:"AES-GCM"} , false, ['encrypt','decrypt','WRONG']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should expect non extractable to not be extractable', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: false, }, {name:"AES-GCM"} , true, ['encrypt','decrypt']) }).to.throw('Cannot be extractable when "ext" is set to false') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_GCM type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_GCM) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-GCM') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['encrypt','decrypt']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) })//jwk })//importKey /** * exportKey */ describe('exportKey', () => { let aes before(() => { aes = new AES_GCM({ name: "AES-GCM", length: 256 }) }) it('should have a valid handle in the key', () => { expect(() => { aes.exportKey('raw', {}) }).to.throw('Missing key material') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.exportKey('WRONG',{handle:"Something"}) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, key, raw before(() => { alg = { name: "AES-GCM", length: 256, } aes = new AES_GCM(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true }, {name:"AES-GCM"}, true, ["encrypt", "decrypt"]) raw = aes.exportKey("raw",key) }) it('should return a valid object', () => { raw.should.instanceof(Object) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, jwk before(() => { alg = { name: "AES-GCM", length: 256, } aes = new AES_GCM(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true }, {name:"AES-GCM"}, true, ["encrypt", "decrypt"]) jwk = aes.exportKey("jwk",key) }) it('should return a valid object', () => { jwk.should.instanceof(Object) }) it('should expect correct kty field', () => { jwk.kty.should.eql("oct") }) it('should expect A128GCM when data length is 16', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A128GCM", ext: true }, {name:"AES-GCM"}, true,["encrypt", "decrypt"])).alg.should.eql("A128GCM") }) it('should expect A192GCM when data length is 24', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A192GCM", ext: true }, {name:"AES-GCM"}, true, ["encrypt", "decrypt"])).alg.should.eql("A192GCM") }) it('should expect A256GCM when data length is 32', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true }, {name:"AES-GCM"}, true, ["encrypt", "decrypt"])).alg.should.eql("A256GCM") }) })//jwk })//exportKey }) webcrypto-0.9.2/test/algorithms/AES-KWSpec.js000066400000000000000000000403651330022407200207710ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const AesKeyAlgorithm = require('../../src/dictionaries/AesKeyAlgorithm') const AES_KW = require('../../src/algorithms/AES-KW') const AES_GCM = require('../../src/algorithms/AES-GCM') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') const CurrentlyNotSupportedError = require('../../src/errors/CurrentlyNotSupportedError') /** * Test code */ const good_iv = Buffer.from([ 220, 29, 37, 164, 41, 84, 153, 197, 157, 122, 156, 254, 196, 161, 114, 74 ]) const bad_iv = new Array() // (2^64 - 1) max size can never occur, as length of array is bounded by 2^32 /** * Tests */ describe('AES_KW', () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { AES_KW.dictionaries.should.eql([ KeyAlgorithm, AesKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { AES_KW.members.publicExponent.should.equal('BufferSource') }) }) /** * wrapKey */ describe('wrapKey', () => { let aes, key, data, signature before(() => { aes = new AES_KW({ name: "AES-KW", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true, }, { name: "AES-KW", }, true, ["wrapKey", "unwrapKey"] ) signature = new Uint8Array([ 63, 180, 233, 152, 186, 3, 20, 59, 64, 210, 44, 117, 189, 178, 116, 253, 244, 208, 240, 194, 57, 201, 96, 118, 236, 78, 183, 171, 194, 117, 62, 142, 167, 21, 169, 255, 111, 227, 86, 199]) }) it('should return an ArrayBuffer', () => { aes.wrapKey("raw",key,key,{ name: "AES-KW" }).should.be.instanceof(ArrayBuffer) }) it('should return a valid wrapped key object', () => { Buffer.from(aes.wrapKey("raw",key,key,{ name: "AES-KW" })) .should.eql(Buffer.from(signature.buffer)) }) it('should fail with invalid key length', () => { expect(() => { aes.wrapKey("raw",Buffer.from("invalid"),key,{name:"AES-KW"}) }).to.throw('Invalid key length. Must be multiple of 8.') }) }) // wrapKey /** * unwrapKey */ describe('unwrapKey', () => { let aes, key, data before(() => { aes = new AES_KW({ name: "AES-KW", length: 256 }) key = aes.importKey( "jwk", { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true, }, { name: "AES-KW", }, true, ["wrapKey", "unwrapKey"] ) data = new Uint8Array([ 63, 180, 233, 152, 186, 3, 20, 59, 64, 210, 44, 117, 189, 178, 116, 253, 244, 208, 240, 194, 57, 201, 96, 118, 236, 78, 183, 171, 194, 117, 62, 142, 167, 21, 169, 255, 111, 227, 86, 199]) }) it('should return an Array', () => { aes.unwrapKey( "raw", data, key, { name: "AES-KW" }, { name: "AES-GCM", length: 256 }, true, ["wrapKey","unwrapKey"] ).should.be.instanceof(Array) }) }) // unwrapKey /** * generateKey */ describe('generateKey', () => { let alg, aes, cryptoKey before(() => { alg = { name: "AES-KW", length: 256, } aes = new AES_KW(alg) return Promise.resolve() .then(() => cryptoKey = aes.generateKey(alg, true, ["wrapKey", "unwrapKey"])) }) it('should throw with invalid usages', () => { expect(() => { aes.generateKey(alg, true, ['wrapKey', 'unwrapKey', 'wrong']) }).to.throw('Key usages can only include "wrapKey" or "unwrapKey"') }) it('should throw with invalid parameter length', () => { expect(() => { aes.generateKey({name:"AES-KW", length:100}, true, ['wrapKey', 'unwrapKey']) }).to.throw('Member length must be 128, 192, or 256.') }) it('should return CryptoKey', () => { cryptoKey.should.be.instanceof(CryptoKey) }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_KW type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_KW) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-KW') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['wrapKey','unwrapKey']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) it('should generate a random handle each time', () => { cryptoKey.handle.should.not.equal( aes.generateKey(alg, true, ['wrapKey', 'unwrapKey']).handle ) }) })//generateKey /** * importKey */ describe('importKey', () => { let aes before(() => { aes = new AES_KW({ name: "AES-KW", length: 256 }) }) it('should throw with invalid usages', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-KW"} , true, ['wrapKey', 'unwrapKey', 'wrong']) }).to.throw('Key usages can only include "wrapKey" or "unwrapKey"') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.importKey('WRONG',{},{},true,[]) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, raw, cryptoKey before(() => { alg = { name: "AES-KW", length: 256, } aes = new AES_KW(alg) raw = new Uint8Array([ 99, 76, 237, 223, 177, 224, 59, 31, 129, 99, 180, 144, 141, 133, 102, 174, 168, 79, 144, 238, 56, 34, 45, 137, 113, 191, 114, 201, 213, 3, 61, 241]) return Promise.resolve() .then(() => cryptoKey = aes.importKey("raw", raw, {name:"AES-KW"}, true, ["wrapKey","unwrapKey"])) }) it('should expect a suitable raw length', () => { expect(() => { aes.importKey('raw', new Uint8Array([1,2,3,4]), {name:"AES-KW"} , true, ['wrapKey','unwrapKey']) }).to.throw('Length of data bits must be 128, 192 or 256.') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_KW type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_KW) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-KW') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(['wrapKey','unwrapKey']) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, cryptoKey before(() => { alg = { name: "AES-KW", length: 256, } aes = new AES_KW(alg) key = { kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true, } return Promise.resolve() .then(() => cryptoKey = aes.importKey("jwk", key, {name:"AES-KW"}, true, ["wrapKey","unwrapKey"])) }) it('should expect a suitable jwk format', () => { expect(() => { aes.importKey('jwk', "Incorrect", {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('Invalid jwk format') }) it('should expect correct kty format', () => { expect(() => { aes.importKey('jwk',{ kty: "WRONG", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('kty property must be "oct"') }) it('should expect data in k property', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", alg: "A256KW", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('k property must not be empty') }) it('should expect A128KW when data length is 16', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A256KW", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('Algorithm "A128KW" must be 128 bits in length') }) it('should expect A192KW when data length is 24', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A256KW", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('Algorithm "A192KW" must be 192 bits in length') }) it('should expect A256KW when data length is 32', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A192KW", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('Algorithm "A256KW" must be 256 bits in length') }) it('should expect mismatched length when k is not appropriate base64url', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37", alg: "A256KW", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('Algorithm and data length mismatch') }) it('should expect correct value when "use" field is used', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", use: "WRONG", ext: true, }, {name:"AES-KW"} , false, ["wrapKey","unwrapKey"]) }).to.throw('Key use must be "enc"') }) it('should expect valid key operations', () => { expect(() => { aes.importKey('jwk', key, {name:"AES-KW"} , false, ["wrapKey","unwrapKey",'WRONG']) }).to.throw('Key usages can only include "wrapKey" or "unwrapKey"') }) it('should expect non extractable to not be extractable', () => { expect(() => { aes.importKey('jwk',{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: false, }, {name:"AES-KW"} , true, ["wrapKey","unwrapKey"]) }).to.throw('Cannot be extractable when "ext" is set to false') }) it('should be a secret key type', () => { cryptoKey.type.should.equal('secret') }) it('should have AES_KW type for algorithm', () => { cryptoKey.algorithm.should.instanceof(AES_KW) }) it('should set algorithm name', () => { cryptoKey.algorithm.name .should.equal('AES-KW') }) it('should set key as extractable', () => { cryptoKey.extractable.should.equal(true) }) it('should set key usages', () => { cryptoKey.usages.should.eql(["wrapKey","unwrapKey"]) }) it('should have correct length key handle', () => { cryptoKey.handle.length.should.equal(cryptoKey.algorithm.length / 8) }) })//jwk })//importKey /** * exportKey */ describe('exportKey', () => { let aes before(() => { aes = new AES_KW({ name: "AES-KW", length: 256 }) }) it('should have a valid handle in the key', () => { expect(() => { aes.exportKey('raw', {}) }).to.throw('Missing key material') }) it('should expect only "raw" or "jwk" formats', () => { expect(() => { aes.exportKey('WRONG',{handle:"Something"}) }).to.throw('WRONG is not a supported key format') }) describe('with "raw" format', () => { let alg, aes, key, raw before(() => { alg = { name: "AES-KW", length: 256, } aes = new AES_KW(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true }, {name:"AES-KW"}, true, ["wrapKey","unwrapKey"]) raw = aes.exportKey("raw",key) }) it('should return a valid object', () => { raw.should.instanceof(Object) }) })//raw describe('with "jwk" format', () => { let alg, aes, key, jwk before(() => { alg = { name: "AES-KW", length: 256, } aes = new AES_KW(alg) key = aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true }, {name:"AES-KW"}, true, ["wrapKey","unwrapKey"]) jwk = aes.exportKey("jwk",key) }) it('should return a valid object', () => { jwk.should.instanceof(Object) }) it('should expect correct kty field', () => { jwk.kty.should.eql("oct") }) it('should expect A128KW when data length is 16', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13Yw", alg: "A128KW", ext: true }, {name:"AES-KW"}, true,["wrapKey","unwrapKey"])).alg.should.eql("A128KW") }) it('should expect A192KW when data length is 24', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "c7WsUB6msAgIdDxTnT13YwY7SQjYVmrq", alg: "A192KW", ext: true }, {name:"AES-KW"}, true, ["wrapKey","unwrapKey"])).alg.should.eql("A192KW") }) it('should expect A256KW when data length is 32', () => { aes.exportKey("jwk",aes.importKey("jwk",{ kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true }, {name:"AES-KW"}, true, ["wrapKey","unwrapKey"])).alg.should.eql("A256KW") }) })//jwk })//exportKey }) webcrypto-0.9.2/test/algorithms/ECDSASpec.js000066400000000000000000000354201330022407200206550ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const EcKeyAlgorithm = require('../../src/dictionaries/EcKeyAlgorithm') const ECDSA = require('../../src/algorithms/ECDSA') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') const CurrentlyNotSupportedError = require('../../src/errors/CurrentlyNotSupportedError') /** * Code under test */ const { ECDSA_K256_PrivateKey, ECDSA_K256_PublicKey, ECDSA_K256_PrivatePem, ECDSA_K256_PublicPem, ECDSA_P256_PrivateKey, ECDSA_P256_PublicKey, ECDSA_P256_PrivatePem, ECDSA_P256_PublicPem, ECDSA_P384_PrivateKey, ECDSA_P384_PublicKey, ECDSA_P384_PrivatePem, ECDSA_P384_PublicPem, ECDSA_P521_PrivateKey, ECDSA_P521_PublicKey, ECDSA_P521_PrivatePem, ECDSA_P521_PublicPem, } = require('../EcdsaKeyPairsForTesting') /** * Tests */ const ECDSATest = ({ ECPrivateKey, ECPublicKey, ECPrivatePem, ECPublicPem }, eccrv, echash) => { describe(`ECDSA ${eccrv}`, () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { ECDSA.dictionaries.should.eql([ KeyAlgorithm, EcKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { ECDSA.members.hash.should.equal('HashAlgorithmIdentifier') }) }) /** * sign */ describe('sign', () => { let alg, ecdsa, data, signature before(() => { alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } } ecdsa = new ECDSA(alg) data = new TextEncoder().encode('signed with elliptic.js module') }) it('should throw with non-private key', () => { expect(() => { ecdsa.sign(ECPublicKey, new Uint8Array()) }).to.throw('Signing requires a private key') }) it('should return an ArrayBuffer', () => { ecdsa.sign(ECPrivateKey, data).should.be.instanceof(ArrayBuffer) }) it('should return a ECDSA signature') }) /** * verify */ describe('verify', () => { let alg, ecdsa, data, signature before(() => { alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } } ecdsa = new ECDSA(alg) data = new TextEncoder().encode('signed with elliptic.js module') signature = new Uint8Array([ 48, 69, 2, 32, 123, 162, 50, 30, 164, 193, 22, 192, 115, 60, 235, 173, 129, 57, 80, 180, 96, 108, 102, 208, 213, 116, 102, 123, 87, 116, 212, 170, 221, 39, 165, 154, 2, 33, 0, 205, 67, 50, 237, 235, 121, 114, 98, 126, 199, 100, 211, 15, 185, 46, 113, 242, 198, 50, 162, 223, 250, 240, 82, 80, 230, 146, 175, 115, 156, 199, 213 ]) }) it('should throw with non-private key', () => { expect(() => { ecdsa.verify(ECPrivateKey, new Uint8Array()) }).to.throw('Verifying requires a public key') }) it.skip('should return true with valid signature', () => { ecdsa.verify(ECPublicKey, signature, data).should.equal(true) }) it('should return false with invalid signature', () => { let invalidData = new TextEncoder().encode('invalid signature') ecdsa.verify(ECPublicKey, signature, invalidData).should.equal(false) }) }) /** * generateKey */ describe('generateKey', () => { let alg, ecdsa, cryptoKeyPair before(() => { alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash }} ecdsa = new ECDSA(alg) return Promise.resolve() .then(() => cryptoKeyPair = ecdsa.generateKey(alg, true, ['sign', 'verify'])) }) it('should throw with invalid usages', () => { expect(() => { ecdsa.generateKey(alg, true, ['sign', 'verify', 'wrong']) }).to.throw('Key usages can only include "sign", or "verify"') }) it('should return CryptoKey', () => { cryptoKeyPair.should.be.instanceof(CryptoKeyPair) }) it('should set public key type', () => { cryptoKeyPair.publicKey.type.should.equal('public') }) it('should set private key type', () => { cryptoKeyPair.privateKey.type.should.equal('private') }) it('should set public key algorithm', () => { cryptoKeyPair.publicKey.algorithm .should.be.instanceof(ECDSA) }) it('should set private key algorithm', () => { cryptoKeyPair.privateKey.algorithm .should.be.instanceof(ECDSA) }) it('should set public key algorithm name', () => { cryptoKeyPair.publicKey.algorithm.name .should.equal('ECDSA') }) it('should set private key algorithm name', () => { cryptoKeyPair.privateKey.algorithm.name .should.equal('ECDSA') }) it('should set public key algorithm hash name', () => { cryptoKeyPair.publicKey.algorithm.hash.name .should.equal(echash) }) it('should set private key algorithm hash name', () => { cryptoKeyPair.privateKey.algorithm.hash.name .should.equal(echash) }) it('should set public key extractable', () => { cryptoKeyPair.publicKey.extractable.should.equal(true) }) it('should set private key extractable', () => { cryptoKeyPair.privateKey.extractable.should.equal(true) }) it('should set public key usages', () => { cryptoKeyPair.publicKey.usages.should.eql(['verify']) }) it('should set private key usages', () => { cryptoKeyPair.privateKey.usages.should.eql(['sign']) }) it('should set public key handle', () => { cryptoKeyPair.publicKey.handle .should.include('-----BEGIN PUBLIC KEY-----') }) it('should set private key handle', () => { cryptoKeyPair.privateKey.handle .should.include('-----BEGIN EC PRIVATE KEY-----') }) }) /** * importKey */ describe('importKey', () => { describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('private key and invalid usages', () => { let key, alg, ec before(() => { key = { kty: 'EC', crv: eccrv, d: 'PR587JJiuSE3aFthaonYf3VJtB9WXaZcN7Vi0OmBUtw', x: 'L_yAQbK4Kg95AknFkfVO8V5rWkN1shsz7jrEyDZ3McA', y: '2Na7_YUSHDMn68XsnIGOfo3TwiIqfbaTXvavUKzT6qo' } alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } } ec = new ECDSA(alg) }) it('should throw SyntaxError', () => { expect(() => { ec.importKey('jwk', key, alg , false, ['bad']) }).to.throw('Key usages must include "sign"') }) }) describe('non-private key and invalid usages', () => { let key, alg, ec before(() => { key = { kty: 'EC', crv: eccrv, x: 'L_yAQbK4Kg95AknFkfVO8V5rWkN1shsz7jrEyDZ3McA', y: '2Na7_YUSHDMn68XsnIGOfo3TwiIqfbaTXvavUKzT6qo' } alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } } ec = new ECDSA(alg) }) it('should throw SyntaxError', () => { expect(() => { ec.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages must include "verify"') }) }) describe('invalid key type', () => { let key, alg, ec before(() => { key = { kty: 'WRONG', crv: eccrv, x: 'L_yAQbK4Kg95AknFkfVO8V5rWkN1shsz7jrEyDZ3McA', y: '2Na7_YUSHDMn68XsnIGOfo3TwiIqfbaTXvavUKzT6qo' } alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } } ec = new ECDSA(alg) }) it('should throw DataError', () => { expect(() => { ec.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key type must be "EC"') }) }) describe('invalid key use', () => { let key, alg, ec before(() => { key = { kty: 'EC', crv: eccrv, x: 'L_yAQbK4Kg95AknFkfVO8V5rWkN1shsz7jrEyDZ3McA', y: '2Na7_YUSHDMn68XsnIGOfo3TwiIqfbaTXvavUKzT6qo', use: "WRONG" } alg = { name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } } ec = new ECDSA(alg) }) it('should throw DataError', () => { expect(() => { ec.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key use must be "sig".') }) }) describe(`private ${eccrv} key`, () => { let key before(() => { key = ECPrivateKey }) it('should define type', () => { key.type.should.equal('private') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(ECDSA) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['sign']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN EC PRIVATE KEY-----') }) }) describe(`public ${eccrv} key`, () => { let key before(() => { key = ECPublicKey }) it('should define type', () => { key.type.should.equal('public') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(ECDSA) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['verify']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN PUBLIC KEY-----') }) }) describe('with "raw" format', () => {}) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let alg = new ECDSA({ name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } }) let caller = () => { alg.importKey('WRONG', {}, alg, false, ['verify']) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) /** * exportKey */ describe('exportKey', () => { describe('with missing key material', () => { it('should throw OperationError', () => { expect(() => { let ec = new ECDSA({ name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } }) ec.exportKey('format', {}) }).to.throw('Missing key material') }) }) describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe(`${eccrv} curve`, () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: echash } }, extractable: true, usages: ['verify'], handle: ECPublicPem }) let ec = new ECDSA({ name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } }) jwk = ec.exportKey('jwk', key) }) it(`should set "crv" to "${eccrv}"`, () => { jwk.crv.should.equal(eccrv) }) }) describe('other hash', () => {}) }) describe('with "raw" format', () => { describe(`${eccrv} curve`, () => { let raw, key before(() => { key = new CryptoKey({ type: 'public', algorithm: { hash: { name: echash } }, extractable: true, usages: ['verify'], handle: ECPublicPem }) let ec = new ECDSA({ name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } }) raw = ec.exportKey('raw', key) }) it('return the handle of CryptoKey', () => { raw.should.deep.equal(Buffer.from(key.handle)) }) }) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: echash } }, extractable: true, usages: ['verify'], handle: ECPublicPem }) let alg = new ECDSA({ name: 'ECDSA', namedCurve: eccrv, hash: { name: echash } }) let caller = () => { alg.exportKey('WRONG', key) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) })//ECDSA TESTS } // K256 ECDSATest({ ECPrivateKey: ECDSA_K256_PrivateKey, ECPublicKey: ECDSA_K256_PublicKey, ECPrivatePem: ECDSA_K256_PrivatePem, ECPublicPem: ECDSA_K256_PublicPem, }, 'K-256', 'SHA-256') // P256 ECDSATest({ ECPrivateKey: ECDSA_P256_PrivateKey, ECPublicKey: ECDSA_P256_PublicKey, ECPrivatePem: ECDSA_P256_PrivatePem, ECPublicPem: ECDSA_P256_PublicPem, }, 'P-256', 'SHA-256') // P384 ECDSATest({ ECPrivateKey: ECDSA_P384_PrivateKey, ECPublicKey: ECDSA_P384_PublicKey, ECPrivatePem: ECDSA_P384_PrivatePem, ECPublicPem: ECDSA_P384_PublicPem, }, 'P-384', 'SHA-384') // P521 ECDSATest({ ECPrivateKey: ECDSA_P521_PrivateKey, ECPublicKey: ECDSA_P521_PublicKey, ECPrivatePem: ECDSA_P521_PrivatePem, ECPublicPem: ECDSA_P521_PublicPem, }, 'P-521', 'SHA-512') webcrypto-0.9.2/test/algorithms/EDDSASpec.js000066400000000000000000000455241330022407200206640ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const JsonWebKey = require('../../src/keys/JsonWebKey') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const EcKeyAlgorithm = require('../../src/dictionaries/EcKeyAlgorithm') const EDDSA = require('../../src/algorithms/EDDSA') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') const CurrentlyNotSupportedError = require('../../src/errors/CurrentlyNotSupportedError') /** * Code under test */ // Taken from https://tools.ietf.org/html/rfc8032#section-7.1, Test 2 let edd25519_private = { type: 'private', hex: `4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb` } let edd25519_public = { type: 'public', hex: `3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c` } /** * Tests */ describe(`EDDSA`, () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { eddsa.dictionaries.should.eql([ KeyAlgorithm, EcKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { eddsa.members.hash.should.equal('HashAlgorithmIdentifier') }) }) /** * sign */ describe('sign', () => { let alg, eddsa, data, signature, eddsaPublicKey, eddsaPrivateKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519' } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) eddsaPrivateKey = eddsa.importKey( "hex", edd25519_private, alg, true, ['sign'] ) data = Buffer.from('72','hex') signature = Buffer.from(`92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00`,'hex') }) it('should throw with non-private key', () => { expect(() => { eddsa.sign(eddsaPublicKey, new Uint8Array()) }).to.throw('Signing requires a private key') }) it('should return an ArrayBuffer', () => { eddsa.sign(eddsaPrivateKey, data).should.be.instanceof(ArrayBuffer) }) it('should return an EDDSA signature', () => { Buffer.from(eddsa.sign(eddsaPrivateKey, data)) .should.deep.equal(signature) }) it('should throw with invalid data type', () => { expect(() => { eddsa.sign(eddsaPrivateKey, {}) }).to.throw('Data must be an Array, Buffer or hex string') }) }) /** * verify */ describe('verify', () => { let alg, eddsa, data, signature, eddsaPublicKey, eddsaPrivateKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519' } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) eddsaPrivateKey = eddsa.importKey( "hex", edd25519_private, alg, true, ['sign'] ) data = Buffer.from('72','hex') signature = Buffer.from(`92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00`,'hex') signature = Uint8Array.from(signature).buffer }) it('should throw with non-private key', () => { expect(() => { eddsa.verify(eddsaPrivateKey, '','') }).to.throw('Verifying requires a public key') }) it('should return true with valid signature', () => { eddsa.verify(eddsaPublicKey, signature, data).should.equal(true) }) it('should return false with invalid signature', () => { let invalidData = Buffer.from(new TextEncoder().encode('invalid signature')) eddsa.verify(eddsaPublicKey, signature, invalidData).should.equal(false) }) }) /** * generateKey */ describe('generateKey', () => { let alg, eddsa, cryptoKeyPair before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519' } eddsa = new EDDSA(alg) return Promise.resolve() .then(() => cryptoKeyPair = eddsa.generateKey(alg, true, ['sign', 'verify'])) }) it('should throw with invalid usages', () => { expect(() => { eddsa.generateKey(alg, true, ['sign', 'verify', 'wrong']) }).to.throw('Key usages can only include "sign", or "verify"') }) it('should return CryptoKey', () => { cryptoKeyPair.should.be.instanceof(CryptoKeyPair) }) it('should set public key type', () => { cryptoKeyPair.publicKey.type.should.equal('public') }) it('should set private key type', () => { cryptoKeyPair.privateKey.type.should.equal('private') }) it('should set public key algorithm', () => { cryptoKeyPair.publicKey.algorithm .should.be.instanceof(EDDSA) }) it('should set private key algorithm', () => { cryptoKeyPair.privateKey.algorithm .should.be.instanceof(EDDSA) }) it('should set public key algorithm name', () => { cryptoKeyPair.publicKey.algorithm.name .should.equal('EDDSA') }) it('should set private key algorithm name', () => { cryptoKeyPair.privateKey.algorithm.name .should.equal('EDDSA') }) it('should set public key extractable', () => { cryptoKeyPair.publicKey.extractable.should.equal(true) }) it('should set private key extractable', () => { cryptoKeyPair.privateKey.extractable.should.equal(true) }) it('should set public key usages', () => { cryptoKeyPair.publicKey.usages.should.eql(['verify']) }) it('should set private key usages', () => { cryptoKeyPair.privateKey.usages.should.eql(['sign']) }) }) /** * importKey */ describe('importKey', () => { describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('private key and invalid usages', () => { let key, alg, ec before(() => { key = { kty: "OKP", crv: "Ed25519", d: "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" } alg = { name: 'EDDSA', namedCurve: 'Ed25519', } ec = new EDDSA(alg) }) it('should throw SyntaxError', () => { expect(() => { ec.importKey('jwk', key, alg , false, ['bad']) }).to.throw('Key usages must include "sign"') }) }) describe('non-private key and invalid usages', () => { let key, alg, ec before(() => { key = { kty: "OKP", crv: "Ed25519", x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" } alg = { name: 'EDDSA', namedCurve: 'Ed25519', } ec = new EDDSA(alg) }) it('should throw SyntaxError', () => { expect(() => { ec.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages must include "verify"') }) }) describe('invalid key type', () => { let key, alg, ec before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } ec = new EDDSA(alg) key = { kty: "WRONG", crv: "Ed25519", x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" } }) it('should throw DataError', () => { expect(() => { ec.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key type must be "OKP"') }) }) describe('invalid key use', () => { let key, alg, eddsa before(() => { key = { kty: "OKP", crv: "Ed25519", d: "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" } alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) }) it('should throw DataError', () => { expect(() => { eddsa.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key usages must include "sign"') }) }) describe(`private Ed25519 key`, () => { let alg,eddsa,key,eddsaPrivateKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPrivateKey = eddsa.importKey( "jwk", { kty: "OKP", crv: "Ed25519", d: "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" }, alg, true, ['sign'] ) key = eddsaPrivateKey }) it('should define type', () => { key.type.should.equal('private') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(EDDSA) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['sign']) }) }) describe(`public Ed25519 key`, () => { let alg,eddsa,key, eddsaPublicKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "jwk", { kty: "OKP", crv: "Ed25519", x: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" }, alg, true, ['verify'] ) key = eddsaPublicKey }) it('should define type', () => { key.type.should.equal('public') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(EDDSA) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['verify']) }) }) describe('with "raw" format', () => {}) }) describe('with "hex" format', () => { describe('private key and invalid usages', () => { let key, alg, ec before(() => { key = edd25519_private alg = { name: 'EDDSA', namedCurve: 'Ed25519', } ec = new EDDSA(alg) }) it('should throw SyntaxError', () => { expect(() => { ec.importKey('hex', key, alg , false, ['bad']) }).to.throw('Key usages must include "sign"') }) }) describe('non-private key and invalid usages', () => { let key, alg, ec before(() => { key = edd25519_public alg = { name: 'EDDSA', namedCurve: 'Ed25519', } ec = new EDDSA(alg) }) it('should throw SyntaxError', () => { expect(() => { ec.importKey('hex', key, alg, false, ['bad']) }).to.throw('Key usages must include "verify"') }) }) describe('invalid key type', () => { let key, alg, ec before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } ec = new EDDSA(alg) key = { type: "GARBAGE", hex: edd25519_public.hex } }) it('should throw DataError', () => { expect(() => { ec.importKey('hex', key, alg, false, ['verify']) }).to.throw('Key type can only be "private" or "public".') }) }) describe('invalid key use', () => { let key, alg, eddsa before(() => { key = edd25519_private alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) }) it('should throw DataError', () => { expect(() => { eddsa.importKey('hex', key, alg, false, ['verify']) }).to.throw('Key usages must include "sign"') }) }) describe(`private Ed25519 key`, () => { let alg,eddsa,key,eddsaPrivateKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPrivateKey = eddsa.importKey( "hex", edd25519_private, alg, true, ['sign'] ) key = eddsaPrivateKey }) it('should define type', () => { key.type.should.equal('private') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(EDDSA) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['sign']) }) }) describe(`public Ed25519 key`, () => { let alg,eddsa,key, eddsaPublicKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) key = eddsaPublicKey }) it('should define type', () => { key.type.should.equal('public') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(EDDSA) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['verify']) }) }) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let alg = new EDDSA({ name: 'EDDSA', namedCurve: 'Ed25519' }) let caller = () => { alg.importKey('WRONG', {}, alg, false, ['verify']) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) /** * exportKey */ describe('exportKey', () => { describe('with missing key material', () => { it('should throw OperationError', () => { expect(() => { let ec = new EDDSA({ name: 'EDDSA', namedCurve: 'Ed25519' }) ec.exportKey('format', {}) }).to.throw('Missing key material') }) }) describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { let alg,eddsa,key, eddsaPublicKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) key = eddsaPublicKey }) it('should return a valid key', () => { eddsa.exportKey("jwk",key).should.be.instanceof(JsonWebKey) }) }) describe('with "raw" format', () => { let alg,eddsa,key, eddsaPublicKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) key = eddsaPublicKey }) it('should return a valid key', () => { eddsa.exportKey("raw",key).should.be.instanceof(Buffer) }) }) describe('with "hex" format', () => { let alg,eddsa,key, eddsaPublicKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) key = eddsaPublicKey }) it('should return a valid key', () => { eddsa.exportKey("hex",key).should.be.an('string') }) }) describe('with other format', () => { let alg,eddsa,key, eddsaPublicKey before(() => { alg = { name: 'EDDSA', namedCurve: 'Ed25519', } eddsa = new EDDSA(alg) eddsaPublicKey = eddsa.importKey( "hex", edd25519_public, alg, true, ['verify'] ) key = eddsaPublicKey }) it('should throw NotSupportedError', () => { let caller = () => { eddsa.exportKey('WRONG', key) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) })//EDDSA TESTSwebcrypto-0.9.2/test/algorithms/HMACSpec.js000066400000000000000000000215751330022407200205540ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const HmacKeyAlgorithm = require('../../src/dictionaries/HmacKeyAlgorithm') const HMAC = require('../../src/algorithms/HMAC') const OperationError = require('../../src/errors/OperationError') /** * Tests */ describe('HMAC', () => { describe('dictionaries getter', () => { it('should return an array', () => { HMAC.dictionaries.should.eql([ KeyAlgorithm, HmacKeyAlgorithm ]) }) }) describe('members getter', () => { it('should return an object', () => { HMAC.members.should.eql({}) }) }) describe('sign', () => { let alg, rawHmacKey, chromeHmacSignature, data, importedHmacKey before(() => { alg = { name: 'HMAC', hash: { name: 'SHA-256' } } rawHmacKey = new Uint8Array([ 137, 35, 38, 29, 130, 138, 121, 216, 20, 204, 169, 61, 76, 80, 127, 140, 197, 193, 48, 6, 207, 97, 70, 77, 57, 30, 72, 245, 249, 9, 204, 207, 215, 1, 53, 33, 189, 28, 105, 9, 61, 158, 152, 113, 46, 83, 3, 228, 234, 140, 20, 31, 192, 34, 254, 113, 117, 59, 17, 78, 164, 52, 116, 38 ]) chromeHmacSignature = new Uint8Array([ 72, 73, 12, 66, 105, 131, 73, 116, 160, 243, 96, 121, 121, 40, 244, 198, 107, 151, 113, 243, 51, 19, 60, 234, 93, 23, 199, 14, 42, 118, 25, 161 ]) data = new TextEncoder() .encode('signed with Chrome generated webcrypto key') return crypto.subtle .importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) .then(cryptoKey => importedHmacKey = cryptoKey) }) it('should return an ArrayBuffer', () => { let hmac = new HMAC(alg) hmac.sign(importedHmacKey, data).should.be.instanceof(ArrayBuffer) }) it('should return a HMAC signature', () => { let hmac = new HMAC(alg) let signature = hmac.sign(importedHmacKey, data) Buffer.from(signature).should.eql(Buffer.from(chromeHmacSignature.buffer)) }) }) describe('verify', () => { let alg, rawHmacKey, chromeHmacSignature, data, importedHmacKey before(() => { alg = { name: 'HMAC', hash: { name: 'SHA-256' } } rawHmacKey = new Uint8Array([ 137, 35, 38, 29, 130, 138, 121, 216, 20, 204, 169, 61, 76, 80, 127, 140, 197, 193, 48, 6, 207, 97, 70, 77, 57, 30, 72, 245, 249, 9, 204, 207, 215, 1, 53, 33, 189, 28, 105, 9, 61, 158, 152, 113, 46, 83, 3, 228, 234, 140, 20, 31, 192, 34, 254, 113, 117, 59, 17, 78, 164, 52, 116, 38 ]) chromeHmacSignature = new Uint8Array([ 72, 73, 12, 66, 105, 131, 73, 116, 160, 243, 96, 121, 121, 40, 244, 198, 107, 151, 113, 243, 51, 19, 60, 234, 93, 23, 199, 14, 42, 118, 25, 161 ]) data = new TextEncoder() .encode('signed with Chrome generated webcrypto key') return crypto.subtle .importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) .then(cryptoKey => importedHmacKey = cryptoKey) }) it('should verify a valid HMAC signature', () => { let hmac = new HMAC(alg) hmac.verify(importedHmacKey, chromeHmacSignature, data).should.be.true }) it('should not verify an invalid HMAC signature', () => { let hmac = new HMAC(alg) let invalidData = new TextEncoder().encode('wrong data') hmac.verify(importedHmacKey, chromeHmacSignature, invalidData).should.be.false }) }) describe('generateKey', () => { let alg, hmac, key beforeEach(() => { alg = { name: 'HMAC', hash: { name: 'SHA-256' } } hmac = new HMAC(alg) key = hmac.generateKey(alg, true, ['sign', 'verify']) }) it('should throw with invalid usages', () => { expect(() => { hmac.generateKey(alg, true, ['sign', 'verify', 'wrong']) }).to.throw('Key usages can only include "sign" and "verify"') }) it('should throw with invalid length', () => { expect(() => { hmac.generateKey({ name: 'HMAC', hash: { name: 'SHA-256' }, length: 0 }, true, ['sign', 'verify']) }).to.throw('Invalid HMAC length') }) it('should return CryptoKey', () => { key.should.be.instanceof(CryptoKey) }) it('should set key type', () => { key.type.should.equal('secret') }) it('should set key algorithm', () => { key.algorithm.should.be.instanceof(HMAC) }) it('should set key algorithm name', () => { key.algorithm.name.should.equal('HMAC') }) it('should set key algorithm hash', () => { key.algorithm.hash.should.be.instanceof(KeyAlgorithm) }) it('should set key algorithm hash name', () => { key.algorithm.hash.name.should.equal('SHA-256') }) it('should set key extractable', () => { key.extractable.should.equal(true) }) it('should set key usages', () => { key.usages.should.eql(['sign', 'verify']) }) it('should set key handle', () => { key.handle.should.be.instanceof(Buffer) }) }) describe('importKey', () => { let alg, hmac, rawHmacKey, key beforeEach(() => { alg = { name: 'HMAC', hash: { name: 'SHA-256' } } hmac = new HMAC(alg) rawHmacKey = new Uint8Array([ 137, 35, 38, 29, 130, 138, 121, 216, 20, 204, 169, 61, 76, 80, 127, 140, 197, 193, 48, 6, 207, 97, 70, 77, 57, 30, 72, 245, 249, 9, 204, 207, 215, 1, 53, 33, 189, 28, 105, 9, 61, 158, 152, 113, 46, 83, 3, 228, 234, 140, 20, 31, 192, 34, 254, 113, 117, 59, 17, 78, 164, 52, 116, 38 ]) key = hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) }) it('should throw with invalid usages', () => { expect(() => { hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify', 'wrong']) }).to.throw('Key usages can only include "sign" and "verify"') }) it('should throw with missing algorithm hash', () => { expect(() => { alg = { name: 'HMAC' } hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) }).to.throw('HmacKeyGenParams: hash: Missing or not an AlgorithmIdentifier') }) it('should throw with unsupported key format', () => { expect(() => { hmac.importKey('WRONG', rawHmacKey, alg, true, ['sign', 'verify']) }).to.throw('WRONG is not a supported key format') }) it('should throw with empty key data', () => { expect(() => { hmac.importKey('raw', new Uint8Array(), alg, true, ['sign', 'verify']) }).to.throw('HMAC key data must not be empty') }) it('should import raw key data and return a CryptoKey', () => { hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) .should.be.instanceof(CryptoKey) }) it('should set key type', () => { hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) .type.should.equal('secret') }) it('should set key algorithm', () => { hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) .algorithm.should.be.instanceof(HMAC) }) it('should set key algorithm name', () => { key.algorithm.name.should.equal('HMAC') }) it('should set key algorithm hash name', () => { key.algorithm.hash.name.should.equal('SHA-256') }) it('should set key extractable', () => { key.extractable.should.equal(true) }) it('should set key usages', () => { key.usages.should.eql(['sign', 'verify']) }) it('should set key handle', () => { key.handle.should.be.instanceof(Buffer) }) }) describe('exportKey', () => { let alg, hmac, rawHmacKey, key beforeEach(() => { alg = { name: 'HMAC', hash: { name: 'SHA-256' } } hmac = new HMAC(alg) rawHmacKey = new Uint8Array([ 137, 35, 38, 29, 130, 138, 121, 216, 20, 204, 169, 61, 76, 80, 127, 140, 197, 193, 48, 6, 207, 97, 70, 77, 57, 30, 72, 245, 249, 9, 204, 207, 215, 1, 53, 33, 189, 28, 105, 9, 61, 158, 152, 113, 46, 83, 3, 228, 234, 140, 20, 31, 192, 34, 254, 113, 117, 59, 17, 78, 164, 52, 116, 38 ]) key = hmac.importKey('raw', rawHmacKey, alg, true, ['sign', 'verify']) }) it('should throw with invalid usages', () => { expect(() => { hmac.exportKey('raw', {}) }).to.throw('argument must be CryptoKey') }) it('should throw with unsupported key format', () => { expect(() => { hmac.exportKey('WRONG', key) }).to.throw('WRONG is not a supported key format') }) it('should return a raw key', () => { hmac.exportKey('raw', key).should.be.instanceof(Buffer) }) }) }) webcrypto-0.9.2/test/algorithms/RSA-OAEPspec.js000066400000000000000000000542331330022407200212500ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() /** * Code under test */ const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const RsaKeyAlgorithm = require('../../src/dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../../src/dictionaries/RsaHashedKeyAlgorithm') const RSA_OAEP = require('../../src/algorithms/RSA-OAEP') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Code under test */ let Rsa = new RSA_OAEP({ name: "RSA-OAEP", hash: { name: 'SHA-1' } }) let RsaPrivateJwk = { "alg":"RSA-OAEP", "d":"OONqS6vhPhdw_a5PZ7e0dIQNk8k2x8S_4wdsGcw5LVKRnsm07IDSb6JgsSBrM16tpthXbdAqFp5Lbcuc8clkRN0RUlH5aBCuFHQDRit5c7hvhDKbR5Tjuu8i6ZfGNCXzU-oFeaPBAP6aiclmJZO0wyRvTYNtvRcjELix11MWfhxulAiMayEXG47AvLycBOim1hui28R3WYwH8Yfc7-BoXITjy8V9ViMRCU2cVnPtXQYnz27KAYFmV7wcAhWgB5T97abSVWwgk_ZIhjfieNjOLuG2veVuDOni-mzMjg_5DwWAtMkx2G9fysSaHJiarcb071BEIurD5uZ3EPKxSksE4Q", "dp":"YU25IwbEb_BVTCYkd01iVZQBCPrkHMEUt0SDkWuFHmOiIfaDgbnIy9euDffwNglJMTDuxmKsXqiOnnJ4Q4Vjxm3v4gKNGsvckhfTxbX9Y_XIyxXTASRCBUDpyGQ2JllgUT3IAMBC4H7sb6c-fuwrGqQurNGSIcrTng3v-jHoedE", "dq":"csjKDq30kz-zoTs9e4YMuZ_h4NmZy9b-X3-oLHsMmA_TU4D2_bWqVaN4j8zURKOutrkepnYzOgacN2oR9dBj_Z8PLyPIgM03EuuFU5InkzAQ-DnUzJQU6gH1RgaWiG2lswLDEHQc3-d2fohveFxM90zAjP0Dhe-BTbt07GpE9sU", "e":"AQAB", "ext":true, "key_ops":["decrypt"], "kty":"RSA", "n":"q6kM0z9Faa2BHYSakuzZKirz3o7dNG83nq3Yw5KC1FOUkQStDtYz8EMkYV99WfHMCaRA_q_WBjRVnweQawFtR4zwNcmEhU-fUEIZCZ17ArKoNOy45Ep8NVuYJG3-OyYHuwnz5xLIvW9GVk2UqAJKaLSatuT2utU6JKeLu-4C0cb4eYUGT_RT-qsTF_NSWyyzdHrZzp9FX7ly-UTZw3inyjZYp5Ps1Ka5HzByzCTHhs_tatzLwG0FgjS7msPmwzE9RZFr1-J9exvIqhCmhvj5LSIdFmm5MEXC_b47fYCqSCE81bBofD2Ee0k72qOA-JfKNhrNXoLzuR7_1Ig1xJ8Ahw", "p":"0ca0ebRJqK1jhNd9e0dRMrl5_cJhxMZAH3jyHNgC-vqSmFjobkNOwvUxzyf-kXLvrNCuJbkQqQHN87saSGunAHpDdFPV1lsymnemLJjsfMNy1Qf5yw6r277gz1mVDcgfJbP_4vcps0v-VmIgaBwtkPNJVTv-PjVAY3PAXpqwSjE", "q":"0XxDaEvgA5ECPsFMiqsuhWajiv8I-nzi3EUeq25Za0PR_9S7HF0TXxk84-EPmCU1WxeilFhL96--g4fmypBjVaszL-nP7Thq4MBBPM5cviPuUoQXmYVOtD1q8rmVmc0HbtuzM5fmBbSfGn9sLhu6DE1ymlabHjvn-FWuIWLcEDc", "qi":"W-VEZ0hgjSA4qFjAkfaBK58NAV9rY45MP4n2MauCSoR9uqjkrYJQm74774G8tILIsw72eKejfObh6mmZUSPvOKRn-femd7KCH6x54sdNExvP3kAbXDVH9NhxgEjNjpsPjoyKXJGGZrAwPV6sncgea-h79gRXKRFYhXSK2cIk6Xk" } let RsaPrivateCryptoKey = Rsa.importKey( "jwk", RsaPrivateJwk, { name: "RSA-OAEP", hash: {name: "SHA-1"}, }, true, ["decrypt"] ) let RsaPublicJwk = { "alg":"RSA-OAEP", "e":"AQAB", "ext":true, "key_ops":["encrypt"], "kty":"RSA", "n":"q6kM0z9Faa2BHYSakuzZKirz3o7dNG83nq3Yw5KC1FOUkQStDtYz8EMkYV99WfHMCaRA_q_WBjRVnweQawFtR4zwNcmEhU-fUEIZCZ17ArKoNOy45Ep8NVuYJG3-OyYHuwnz5xLIvW9GVk2UqAJKaLSatuT2utU6JKeLu-4C0cb4eYUGT_RT-qsTF_NSWyyzdHrZzp9FX7ly-UTZw3inyjZYp5Ps1Ka5HzByzCTHhs_tatzLwG0FgjS7msPmwzE9RZFr1-J9exvIqhCmhvj5LSIdFmm5MEXC_b47fYCqSCE81bBofD2Ee0k72qOA-JfKNhrNXoLzuR7_1Ig1xJ8Ahw" } let RsaPublicCryptoKey = Rsa.importKey( "jwk", RsaPublicJwk, { name: "RSA-OAEP", hash: {name: "SHA-1"}, }, true, ["encrypt"] ) let RsaPublicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq6kM0z9Faa2BHYSakuzZ Kirz3o7dNG83nq3Yw5KC1FOUkQStDtYz8EMkYV99WfHMCaRA/q/WBjRVnweQawFt R4zwNcmEhU+fUEIZCZ17ArKoNOy45Ep8NVuYJG3+OyYHuwnz5xLIvW9GVk2UqAJK aLSatuT2utU6JKeLu+4C0cb4eYUGT/RT+qsTF/NSWyyzdHrZzp9FX7ly+UTZw3in yjZYp5Ps1Ka5HzByzCTHhs/tatzLwG0FgjS7msPmwzE9RZFr1+J9exvIqhCmhvj5 LSIdFmm5MEXC/b47fYCqSCE81bBofD2Ee0k72qOA+JfKNhrNXoLzuR7/1Ig1xJ8A hwIDAQAB -----END PUBLIC KEY----- ` /** * Tests */ describe('RSA_OAEP', () => { /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { RSA_OAEP.dictionaries.should.eql([ KeyAlgorithm, RsaKeyAlgorithm, RsaHashedKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { RSA_OAEP.members.publicExponent.should.equal('BufferSource') RSA_OAEP.members.hash.should.equal('HashAlgorithmIdentifier') }) }) /** * encrypt */ describe('encrypt', () => { let alg, rsa, data, signature before(() => { alg = { name: "RSA-OAEP", hash: { name: 'SHA-1' } } rsa = new RSA_OAEP(alg) data = new TextEncoder().encode('signed with Chrome webcrypto') }) it('should throw with non-private key', () => { expect(() => { rsa.encrypt(alg, RsaPrivateCryptoKey, new Uint8Array()) }).to.throw('Encrypt requires a public key') }) it('should return an ArrayBuffer', () => { rsa.encrypt(alg, RsaPublicCryptoKey, data).should.be.instanceof(ArrayBuffer) }) }) /** * decrypt */ describe('decrypt', () => { let alg, rsa, data, signature before(() => { alg = { name: "RSA-OAEP", hash: { name: 'SHA-1' } } rsa = new RSA_OAEP(alg) data = new TextEncoder().encode('signed with Chrome webcrypto') signature = new Uint8Array([ 22,101,79,138,156,147,203,26,157,52,218,189,207,28,192,159,210,80,154,46,234, 227,224,21,90,105,28,181,31,92,255,166,158,27,162,118,137,11,72,230,33,137,19, 189,208,227,31,134,82,51,72,162,102,12,162,250,143,207,253,111,144,135,244,145, 220,225,168,21,176,57,220,173,75,41,45,9,41,50,92,229,54,214,100,200,192,11,235, 44,162,240,24,215,227,19,63,112,222,111,233,6,147,151,98,12,36,120,83,157,6,129, 117,28,28,188,32,124,218,161,192,247,153,156,176,166,119,77,67,98,80,250,0,254, 175,63,107,171,70,168,156,103,247,6,70,143,11,21,184,229,53,164,140,169,32,137, 8,41,89,183,2,242,213,244,115,197,134,169,70,160,90,91,170,9,51,104,108,165,85, 67,165,171,92,8,229,224,68,10,74,23,156,101,97,81,48,122,47,228,67,80,210,179, 118,0,101,185,63,220,49,107,52,61,11,189,242,43,167,43,159,107,114,12,226,228, 120,140,7,21,37,207,13,217,80,235,149,213,1,255,255,86,58,167,181,4,173,223, 234,104,104,225,26,54,46,162,201,37,167,149 ]) }) it('should throw with non-private key', () => { expect(() => { rsa.decrypt(alg, RsaPublicCryptoKey, new Uint8Array()) }).to.throw('Decrypt requires a private key') }) it('should return an ArrayBuffer', () => { rsa.decrypt(alg, RsaPrivateCryptoKey, signature).should.be.instanceof(ArrayBuffer) }) it('should return a valid decryption', () => { Buffer.from(rsa.decrypt(alg, RsaPrivateCryptoKey, signature)) .should.eql(Buffer.from(data.buffer)) }) }) /** * generateKey */ describe('generateKey', () => { let alg, rsa, cryptoKeyPair before(() => { alg = { name: 'RSA-OAEP', hash: { name: 'SHA-256' } } rsa = new RSA_OAEP(alg) return Promise.resolve() .then(() => cryptoKeyPair = rsa.generateKey( { name: "RSA-OAEP", modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}, }, true, ["encrypt", "decrypt"] )) }) it('should throw with invalid usages', () => { expect(() => { rsa.generateKey(alg, true, ['encrypt', 'decrypt', 'wrong']) }).to.throw('Key usages can only include "encrypt", "decrypt", "wrapKey" or "unwrapKey"') }) it('should return CryptoKey', () => { cryptoKeyPair.should.be.instanceof(CryptoKeyPair) }) it('should set public key type', () => { cryptoKeyPair.publicKey.type.should.equal('public') }) it('should set private key type', () => { cryptoKeyPair.privateKey.type.should.equal('private') }) it('should set public key algorithm', () => { cryptoKeyPair.publicKey.algorithm .should.be.instanceof(RSA_OAEP) }) it('should set private key algorithm', () => { cryptoKeyPair.privateKey.algorithm .should.be.instanceof(RSA_OAEP) }) it('should set public key algorithm name', () => { cryptoKeyPair.publicKey.algorithm.name .should.equal('RSA-OAEP') }) it('should set private key algorithm name', () => { cryptoKeyPair.privateKey.algorithm.name .should.equal('RSA-OAEP') }) //it('should set public key algorithm hash', () => { // cryptoKeyPair.publicKey.algorithm.hash // .should.be.instanceof(KeyAlgorithm) //}) //it('should set private key algorithm hash', () => { // cryptoKeyPair.privateKey.algorithm.hash // .should.be.instanceof(KeyAlgorithm) //}) it('should set public key algorithm hash name', () => { cryptoKeyPair.publicKey.algorithm.hash.name .should.equal('SHA-256') }) it('should set private key algorithm hash name', () => { cryptoKeyPair.privateKey.algorithm.hash.name .should.equal('SHA-256') }) it('should set public key extractable', () => { cryptoKeyPair.publicKey.extractable.should.equal(true) }) it('should set private key extractable', () => { cryptoKeyPair.privateKey.extractable.should.equal(true) }) it('should set public key usages', () => { cryptoKeyPair.publicKey.usages.should.eql(['encrypt','wrapKey']) }) it('should set private key usages', () => { cryptoKeyPair.privateKey.usages.should.eql(['decrypt','unwrapKey']) }) it('should set public key handle', () => { cryptoKeyPair.publicKey.handle .should.include('-----BEGIN PUBLIC KEY-----') }) it('should set private key handle', () => { cryptoKeyPair.privateKey.handle .should.include('-----BEGIN RSA PRIVATE KEY-----') }) }) /** * importKey */ describe('importKey', () => { describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('private key and invalid usages', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", d: "FAKE", alg: "RS256", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw SyntaxError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages can only include "decrypt" or "unwrapKey"') }) }) describe('non-private key and invalid usages', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw SyntaxError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages can only include "encrypt" or "wrapKey"') }) }) describe('invalid key type', () => { let key, alg before(() => { key = { kty: "WRONG", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['encrypt']) }).to.throw('Key type must be RSA') }) }) describe('invalid key use', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", use: "WRONG", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['encrypt']) }).to.throw('Key use must be "sig"') }) }) describe('RSA-OAEP key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RSA-OAEP", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) key = alg.importKey('jwk', jwk, alg, false, ['encrypt']) }) it('should set SHA-1 hash', () => { key.algorithm.hash.name.should.equal('SHA-1') }) }) describe('RSA-OAEP-256 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RSA-OAEP-256", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-256" }}) key = alg.importKey('jwk', jwk, alg, false, ['encrypt']) }) it('should set SHA-256 hash', () => { key.algorithm.hash.name.should.equal('SHA-256') }) }) describe('RSA-OAEP-384 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RSA-OAEP-384", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-384" } }) key = alg.importKey('jwk', jwk, alg, false, ['encrypt']) }) it('should set SHA-384 hash', () => { key.algorithm.hash.name.should.equal('SHA-384') }) }) describe('RSA-OAEP-512 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RSA-OAEP-512", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-512" } }) key = alg.importKey('jwk', jwk, alg, false, ['encrypt']) }) it('should set SHA-512 hash', () => { key.algorithm.hash.name.should.equal('SHA-512') }) }) describe('invalid key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "WRONG", ext: true } alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', jwk, alg, false, ['encrypt']) }).to.throw('Currently \'WRONG\' is not a supported format. Please use \'RSA-OAEP\' in the interim.') }) }) describe('private RSA key', () => { let key, alg before(() => { alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) key = alg.importKey('jwk', RsaPrivateJwk, alg, false, ['decrypt']) }) it('should define type', () => { key.type.should.equal('private') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(RSA_OAEP) }) it('should define extractable', () => { key.extractable.should.equal(false) }) it('should define usages', () => { key.usages.should.eql(['decrypt']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN RSA PRIVATE KEY-----') }) }) describe('public RSA key', () => { let key, alg before(() => { alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) key = alg.importKey('jwk', RsaPublicJwk, alg, false, ['encrypt']) }) it('should define type', () => { key.type.should.equal('public') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(RSA_OAEP) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['encrypt']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN PUBLIC KEY-----') }) }) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) let caller = () => { alg.importKey('WRONG', RsaPublicJwk, alg, false, ['decrypt']) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) /** * exportKey */ describe('exportKey', () => { describe('with missing key material', () => { it('should throw OperationError', () => { expect(() => { let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) alg.exportKey('format', {}) }).to.throw('Missing key material') }) }) describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('SHA-1 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-1' } }, extractable: true, usages: ['encrypt'], handle: RsaPublicKey }) let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RSA-OAEP"', () => { jwk.alg.should.equal('RSA-OAEP') }) }) describe('SHA-256 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-256' } }, extractable: true, usages: ['encrypt'], handle: RsaPublicKey }) let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-256" } }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RSA-OAEP-256"', () => { jwk.alg.should.equal('RSA-OAEP-256') }) }) describe('SHA-384 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-384' } }, extractable: true, usages: ['encrypt'], handle: RsaPublicKey }) let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-384" } }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RSA-OAEP-384"', () => { jwk.alg.should.equal('RSA-OAEP-384') }) }) describe('SHA-512 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-512' } }, extractable: true, usages: ['encrypt'], handle: RsaPublicKey }) let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-512" } }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RSA-OAEP-512"', () => { jwk.alg.should.equal('RSA-OAEP-512') }) }) describe('other hash', () => {}) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let key = new CryptoKey({ type: 'public', algorithm: {}, extractable: true, usages: ['encrypt'], handle: RsaPublicKey }) let alg = new RSA_OAEP({ name: 'RSA-OAEP', hash: { name: "SHA-1" } }) let caller = () => { alg.exportKey('WRONG', key) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) }) webcrypto-0.9.2/test/algorithms/RSA-PSSSpec.js000066400000000000000000000746201330022407200211330ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect const {TextEncoder} = require('text-encoding') /** * Assertions */ chai.should() /** * Code under test */ const { RsaPrivateKey, RsaPrivateJwk, RsaPrivateCryptoKeySHA1, RsaPrivateCryptoKeySHA256, RsaPrivateCryptoKeySHA384, RsaPrivateCryptoKeySHA512, RsaPublicKey, RsaPublicJwk, RsaPublicCryptoKeySHA1, RsaPublicCryptoKeySHA256, RsaPublicCryptoKeySHA384, RsaPublicCryptoKeySHA512 } = require('../RsaKeyPairForPSSTesting') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const RsaKeyAlgorithm = require('../../src/dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../../src/dictionaries/RsaHashedKeyAlgorithm') const RSA_PSS = require('../../src/algorithms/RSA-PSS') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Tests */ /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { RSA_PSS.dictionaries.should.eql([ KeyAlgorithm, RsaKeyAlgorithm, RsaHashedKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { RSA_PSS.members.publicExponent.should.equal('BufferSource') RSA_PSS.members.hash.should.equal('HashAlgorithmIdentifier') }) }) /** * sign */ describe('sign', () => { let data, rsa1, rsa256, rsa384, rsa512, signatureSHA1, signatureSHA256, signatureSHA384, signatureSHA512 before(() => { rsa1 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-1' }, saltLength:128 }) rsa256 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-256' }, saltLength:128 }) rsa384 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-384' }, saltLength:128 }) rsa512 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-512' }, saltLength:128 }) data = new TextEncoder().encode('signed with Chrome webcrypto') signatureSHA1 = new Uint8Array([ 106,72,85,203,236,250,251,24,235,182,101,41,84,69,124,31,49,152,145,7,136, 189,121,111,124,89,102,33,83,247,172,99,104,241,202,99,139,60,16,215,205, 211,158,56,183,2,36,126,25,230,117,110,176,14,13,215,204,218,140,160,166, 148,149,191,60,244,179,23,124,34,194,4,32,62,118,27,241,42,19,9,226,176, 230,104,15,144,17,229,182,43,10,89,154,221,181,222,120,114,168,23,86,4, 114,45,73,72,96,160,237,51,136,131,4,145,54,144,192,191,123,225,23,213,235, 121,198,61,54,162,28,126,104,20,123,70,39,173,201,41,232,231,211,113,74, 116,179,108,241,168,131,89,99,187,201,6,80,18,204,230,150,102,55,126,29, 224,252,26,66,49,244,164,163,187,182,118,251,228,107,81,199,151,206,223, 236,82,146,41,145,175,160,64,21,158,119,205,228,169,2,201,14,46,75,237,157, 22,83,128,43,83,140,14,133,125,234,253,243,83,232,145,192,22,121,173,194, 179,64,134,217,52,79,164,29,117,229,231,201,1,161,233,148,143,45,170,115, 151,188,110,40,201,7,19,167,206,66,179,157,166 ]) signatureSHA256 = new Uint8Array([ 125,62,110,162,81,189,84,124,6,128,24,121,105,62,151,102,224,113,59, 113,147,64,65,194,190,53,225,5,97,158,120,193,192,12,216,137,232,192, 22,184,142,237,44,1,111,108,183,0,1,216,215,114,11,145,224,178,122, 227,99,151,107,40,17,22,207,108,234,141,44,155,82,214,129,234,248, 75,77,242,201,11,240,157,167,151,61,213,120,255,15,28,232,161,209, 229,81,79,83,108,48,141,157,12,55,53,43,223,119,196,127,227,230,255, 240,51,207,55,197,73,195,86,249,130,179,173,102,187,210,70,199,202, 20,53,83,200,175,197,137,224,70,18,35,231,59,219,119,185,180,64,186, 140,54,188,200,105,15,142,181,148,187,30,115,90,17,169,58,128,180,77, 93,37,215,216,135,139,134,190,176,185,233,112,35,82,64,158,250,165,11, 40,140,26,21,148,57,129,207,169,52,70,158,87,55,38,47,189,17,81,187, 195,127,142,161,205,127,44,168,53,75,85,14,49,160,227,156,130,210,159, 8,159,238,192,105,165,195,150,217,118,64,167,113,215,136,7,110,231,224, 111,127,34,48,243,216,233,37,95,240,20 ]) signatureSHA384 = new Uint8Array([ 7,209,224,125,70,61,157,196,171,235,111,163,88,171,190,70,134,216,253,62, 163,124,28,174,136,175,191,198,238,213,65,4,172,152,202,42,101,190,87,159, 165,5,107,252,28,45,147,190,98,91,128,115,232,206,33,238,23,245,122,86,167, 16,239,21,188,28,58,208,248,92,147,164,245,254,76,83,8,41,72,96,222,230, 140,28,248,120,111,228,69,229,5,21,210,35,108,40,145,159,142,133,75,226, 134,54,182,156,35,112,108,44,20,14,8,94,160,250,79,116,57,226,32,109,211, 80,68,160,55,39,152,189,118,195,212,241,183,199,195,190,71,78,178,70,22, 76,128,224,104,234,128,40,104,37,148,166,34,158,154,225,179,38,197,123, 246,167,137,226,44,242,90,179,53,164,242,76,235,247,235,215,78,198,9,191, 253,137,46,213,121,83,38,160,168,229,129,21,140,204,205,37,61,144,27,254, 175,189,44,230,26,69,228,182,57,51,32,63,108,123,227,139,113,38,229,173, 121,98,193,76,220,95,235,89,122,120,182,112,20,121,167,249,48,132,80,52, 40,153,60,133,175,132,118,184,0,233,49,155,39,121 ]) signatureSHA512 = new Uint8Array([ 75,151,232,209,207,40,6,156,129,0,77,63,171,160,14,6,186,187,192,149,244,120, 136,30,25,69,16,155,35,174,28,43,216,85,71,145,36,242,35,248,239,44,223,71, 252,129,22,202,184,156,114,88,56,57,7,171,37,64,170,30,98,53,96,164,149,124, 212,224,87,184,182,147,241,203,219,138,15,229,9,45,42,86,224,72,52,23,126, 148,53,40,137,61,40,162,97,203,138,146,49,60,65,99,68,240,107,253,4,127,16, 30,241,248,22,87,77,117,167,150,159,67,250,194,151,80,106,172,110,125,148, 198,30,179,15,69,187,14,127,195,139,165,140,216,138,178,75,27,246,164,115, 88,15,105,66,59,7,185,56,92,176,21,39,10,178,133,40,114,138,37,227,180,241, 160,90,156,173,155,156,73,77,39,200,147,175,151,165,70,62,103,151,70,27,87, 146,203,162,242,15,102,117,72,178,145,49,211,77,171,130,19,110,182,154,212, 115,211,64,198,111,254,9,23,61,128,119,9,24,80,129,26,251,0,37,142,205,134, 143,144,97,175,37,200,93,64,58,106,230,4,77,233,131,80,168,107,173,11,177,128 ]) }) it('should throw with non-private key', () => { expect(() => { rsa256.sign(RsaPublicCryptoKeySHA256, new Uint8Array()) }).to.throw('Signing requires a private key') }) it('should return an ArrayBuffer', () => { rsa256.sign(RsaPrivateCryptoKeySHA256, data).should.be.instanceof(ArrayBuffer) }) /* // These tests will not result in matching signatures since the data is salted by a random generated // salt of specified saltLength. Hence the resulting signatures will (or should) always differ // Unless these is a way to specificy the exact salt there is no way to consistantly test this // use case except through generating the signature natively, and verifying it in Chrome // (Which is manually tested before each npm release) it('should return a RSA-PSS SHA-1 signature', () => { Buffer.from(rsa1.sign(RsaPrivateCryptoKeySHA1, data)) .should.eql(Buffer.from(signatureSHA1.buffer)) }) it('should return a RSA-PSS SHA-256 signature', () => { Buffer.from(rsa256.sign(RsaPrivateCryptoKeySHA256, data)) .should.eql(Buffer.from(signatureSHA256.buffer)) }) it('should return a RSA-PSS SHA-384 signature', () => { Buffer.from(rsa384.sign(RsaPrivateCryptoKeySHA384, data)) .should.eql(Buffer.from(signatureSHA384.buffer)) }) it('should return a RSA-PSS SHA-512 signature', () => { Buffer.from(rsa512.sign(RsaPrivateCryptoKeySHA512, data)) .should.eql(Buffer.from(signatureSHA512.buffer)) })*/ it('should return a correct length RSA-PSS SHA-1 signature', () => { Buffer.from(rsa1.sign(RsaPrivateCryptoKeySHA1, data)).length .should.eql(256) }) it('should return a correct length RSA-PSS SHA-256 signature', () => { Buffer.from(rsa256.sign(RsaPrivateCryptoKeySHA256, data)).length .should.eql(256) }) it('should return a correct length RSA-PSS SHA-384 signature', () => { Buffer.from(rsa384.sign(RsaPrivateCryptoKeySHA384, data)).length .should.eql(256) }) it('should return a correct length RSA-PSS SHA-512 signature', () => { Buffer.from(rsa512.sign(RsaPrivateCryptoKeySHA512, data)).length .should.eql(256) }) }) /** * verify */ describe('verify', () => { let data, rsa1, rsa256, rsa384, rsa512, signatureSHA1, signatureSHA256, signatureSHA384, signatureSHA512 before(() => { rsa1 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-1' }, saltLength:128 }) rsa256 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-256' }, saltLength:128 }) rsa384 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-384' }, saltLength:128 }) rsa512 = new RSA_PSS({ name: "RSA-PSS", hash: { name: 'SHA-512' }, saltLength:128 }) data = new TextEncoder().encode('signed with Chrome webcrypto') signatureSHA1 = new Uint8Array([ 106,72,85,203,236,250,251,24,235,182,101,41,84,69,124,31,49,152,145,7,136, 189,121,111,124,89,102,33,83,247,172,99,104,241,202,99,139,60,16,215,205, 211,158,56,183,2,36,126,25,230,117,110,176,14,13,215,204,218,140,160,166, 148,149,191,60,244,179,23,124,34,194,4,32,62,118,27,241,42,19,9,226,176, 230,104,15,144,17,229,182,43,10,89,154,221,181,222,120,114,168,23,86,4, 114,45,73,72,96,160,237,51,136,131,4,145,54,144,192,191,123,225,23,213,235, 121,198,61,54,162,28,126,104,20,123,70,39,173,201,41,232,231,211,113,74, 116,179,108,241,168,131,89,99,187,201,6,80,18,204,230,150,102,55,126,29, 224,252,26,66,49,244,164,163,187,182,118,251,228,107,81,199,151,206,223, 236,82,146,41,145,175,160,64,21,158,119,205,228,169,2,201,14,46,75,237,157, 22,83,128,43,83,140,14,133,125,234,253,243,83,232,145,192,22,121,173,194, 179,64,134,217,52,79,164,29,117,229,231,201,1,161,233,148,143,45,170,115, 151,188,110,40,201,7,19,167,206,66,179,157,166 ]) signatureSHA256 = new Uint8Array([ 125,62,110,162,81,189,84,124,6,128,24,121,105,62,151,102,224,113,59, 113,147,64,65,194,190,53,225,5,97,158,120,193,192,12,216,137,232,192, 22,184,142,237,44,1,111,108,183,0,1,216,215,114,11,145,224,178,122, 227,99,151,107,40,17,22,207,108,234,141,44,155,82,214,129,234,248, 75,77,242,201,11,240,157,167,151,61,213,120,255,15,28,232,161,209, 229,81,79,83,108,48,141,157,12,55,53,43,223,119,196,127,227,230,255, 240,51,207,55,197,73,195,86,249,130,179,173,102,187,210,70,199,202, 20,53,83,200,175,197,137,224,70,18,35,231,59,219,119,185,180,64,186, 140,54,188,200,105,15,142,181,148,187,30,115,90,17,169,58,128,180,77, 93,37,215,216,135,139,134,190,176,185,233,112,35,82,64,158,250,165,11, 40,140,26,21,148,57,129,207,169,52,70,158,87,55,38,47,189,17,81,187, 195,127,142,161,205,127,44,168,53,75,85,14,49,160,227,156,130,210,159, 8,159,238,192,105,165,195,150,217,118,64,167,113,215,136,7,110,231,224, 111,127,34,48,243,216,233,37,95,240,20 ]) signatureSHA384 = new Uint8Array([ 7,209,224,125,70,61,157,196,171,235,111,163,88,171,190,70,134,216,253,62, 163,124,28,174,136,175,191,198,238,213,65,4,172,152,202,42,101,190,87,159, 165,5,107,252,28,45,147,190,98,91,128,115,232,206,33,238,23,245,122,86,167, 16,239,21,188,28,58,208,248,92,147,164,245,254,76,83,8,41,72,96,222,230, 140,28,248,120,111,228,69,229,5,21,210,35,108,40,145,159,142,133,75,226, 134,54,182,156,35,112,108,44,20,14,8,94,160,250,79,116,57,226,32,109,211, 80,68,160,55,39,152,189,118,195,212,241,183,199,195,190,71,78,178,70,22, 76,128,224,104,234,128,40,104,37,148,166,34,158,154,225,179,38,197,123, 246,167,137,226,44,242,90,179,53,164,242,76,235,247,235,215,78,198,9,191, 253,137,46,213,121,83,38,160,168,229,129,21,140,204,205,37,61,144,27,254, 175,189,44,230,26,69,228,182,57,51,32,63,108,123,227,139,113,38,229,173, 121,98,193,76,220,95,235,89,122,120,182,112,20,121,167,249,48,132,80,52, 40,153,60,133,175,132,118,184,0,233,49,155,39,121 ]) signatureSHA512 = new Uint8Array([ 75,151,232,209,207,40,6,156,129,0,77,63,171,160,14,6,186,187,192,149,244,120, 136,30,25,69,16,155,35,174,28,43,216,85,71,145,36,242,35,248,239,44,223,71, 252,129,22,202,184,156,114,88,56,57,7,171,37,64,170,30,98,53,96,164,149,124, 212,224,87,184,182,147,241,203,219,138,15,229,9,45,42,86,224,72,52,23,126, 148,53,40,137,61,40,162,97,203,138,146,49,60,65,99,68,240,107,253,4,127,16, 30,241,248,22,87,77,117,167,150,159,67,250,194,151,80,106,172,110,125,148, 198,30,179,15,69,187,14,127,195,139,165,140,216,138,178,75,27,246,164,115, 88,15,105,66,59,7,185,56,92,176,21,39,10,178,133,40,114,138,37,227,180,241, 160,90,156,173,155,156,73,77,39,200,147,175,151,165,70,62,103,151,70,27,87, 146,203,162,242,15,102,117,72,178,145,49,211,77,171,130,19,110,182,154,212, 115,211,64,198,111,254,9,23,61,128,119,9,24,80,129,26,251,0,37,142,205,134, 143,144,97,175,37,200,93,64,58,106,230,4,77,233,131,80,168,107,173,11,177,128 ]) }) it('should throw with non-private key', () => { expect(() => { rsa256.verify(RsaPrivateCryptoKeySHA256, new Uint8Array()) }).to.throw('Verifying requires a public key') }) it('should return false with invalid signature', () => { let invalidData = new TextEncoder().encode('invalid signature') rsa256.verify(RsaPublicCryptoKeySHA256, signatureSHA256, invalidData).should.equal(false) }) it('should return true with valid SHA-1 signature', () => { rsa1.verify(RsaPublicCryptoKeySHA1, signatureSHA1, data).should.equal(true) }) it('should return true with valid SHA-256 signature', () => { rsa256.verify(RsaPublicCryptoKeySHA256, signatureSHA256, data).should.equal(true) }) it('should return true with valid SHA-384 signature', () => { rsa384.verify(RsaPublicCryptoKeySHA384, signatureSHA384, data).should.equal(true) }) it('should return true with valid SHA-512 signature', () => { rsa512.verify(RsaPublicCryptoKeySHA512, signatureSHA512, data).should.equal(true) }) }) /** * generateKey */ describe('generateKey', () => { let alg, rsa, cryptoKeyPair before(() => { alg = { name: 'RSA-PSS', modulusLength: 2048, hash: { name: 'SHA-256' } } rsa = new RSA_PSS(alg) return Promise.resolve() .then(() => cryptoKeyPair = rsa.generateKey(alg, true, ['sign', 'verify'])) }) it('should throw with invalid usages', () => { expect(() => { rsa.generateKey(alg, true, ['sign', 'verify', 'wrong']) }).to.throw('Key usages can only include "sign" and "verify"') }) it('should return CryptoKey', () => { cryptoKeyPair.should.be.instanceof(CryptoKeyPair) }) it('should set public key type', () => { cryptoKeyPair.publicKey.type.should.equal('public') }) it('should set private key type', () => { cryptoKeyPair.privateKey.type.should.equal('private') }) it('should set public key algorithm', () => { cryptoKeyPair.publicKey.algorithm .should.be.instanceof(RSA_PSS) }) it('should set private key algorithm', () => { cryptoKeyPair.privateKey.algorithm .should.be.instanceof(RSA_PSS) }) it('should set public key algorithm name', () => { cryptoKeyPair.publicKey.algorithm.name .should.equal('RSA-PSS') }) it('should set private key algorithm name', () => { cryptoKeyPair.privateKey.algorithm.name .should.equal('RSA-PSS') }) //it('should set public key algorithm hash', () => { // cryptoKeyPair.publicKey.algorithm.hash // .should.be.instanceof(KeyAlgorithm) //}) //it('should set private key algorithm hash', () => { // cryptoKeyPair.privateKey.algorithm.hash // .should.be.instanceof(KeyAlgorithm) //}) it('should set public key algorithm hash name', () => { cryptoKeyPair.publicKey.algorithm.hash.name .should.equal('SHA-256') }) it('should set private key algorithm hash name', () => { cryptoKeyPair.privateKey.algorithm.hash.name .should.equal('SHA-256') }) it('should set public key extractable', () => { cryptoKeyPair.publicKey.extractable.should.equal(true) }) it('should set private key extractable', () => { cryptoKeyPair.privateKey.extractable.should.equal(true) }) it('should set public key usages', () => { cryptoKeyPair.publicKey.usages.should.eql(['verify']) }) it('should set private key usages', () => { cryptoKeyPair.privateKey.usages.should.eql(['sign']) }) it('should set public key handle', () => { cryptoKeyPair.publicKey.handle .should.include('-----BEGIN PUBLIC KEY-----') }) it('should set private key handle', () => { cryptoKeyPair.privateKey.handle .should.include('-----BEGIN RSA PRIVATE KEY-----') }) }) /** * importKey */ describe('importKey', () => { describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('private key and invalid usages', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", d: "FAKE", alg: "PS256", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw SyntaxError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages must include "sign"') }) }) describe('non-private key and invalid usages', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS256", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw SyntaxError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages must include "verify"') }) }) describe('invalid key type', () => { let key, alg before(() => { key = { kty: "WRONG", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS256", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key type must be RSA') }) }) describe('invalid key use', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS256", use: "WRONG", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key use must be "sig"') }) }) describe('PS1 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS1", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-1 hash', () => { key.algorithm.hash.name.should.equal('SHA-1') }) }) describe('PS256 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS256", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-256 hash', () => { key.algorithm.hash.name.should.equal('SHA-256') }) }) describe('PS384 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS384", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-384 hash', () => { key.algorithm.hash.name.should.equal('SHA-384') }) }) describe('PS512 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS512", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-512 hash', () => { key.algorithm.hash.name.should.equal('SHA-512') }) }) describe('invalid key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "WTF", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS' }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', jwk, alg, false, ['verify']) }).to.throw('Key alg must be "PS1", "PS256", "PS384", or "PS512"') }) }) describe.skip('undefined key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", ext: true } alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should not define hash', () => { expect(key.algorithm.hash).to.be.undefined }) }) describe('private RSA key', () => { let key, alg before(() => { alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', RsaPrivateJwk, alg, false, ['sign']) }) it('should define type', () => { key.type.should.equal('private') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(RSA_PSS) }) it('should define modulusLength', () => { key.algorithm.modulusLength.should.eql(2048) }) it('should define publicExponent', () => { key.algorithm.publicExponent.should.eql(new Uint8Array([0x01, 0x00, 0x01])) }) it('should define extractable', () => { key.extractable.should.equal(false) }) it('should define usages', () => { key.usages.should.eql(['sign']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN RSA PRIVATE KEY-----') }) }) describe('public RSA key', () => { let key, alg before(() => { alg = new RSA_PSS({ name: 'RSA-PSS' }) key = alg.importKey('jwk', RsaPublicJwk, alg, false, ['verify']) }) it('should define type', () => { key.type.should.equal('public') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(RSA_PSS) }) it('should define modulusLength', () => { key.algorithm.modulusLength.should.eql(2048) }) it('should define publicExponent', () => { key.algorithm.publicExponent.should.eql(new Uint8Array([0x01, 0x00, 0x01])) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['verify']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN PUBLIC KEY-----') }) }) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let alg = new RSA_PSS({ name: 'RSA-PSS' }) let caller = () => { alg.importKey('WRONG', RsaPublicJwk, alg, false, ['verify']) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) /** * exportKey */ describe('exportKey', () => { describe('with missing key material', () => { it('should throw OperationError', () => { expect(() => { let alg = new RSA_PSS({ name: 'RSA-PSS' }) alg.exportKey('format', {}) }).to.throw('Missing key material') }) }) describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('SHA-1 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-1' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSA_PSS({ name: 'RSA-PSS' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "PS1"', () => { jwk.alg.should.equal('PS1') }) }) describe('SHA-256 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-256' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSA_PSS({ name: 'RSA-PSS' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "PS256"', () => { jwk.alg.should.equal('PS256') }) }) describe('SHA-384 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-384' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSA_PSS({ name: 'RSA-PSS' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "PS384"', () => { jwk.alg.should.equal('PS384') }) }) describe('SHA-512 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-512' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSA_PSS({ name: 'RSA-PSS' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "PS512"', () => { jwk.alg.should.equal('PS512') }) }) describe('other hash', () => {}) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let key = new CryptoKey({ type: 'public', algorithm: {}, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSA_PSS({ name: 'RSA-PSS' }) let caller = () => { alg.exportKey('WRONG', key) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) })webcrypto-0.9.2/test/algorithms/RSASSA-PKCS1-v1_5_Spec.js000066400000000000000000000746471330022407200225760ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect const {TextEncoder} = require('text-encoding') /** * Assertions */ chai.should() /** * Code under test */ const { RsaPrivateKey, RsaPrivateJwk, RsaPrivateCryptoKeySHA1, RsaPrivateCryptoKeySHA256, RsaPrivateCryptoKeySHA384, RsaPrivateCryptoKeySHA512, RsaPublicKey, RsaPublicJwk, RsaPublicCryptoKeySHA1, RsaPublicCryptoKeySHA256, RsaPublicCryptoKeySHA384, RsaPublicCryptoKeySHA512 } = require('../RsaKeyPairForTesting') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const RsaKeyAlgorithm = require('../../src/dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../../src/dictionaries/RsaHashedKeyAlgorithm') const RSASSA_PKCS1_v1_5 = require('../../src/algorithms/RSASSA-PKCS1-v1_5') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Tests */ /** * dictionaries getter */ describe.skip('dictionaries getter', () => { it('should return an array', () => { RSASSA_PKCS1_v1_5.dictionaries.should.eql([ KeyAlgorithm, RsaKeyAlgorithm, RsaHashedKeyAlgorithm ]) }) }) /** * members getter */ describe.skip('members getter', () => { it('should return an object', () => { RSASSA_PKCS1_v1_5.members.publicExponent.should.equal('BufferSource') RSASSA_PKCS1_v1_5.members.hash.should.equal('HashAlgorithmIdentifier') }) }) /** * sign */ describe('sign', () => { let data, rsa1, rsa256, rsa384, rsa512, signatureSHA1, signatureSHA256, signatureSHA384, signatureSHA512 before(() => { rsa1 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-1' }}) rsa256 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-256' }}) rsa384 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-384' }}) rsa512 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-512' }}) data = new TextEncoder().encode('signed with Chrome webcrypto') signatureSHA1 = new Uint8Array([ 127,216,28,63,83,35,34,208,245,91,207,119,10,184,129,202, 139,66,206,41,38,172,58,191,191,192,170,0,50,252,203,79,122, 189,47,152,221,146,48,67,138,202,133,8,129,52,124,23,54,221, 74,255,46,115,31,175,254,168,16,54,106,148,120,155,95,209, 239,49,224,192,150,248,194,219,147,147,125,115,196,40,254, 13,36,115,150,178,102,249,182,214,61,30,134,186,50,187,244, 120,160,29,208,130,92,192,213,98,166,182,109,179,67,120,99, 142,173,192,83,1,151,56,236,123,92,232,170,145,139,7,170,135, 54,18,177,153,63,6,130,239,175,165,64,78,154,125,150,185,47, 92,113,83,169,254,192,127,102,214,36,173,94,39,123,58,137,2, 108,12,202,141,26,72,95,4,235,54,187,254,90,7,4,202,109,197, 16,16,98,205,96,250,74,234,136,108,154,231,19,213,145,97,166, 68,145,210,203,141,107,42,86,116,111,28,68,211,252,202,204, 219,96,183,3,98,113,51,196,140,164,123,226,223,194,186,161, 194,39,115,227,85,167,219,182,201,34,84,63,69,139,198,150, 141,163,227,34,215,156,56,98,21 ]) signatureSHA256 = new Uint8Array([ 84, 181, 186, 121, 235, 76, 199, 102, 174, 125, 176, 216, 94, 190, 243, 201, 219, 114, 227, 61, 54, 194, 237, 14, 248, 204, 120, 109, 249, 220, 229, 80, 44, 48, 86, 133, 96, 129, 85, 213, 70, 19, 126, 0, 160, 91, 18, 185, 200, 102, 180, 181, 69, 27, 162, 181, 189, 110, 188, 112, 124, 93, 57, 208, 91, 142, 182, 192, 87, 167, 193, 111, 88, 5, 244, 108, 200, 150, 133, 68, 144, 208, 27, 155, 222, 213, 189, 224, 156, 226, 124, 65, 178, 69, 71, 63, 243, 141, 3, 126, 209, 237, 45, 179, 240, 255, 194, 245, 43, 148, 123, 97, 172, 239, 168, 221, 44, 186, 72, 194, 29, 9, 171, 103, 125, 182, 39, 95, 163, 80, 3, 208, 184, 184, 48, 114, 135, 7, 111, 114, 38, 25, 28, 234, 82, 18, 49, 113, 20, 251, 59, 147, 206, 7, 134, 15, 189, 201, 253, 241, 120, 236, 58, 235, 148, 27, 204, 233, 165, 31, 27, 223, 28, 10, 214, 159, 109, 186, 239, 71, 126, 18, 63, 111, 198, 115, 226, 237, 145, 26, 12, 120, 56, 166, 13, 195, 65, 11, 114, 149, 145, 255, 242, 97, 190, 255, 202, 219, 144, 83, 238, 240, 182, 82, 165, 229, 118, 146, 29, 95, 127, 76, 188, 247, 138, 254, 72, 18, 251, 42, 118, 156, 229, 66, 8, 106, 55, 106, 83, 232, 234, 23, 195, 160, 167, 133, 14, 181, 126, 5, 36, 157, 2, 81, 144, 83 ]) signatureSHA384 = new Uint8Array([ 21,153,55,225,112,89,64,99,7,223,198,5,88,40,109,185,100,147,36, 146,188,103,131,247,20,84,227,185,14,55,5,48,253,39,179,227,168, 118,94,230,243,115,28,153,185,140,129,238,38,185,168,43,113,4,48, 112,236,65,242,19,60,56,250,127,20,116,45,137,123,24,81,88,219, 181,124,87,139,60,107,74,2,192,19,155,225,115,169,246,76,168,24, 45,111,53,231,173,213,3,187,168,216,37,47,116,133,180,76,184,88, 251,156,96,197,159,127,215,166,244,39,195,169,103,15,139,182,206, 192,181,32,35,18,197,99,90,48,45,33,237,89,186,201,46,147,122,30, 78,246,173,98,47,34,92,7,197,159,205,121,150,238,169,89,212,66, 134,141,194,237,214,81,171,30,159,15,35,117,39,34,47,78,122,161, 160,21,212,112,153,129,74,79,206,117,95,161,15,66,106,48,247,199, 96,230,136,139,87,144,239,64,234,218,143,78,145,85,3,157,135,245, 38,155,7,174,78,157,2,20,36,160,151,205,4,172,238,20,130,129,229, 130,26,7,177,210,20,72,39,74,66,240,168,224,121,142,128,14,204, 114,190 ]) signatureSHA512 = new Uint8Array([ 4,158,87,2,1,45,7,135,46,182,165,62,255,35,13,36,73,13,129,70,162, 147,210,17,218,88,16,176,243,63,97,255,26,184,128,7,148,56,46,63, 113,52,71,149,189,255,91,195,209,1,129,39,128,24,255,109,250,80,16, 240,38,152,10,227,38,153,110,14,32,153,103,222,48,215,89,48,118,46, 172,245,13,200,125,196,27,101,13,251,223,91,128,245,30,158,22,233, 78,129,125,168,49,211,195,50,120,189,250,29,54,102,58,5,168,81,241, 252,9,168,138,36,92,233,24,246,103,82,39,200,10,142,168,83,150,243, 91,83,120,149,109,163,184,155,155,116,72,251,120,146,62,119,134,194, 12,250,195,21,92,49,196,120,100,85,125,26,5,86,89,83,102,89,249,228, 251,50,181,101,109,130,199,222,237,198,195,190,142,166,94,78,71,24, 145,101,199,239,212,125,235,110,43,191,235,176,233,97,52,24,205,93, 101,144,107,122,14,27,108,202,20,43,227,151,8,181,209,3,181,68,35, 14,171,17,142,67,215,135,65,39,245,152,103,106,26,53,56,207,78,93, 181,160,196,6,25,200,4,59,48,83 ]) }) it('should throw with non-private key', () => { expect(() => { rsa256.sign(RsaPublicCryptoKeySHA256, new Uint8Array()) }).to.throw('Signing requires a private key') }) it('should return an ArrayBuffer', () => { rsa256.sign(RsaPrivateCryptoKeySHA256, data).should.be.instanceof(ArrayBuffer) }) it('should return a RSASSA-PKCS1-v1_5 SHA-1 signature', () => { Buffer.from(rsa1.sign(RsaPrivateCryptoKeySHA1, data)) .should.eql(Buffer.from(signatureSHA1.buffer)) }) it('should return a RSASSA-PKCS1-v1_5 SHA-256 signature', () => { Buffer.from(rsa256.sign(RsaPrivateCryptoKeySHA256, data)) .should.eql(Buffer.from(signatureSHA256.buffer)) }) it('should return a RSASSA-PKCS1-v1_5 SHA-384 signature', () => { Buffer.from(rsa384.sign(RsaPrivateCryptoKeySHA384, data)) .should.eql(Buffer.from(signatureSHA384.buffer)) }) it('should return a RSASSA-PKCS1-v1_5 SHA-512 signature', () => { Buffer.from(rsa512.sign(RsaPrivateCryptoKeySHA512, data)) .should.eql(Buffer.from(signatureSHA512.buffer)) }) }) /** * verify */ describe('verify', () => { let data, rsa1, rsa256, rsa384, rsa512, signatureSHA1, signatureSHA256, signatureSHA384, signatureSHA512 before(() => { rsa1 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-1' }}) rsa256 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-256' }}) rsa384 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-384' }}) rsa512 = new RSASSA_PKCS1_v1_5({ name: "RSASSA-PKCS1-v1_5", hash: { name: 'SHA-512' }}) data = new TextEncoder().encode('signed with Chrome webcrypto') signatureSHA1 = new Uint8Array([ 127,216,28,63,83,35,34,208,245,91,207,119,10,184,129,202, 139,66,206,41,38,172,58,191,191,192,170,0,50,252,203,79,122, 189,47,152,221,146,48,67,138,202,133,8,129,52,124,23,54,221, 74,255,46,115,31,175,254,168,16,54,106,148,120,155,95,209, 239,49,224,192,150,248,194,219,147,147,125,115,196,40,254, 13,36,115,150,178,102,249,182,214,61,30,134,186,50,187,244, 120,160,29,208,130,92,192,213,98,166,182,109,179,67,120,99, 142,173,192,83,1,151,56,236,123,92,232,170,145,139,7,170,135, 54,18,177,153,63,6,130,239,175,165,64,78,154,125,150,185,47, 92,113,83,169,254,192,127,102,214,36,173,94,39,123,58,137,2, 108,12,202,141,26,72,95,4,235,54,187,254,90,7,4,202,109,197, 16,16,98,205,96,250,74,234,136,108,154,231,19,213,145,97,166, 68,145,210,203,141,107,42,86,116,111,28,68,211,252,202,204, 219,96,183,3,98,113,51,196,140,164,123,226,223,194,186,161, 194,39,115,227,85,167,219,182,201,34,84,63,69,139,198,150, 141,163,227,34,215,156,56,98,21 ]) signatureSHA256 = new Uint8Array([ 84, 181, 186, 121, 235, 76, 199, 102, 174, 125, 176, 216, 94, 190, 243, 201, 219, 114, 227, 61, 54, 194, 237, 14, 248, 204, 120, 109, 249, 220, 229, 80, 44, 48, 86, 133, 96, 129, 85, 213, 70, 19, 126, 0, 160, 91, 18, 185, 200, 102, 180, 181, 69, 27, 162, 181, 189, 110, 188, 112, 124, 93, 57, 208, 91, 142, 182, 192, 87, 167, 193, 111, 88, 5, 244, 108, 200, 150, 133, 68, 144, 208, 27, 155, 222, 213, 189, 224, 156, 226, 124, 65, 178, 69, 71, 63, 243, 141, 3, 126, 209, 237, 45, 179, 240, 255, 194, 245, 43, 148, 123, 97, 172, 239, 168, 221, 44, 186, 72, 194, 29, 9, 171, 103, 125, 182, 39, 95, 163, 80, 3, 208, 184, 184, 48, 114, 135, 7, 111, 114, 38, 25, 28, 234, 82, 18, 49, 113, 20, 251, 59, 147, 206, 7, 134, 15, 189, 201, 253, 241, 120, 236, 58, 235, 148, 27, 204, 233, 165, 31, 27, 223, 28, 10, 214, 159, 109, 186, 239, 71, 126, 18, 63, 111, 198, 115, 226, 237, 145, 26, 12, 120, 56, 166, 13, 195, 65, 11, 114, 149, 145, 255, 242, 97, 190, 255, 202, 219, 144, 83, 238, 240, 182, 82, 165, 229, 118, 146, 29, 95, 127, 76, 188, 247, 138, 254, 72, 18, 251, 42, 118, 156, 229, 66, 8, 106, 55, 106, 83, 232, 234, 23, 195, 160, 167, 133, 14, 181, 126, 5, 36, 157, 2, 81, 144, 83 ]) signatureSHA384 = new Uint8Array([ 21,153,55,225,112,89,64,99,7,223,198,5,88,40,109,185,100,147,36, 146,188,103,131,247,20,84,227,185,14,55,5,48,253,39,179,227,168, 118,94,230,243,115,28,153,185,140,129,238,38,185,168,43,113,4,48, 112,236,65,242,19,60,56,250,127,20,116,45,137,123,24,81,88,219, 181,124,87,139,60,107,74,2,192,19,155,225,115,169,246,76,168,24, 45,111,53,231,173,213,3,187,168,216,37,47,116,133,180,76,184,88, 251,156,96,197,159,127,215,166,244,39,195,169,103,15,139,182,206, 192,181,32,35,18,197,99,90,48,45,33,237,89,186,201,46,147,122,30, 78,246,173,98,47,34,92,7,197,159,205,121,150,238,169,89,212,66, 134,141,194,237,214,81,171,30,159,15,35,117,39,34,47,78,122,161, 160,21,212,112,153,129,74,79,206,117,95,161,15,66,106,48,247,199, 96,230,136,139,87,144,239,64,234,218,143,78,145,85,3,157,135,245, 38,155,7,174,78,157,2,20,36,160,151,205,4,172,238,20,130,129,229, 130,26,7,177,210,20,72,39,74,66,240,168,224,121,142,128,14,204, 114,190 ]) signatureSHA512 = new Uint8Array([ 4,158,87,2,1,45,7,135,46,182,165,62,255,35,13,36,73,13,129,70,162, 147,210,17,218,88,16,176,243,63,97,255,26,184,128,7,148,56,46,63, 113,52,71,149,189,255,91,195,209,1,129,39,128,24,255,109,250,80,16, 240,38,152,10,227,38,153,110,14,32,153,103,222,48,215,89,48,118,46, 172,245,13,200,125,196,27,101,13,251,223,91,128,245,30,158,22,233, 78,129,125,168,49,211,195,50,120,189,250,29,54,102,58,5,168,81,241, 252,9,168,138,36,92,233,24,246,103,82,39,200,10,142,168,83,150,243, 91,83,120,149,109,163,184,155,155,116,72,251,120,146,62,119,134,194, 12,250,195,21,92,49,196,120,100,85,125,26,5,86,89,83,102,89,249,228, 251,50,181,101,109,130,199,222,237,198,195,190,142,166,94,78,71,24, 145,101,199,239,212,125,235,110,43,191,235,176,233,97,52,24,205,93, 101,144,107,122,14,27,108,202,20,43,227,151,8,181,209,3,181,68,35, 14,171,17,142,67,215,135,65,39,245,152,103,106,26,53,56,207,78,93, 181,160,196,6,25,200,4,59,48,83 ]) }) it('should throw with non-private key', () => { expect(() => { rsa256.verify(RsaPrivateCryptoKeySHA256, new Uint8Array()) }).to.throw('Verifying requires a public key') }) it('should return false with invalid signature', () => { let invalidData = new TextEncoder().encode('invalid signature') rsa256.verify(RsaPublicCryptoKeySHA256, signatureSHA256, invalidData).should.equal(false) }) it('should return true with valid SHA-1 signature', () => { rsa1.verify(RsaPublicCryptoKeySHA1, signatureSHA1, data).should.equal(true) }) it('should return true with valid SHA-256 signature', () => { rsa256.verify(RsaPublicCryptoKeySHA256, signatureSHA256, data).should.equal(true) }) it('should return true with valid SHA-384 signature', () => { rsa384.verify(RsaPublicCryptoKeySHA384, signatureSHA384, data).should.equal(true) }) it('should return true with valid SHA-512 signature', () => { rsa512.verify(RsaPublicCryptoKeySHA512, signatureSHA512, data).should.equal(true) }) }) /** * generateKey */ describe('generateKey', () => { let alg, rsa, cryptoKeyPair before(() => { alg = { name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, hash: { name: 'SHA-256' } } rsa = new RSASSA_PKCS1_v1_5(alg) return Promise.resolve() .then(() => cryptoKeyPair = rsa.generateKey(alg, true, ['sign', 'verify'])) }) it('should throw with invalid usages', () => { expect(() => { rsa.generateKey(alg, true, ['sign', 'verify', 'wrong']) }).to.throw('Key usages can only include "sign" and "verify"') }) it('should return CryptoKey', () => { cryptoKeyPair.should.be.instanceof(CryptoKeyPair) }) it('should set public key type', () => { cryptoKeyPair.publicKey.type.should.equal('public') }) it('should set private key type', () => { cryptoKeyPair.privateKey.type.should.equal('private') }) it('should set public key algorithm', () => { cryptoKeyPair.publicKey.algorithm .should.be.instanceof(RSASSA_PKCS1_v1_5) }) it('should set private key algorithm', () => { cryptoKeyPair.privateKey.algorithm .should.be.instanceof(RSASSA_PKCS1_v1_5) }) it('should set public key algorithm name', () => { cryptoKeyPair.publicKey.algorithm.name .should.equal('RSASSA-PKCS1-v1_5') }) it('should set private key algorithm name', () => { cryptoKeyPair.privateKey.algorithm.name .should.equal('RSASSA-PKCS1-v1_5') }) //it('should set public key algorithm hash', () => { // cryptoKeyPair.publicKey.algorithm.hash // .should.be.instanceof(KeyAlgorithm) //}) //it('should set private key algorithm hash', () => { // cryptoKeyPair.privateKey.algorithm.hash // .should.be.instanceof(KeyAlgorithm) //}) it('should set public key algorithm hash name', () => { cryptoKeyPair.publicKey.algorithm.hash.name .should.equal('SHA-256') }) it('should set private key algorithm hash name', () => { cryptoKeyPair.privateKey.algorithm.hash.name .should.equal('SHA-256') }) it('should set public key extractable', () => { cryptoKeyPair.publicKey.extractable.should.equal(true) }) it('should set private key extractable', () => { cryptoKeyPair.privateKey.extractable.should.equal(true) }) it('should set public key usages', () => { cryptoKeyPair.publicKey.usages.should.eql(['verify']) }) it('should set private key usages', () => { cryptoKeyPair.privateKey.usages.should.eql(['sign']) }) it('should set public key handle', () => { cryptoKeyPair.publicKey.handle .should.include('-----BEGIN PUBLIC KEY-----') }) it('should set private key handle', () => { cryptoKeyPair.privateKey.handle .should.include('-----BEGIN RSA PRIVATE KEY-----') }) }) /** * importKey */ describe('importKey', () => { describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('private key and invalid usages', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", d: "FAKE", alg: "RS256", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw SyntaxError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages must include "sign"') }) }) describe('non-private key and invalid usages', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw SyntaxError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['bad']) }).to.throw('Key usages must include "verify"') }) }) describe('invalid key type', () => { let key, alg before(() => { key = { kty: "WRONG", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key type must be RSA') }) }) describe('invalid key use', () => { let key, alg before(() => { key = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", use: "WRONG", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' } }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', key, alg, false, ['verify']) }).to.throw('Key use must be "sig"') }) }) describe('RS1 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS1", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-1 hash', () => { key.algorithm.hash.name.should.equal('SHA-1') }) }) describe('RS256 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-256 hash', () => { key.algorithm.hash.name.should.equal('SHA-256') }) }) describe('RS384 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS384", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-384 hash', () => { key.algorithm.hash.name.should.equal('SHA-384') }) }) describe('RS512 key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS512", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should set SHA-512 hash', () => { key.algorithm.hash.name.should.equal('SHA-512') }) }) describe('invalid key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "WTF", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) }) it('should throw DataError', () => { expect(() => { alg.importKey('jwk', jwk, alg, false, ['verify']) }).to.throw('Key alg must be "RS1", "RS256", "RS384", or "RS512"') }) }) describe.skip('undefined key alg', () => { let key, jwk, alg before(() => { jwk = { kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", ext: true } alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', jwk, alg, false, ['verify']) }) it('should not define hash', () => { expect(key.algorithm.hash).to.be.undefined }) }) describe('private RSA key', () => { let key, alg before(() => { alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', RsaPrivateJwk, alg, false, ['sign']) }) it('should define type', () => { key.type.should.equal('private') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(RSASSA_PKCS1_v1_5) }) it('should define modulusLength', () => { key.algorithm.modulusLength.should.eql(2048) }) it('should define publicExponent', () => { key.algorithm.publicExponent.should.eql(new Uint8Array([0x01, 0x00, 0x01])) }) it('should define extractable', () => { key.extractable.should.equal(false) }) it('should define usages', () => { key.usages.should.eql(['sign']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN RSA PRIVATE KEY-----') }) }) describe('public RSA key', () => { let key, alg before(() => { alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) key = alg.importKey('jwk', RsaPublicJwk, alg, false, ['verify']) }) it('should define type', () => { key.type.should.equal('public') }) it('should define algorithm', () => { key.algorithm.should.be.instanceof(RSASSA_PKCS1_v1_5) }) it('should define modulusLength', () => { key.algorithm.modulusLength.should.eql(2048) }) it('should define publicExponent', () => { key.algorithm.publicExponent.should.eql(new Uint8Array([0x01, 0x00, 0x01])) }) it('should define extractable', () => { key.extractable.should.equal(true) }) it('should define usages', () => { key.usages.should.eql(['verify']) }) it('should define handle', () => { key.handle.should.contain('-----BEGIN PUBLIC KEY-----') }) }) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) let caller = () => { alg.importKey('WRONG', RsaPublicJwk, alg, false, ['verify']) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) }) /** * exportKey */ describe('exportKey', () => { describe('with missing key material', () => { it('should throw OperationError', () => { expect(() => { let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) alg.exportKey('format', {}) }).to.throw('Missing key material') }) }) describe('with "spki" format', () => {}) describe('with "pkcs8 format"', () => {}) describe('with "jwk" format', () => { describe('SHA-1 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-1' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RS1"', () => { jwk.alg.should.equal('RS1') }) }) describe('SHA-256 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-256' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RS256"', () => { jwk.alg.should.equal('RS256') }) }) describe('SHA-384 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-384' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RS384"', () => { jwk.alg.should.equal('RS384') }) }) describe('SHA-512 hash', () => { let jwk before(() => { let key = new CryptoKey({ type: 'public', algorithm: { hash: { name: 'SHA-512' } }, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) jwk = alg.exportKey('jwk', key) }) it('should set "alg" to "RS512"', () => { jwk.alg.should.equal('RS512') }) }) describe('other hash', () => {}) }) describe('with other format', () => { it('should throw NotSupportedError', () => { let key = new CryptoKey({ type: 'public', algorithm: {}, extractable: true, usages: ['verify'], handle: RsaPublicKey }) let alg = new RSASSA_PKCS1_v1_5({ name: 'RSASSA-PKCS1-v1_5' }) let caller = () => { alg.exportKey('WRONG', key) } expect(caller).to.throw(NotSupportedError) expect(caller).to.throw('is not a supported key format') }) }) })webcrypto-0.9.2/test/algorithms/RegisteredAlgorithmsSpec.js000066400000000000000000000023601330022407200241620ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const RegisteredAlgorithms = require('../../src/algorithms/RegisteredAlgorithms') /** * Tests */ describe('RegisteredAlgorithms', () => { describe('constructor', () => { it('should assign object argument properties', () => { let registeredAlgorithms = new RegisteredAlgorithms({ a: 1, b: 2 }) registeredAlgorithms.should.eql({ a: 1, b: 2 }) }) }) describe('getCaseInsensitive', () => { let registeredAlgorithms beforeEach(() => { registeredAlgorithms = new RegisteredAlgorithms({ 'RSASSA-PKCS1-v1_5': {} }) }) it('should match a known property with exact case', () => { registeredAlgorithms .getCaseInsensitive('RSASSA-PKCS1-v1_5') .should.equal('RSASSA-PKCS1-v1_5') }) it('should match a known property with different case', () => { registeredAlgorithms .getCaseInsensitive('rsassa-pkcs1-v1_5') .should.equal('RSASSA-PKCS1-v1_5') }) it('should return "undefined" with no match', () => { expect(registeredAlgorithms.getCaseInsensitive('unknown')).to.be.undefined }) }) }) webcrypto-0.9.2/test/algorithms/SHASpec.js000066400000000000000000000073531330022407200204550ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const {TextEncoder} = require('text-encoding') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const ShaKeyAlgorithm = require('../../src/dictionaries/ShaKeyAlgorithm') const SHA = require('../../src/algorithms/SHA') const OperationError = require('../../src/errors/OperationError') /** * Tests */ describe('SHA', () => { describe('dictionaries getter', () => { it('should return an array', () => { SHA.dictionaries.should.eql([ KeyAlgorithm, ShaKeyAlgorithm ]) }) }) describe('members getter', () => { it('should return an object', () => { SHA.members.should.eql({}) }) }) describe('digest', () => { it('should return an ArrayBuffer', () => { let algorithm = { name: 'SHA-256' } let data = new TextEncoder().encode('return an ArrayBuffer') let sha = new SHA(algorithm) let result = sha.digest(algorithm, data) result.should.be.instanceof(ArrayBuffer) }) it('should return a SHA-1 digest', () => { let algorithm = { name: 'SHA-1' } let data = new TextEncoder().encode('created with webcrypto in Chrome') let digest = new Uint8Array([ 240, 245, 162, 97, 158, 225, 111, 59, 198, 40, 103, 60, 84, 159, 139, 205, 10, 116, 39, 41 ]) let sha = new SHA(algorithm) let result = sha.digest(algorithm, data) Buffer.from(result).should.eql(Buffer.from(digest.buffer)) }) it('should return a SHA-256 digest', () => { let algorithm = { name: 'SHA-256' } let data = new TextEncoder().encode('created with webcrypto in Chrome') let digest = new Uint8Array([ 34, 103, 130, 78, 94, 197, 88, 55, 100, 33, 101, 214, 153, 38, 251, 0, 246, 42, 150, 222, 243, 57, 184, 244, 74, 187, 55, 10, 206, 17, 146, 65 ]) let sha = new SHA(algorithm) let result = sha.digest(algorithm, data) Buffer.from(result).should.eql(Buffer.from(digest.buffer)) }) it('should return a SHA-384 digest', () => { let algorithm = { name: 'SHA-384' } let data = new TextEncoder().encode('created with webcrypto in Chrome') let digest = new Uint8Array([ 114, 126, 90, 78, 53, 164, 76, 208, 239, 167, 250, 77, 174, 115, 146, 12, 35, 96, 15, 73, 222, 48, 186, 102, 200, 91, 124, 153, 232, 76, 252, 143, 50, 251, 81, 152, 45, 189, 41, 167, 139, 29, 52, 9, 140, 197, 5, 238 ]) let sha = new SHA(algorithm) let result = sha.digest(algorithm, data) Buffer.from(result).should.eql(Buffer.from(digest.buffer)) }) it('should return a SHA-512 digest', () => { let algorithm = { name: 'SHA-512' } let data = new TextEncoder().encode('created with webcrypto in Chrome') let digest = new Uint8Array([ 101, 55, 12, 162, 223, 251, 198, 26, 154, 74, 173, 61, 47, 45, 191, 105, 49, 36, 189, 141, 96, 145, 253, 102, 28, 145, 34, 244, 192, 232, 147, 88, 251, 73, 145, 241, 204, 213, 77, 129, 119, 107, 197, 94, 204, 57, 20, 153, 181, 113, 113, 50, 249, 134, 126, 99, 254, 190, 84, 124, 180, 216, 176, 112 ]) let sha = new SHA(algorithm) let result = sha.digest(algorithm, data) Buffer.from(result).should.eql(Buffer.from(digest.buffer)) }) it('should throw an OperationError with unknown algorithm', () => { let algorithm = { name: 'SHA-UNKNOWN' } let data = new TextEncoder().encode('I am undigestable') let sha = new SHA(algorithm) expect(() => { sha.digest(algorithm, data) }).to.throw('SHA-UNKNOWN is not a supported algorithm') }) }) }) webcrypto-0.9.2/test/algorithms/SupportedAlgorithmsSpec.js000066400000000000000000000100161330022407200240470ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() /** * Code under test */ const supportedAlgorithms = require('../../src/algorithms') const SupportedAlgorithms = require('../../src/algorithms/SupportedAlgorithms') const RegisteredAlgorithms = require('../../src/algorithms/RegisteredAlgorithms') const RSASSA_PKCS1_v1_5 = require('../../src/algorithms/RSASSA-PKCS1-v1_5') const SHA = require('../../src/algorithms/SHA') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Tests */ describe('SupportedAlgorithms', () => { /** * Constructor */ describe('constructor', () => { it('should initialize a container for each operation', () => { let operations = SupportedAlgorithms.operations operations.forEach(op => { supportedAlgorithms[op].should.be.instanceof(RegisteredAlgorithms) }) }) }) /** * Operations */ describe('operations', () => { it('should include specified operations', () => { let operations = SupportedAlgorithms.operations operations.should.include('encrypt') operations.should.include('decrypt') operations.should.include('sign') operations.should.include('verify') operations.should.include('deriveBits') operations.should.include('wrapKey') operations.should.include('unwrapKey') operations.should.include('generateKey') operations.should.include('importKey') operations.should.include('exportKey') operations.should.include('getLength') }) }) /** * Define */ describe('define', () => { it('should registered a type for an operation of an algorithm', () => { class Dictionary {} let alg = 'FAKE' supportedAlgorithms.define(alg, 'sign', Dictionary) supportedAlgorithms.sign[alg].should.equal(Dictionary) }) }) /** * Normalize */ describe('normalize', () => { describe('with string "alg" argument', () => { describe('unknown algorithm', () => { let normalizedAlgorithm before(() => { normalizedAlgorithm = supportedAlgorithms.normalize('sign', 'UNKNOWN') }) it('should return an error', () => { normalizedAlgorithm.should.be.instanceof(NotSupportedError) }) }) describe('valid algorithm', () => { let normalizedAlgorithm before(() => { normalizedAlgorithm = supportedAlgorithms.normalize('digest', 'SHA-256') }) it('should return the normalized algorithm', () => { normalizedAlgorithm.should.be.instanceof(SHA) }) }) }) describe('with object "alg" argument', () => { describe('invalid "name"', () => { let normalizedAlgorithm before(() => { normalizedAlgorithm = supportedAlgorithms.normalize('sign', {}) }) it('should return an error', () => { normalizedAlgorithm.should.be.instanceof(Error) }) }) describe('unknown algorithm', () => { let normalizedAlgorithm before(() => { normalizedAlgorithm = supportedAlgorithms.normalize('sign', { name: 'UNKNOWN' }) }) it('should return a NotSupportedError', () => { normalizedAlgorithm.should.be.instanceof(NotSupportedError) }) }) describe('invalid param', () => { it('should return an error') }) describe('valid params', () => { let normalizedAlgorithm before(() => { normalizedAlgorithm = supportedAlgorithms.normalize('generateKey', { name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-1' }) }) it('should return the normalized algorithm', () => { normalizedAlgorithm.should.be.instanceof(RSASSA_PKCS1_v1_5) }) }) }) }) /** * Default registration */ describe('default registration', () => {}) }) webcrypto-0.9.2/test/dictionaries/000077500000000000000000000000001330022407200171655ustar00rootroot00000000000000webcrypto-0.9.2/test/dictionaries/AlgorithmSpec.js000066400000000000000000000017731330022407200222740ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const Algorithm = require('../../src/dictionaries/Algorithm') /** * Tests */ describe('Algorithm', () => { describe('constructor', () => { describe('with string "algorithm" argument', () => { it('should set instance name to argument value', () => { let algorithm = new Algorithm('RSASSA-PKCS1-v1_5') algorithm.name.should.equal('RSASSA-PKCS1-v1_5') }) }) describe('with object "algorithm" argument', () => { it('should assign argument property values to instance', () => { let algorithm = new Algorithm({ name: 'RSASSA-PKCS1-v1_5' }) algorithm.name.should.equal('RSASSA-PKCS1-v1_5') }) it('should require algorithm name to be a string', () => { expect(() => { new Algorithm({ other: false }) }).to.throw('Algorithm name must be a string') }) }) }) }) webcrypto-0.9.2/test/dictionaries/HmacKeyAlgorithmSpec.js000066400000000000000000000010531330022407200235250ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const HmacKeyAlgorithm = require('../../src/dictionaries/HmacKeyAlgorithm') const OperationError = require('../../src/errors/OperationError') /** * Tests */ describe('HmacKeyAlgorithm', () => { }) webcrypto-0.9.2/test/dictionaries/KeyAlgorithmSpec.js000066400000000000000000000013721330022407200227400ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Tests */ describe('KeyAlgorithm', () => { describe('constructor', () => { it('should assign argument property values to instance', () => { let keyAlgorithm = new KeyAlgorithm({ name: 'RSASSA-PKCS1-v1_5' }) keyAlgorithm.name.should.equal('RSASSA-PKCS1-v1_5') }) it('should require algorithm name', () => { expect(() => { new KeyAlgorithm({ other: false }) }).to.throw('KeyAlgorithm must have a name') }) }) }) webcrypto-0.9.2/test/dictionaries/RsaHashedKeyAlgorithmSpec.js000066400000000000000000000017401330022407200245220ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') const expect = chai.expect /** * Assertions */ chai.should() /** * Code under test */ const { RsaPrivateKey, RsaPrivateJwk, RsaPrivateCryptoKey, RsaPublicKey, RsaPublicJwk, RsaPublicCryptoKey } = require('../RsaKeyPairForTesting') const {TextEncoder} = require('text-encoding') const crypto = require('../../src') const CryptoKey = require('../../src/keys/CryptoKey') const CryptoKeyPair = require('../../src/keys/CryptoKeyPair') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const RsaKeyAlgorithm = require('../../src/dictionaries/RsaKeyAlgorithm') const RsaHashedKeyAlgorithm = require('../../src/dictionaries/RsaHashedKeyAlgorithm') const DataError = require('../../src/errors/DataError') const OperationError = require('../../src/errors/OperationError') const NotSupportedError = require('../../src/errors/NotSupportedError') /** * Tests */ describe('RsaHashedKeyAlgorithm', () => { }) webcrypto-0.9.2/test/dictionaries/ShaKeyAlgorithmSpec.js000066400000000000000000000007161330022407200233750ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() const expect = chai.expect /** * Code under test */ const {TextEncoder} = require('text-encoding') const KeyAlgorithm = require('../../src/dictionaries/KeyAlgorithm') const ShaKeyAlgorithm = require('../../src/dictionaries/ShaKeyAlgorithm') const OperationError = require('../../src/errors/OperationError') /** * Tests */ describe('ShaKeyAlgorithm', () => { }) webcrypto-0.9.2/test/keys/000077500000000000000000000000001330022407200154635ustar00rootroot00000000000000webcrypto-0.9.2/test/keys/CryptoKeyPairSpec.js000066400000000000000000000000001330022407200213670ustar00rootroot00000000000000webcrypto-0.9.2/test/keys/CryptoKeySpec.js000066400000000000000000000000001330022407200205530ustar00rootroot00000000000000webcrypto-0.9.2/test/keys/JsonWebKeySpec.js000066400000000000000000000000001330022407200206420ustar00rootroot00000000000000webcrypto-0.9.2/test/keys/recognizedKeyUsagesSpec.js000066400000000000000000000020521330022407200226050ustar00rootroot00000000000000/** * Test dependencies */ const chai = require('chai') /** * Assertions */ chai.should() /** * Code under test */ const recognizedKeyUsages = require('../../src/keys/recognizedKeyUsages') const KeyUsage = recognizedKeyUsages.constructor /** * Tests */ describe('recognizedKeyUsages', () => { /** * constructor */ describe('constructor', () => { it('should initialize the list', () => { let usages = new KeyUsage(['sign', 'verify']) usages.should.include('sign') usages.should.include('verify') usages.length.should.equal(2) }) }) /** * normalize */ describe('normalize', () => { let normalized before(() => { normalized = recognizedKeyUsages.normalize(['foo', 'sign', 'bar', 'verify']) }) it('should include recognized usages', () => { normalized.should.include('sign') normalized.should.include('verify') }) it('should ignore unknown usages', () => { normalized.should.not.include('foo') normalized.should.not.include('bar') }) }) }) webcrypto-0.9.2/test/mocha.opts000066400000000000000000000000241330022407200165020ustar00rootroot00000000000000-R spec --recursive