diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..09e23fb --- /dev/null +++ b/.eslintrc @@ -0,0 +1,50 @@ +{ + "root": true, + + "extends": "@ljharb", + + "rules": { + "func-style": "warn", + "indent": ["error", 2], + "multiline-comment-style": "off", + "sort-keys": "off", + }, + + "overrides": [ + { + "files": "browser/index.js", + "rules": { + "func-name-matching": "off", + "max-statements-per-line": "off", + "no-underscore-dangle": "warn", + }, + }, + { + "files": "browser/verify.js", + "rules": { + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "no-param-reassign": "warn", + "no-plusplus": "warn", + "no-use-before-define": "warn", + } + }, + { + "files": "browser/sign.js", + "rules": { + "max-params": "off", + "max-statements-per-line": "off", + "no-param-reassign": "warn", + "no-plusplus": "warn", + "no-use-before-define": "warn", + } + }, + { + "files": "test/*.js", + "rules": { + "max-lines-per-function": "off", + }, + }, + ], +} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..8cf3067 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [ljharb] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: npm/browserify-sign +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/node-aught.yml b/.github/workflows/node-aught.yml new file mode 100644 index 0000000..afd23fc --- /dev/null +++ b/.github/workflows/node-aught.yml @@ -0,0 +1,18 @@ +name: 'Tests: node.js 4 - 10' + +on: [pull_request, push] + +jobs: + tests: + uses: ljharb/actions/.github/workflows/node.yml@main + with: + range: '>= 4 < 10' + type: minors + command: npm run tests-only + + node: + name: 'node 4 - 10' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: 'echo tests completed' diff --git a/.github/workflows/node-pretest.yml b/.github/workflows/node-pretest.yml new file mode 100644 index 0000000..765edf7 --- /dev/null +++ b/.github/workflows/node-pretest.yml @@ -0,0 +1,7 @@ +name: 'Tests: pretest/posttest' + +on: [pull_request, push] + +jobs: + tests: + uses: ljharb/actions/.github/workflows/pretest.yml@main diff --git a/.github/workflows/node-tens.yml b/.github/workflows/node-tens.yml new file mode 100644 index 0000000..b49ceb1 --- /dev/null +++ b/.github/workflows/node-tens.yml @@ -0,0 +1,18 @@ +name: 'Tests: node.js >= 10' + +on: [pull_request, push] + +jobs: + tests: + uses: ljharb/actions/.github/workflows/node.yml@main + with: + range: '>= 10' + type: minors + command: npm run tests-only + + node: + name: 'node >= 10' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: 'echo tests completed' diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml new file mode 100644 index 0000000..b9e1712 --- /dev/null +++ b/.github/workflows/rebase.yml @@ -0,0 +1,9 @@ +name: Automatic Rebase + +on: [pull_request_target] + +jobs: + _: + uses: ljharb/actions/.github/workflows/rebase.yml@main + secrets: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/require-allow-edits.yml b/.github/workflows/require-allow-edits.yml new file mode 100644 index 0000000..7b842f8 --- /dev/null +++ b/.github/workflows/require-allow-edits.yml @@ -0,0 +1,12 @@ +name: Require “Allow Edits” + +on: [pull_request_target] + +jobs: + _: + name: "Require “Allow Edits”" + + runs-on: ubuntu-latest + + steps: + - uses: ljharb/require-allow-edits@main diff --git a/.gitignore b/.gitignore index 93f1361..e1e972d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ +# gitignore +.nyc_output node_modules + npm-debug.log + +# Only apps should have lockfiles +npm-shrinkwrap.json +package-lock.json +yarn.lock + +.npmignore diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 2c5a439..0000000 --- a/.jshintrc +++ /dev/null @@ -1,27 +0,0 @@ -{ - "asi": true, - "browser": true, - "devel": true, - "eqeqeq": true, - "eqnull": true, - "esnext": true, - "expr": true, - "globals": { - "chrome": false, - "FileList": false - }, - "globalstrict": true, - "immed": true, - "latedef": "nofunc", - "laxbreak": true, - "loopfunc": true, - "newcap": true, - "noarg": true, - "node": true, - "predef": [ - "escape", - "unescape" - ], - "strict": false, - "undef": "nofunc" -} \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 9daeafb..0000000 --- a/.npmignore +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..eacea13 --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +package-lock=false +allow-same-version=true +message=v%s diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1f1ec66..0000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -sudo: false -language: node_js -node_js: - - "0.10" - - "0.11" - - "0.12" - - "iojs" -env: - - TEST_SUITE=standard - - TEST_SUITE=unit -script: "npm run-script $TEST_SUITE" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7fa5311 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,303 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v4.2.2](https://github.com/browserify/browserify-sign/compare/v4.2.1...v4.2.2) - 2023-10-25 + +### Fixed + +- [Tests] log when openssl doesn't support cipher [`#37`](https://github.com/browserify/browserify-sign/issues/37) + +### Commits + +- Only apps should have lockfiles [`09a8995`](https://github.com/browserify/browserify-sign/commit/09a89959393b3c89fedd4f7f3bafa4fec44371d7) +- [eslint] switch to eslint [`83fe463`](https://github.com/browserify/browserify-sign/commit/83fe46374b819e959d56d2c0b931308f7451a664) +- [meta] add `npmignore` and `auto-changelog` [`4418183`](https://github.com/browserify/browserify-sign/commit/44181838e7dcc4d5d0c568f74312ea28f0bcdfd5) +- [meta] fix package.json indentation [`9ac5a5e`](https://github.com/browserify/browserify-sign/commit/9ac5a5eaaac8a11eb70ec2febd13745c8764ae02) +- [Tests] migrate from travis to github actions [`d845d85`](https://github.com/browserify/browserify-sign/commit/d845d855def38e2085d5a21e447a48300f99fa60) +- [Fix] `sign`: throw on unsupported padding scheme [`8767739`](https://github.com/browserify/browserify-sign/commit/8767739a4516289568bcce9fed8a3b7e23478de9) +- [Fix] properly check the upper bound for DSA signatures [`85994cd`](https://github.com/browserify/browserify-sign/commit/85994cd6348b50f2fd1b73c54e20881416f44a30) +- [Tests] handle openSSL not supporting a scheme [`f5f17c2`](https://github.com/browserify/browserify-sign/commit/f5f17c27f9824de40b5ce8ebd8502111203fd6af) +- [Deps] update `bn.js`, `browserify-rsa`, `elliptic`, `parse-asn1`, `readable-stream`, `safe-buffer` [`a67d0eb`](https://github.com/browserify/browserify-sign/commit/a67d0eb4ffceabb366b69da69ce9a223e9d5e96b) +- [Dev Deps] update `nyc`, `standard`, `tape` [`cc5350b`](https://github.com/browserify/browserify-sign/commit/cc5350b96702fcba930e0662cf763844fd2f59bf) +- [Tests] always run coverage; downgrade `nyc` [`75ce1d5`](https://github.com/browserify/browserify-sign/commit/75ce1d5c49a6591dd13422016c07f8f9cae13371) +- [meta] add `safe-publish-latest` [`dcf49ce`](https://github.com/browserify/browserify-sign/commit/dcf49ce85a1a66a6fb31689508d916d7894286a9) +- [Tests] add `npm run posttest` [`75dd8fd`](https://github.com/browserify/browserify-sign/commit/75dd8fd6ce56eb37b12e30807e5f913867b21733) +- [Dev Deps] update `tape` [`3aec038`](https://github.com/browserify/browserify-sign/commit/3aec0386dc8dfba8698be756ec770df863867c84) +- [Tests] skip unsupported schemes [`703c83e`](https://github.com/browserify/browserify-sign/commit/703c83ea72db2f45714fe749c6f04b05243ca9a8) +- [Tests] node < 6 lacks array `includes` [`3aa43cf`](https://github.com/browserify/browserify-sign/commit/3aa43cfbc1fdde8481bcdd3bff581574159b869a) +- [Dev Deps] fix eslint range [`98d4e0d`](https://github.com/browserify/browserify-sign/commit/98d4e0d7ff18871b0ca07415f758a610ccf8ebbe) + +## [v4.2.1](https://github.com/browserify/browserify-sign/compare/v4.2.0...v4.2.1) - 2020-08-04 + +### Merged + +- bump elliptic [`#58`](https://github.com/browserify/browserify-sign/pull/58) + +## [v4.2.0](https://github.com/browserify/browserify-sign/compare/v4.1.0...v4.2.0) - 2020-05-18 + +### Merged + +- switch to safe buffer [`#53`](https://github.com/browserify/browserify-sign/pull/53) + +## [v4.1.0](https://github.com/browserify/browserify-sign/compare/v4.0.4...v4.1.0) - 2020-05-05 + +### Merged + +- update deps, modernise usage, use readable-stream [`#49`](https://github.com/browserify/browserify-sign/pull/49) + +## [v4.0.4](https://github.com/browserify/browserify-sign/compare/v4.0.3...v4.0.4) - 2017-03-28 + +### Merged + +- Fix algorithms require path, add the extension [`#36`](https://github.com/browserify/browserify-sign/pull/36) + +### Commits + +- extranious semi-colon [`bf59e00`](https://github.com/browserify/browserify-sign/commit/bf59e00d0370a53876597be91a8ff7bfe855e0fc) + +## [v4.0.3](https://github.com/browserify/browserify-sign/compare/v4.0.2...v4.0.3) - 2017-03-27 + +### Commits + +- files key in the package.json [`1e0bea0`](https://github.com/browserify/browserify-sign/commit/1e0bea0e263e81b89bf564d7e0c7bddd3b7278f9) + +## [v4.0.2](https://github.com/browserify/browserify-sign/compare/v4.0.1...v4.0.2) - 2017-03-27 + +### Commits + +- put back in algos [`fd27cd3`](https://github.com/browserify/browserify-sign/commit/fd27cd3e6346c054dec937ae53f341740888e03f) + +## [v4.0.1](https://github.com/browserify/browserify-sign/compare/v4.0.0...v4.0.1) - 2017-03-27 + +### Merged + +- add support for calling ECDSA signatures RSA signatures, cuz node allows it [`#33`](https://github.com/browserify/browserify-sign/pull/33) +- don't generate a new key in ecSign [`#30`](https://github.com/browserify/browserify-sign/pull/30) +- more ecdsa [`#29`](https://github.com/browserify/browserify-sign/pull/29) +- use json files [`#26`](https://github.com/browserify/browserify-sign/pull/26) +- renaming files [`#25`](https://github.com/browserify/browserify-sign/pull/25) + +### Commits + +- algorithms as JSON file [`c41a01b`](https://github.com/browserify/browserify-sign/commit/c41a01bcb477df1ab20f6d3a311b7801a3da9ff6) +- add new fixtures [`16edebd`](https://github.com/browserify/browserify-sign/commit/16edebde35421ff376aeb7e8e62cfe5a3c1ffbee) +- curves as JSON file [`f40f060`](https://github.com/browserify/browserify-sign/commit/f40f0602f8dc6c2db8c9c1c02dc095a1e4837b89) +- update tests and travis [`9f6e80b`](https://github.com/browserify/browserify-sign/commit/9f6e80b4e1d748958bf46f7ddcb09bd38e8c3a21) +- remove unused files [`9a76f12`](https://github.com/browserify/browserify-sign/commit/9a76f12f6e673c0e9e87aed0d52f13f0ce644865) +- update package.json [`13f7b67`](https://github.com/browserify/browserify-sign/commit/13f7b67e78584a66d2275fc58978bdf59d365b03) +- update README.md [`b03de58`](https://github.com/browserify/browserify-sign/commit/b03de586a090c38e993f5e20ab94edbaa9b87b88) +- nits [`be99732`](https://github.com/browserify/browserify-sign/commit/be99732907b8ae2ea58b8935b6b33e58502239b2) +- we aparently no longer support 0.10 [`aec5180`](https://github.com/browserify/browserify-sign/commit/aec51801103b2755fc4127d2633a1c4369b3f427) +- better message [`06d76ed`](https://github.com/browserify/browserify-sign/commit/06d76ed4abb2094d8f86c395282ba53f1ffe47a6) +- move browser files to folder [`b648108`](https://github.com/browserify/browserify-sign/commit/b64810806e6f6c9c93624f1faa878ad5750a2e18) + +## [v4.0.0](https://github.com/browserify/browserify-sign/compare/v3.0.8...v4.0.0) - 2015-11-02 + +### Merged + +- upgrade bn and add 2 curves [`#22`](https://github.com/browserify/browserify-sign/pull/22) +- Add LICENSE file. [`#21`](https://github.com/browserify/browserify-sign/pull/21) + +### Commits + +- Revert "remove p521" [`0ad9f5c`](https://github.com/browserify/browserify-sign/commit/0ad9f5c5b2bed736a254722d3cd7eb779c4b45b7) +- remove p521 [`352ea17`](https://github.com/browserify/browserify-sign/commit/352ea1757d7bbcf1877757c5dc0101a7903c510c) +- add pack in p521 and update deps [`6e58dc4`](https://github.com/browserify/browserify-sign/commit/6e58dc410fa923344b9b1c7863fbf5c5f8f4f731) +- Create LICENSE [`e31c4a1`](https://github.com/browserify/browserify-sign/commit/e31c4a1e3c66a6124191e52052cadb4710814d71) +- update deps [`7ca87bc`](https://github.com/browserify/browserify-sign/commit/7ca87bc5465a9d19b4a01542eb99d70d97e84c6f) +- patch bn to 4.1.1 [`bd8dc2e`](https://github.com/browserify/browserify-sign/commit/bd8dc2e9eb8bd5cd4b7b255c1914c2f34f594ace) +- LICENSE: add @calvinmetcalf [`153a93f`](https://github.com/browserify/browserify-sign/commit/153a93f0f05c4368c76789df2df4a09ea455a8a9) +- package: adds description [`555b793`](https://github.com/browserify/browserify-sign/commit/555b79372cc4e8c29049e7f2b027f2694f7c7dd5) + +## [v3.0.8](https://github.com/browserify/browserify-sign/compare/v3.0.3...v3.0.8) - 2015-09-05 + +### Merged + +- Format [`#20`](https://github.com/browserify/browserify-sign/pull/20) +- Fixes unreachable return error [`#19`](https://github.com/browserify/browserify-sign/pull/19) + +### Fixed + +- adds standard (resolves #15) [`#15`](https://github.com/browserify/browserify-sign/issues/15) + +### Commits + +- add dsa back in [`1b8014d`](https://github.com/browserify/browserify-sign/commit/1b8014d8edfc228dc1f21e2b98442d1d297be458) +- merge [`6ada8de`](https://github.com/browserify/browserify-sign/commit/6ada8de15ebe83cedbaa2242409dbb1de441b5ed) +- standard format [`4f8a8e9`](https://github.com/browserify/browserify-sign/commit/4f8a8e90122eb1fab9be86cdfdf697989e51a507) +- comment unused functions [`2c68e08`](https://github.com/browserify/browserify-sign/commit/2c68e0828fe5c494ee5b75742bef549171404eea) +- fix use of lowercase constructor [`5032abe`](https://github.com/browserify/browserify-sign/commit/5032abe9eaaef64546f9ed085f9cf23f96eabe9a) +- README: remove TODOs [`dd76c98`](https://github.com/browserify/browserify-sign/commit/dd76c988ce7d1a6ff24e5ea55408d1771aa62380) +- algos: use 2 spaces, not tabs [`7097997`](https://github.com/browserify/browserify-sign/commit/709799742c576a57ead7d3686f00ad21de78112d) +- .travis.yml: update to new targets [`668ab5b`](https://github.com/browserify/browserify-sign/commit/668ab5b2f656854098c95d0f82b4b3b9da9e5c39) +- rm unused exports [`ddc0820`](https://github.com/browserify/browserify-sign/commit/ddc0820c766ceda98dcaf8d8bb99647d86b2fb0b) +- Rename readme.md to README.md [`557119b`](https://github.com/browserify/browserify-sign/commit/557119b51a6f8373bdededdedbd9d86be7801646) +- package: fix bad JSON [`b25808b`](https://github.com/browserify/browserify-sign/commit/b25808bea4860136edd87ced17d6bb6ccc6e143a) + +## [v3.0.3](https://github.com/browserify/browserify-sign/compare/v3.0.2...v3.0.3) - 2015-08-07 + +### Merged + +- add npmignore [`#17`](https://github.com/browserify/browserify-sign/pull/17) + +## [v3.0.2](https://github.com/browserify/browserify-sign/compare/v3.0.1...v3.0.2) - 2015-05-20 + +### Merged + +- correct error message [`#12`](https://github.com/browserify/browserify-sign/pull/12) + +### Commits + +- failing test [`93be166`](https://github.com/browserify/browserify-sign/commit/93be16675c1b276b5aae918d9cdf5825dc47cd4a) +- update deps, fixutres, and verify [`ef78685`](https://github.com/browserify/browserify-sign/commit/ef78685c39f9e234208a96488bdb845ea7ddaa18) +- test our own sigs [`2ea39b2`](https://github.com/browserify/browserify-sign/commit/2ea39b275415bf246ff0521e3a1f1fe99f91c3b5) +- update elleptic all the way [`525ea93`](https://github.com/browserify/browserify-sign/commit/525ea93f74e1543e722c6f967cb394e4b71fbd75) + +## [v3.0.1](https://github.com/browserify/browserify-sign/compare/v3.0.0...v3.0.1) - 2015-03-11 + +### Commits + +- tests: move all pre-produced data to fixtures, tests only test [`578bd27`](https://github.com/browserify/browserify-sign/commit/578bd275edb23e07d7a2e378d9f4442f29237970) +- inline fixtures [`c7fd8eb`](https://github.com/browserify/browserify-sign/commit/c7fd8eba2e58ccca5b2ba11c9a6cb447ec9b6a58) +- fixtures: convert to pure JSON [`1695735`](https://github.com/browserify/browserify-sign/commit/16957358f2026687035a999e56fcccc7e12c656d) +- passes standard [`2ba9c4c`](https://github.com/browserify/browserify-sign/commit/2ba9c4ce4b3a2fde1252da3b73f9c5dc3fedd491) +- rm node11 attribute [`456236d`](https://github.com/browserify/browserify-sign/commit/456236d0bab2d0f1aa3c365447ff6e6165c2c45e) +- check sign type [`af82685`](https://github.com/browserify/browserify-sign/commit/af826857539b1abf7075d65b21784cfabeff8d2c) +- tests/fixtures: re-compute signatures and assert equality [`69c0dd3`](https://github.com/browserify/browserify-sign/commit/69c0dd307251727c1d0db05868458451961b0215) +- fix tests in node 10 and 3 formatting issues [`a8796b0`](https://github.com/browserify/browserify-sign/commit/a8796b01dc99bbe393be49a1c5d74b71a385e7c3) +- tests: sort requires [`33591b9`](https://github.com/browserify/browserify-sign/commit/33591b9af8307f27178138271d26c020e72c6033) +- more tests [`3db65cf`](https://github.com/browserify/browserify-sign/commit/3db65cf75e990b0bc3f7a6fa1599197977c0a4c8) +- propper node10 test [`b0aa652`](https://github.com/browserify/browserify-sign/commit/b0aa65210afcb299e9a945fdf82a068a4821f5e8) +- fix typo in travis.yml [`4e42f0a`](https://github.com/browserify/browserify-sign/commit/4e42f0ac4c7b9a3cb751f41126b26749354b105d) + +## [v3.0.0](https://github.com/browserify/browserify-sign/compare/v2.8.0...v3.0.0) - 2015-03-10 + +### Merged + +- Modularize [`#8`](https://github.com/browserify/browserify-sign/pull/8) + +### Commits + +- modularize format [`d2a3f77`](https://github.com/browserify/browserify-sign/commit/d2a3f77b244ce8e967bd2b3067cdfaee670dfecf) +- better [`5077b98`](https://github.com/browserify/browserify-sign/commit/5077b984edc44440b65579fe100d74ca3e91a823) +- properly check signatures and test for it [`48f8881`](https://github.com/browserify/browserify-sign/commit/48f888175d1c1ab727cebba73def1dec48769375) +- other 3 curves [`b78737b`](https://github.com/browserify/browserify-sign/commit/b78737b27e1bcaae3f771caa89f7161bdc17c1f3) +- determanistic k [`2e1bf48`](https://github.com/browserify/browserify-sign/commit/2e1bf48e180d2ea699225b6e584e3a30c90ba312) +- formatting [`07a8727`](https://github.com/browserify/browserify-sign/commit/07a87278e6eb13539ee0a58262df3213e8cea4da) +- fixed bug with hash shorter then q [`438717a`](https://github.com/browserify/browserify-sign/commit/438717a2f00efbae18ba158b436555d56f2c9bbd) +- sign: s/getKay/getKey [`cec421c`](https://github.com/browserify/browserify-sign/commit/cec421c69d563f4cc51df5d0c323ed294e0df33e) +- make sure everything is strict [`3f10450`](https://github.com/browserify/browserify-sign/commit/3f1045017b95fdb0a0da87fe57b467705edbafdf) + +## [v2.8.0](https://github.com/browserify/browserify-sign/compare/v2.7.5...v2.8.0) - 2015-01-12 + +### Commits + +- better [`18b953c`](https://github.com/browserify/browserify-sign/commit/18b953c021e88ccdcdab809f93a1d5d2a42d3ea0) +- determanistic k [`9f1c348`](https://github.com/browserify/browserify-sign/commit/9f1c348009475ac7872e9f4e0f014bb15b88101f) +- fixed bug with hash shorter then q [`222dc8e`](https://github.com/browserify/browserify-sign/commit/222dc8ecb01f01999f69634af57ae9e64489dfb0) + +## [v2.7.5](https://github.com/browserify/browserify-sign/compare/v2.7.4...v2.7.5) - 2015-01-06 + +### Commits + +- update eliptic [`e4e5b42`](https://github.com/browserify/browserify-sign/commit/e4e5b427f7c3be3c1ded12147a66b134ae31eb0c) + +## [v2.7.4](https://github.com/browserify/browserify-sign/compare/v2.7.3...v2.7.4) - 2015-01-06 + +### Commits + +- update parse-asn1 [`22a3f57`](https://github.com/browserify/browserify-sign/commit/22a3f57340c08211547f14b63ab0cc9ab5d97dc9) + +## [v2.7.3](https://github.com/browserify/browserify-sign/compare/v2.7.2...v2.7.3) - 2015-01-06 + +### Commits + +- Update bn.js [`4519962`](https://github.com/browserify/browserify-sign/commit/4519962b2d2b73a9a118296de98280411f07fd2d) + +## [v2.7.2](https://github.com/browserify/browserify-sign/compare/v2.7.1...v2.7.2) - 2015-01-05 + +### Commits + +- aliases for sign and verify [`fcc366f`](https://github.com/browserify/browserify-sign/commit/fcc366ffe2f60e9c20d9b62b2321a96f7e9445d6) + +## [v2.7.1](https://github.com/browserify/browserify-sign/compare/v2.7.0...v2.7.1) - 2015-01-03 + +### Commits + +- Update bn.js [`c55b4aa`](https://github.com/browserify/browserify-sign/commit/c55b4aa577ef6a9414c366c760206434f97e3cce) + +## [v2.7.0](https://github.com/browserify/browserify-sign/compare/v2.6.1...v2.7.0) - 2014-12-22 + +### Commits + +- pull out rsa stuff [`0c076ff`](https://github.com/browserify/browserify-sign/commit/0c076ff1ff2aa4b626cdf25911200090a60d86c4) + +## [v2.6.1](https://github.com/browserify/browserify-sign/compare/v2.6.0...v2.6.1) - 2014-12-19 + +### Commits + +- just use regular stream not readable [`dfdd33d`](https://github.com/browserify/browserify-sign/commit/dfdd33d4bfd4823aa0308aa8215d6a32dfc210e9) + +## [v2.6.0](https://github.com/browserify/browserify-sign/compare/v2.5.2...v2.6.0) - 2014-12-18 + +### Commits + +- dsa [`e01ff39`](https://github.com/browserify/browserify-sign/commit/e01ff3987ecf80670bb6e5d38ad7a1dc08a429b0) +- varient encoding of password protected keys [`eaaf2d5`](https://github.com/browserify/browserify-sign/commit/eaaf2d53a385d6b13fcff33734675c3d886b5b51) + +## [v2.5.2](https://github.com/browserify/browserify-sign/compare/v2.5.1...v2.5.2) - 2014-12-17 + +### Commits + +- pull out parseKey [`b25775e`](https://github.com/browserify/browserify-sign/commit/b25775e1f4ed1b3df3ed776f3d0a352f2fa338cf) + +## [v2.5.1](https://github.com/browserify/browserify-sign/compare/v2.5.0...v2.5.1) - 2014-12-09 + +### Commits + +- circular dependancy [`1c15e75`](https://github.com/browserify/browserify-sign/commit/1c15e75b27a20b34bb7dd32eb833beb57716f69c) + +## [v2.5.0](https://github.com/browserify/browserify-sign/compare/v2.4.0...v2.5.0) - 2014-11-25 + +### Commits + +- add md5 and ripemd160 also make sure to include algorythm id when verifying [`da03fb0`](https://github.com/browserify/browserify-sign/commit/da03fb07ad10b61f4386560503802e16af8fa80e) +- cross off ecdsa [`1a3e3f3`](https://github.com/browserify/browserify-sign/commit/1a3e3f3e466c3de43ff02fd5434922e3b19fe77b) + +## [v2.4.0](https://github.com/browserify/browserify-sign/compare/v2.3.0...v2.4.0) - 2014-11-16 + +### Commits + +- eliptical curves [`17745d2`](https://github.com/browserify/browserify-sign/commit/17745d23773baad7b1ec1289d86ac46e87da9323) +- ecdsa with password [`2186465`](https://github.com/browserify/browserify-sign/commit/2186465dab56a1468d13964a3c6b3ef7b2b44437) +- encryption is out of scope [`f975416`](https://github.com/browserify/browserify-sign/commit/f97541615c9853b276a33cf40f394e079f3988b9) + +## [v2.3.0](https://github.com/browserify/browserify-sign/compare/v2.2.0...v2.3.0) - 2014-11-15 + +### Commits + +- Chinese remainder algorithm [`140a41f`](https://github.com/browserify/browserify-sign/commit/140a41fb482e02716e0d7b79ae390f6979cab031) + +## [v2.2.0](https://github.com/browserify/browserify-sign/compare/v2.1.0...v2.2.0) - 2014-11-15 + +### Commits + +- passwords! [`8c95b09`](https://github.com/browserify/browserify-sign/commit/8c95b09e5ba43d041f6527e3d62e7e216ec1d5ae) + +## v2.1.0 - 2014-11-15 + +### Commits + +- in prog [`d55225f`](https://github.com/browserify/browserify-sign/commit/d55225f0c3bd669ad616481dbc347fcab6654db1) +- working! [`130b1e2`](https://github.com/browserify/browserify-sign/commit/130b1e2703f807ff58ebf26612487a9a4d1e875c) +- generic key files [`7bd3f91`](https://github.com/browserify/browserify-sign/commit/7bd3f91d99b79a6077efb7c2239fcde5e2ebe95c) +- node stuff [`342c74f`](https://github.com/browserify/browserify-sign/commit/342c74f0db7ae0ae071f898f1cd8fcce3170b851) +- repo [`7e9b914`](https://github.com/browserify/browserify-sign/commit/7e9b91446c335d41e9e53466f8b4e07b697570ac) +- todo [`15410f2`](https://github.com/browserify/browserify-sign/commit/15410f260d813e07213b4bb51a2d2a747a8fd82a) +- test messages [`735a056`](https://github.com/browserify/browserify-sign/commit/735a056eb785387510bb9f0624ea6528447c4b8b) +- travis .yml file [`173fd78`](https://github.com/browserify/browserify-sign/commit/173fd7806d63d9808a2b1a7167b1fd3780f34a0d) +- travis [`9b562e6`](https://github.com/browserify/browserify-sign/commit/9b562e633e26e266153756cc70e0ba90284a0b3b) diff --git a/README.md b/README.md index 0bcf124..0a9f43d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ -browserify-sign [![Build Status](https://travis-ci.org/crypto-browserify/browserify-sign.svg)](https://travis-ci.org/crypto-browserify/browserify-sign) -=== +# browserify-sign -A package to duplicate the functionality of node's crypto public key functions, much of this is based on [Fedor Indutny's](https://github.com/indutny) work on [tls.js](https://github.com/indutny/tls.js). +[![NPM Package](https://img.shields.io/npm/v/browserify-sign.svg?style=flat-square)](https://www.npmjs.org/package/browserify-sign) +[![Build Status](https://img.shields.io/travis/crypto-browserify/browserify-sign.svg?branch=master&style=flat-square)](https://travis-ci.org/crypto-browserify/browserify-sign) +[![Dependency status](https://img.shields.io/david/crypto-browserify/browserify-sign.svg?style=flat-square)](https://david-dm.org/crypto-browserify/browserify-sign#info=dependencies) + +[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) + +A package to duplicate the functionality of node's crypto public key functions, much of this is based on [Fedor Indutny's](https://github.com/indutny) work on [indutny/tls.js](https://github.com/indutny/tls.js). + +## LICENSE + +ISC diff --git a/algos.js b/algos.js index 1ee2db4..060d8dc 100644 --- a/algos.js +++ b/algos.js @@ -1,72 +1,3 @@ -'use strict' -exports['RSA-SHA224'] = exports.sha224WithRSAEncryption = { - sign: 'rsa', - hash: 'sha224', - id: new Buffer('302d300d06096086480165030402040500041c', 'hex') -} -exports['RSA-SHA256'] = exports.sha256WithRSAEncryption = { - sign: 'rsa', - hash: 'sha256', - id: new Buffer('3031300d060960864801650304020105000420', 'hex') -} -exports['RSA-SHA384'] = exports.sha384WithRSAEncryption = { - sign: 'rsa', - hash: 'sha384', - id: new Buffer('3041300d060960864801650304020205000430', 'hex') -} -exports['RSA-SHA512'] = exports.sha512WithRSAEncryption = { - sign: 'rsa', - hash: 'sha512', - id: new Buffer('3051300d060960864801650304020305000440', 'hex') -} -exports['RSA-SHA1'] = { - sign: 'rsa', - hash: 'sha1', - id: new Buffer('3021300906052b0e03021a05000414', 'hex') -} -exports['ecdsa-with-SHA1'] = { - sign: 'ecdsa', - hash: 'sha1', - id: new Buffer('', 'hex') -} +'use strict'; -exports.DSA = exports['DSA-SHA1'] = exports['DSA-SHA'] = { - sign: 'dsa', - hash: 'sha1', - id: new Buffer('', 'hex') -} -exports['DSA-SHA224'] = exports['DSA-WITH-SHA224'] = { - sign: 'dsa', - hash: 'sha224', - id: new Buffer('', 'hex') -} -exports['DSA-SHA256'] = exports['DSA-WITH-SHA256'] = { - sign: 'dsa', - hash: 'sha256', - id: new Buffer('', 'hex') -} -exports['DSA-SHA384'] = exports['DSA-WITH-SHA384'] = { - sign: 'dsa', - hash: 'sha384', - id: new Buffer('', 'hex') -} -exports['DSA-SHA512'] = exports['DSA-WITH-SHA512'] = { - sign: 'dsa', - hash: 'sha512', - id: new Buffer('', 'hex') -} -exports['DSA-RIPEMD160'] = { - sign: 'dsa', - hash: 'rmd160', - id: new Buffer('', 'hex') -} -exports['RSA-RIPEMD160'] = exports.ripemd160WithRSA = { - sign: 'rsa', - hash: 'rmd160', - id: new Buffer('3021300906052b2403020105000414', 'hex') -} -exports['RSA-MD5'] = exports.md5WithRSAEncryption = { - sign: 'rsa', - hash: 'md5', - id: new Buffer('3020300c06082a864886f70d020505000410', 'hex') -} +module.exports = require('./browser/algorithms.json'); diff --git a/algos.json b/algos.json deleted file mode 100644 index 8825455..0000000 --- a/algos.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "sha1":"da39a3ee 5e6b4b0d 3255bfef 95601890 afd80709", - - "sha224":"d14a028c 2a3a2bc9 476102bb 288234c4 15a2b01f 828ea62a c5b3e42f", - - "sha256": "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855", - - "sha384": "38b060a7 51ac9638 4cd9327e b1b1e36a 21fdb711 14be0743 4c0cc7bf 63f6e1da 274edebf e76f65fb d51ad2f1 4898b95b", - - "sha512": "cf83e135 7eefb8bd f1542850 d66d8007 d620e405 0b5715dc 83f4a921 d36ce9ce 47d0d13c 5d85f2b0 ff8318d2 877eec2f 63b931bd 47417a81 a538327a f927da3e", - - "sha512/224": "6ed0dd02 806fa89e 25de060c 19d3ac86 cabb87d6 a0ddd05c 333b84f4", - - "sha512/256": "c672b8d1 ef56ed28 ab87c362 2c511406 9bdd3ad7 b8f97374 98d0c01e cef0967a" -} \ No newline at end of file diff --git a/browser.js b/browser.js deleted file mode 100644 index 4ee02ea..0000000 --- a/browser.js +++ /dev/null @@ -1,103 +0,0 @@ -var _algos = require('./algos') -var createHash = require('create-hash') -var inherits = require('inherits') -var sign = require('./sign') -var stream = require('stream') -var verify = require('./verify') - -var algos = {} -Object.keys(_algos).forEach(function (key) { - algos[key] = algos[key.toLowerCase()] = _algos[key] -}) - -function Sign (algorithm) { - stream.Writable.call(this) - - var data = algos[algorithm] - if (!data) { - throw new Error('Unknown message digest') - } - - this._hashType = data.hash - this._hash = createHash(data.hash) - this._tag = data.id - this._signType = data.sign -} -inherits(Sign, stream.Writable) - -Sign.prototype._write = function _write (data, _, done) { - this._hash.update(data) - done() -} - -Sign.prototype.update = function update (data, enc) { - if (typeof data === 'string') { - data = new Buffer(data, enc) - } - - this._hash.update(data) - return this -} - -Sign.prototype.sign = function signMethod (key, enc) { - this.end() - var hash = this._hash.digest() - var sig = sign(Buffer.concat([this._tag, hash]), key, this._hashType, this._signType) - - return enc ? sig.toString(enc) : sig -} - -function Verify (algorithm) { - stream.Writable.call(this) - - var data = algos[algorithm] - if (!data) { - throw new Error('Unknown message digest') - } - - this._hash = createHash(data.hash) - this._tag = data.id - this._signType = data.sign -} -inherits(Verify, stream.Writable) - -Verify.prototype._write = function _write (data, _, done) { - this._hash.update(data) - - done() -} - -Verify.prototype.update = function update (data, enc) { - if (typeof data === 'string') { - data = new Buffer(data, enc) - } - - this._hash.update(data) - return this -} - -Verify.prototype.verify = function verifyMethod (key, sig, enc) { - if (typeof sig === 'string') { - sig = new Buffer(sig, enc) - } - - this.end() - var hash = this._hash.digest() - - return verify(sig, Buffer.concat([this._tag, hash]), key, this._signType) -} - -function createSign (algorithm) { - return new Sign(algorithm) -} - -function createVerify (algorithm) { - return new Verify(algorithm) -} - -module.exports = { - Sign: createSign, - Verify: createVerify, - createSign: createSign, - createVerify: createVerify -} diff --git a/browser/algorithms.json b/browser/algorithms.json new file mode 100644 index 0000000..39324a3 --- /dev/null +++ b/browser/algorithms.json @@ -0,0 +1,152 @@ +{ + "sha224WithRSAEncryption": { + "sign": "rsa", + "hash": "sha224", + "id": "302d300d06096086480165030402040500041c" + }, + "RSA-SHA224": { + "sign": "ecdsa/rsa", + "hash": "sha224", + "id": "302d300d06096086480165030402040500041c" + }, + "sha256WithRSAEncryption": { + "sign": "rsa", + "hash": "sha256", + "id": "3031300d060960864801650304020105000420" + }, + "RSA-SHA256": { + "sign": "ecdsa/rsa", + "hash": "sha256", + "id": "3031300d060960864801650304020105000420" + }, + "sha384WithRSAEncryption": { + "sign": "rsa", + "hash": "sha384", + "id": "3041300d060960864801650304020205000430" + }, + "RSA-SHA384": { + "sign": "ecdsa/rsa", + "hash": "sha384", + "id": "3041300d060960864801650304020205000430" + }, + "sha512WithRSAEncryption": { + "sign": "rsa", + "hash": "sha512", + "id": "3051300d060960864801650304020305000440" + }, + "RSA-SHA512": { + "sign": "ecdsa/rsa", + "hash": "sha512", + "id": "3051300d060960864801650304020305000440" + }, + "RSA-SHA1": { + "sign": "rsa", + "hash": "sha1", + "id": "3021300906052b0e03021a05000414" + }, + "ecdsa-with-SHA1": { + "sign": "ecdsa", + "hash": "sha1", + "id": "" + }, + "sha256": { + "sign": "ecdsa", + "hash": "sha256", + "id": "" + }, + "sha224": { + "sign": "ecdsa", + "hash": "sha224", + "id": "" + }, + "sha384": { + "sign": "ecdsa", + "hash": "sha384", + "id": "" + }, + "sha512": { + "sign": "ecdsa", + "hash": "sha512", + "id": "" + }, + "DSA-SHA": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA-SHA1": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA-WITH-SHA224": { + "sign": "dsa", + "hash": "sha224", + "id": "" + }, + "DSA-SHA224": { + "sign": "dsa", + "hash": "sha224", + "id": "" + }, + "DSA-WITH-SHA256": { + "sign": "dsa", + "hash": "sha256", + "id": "" + }, + "DSA-SHA256": { + "sign": "dsa", + "hash": "sha256", + "id": "" + }, + "DSA-WITH-SHA384": { + "sign": "dsa", + "hash": "sha384", + "id": "" + }, + "DSA-SHA384": { + "sign": "dsa", + "hash": "sha384", + "id": "" + }, + "DSA-WITH-SHA512": { + "sign": "dsa", + "hash": "sha512", + "id": "" + }, + "DSA-SHA512": { + "sign": "dsa", + "hash": "sha512", + "id": "" + }, + "DSA-RIPEMD160": { + "sign": "dsa", + "hash": "rmd160", + "id": "" + }, + "ripemd160WithRSA": { + "sign": "rsa", + "hash": "rmd160", + "id": "3021300906052b2403020105000414" + }, + "RSA-RIPEMD160": { + "sign": "rsa", + "hash": "rmd160", + "id": "3021300906052b2403020105000414" + }, + "md5WithRSAEncryption": { + "sign": "rsa", + "hash": "md5", + "id": "3020300c06082a864886f70d020505000410" + }, + "RSA-MD5": { + "sign": "rsa", + "hash": "md5", + "id": "3020300c06082a864886f70d020505000410" + } +} diff --git a/browser/curves.json b/browser/curves.json new file mode 100644 index 0000000..8a713cf --- /dev/null +++ b/browser/curves.json @@ -0,0 +1,8 @@ +{ + "1.3.132.0.10": "secp256k1", + "1.3.132.0.33": "p224", + "1.2.840.10045.3.1.1": "p192", + "1.2.840.10045.3.1.7": "p256", + "1.3.132.0.34": "p384", + "1.3.132.0.35": "p521" +} diff --git a/browser/index.js b/browser/index.js new file mode 100644 index 0000000..ce228c4 --- /dev/null +++ b/browser/index.js @@ -0,0 +1,92 @@ +'use strict'; + +var Buffer = require('safe-buffer').Buffer; +var createHash = require('create-hash'); +var stream = require('readable-stream'); +var inherits = require('inherits'); +var sign = require('./sign'); +var verify = require('./verify'); + +var algorithms = require('./algorithms.json'); +Object.keys(algorithms).forEach(function (key) { + algorithms[key].id = Buffer.from(algorithms[key].id, 'hex'); + algorithms[key.toLowerCase()] = algorithms[key]; +}); + +function Sign(algorithm) { + stream.Writable.call(this); + + var data = algorithms[algorithm]; + if (!data) { throw new Error('Unknown message digest'); } + + this._hashType = data.hash; + this._hash = createHash(data.hash); + this._tag = data.id; + this._signType = data.sign; +} +inherits(Sign, stream.Writable); + +Sign.prototype._write = function _write(data, _, done) { + this._hash.update(data); + done(); +}; + +Sign.prototype.update = function update(data, enc) { + this._hash.update(typeof data === 'string' ? Buffer.from(data, enc) : data); + + return this; +}; + +Sign.prototype.sign = function signMethod(key, enc) { + this.end(); + var hash = this._hash.digest(); + var sig = sign(hash, key, this._hashType, this._signType, this._tag); + + return enc ? sig.toString(enc) : sig; +}; + +function Verify(algorithm) { + stream.Writable.call(this); + + var data = algorithms[algorithm]; + if (!data) { throw new Error('Unknown message digest'); } + + this._hash = createHash(data.hash); + this._tag = data.id; + this._signType = data.sign; +} +inherits(Verify, stream.Writable); + +Verify.prototype._write = function _write(data, _, done) { + this._hash.update(data); + done(); +}; + +Verify.prototype.update = function update(data, enc) { + this._hash.update(typeof data === 'string' ? Buffer.from(data, enc) : data); + + return this; +}; + +Verify.prototype.verify = function verifyMethod(key, sig, enc) { + var sigBuffer = typeof sig === 'string' ? Buffer.from(sig, enc) : sig; + + this.end(); + var hash = this._hash.digest(); + return verify(sigBuffer, hash, key, this._signType, this._tag); +}; + +function createSign(algorithm) { + return new Sign(algorithm); +} + +function createVerify(algorithm) { + return new Verify(algorithm); +} + +module.exports = { + Sign: createSign, + Verify: createVerify, + createSign: createSign, + createVerify: createVerify +}; diff --git a/browser/sign.js b/browser/sign.js new file mode 100644 index 0000000..f581825 --- /dev/null +++ b/browser/sign.js @@ -0,0 +1,150 @@ +'use strict'; + +// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js +var Buffer = require('safe-buffer').Buffer; +var createHmac = require('create-hmac'); +var crt = require('browserify-rsa'); +var EC = require('elliptic').ec; +var BN = require('bn.js'); +var parseKeys = require('parse-asn1'); +var curves = require('./curves.json'); + +var RSA_PKCS1_PADDING = 1; + +function sign(hash, key, hashType, signType, tag) { + var priv = parseKeys(key); + if (priv.curve) { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong private key type'); } + return ecSign(hash, priv); + } else if (priv.type === 'dsa') { + if (signType !== 'dsa') { throw new Error('wrong private key type'); } + return dsaSign(hash, priv, hashType); + } + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong private key type'); } + if (key.padding !== undefined && key.padding !== RSA_PKCS1_PADDING) { throw new Error('illegal or unsupported padding mode'); } + + hash = Buffer.concat([tag, hash]); + var len = priv.modulus.byteLength(); + var pad = [0, 1]; + while (hash.length + pad.length + 1 < len) { pad.push(0xff); } + pad.push(0x00); + var i = -1; + while (++i < hash.length) { pad.push(hash[i]); } + + var out = crt(pad, priv); + return out; +} + +function ecSign(hash, priv) { + var curveId = curves[priv.curve.join('.')]; + if (!curveId) { throw new Error('unknown curve ' + priv.curve.join('.')); } + + var curve = new EC(curveId); + var key = curve.keyFromPrivate(priv.privateKey); + var out = key.sign(hash); + + return Buffer.from(out.toDER()); +} + +function dsaSign(hash, priv, algo) { + var x = priv.params.priv_key; + var p = priv.params.p; + var q = priv.params.q; + var g = priv.params.g; + var r = new BN(0); + var k; + var H = bits2int(hash, q).mod(q); + var s = false; + var kv = getKey(x, q, hash, algo); + while (s === false) { + k = makeKey(q, kv, algo); + r = makeR(g, k, p, q); + s = k.invm(q).imul(H.add(x.mul(r))).mod(q); + if (s.cmpn(0) === 0) { + s = false; + r = new BN(0); + } + } + return toDER(r, s); +} + +function toDER(r, s) { + r = r.toArray(); + s = s.toArray(); + + // Pad values + if (r[0] & 0x80) { r = [0].concat(r); } + if (s[0] & 0x80) { s = [0].concat(s); } + + var total = r.length + s.length + 4; + var res = [ + 0x30, total, 0x02, r.length + ]; + res = res.concat(r, [0x02, s.length], s); + return Buffer.from(res); +} + +function getKey(x, q, hash, algo) { + x = Buffer.from(x.toArray()); + if (x.length < q.byteLength()) { + var zeros = Buffer.alloc(q.byteLength() - x.length); + x = Buffer.concat([zeros, x]); + } + var hlen = hash.length; + var hbits = bits2octets(hash, q); + var v = Buffer.alloc(hlen); + v.fill(1); + var k = Buffer.alloc(hlen); + k = createHmac(algo, k).update(v).update(Buffer.from([0])).update(x).update(hbits).digest(); + v = createHmac(algo, k).update(v).digest(); + k = createHmac(algo, k).update(v).update(Buffer.from([1])).update(x).update(hbits).digest(); + v = createHmac(algo, k).update(v).digest(); + return { k: k, v: v }; +} + +function bits2int(obits, q) { + var bits = new BN(obits); + var shift = (obits.length << 3) - q.bitLength(); + if (shift > 0) { bits.ishrn(shift); } + return bits; +} + +function bits2octets(bits, q) { + bits = bits2int(bits, q); + bits = bits.mod(q); + var out = Buffer.from(bits.toArray()); + if (out.length < q.byteLength()) { + var zeros = Buffer.alloc(q.byteLength() - out.length); + out = Buffer.concat([zeros, out]); + } + return out; +} + +function makeKey(q, kv, algo) { + var t; + var k; + + do { + t = Buffer.alloc(0); + + while (t.length * 8 < q.bitLength()) { + kv.v = createHmac(algo, kv.k).update(kv.v).digest(); + t = Buffer.concat([t, kv.v]); + } + + k = bits2int(t, q); + kv.k = createHmac(algo, kv.k).update(kv.v).update(Buffer.from([0])).digest(); + kv.v = createHmac(algo, kv.k).update(kv.v).digest(); + } while (k.cmp(q) !== -1); + + return k; +} + +function makeR(g, k, p, q) { + return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q); +} + +module.exports = sign; +module.exports.getKey = getKey; +module.exports.makeKey = makeKey; diff --git a/browser/verify.js b/browser/verify.js new file mode 100644 index 0000000..5a18080 --- /dev/null +++ b/browser/verify.js @@ -0,0 +1,86 @@ +'use strict'; + +// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js +var Buffer = require('safe-buffer').Buffer; +var BN = require('bn.js'); +var EC = require('elliptic').ec; +var parseKeys = require('parse-asn1'); +var curves = require('./curves.json'); + +function verify(sig, hash, key, signType, tag) { + var pub = parseKeys(key); + if (pub.type === 'ec') { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong public key type'); } + return ecVerify(sig, hash, pub); + } else if (pub.type === 'dsa') { + if (signType !== 'dsa') { throw new Error('wrong public key type'); } + return dsaVerify(sig, hash, pub); + } + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') { throw new Error('wrong public key type'); } + + hash = Buffer.concat([tag, hash]); + var len = pub.modulus.byteLength(); + var pad = [1]; + var padNum = 0; + while (hash.length + pad.length + 2 < len) { + pad.push(0xff); + padNum += 1; + } + pad.push(0x00); + var i = -1; + while (++i < hash.length) { + pad.push(hash[i]); + } + pad = Buffer.from(pad); + var red = BN.mont(pub.modulus); + sig = new BN(sig).toRed(red); + + sig = sig.redPow(new BN(pub.publicExponent)); + sig = Buffer.from(sig.fromRed().toArray()); + var out = padNum < 8 ? 1 : 0; + len = Math.min(sig.length, pad.length); + if (sig.length !== pad.length) { out = 1; } + + i = -1; + while (++i < len) { out |= sig[i] ^ pad[i]; } + return out === 0; +} + +function ecVerify(sig, hash, pub) { + var curveId = curves[pub.data.algorithm.curve.join('.')]; + if (!curveId) { throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.')); } + + var curve = new EC(curveId); + var pubkey = pub.data.subjectPrivateKey.data; + + return curve.verify(hash, sig, pubkey); +} + +function dsaVerify(sig, hash, pub) { + var p = pub.data.p; + var q = pub.data.q; + var g = pub.data.g; + var y = pub.data.pub_key; + var unpacked = parseKeys.signature.decode(sig, 'der'); + var s = unpacked.s; + var r = unpacked.r; + checkValue(s, q); + checkValue(r, q); + var montp = BN.mont(p); + var w = s.invm(q); + var v = g.toRed(montp) + .redPow(new BN(hash).mul(w).mod(q)) + .fromRed() + .mul(y.toRed(montp).redPow(r.mul(w).mod(q)).fromRed()) + .mod(p) + .mod(q); + return v.cmp(r) === 0; +} + +function checkValue(b, q) { + if (b.cmpn(0) <= 0) { throw new Error('invalid sig'); } + if (b.cmp(q) >= 0) { throw new Error('invalid sig'); } +} + +module.exports = verify; diff --git a/curves.js b/curves.js deleted file mode 100644 index ea28991..0000000 --- a/curves.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' -exports['1.3.132.0.10'] = 'secp256k1' - -exports['1.3.132.0.33'] = 'p224' - -exports['1.2.840.10045.3.1.1'] = 'p192' - -exports['1.2.840.10045.3.1.7'] = 'p256' - -exports['1.3.132.0.34'] = 'p384' - -exports['1.3.132.0.35'] = 'p521' diff --git a/ec.param b/ec.param deleted file mode 100644 index 9728ddd..0000000 --- a/ec.param +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN EC PARAMETERS----- -BgUrgQQAIQ== ------END EC PARAMETERS----- diff --git a/index.js b/index.js index dafa0bc..40281f6 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,9 @@ -var crypto = require('crypto') +'use strict'; -exports.createSign = crypto.createSign -exports.Sign = crypto.Sign +var crypto = require('crypto'); -exports.createVerify = crypto.createVerify -exports.Verify = crypto.Verify +exports.createSign = crypto.createSign; +exports.Sign = crypto.Sign; + +exports.createVerify = crypto.createVerify; +exports.Verify = crypto.Verify; diff --git a/package.json b/package.json index eafe82b..f275524 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,71 @@ { - "name": "browserify-sign", - "version": "4.0.0", - "description": "adds node crypto signing for browsers", - "main": "index.js", - "browser": "browser.js", - "scripts": { - "unit": "node test/index.js | tspec", - "standard": "standard", - "test": "npm run standard && npm run unit" - }, - "repository": { - "type": "git", - "url": "git://github.com/crypto-browserify/browserify-sign.git" - }, - "author": "", - "license": "ISC", - "dependencies": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - }, - "devDependencies": { - "tap-spec": "^1.0.1", - "tape": "^3.0.3", - "standard": "^5.0.0" - } + "name": "browserify-sign", + "version": "4.2.2", + "description": "adds node crypto signing for browsers", + "bugs": { + "url": "https://github.com/crypto-browserify/browserify-sign/issues" + }, + "license": "ISC", + "files": [ + "browser", + "index.js", + "algos.js" + ], + "main": "index.js", + "repository": { + "type": "git", + "url": "https://github.com/crypto-browserify/browserify-sign.git" + }, + "scripts": { + "prepack": "npmignore --auto --commentLines=autogenerated", + "prepublish": "not-in-publish || npm run prepublishOnly", + "prepublishOnly": "safe-publish-latest", + "lint": "eslint --ext=js,mjs .", + "tests-only": "nyc tape 'test/**/*.js'", + "pretest": "npm run lint", + "test": "npm run tests-only", + "posttest": "aud --production", + "version": "auto-changelog && git add CHANGELOG.md", + "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" + }, + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + }, + "devDependencies": { + "@ljharb/eslint-config": "^21.1.0", + "aud": "^2.0.3", + "auto-changelog": "^2.4.0", + "eslint": "=8.8.0", + "in-publish": "^2.0.1", + "npmignore": "^0.3.0", + "nyc": "^10.3.2", + "safe-publish-latest": "^2.0.0", + "semver": "^6.3.1", + "tape": "^5.7.2" + }, + "browser": "browser/index.js", + "engines": { + "node": ">= 4" + }, + "auto-changelog": { + "output": "CHANGELOG.md", + "template": "keepachangelog", + "unreleased": false, + "commitLimit": false, + "backfillLimit": false, + "hideCredit": true + }, + "publishConfig": { + "ignore": [ + ".github/workflows" + ] + } } diff --git a/sign.js b/sign.js deleted file mode 100644 index 571f24d..0000000 --- a/sign.js +++ /dev/null @@ -1,185 +0,0 @@ -// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js -var createHmac = require('create-hmac') -var crt = require('browserify-rsa') -var curves = require('./curves') -var elliptic = require('elliptic') -var parseKeys = require('parse-asn1') - -var BN = require('bn.js') -var EC = elliptic.ec - -function sign (hash, key, hashType, signType) { - var priv = parseKeys(key) - if (priv.curve) { - if (signType !== 'ecdsa') throw new Error('wrong private key type') - - return ecSign(hash, priv) - } else if (priv.type === 'dsa') { - if (signType !== 'dsa') { - throw new Error('wrong private key type') - } - return dsaSign(hash, priv, hashType) - } else { - if (signType !== 'rsa') throw new Error('wrong private key type') - } - - var len = priv.modulus.byteLength() - var pad = [ 0, 1 ] - while (hash.length + pad.length + 1 < len) { - pad.push(0xff) - } - pad.push(0x00) - var i = -1 - while (++i < hash.length) { - pad.push(hash[i]) - } - - var out = crt(pad, priv) - return out -} - -function ecSign (hash, priv) { - var curveId = curves[priv.curve.join('.')] - if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.')) - - var curve = new EC(curveId) - var key = curve.genKeyPair() - - key._importPrivate(priv.privateKey) - var out = key.sign(hash) - - return new Buffer(out.toDER()) -} - -function dsaSign (hash, priv, algo) { - var x = priv.params.priv_key - var p = priv.params.p - var q = priv.params.q - var g = priv.params.g - var r = new BN(0) - var k - var H = bits2int(hash, q).mod(q) - var s = false - var kv = getKey(x, q, hash, algo) - while (s === false) { - k = makeKey(q, kv, algo) - r = makeR(g, k, p, q) - s = k.invm(q).imul(H.add(x.mul(r))).mod(q) - if (!s.cmpn(0)) { - s = false - r = new BN(0) - } - } - return toDER(r, s) -} - -function toDER (r, s) { - r = r.toArray() - s = s.toArray() - - // Pad values - if (r[0] & 0x80) { - r = [ 0 ].concat(r) - } - // Pad values - if (s[0] & 0x80) { - s = [0].concat(s) - } - - var total = r.length + s.length + 4 - var res = [ 0x30, total, 0x02, r.length ] - res = res.concat(r, [ 0x02, s.length ], s) - return new Buffer(res) -} - -function getKey (x, q, hash, algo) { - x = new Buffer(x.toArray()) - if (x.length < q.byteLength()) { - var zeros = new Buffer(q.byteLength() - x.length) - zeros.fill(0) - x = Buffer.concat([zeros, x]) - } - var hlen = hash.length - var hbits = bits2octets(hash, q) - var v = new Buffer(hlen) - v.fill(1) - var k = new Buffer(hlen) - k.fill(0) - k = createHmac(algo, k) - .update(v) - .update(new Buffer([0])) - .update(x) - .update(hbits) - .digest() - v = createHmac(algo, k) - .update(v) - .digest() - k = createHmac(algo, k) - .update(v) - .update(new Buffer([1])) - .update(x) - .update(hbits) - .digest() - v = createHmac(algo, k) - .update(v) - .digest() - return { - k: k, - v: v - } -} - -function bits2int (obits, q) { - var bits = new BN(obits) - var shift = (obits.length << 3) - q.bitLength() - if (shift > 0) { - bits.ishrn(shift) - } - return bits -} - -function bits2octets (bits, q) { - bits = bits2int(bits, q) - bits = bits.mod(q) - var out = new Buffer(bits.toArray()) - if (out.length < q.byteLength()) { - var zeros = new Buffer(q.byteLength() - out.length) - zeros.fill(0) - out = Buffer.concat([zeros, out]) - } - return out -} - -function makeKey (q, kv, algo) { - var t, k - - do { - t = new Buffer('') - - while (t.length * 8 < q.bitLength()) { - kv.v = createHmac(algo, kv.k) - .update(kv.v) - .digest() - t = Buffer.concat([t, kv.v]) - } - - k = bits2int(t, q) - kv.k = createHmac(algo, kv.k) - .update(kv.v) - .update(new Buffer([0])) - .digest() - kv.v = createHmac(algo, kv.k) - .update(kv.v) - .digest() - } while (k.cmp(q) !== -1) - - return k -} - -function makeR (g, k, p, q) { - return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q) -} - -module.exports = sign -module.exports.getKey = getKey -module.exports.makeKey = makeKey diff --git a/test/fixtures.json b/test/fixtures.json index d407bb7..29bcc8b 100644 --- a/test/fixtures.json +++ b/test/fixtures.json @@ -80,6 +80,206 @@ "message": "ECDSA with P-521", "scheme": "ecdsa-with-SHA1", "signature": "3081880242010dafc92bec374d0fb6b191fe7f007b753a4734511d9ac66cd98ebd410596981e0db3dc4fe043709094ebe5b1f8a87611ddf63ea0fa2037a591950c8669a3f7863f0242018a0d1ed724b8bb5e5fa2be736620c954c6f1428d3c01062e3aec53bccd530ae6ca5e69c4be5d5a3ea1acb70c0d70fa8b495df2653df7005f7ccdca277ace70caca" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IUUNBUUVFSURGNlh2OFN2Ly93R1VXRCtjNzgwcHBHclUwUWRaV0NBenhBUVBRWDhyL3VvQWNHQlN1QkJBQUsKb1VRRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUmlqYTRlL3FFTWlrT0hKYWk3Z2VlVXJlVQpyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBFQyBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha224: ecdsa with sha224", + "signature": "304502204cf5f861a5360228a83a97fd6ba809619422456c1f5c0e05ddc7abd76325ceeb02210098f39257764153fd4815af56482bd8679a5ec769ed4231ef914074ac23fe252f", + "scheme": "sha224" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUVrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRRURNZ0FFWFBFMExldVdhSVhyWXlPbGwvTDlwdlhTVTJJOQpvNHY5MTZUMWZMNzB6ZlNoUW45U09CQVhBNUdlQ3A2d3dNN1AKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQVE9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1GOENBUUVFR0kvYmg3bldaUVJBcDBBSXhCTnFzTVh6K0R3SlZLb00vYUFLQmdncWhrak9QUU1CQWFFMEF6SUEKQkZ6eE5DM3JsbWlGNjJNanBaZnkvYWIxMGxOaVBhT0wvZGVrOVh5KzlNMzBvVUovVWpnUUZ3T1JuZ3Flc01ETwp6dz09Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha224: ecdsa with p192 key with sha224", + "signature": "30350219008ab2d43d2cb223162723029c169db82961e8059a373491870218306abd2baa6571b671223298883e6461b127ce9a10bbadf3", + "scheme": "sha224" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUU0d0VBWUhLb1pJemowQ0FRWUZLNEVFQUNFRE9nQUVnZFdMVDZaSWJoUEd3M29wWC93WFVmUmdJMndTeDVJOApyUEY2N0lzZ1BKc1J4MjZYZG1zWFpLOXNhMnA4MWNVSzNXYkZ0bHF5SzhrPQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJUT09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUdnQ0FRRUVIR1E5aGlhenluZ1J2SjJFYW5Ja2FyMG5YTnZXOG1pTUxKS3JGNjZnQndZRks0RUVBQ0doUEFNNgpBQVNCMVl0UHBraHVFOGJEZWlsZi9CZFI5R0FqYkJMSGtqeXM4WHJzaXlBOG14SEhicGQyYXhka3IyeHJhbnpWCnhRcmRac1cyV3JJcnlRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha224: ecdsa with p224 key with sha224", + "signature": "303d021c40eb466c2992b0bd79205c8ac2e3b61fb83e4963f3b0ec076a6ca55d021d0094d36fe79e707fc71121e4472bb8614fc7b1da4159bda489abd7d061", + "scheme": "sha224" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1NgpqeWJLOVl1Qm56V0VHMllHREVPVTFma3NTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQnc9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1hQXE4bktUM0lxVmFZODcxTUpTM3lZUDBYUER3RU1ON2R0UlR3U1FXaDBvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1Nmp5Yks5WXVCbnpXRUcyWUdERU9VMWZrcwpTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha224: ecdsa with p256 key with sha224", + "signature": "3045022100a311a8d448ca4f2bd8a528003479e5be616411ea630e16d32c1e8f13f8c27c0c02200dfda413da8b0288ae98ee7342d1658e408adce37a40ef3426bb79090a962faa", + "scheme": "sha224" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLQpNSUhlTUVrR0NTcUdTSWIzRFFFRkRUQThNQnNHQ1NxR1NJYjNEUUVGRERBT0JBaTlMcVpReDRKRlhBSUNDQUF3CkhRWUpZSVpJQVdVREJBRUNCQkEranMxZkc0UnYveVJON29adnhiZ3lCSUdRL0Q0eWo4Nk0xeDhsTXNuQUhRL0sKNy9yeWIvYmFETkhxTjlMVFphbkVHQnV5eGdyVHp0MDhTaUwraDkxeUZHTW9hbHkwMjlLMVZnRUk4THh1NU5wLwpBK0xLN2V3aDczQUJ6c2J1eFlkY1hJK3JLbnJ2TE45VHQ2dmVEczRHbHFUVHNXd3E1d0YwQys2Z2FZUkJYQTc0ClQxYjZOeWtHaDJVTkw1VTVwSFpFWWRPVkx6K2xSSkw3Z1lxbHdlTkhQL1MzCi0tLS0tRU5EIEVOQ1JZUFRFRCBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha224: ecdsa with password", + "signature": "304502202c1ef7e03bd9b12c4b45c6e56acb9ebef0c42940dbdd83d049e76ca3ad6a1b93022100be459a29029ef25b99f45d53ab1a7a9bc4c8de3246d4efe9bfd7b51a158b41a2", + "scheme": "sha224", + "passphrase": "bard" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVXVUIzL0RwOVZSWGR5VjhZY3lqRVFVWGRkMEFzUHh3bwpQTVpBRzJQbG1SVlhuRmMyZWhuT0tOVDVxdklGeXJTb0JYS285ckNmZi9CN0kwR3hpNzBNOHVML0JRS2Z5MWpBCkRvSEp1WndWVXpMa0RkZU1lL2ZiK1dXNFF1YUFVbHBDCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JR2tBZ0VCQkRBME5VbVMzOHoxcU1QK2R6Sjk4Y3J4bFkzZXhzN0tOVVlqZ25zODZzZ0ZBTmhPd3YyT09uVVgKcTcvbHZZUW1QN1NnQndZRks0RUVBQ0toWkFOaUFBUlpRSGY4T24xVkZkM0pYeGh6S01SQlJkMTNRQ3cvSENnOAp4a0FiWStXWkZWZWNWelo2R2M0bzFQbXE4Z1hLdEtnRmNxajJzSjkvOEhzalFiR0x2UXp5NHY4RkFwL0xXTUFPCmdjbTVuQlZUTXVRTjE0eDc5OXY1WmJoQzVvQlNXa0k9Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha224: ECDSA with P-384", + "signature": "306402305114b2c6b5f84cfbc588d81d28a71a5a8bbae986712d7686ecb470881295aeef928ae4db8945bafb5fa4ed87e341f4100230516a4f85d97fd9418dc9972091b75b95a566218f6fa9ac319a540de8cbb3e070ab92f827b8916f76d49d7394411a71e7", + "scheme": "sha224" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHYk1CQUdCeXFHU000OUFnRUdCU3VCQkFBakE0R0dBQVFBWEhXdnJrSXF5NnBGZXMxT1E4MmQ2NDYwZUxaOQo5UFdCWGdmaHBLRU1nY2NNamZtQ3FncUV5TGY2YjE3WUVJNEQxdGZKVTFvR3pXQm0zOUhsTDVYVm95OEJyZlBSCm1SRWQ5ZEJOMmg5YWVJYjZtMVFKWDdYdGVPWHljNklobi81dU1Za1Fnb3RpRlkwaVRqeitSaGQwbi9xN3krTlYKL3NCYTlNcFVjdEgvanpIRkQ5Zz0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JSGNBZ0VCQkVJQlNwRlprcnorTzAzK3ErdnlOdUJPMng2S3JKR1NVSzNQT1kyQkdaR0RpUUV3b3lkK1llS1EKNWVwdjJDL2puVEJlc1lVeXhrck5MMHF4VTZpamthdE44bmlnQndZRks0RUVBQ09oZ1lrRGdZWUFCQUJjZGErdQpRaXJMcWtWNnpVNUR6WjNyanJSNHRuMzA5WUZlQitHa29ReUJ4d3lOK1lLcUNvVEl0L3B2WHRnUWpnUFcxOGxUCldnYk5ZR2JmMGVVdmxkV2pMd0d0ODlHWkVSMzEwRTNhSDFwNGh2cWJWQWxmdGUxNDVmSnpvaUdmL200eGlSQ0MKaTJJVmpTSk9QUDVHRjNTZitydkw0MVgrd0ZyMHlsUnkwZitQTWNVUDJBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha224: ECDSA with P-521", + "signature": "30818702413ccd1478534151fee414808c8ccaae14bb8d1c48ff7168f3567195e823b4dad411ccaa6b0349b2d60cc9a59fbb7bbec69074e2e239e993b35242b2d953708b10f0024200fc2e4fee98e6a896b7ffb279bf691d1acc8a86537d2b394b3b5ca20fd6cce34b439c8b33bf5d008aae771f993135aa917c476069621d470a1ad460bf0680276fcf", + "scheme": "sha224" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IUUNBUUVFSURGNlh2OFN2Ly93R1VXRCtjNzgwcHBHclUwUWRaV0NBenhBUVBRWDhyL3VvQWNHQlN1QkJBQUsKb1VRRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUmlqYTRlL3FFTWlrT0hKYWk3Z2VlVXJlVQpyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBFQyBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha256: ecdsa with sha256", + "signature": "3044022053e316f973116c6daa7e1b53737bf46718996bb2c884ff6fa7aa12c4f0e5e7e002201f25f27744e66359fee94a14c009d3172010423e78fdd6ad40cb02ea303765a9", + "scheme": "sha256" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUVrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRRURNZ0FFWFBFMExldVdhSVhyWXlPbGwvTDlwdlhTVTJJOQpvNHY5MTZUMWZMNzB6ZlNoUW45U09CQVhBNUdlQ3A2d3dNN1AKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQVE9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1GOENBUUVFR0kvYmg3bldaUVJBcDBBSXhCTnFzTVh6K0R3SlZLb00vYUFLQmdncWhrak9QUU1CQWFFMEF6SUEKQkZ6eE5DM3JsbWlGNjJNanBaZnkvYWIxMGxOaVBhT0wvZGVrOVh5KzlNMzBvVUovVWpnUUZ3T1JuZ3Flc01ETwp6dz09Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha256: ecdsa with p192 key with sha256", + "signature": "303502180fc8fa9c63cb73cb342a7971f1a0bb0a960ee4be231844000219008b186c5c24ee5fc3b701ef395119b0bad398288263daba60", + "scheme": "sha256" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUU0d0VBWUhLb1pJemowQ0FRWUZLNEVFQUNFRE9nQUVnZFdMVDZaSWJoUEd3M29wWC93WFVmUmdJMndTeDVJOApyUEY2N0lzZ1BKc1J4MjZYZG1zWFpLOXNhMnA4MWNVSzNXYkZ0bHF5SzhrPQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJUT09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUdnQ0FRRUVIR1E5aGlhenluZ1J2SjJFYW5Ja2FyMG5YTnZXOG1pTUxKS3JGNjZnQndZRks0RUVBQ0doUEFNNgpBQVNCMVl0UHBraHVFOGJEZWlsZi9CZFI5R0FqYkJMSGtqeXM4WHJzaXlBOG14SEhicGQyYXhka3IyeHJhbnpWCnhRcmRac1cyV3JJcnlRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha256: ecdsa with p224 key with sha256", + "signature": "303c021c6bccc7c195df9fee3a884f3f4d9a9dabf4e05eb87fb47e01d750514f021c68cddd7fb8ea839e3dd75bb64f3ec7e162edf43d9ba0f839ee758d2b", + "scheme": "sha256" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1NgpqeWJLOVl1Qm56V0VHMllHREVPVTFma3NTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQnc9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1hQXE4bktUM0lxVmFZODcxTUpTM3lZUDBYUER3RU1ON2R0UlR3U1FXaDBvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1Nmp5Yks5WXVCbnpXRUcyWUdERU9VMWZrcwpTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha256: ecdsa with p256 key with sha256", + "signature": "304402203de4424cdca5b8d26dc7673052b54f6889047ede5dc6f937152974804926c296022027ebbf7cd1591afa7fdcef883b3840108ccd620f89bf943b071f6a9bc73545ac", + "scheme": "sha256" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLQpNSUhlTUVrR0NTcUdTSWIzRFFFRkRUQThNQnNHQ1NxR1NJYjNEUUVGRERBT0JBaTlMcVpReDRKRlhBSUNDQUF3CkhRWUpZSVpJQVdVREJBRUNCQkEranMxZkc0UnYveVJON29adnhiZ3lCSUdRL0Q0eWo4Nk0xeDhsTXNuQUhRL0sKNy9yeWIvYmFETkhxTjlMVFphbkVHQnV5eGdyVHp0MDhTaUwraDkxeUZHTW9hbHkwMjlLMVZnRUk4THh1NU5wLwpBK0xLN2V3aDczQUJ6c2J1eFlkY1hJK3JLbnJ2TE45VHQ2dmVEczRHbHFUVHNXd3E1d0YwQys2Z2FZUkJYQTc0ClQxYjZOeWtHaDJVTkw1VTVwSFpFWWRPVkx6K2xSSkw3Z1lxbHdlTkhQL1MzCi0tLS0tRU5EIEVOQ1JZUFRFRCBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha256: ecdsa with password", + "signature": "3046022100fb481aee90e590e3f5f8beb2cb04560b6d1874a6d5509f1bd8a9fe66be53721d022100c64a228d578398ee6dd5fe345f494639fcc342218513660a7bc0df5cc1c18906", + "scheme": "sha256", + "passphrase": "bard" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVXVUIzL0RwOVZSWGR5VjhZY3lqRVFVWGRkMEFzUHh3bwpQTVpBRzJQbG1SVlhuRmMyZWhuT0tOVDVxdklGeXJTb0JYS285ckNmZi9CN0kwR3hpNzBNOHVML0JRS2Z5MWpBCkRvSEp1WndWVXpMa0RkZU1lL2ZiK1dXNFF1YUFVbHBDCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JR2tBZ0VCQkRBME5VbVMzOHoxcU1QK2R6Sjk4Y3J4bFkzZXhzN0tOVVlqZ25zODZzZ0ZBTmhPd3YyT09uVVgKcTcvbHZZUW1QN1NnQndZRks0RUVBQ0toWkFOaUFBUlpRSGY4T24xVkZkM0pYeGh6S01SQlJkMTNRQ3cvSENnOAp4a0FiWStXWkZWZWNWelo2R2M0bzFQbXE4Z1hLdEtnRmNxajJzSjkvOEhzalFiR0x2UXp5NHY4RkFwL0xXTUFPCmdjbTVuQlZUTXVRTjE0eDc5OXY1WmJoQzVvQlNXa0k9Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha256: ECDSA with P-384", + "signature": "3064023000eedd65dbe8c91c269e1d0f4a279f76390859fd551ac619ceadb096278524d689aabecc46321a0669127186122b5557023039b616bf72b66cd78d7b16a49764c0224031a5f60abaf8967cf845ff59a44cd094dc2c1f3a300714ea5fd05a07892c6f", + "scheme": "sha256" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHYk1CQUdCeXFHU000OUFnRUdCU3VCQkFBakE0R0dBQVFBWEhXdnJrSXF5NnBGZXMxT1E4MmQ2NDYwZUxaOQo5UFdCWGdmaHBLRU1nY2NNamZtQ3FncUV5TGY2YjE3WUVJNEQxdGZKVTFvR3pXQm0zOUhsTDVYVm95OEJyZlBSCm1SRWQ5ZEJOMmg5YWVJYjZtMVFKWDdYdGVPWHljNklobi81dU1Za1Fnb3RpRlkwaVRqeitSaGQwbi9xN3krTlYKL3NCYTlNcFVjdEgvanpIRkQ5Zz0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JSGNBZ0VCQkVJQlNwRlprcnorTzAzK3ErdnlOdUJPMng2S3JKR1NVSzNQT1kyQkdaR0RpUUV3b3lkK1llS1EKNWVwdjJDL2puVEJlc1lVeXhrck5MMHF4VTZpamthdE44bmlnQndZRks0RUVBQ09oZ1lrRGdZWUFCQUJjZGErdQpRaXJMcWtWNnpVNUR6WjNyanJSNHRuMzA5WUZlQitHa29ReUJ4d3lOK1lLcUNvVEl0L3B2WHRnUWpnUFcxOGxUCldnYk5ZR2JmMGVVdmxkV2pMd0d0ODlHWkVSMzEwRTNhSDFwNGh2cWJWQWxmdGUxNDVmSnpvaUdmL200eGlSQ0MKaTJJVmpTSk9QUDVHRjNTZitydkw0MVgrd0ZyMHlsUnkwZitQTWNVUDJBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha256: ECDSA with P-521", + "signature": "3081860241625c2d2149a0117db292e808b2585871aed0f2e668ee6ceb51b1eaa67e175963359c2195e3f406b59f7283f41450013d4aac0cfababa84868e587b077f9765c3ec024152011eb95d087c42907a09643e5b3dac1ac1b59c6893ed3da56a8e92472075cfaaad6968c77366695aa9abed1ae12cccd0632ab0de97f3f6aad9206e02b1a64697", + "scheme": "sha256" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IUUNBUUVFSURGNlh2OFN2Ly93R1VXRCtjNzgwcHBHclUwUWRaV0NBenhBUVBRWDhyL3VvQWNHQlN1QkJBQUsKb1VRRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUmlqYTRlL3FFTWlrT0hKYWk3Z2VlVXJlVQpyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBFQyBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha384: ecdsa with sha384", + "signature": "3046022100b24a486fd32c82485576afe47201265d9a5b131b826879d288824fa26a359492022100d93509ad88c30532fd020288e9440eae5d9f8d3b61019366f4c36f10b82e2a74", + "scheme": "sha384" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUVrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRRURNZ0FFWFBFMExldVdhSVhyWXlPbGwvTDlwdlhTVTJJOQpvNHY5MTZUMWZMNzB6ZlNoUW45U09CQVhBNUdlQ3A2d3dNN1AKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQVE9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1GOENBUUVFR0kvYmg3bldaUVJBcDBBSXhCTnFzTVh6K0R3SlZLb00vYUFLQmdncWhrak9QUU1CQWFFMEF6SUEKQkZ6eE5DM3JsbWlGNjJNanBaZnkvYWIxMGxOaVBhT0wvZGVrOVh5KzlNMzBvVUovVWpnUUZ3T1JuZ3Flc01ETwp6dz09Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha384: ecdsa with p192 key with sha384", + "signature": "303502187025a05f4d650a1f91221821ade91e47f92430d1b00db3b1021900ccbd57feda2e1ff96f6eb0a3f7996b6c6e186aa86b5bcfb2", + "scheme": "sha384" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUU0d0VBWUhLb1pJemowQ0FRWUZLNEVFQUNFRE9nQUVnZFdMVDZaSWJoUEd3M29wWC93WFVmUmdJMndTeDVJOApyUEY2N0lzZ1BKc1J4MjZYZG1zWFpLOXNhMnA4MWNVSzNXYkZ0bHF5SzhrPQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJUT09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUdnQ0FRRUVIR1E5aGlhenluZ1J2SjJFYW5Ja2FyMG5YTnZXOG1pTUxKS3JGNjZnQndZRks0RUVBQ0doUEFNNgpBQVNCMVl0UHBraHVFOGJEZWlsZi9CZFI5R0FqYkJMSGtqeXM4WHJzaXlBOG14SEhicGQyYXhka3IyeHJhbnpWCnhRcmRac1cyV3JJcnlRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha384: ecdsa with p224 key with sha384", + "signature": "303d021d00a5b0b18690ad39e3c09b7de8eb29e7e9f6e711816833436f922f6a98021c0b9590ad17bb3259fac25120ac173cb0f71df8d498af89553bb32abe", + "scheme": "sha384" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1NgpqeWJLOVl1Qm56V0VHMllHREVPVTFma3NTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQnc9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1hQXE4bktUM0lxVmFZODcxTUpTM3lZUDBYUER3RU1ON2R0UlR3U1FXaDBvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1Nmp5Yks5WXVCbnpXRUcyWUdERU9VMWZrcwpTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha384: ecdsa with p256 key with sha384", + "signature": "30450220084aa54b5dbb27c86d30641fc1f262faee7ec500ae34b976bf640d3f6d43e01c022100ee50adeb0a3ee585dfe3bd4b543f5ab7869431238fdafd318d5963613b9cb4a3", + "scheme": "sha384" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLQpNSUhlTUVrR0NTcUdTSWIzRFFFRkRUQThNQnNHQ1NxR1NJYjNEUUVGRERBT0JBaTlMcVpReDRKRlhBSUNDQUF3CkhRWUpZSVpJQVdVREJBRUNCQkEranMxZkc0UnYveVJON29adnhiZ3lCSUdRL0Q0eWo4Nk0xeDhsTXNuQUhRL0sKNy9yeWIvYmFETkhxTjlMVFphbkVHQnV5eGdyVHp0MDhTaUwraDkxeUZHTW9hbHkwMjlLMVZnRUk4THh1NU5wLwpBK0xLN2V3aDczQUJ6c2J1eFlkY1hJK3JLbnJ2TE45VHQ2dmVEczRHbHFUVHNXd3E1d0YwQys2Z2FZUkJYQTc0ClQxYjZOeWtHaDJVTkw1VTVwSFpFWWRPVkx6K2xSSkw3Z1lxbHdlTkhQL1MzCi0tLS0tRU5EIEVOQ1JZUFRFRCBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha384: ecdsa with password", + "signature": "30450220704c321ce63ebfa0bfcc17f243d325e5551605979ae91038d0da7ca388c0a62e022100d498f51e5dee2f4fea968603e1795b0997d81f0373432dfc4615a93dd9ad0f2f", + "scheme": "sha384", + "passphrase": "bard" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVXVUIzL0RwOVZSWGR5VjhZY3lqRVFVWGRkMEFzUHh3bwpQTVpBRzJQbG1SVlhuRmMyZWhuT0tOVDVxdklGeXJTb0JYS285ckNmZi9CN0kwR3hpNzBNOHVML0JRS2Z5MWpBCkRvSEp1WndWVXpMa0RkZU1lL2ZiK1dXNFF1YUFVbHBDCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JR2tBZ0VCQkRBME5VbVMzOHoxcU1QK2R6Sjk4Y3J4bFkzZXhzN0tOVVlqZ25zODZzZ0ZBTmhPd3YyT09uVVgKcTcvbHZZUW1QN1NnQndZRks0RUVBQ0toWkFOaUFBUlpRSGY4T24xVkZkM0pYeGh6S01SQlJkMTNRQ3cvSENnOAp4a0FiWStXWkZWZWNWelo2R2M0bzFQbXE4Z1hLdEtnRmNxajJzSjkvOEhzalFiR0x2UXp5NHY4RkFwL0xXTUFPCmdjbTVuQlZUTXVRTjE0eDc5OXY1WmJoQzVvQlNXa0k9Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha384: ECDSA with P-384", + "signature": "3064023070257c6698e7ce8c1dde9982093e29934f047bd3854e5c1e525733ef499dd10bfc0a7b0a0841787e0e061411ce238ab8023002fdf8de4ef9d1244875e251d5de6b9dd81658379b3c7344b16e56bd7a8363d6000500b111557e4b37fbb5bbbfc28e56", + "scheme": "sha384" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHYk1CQUdCeXFHU000OUFnRUdCU3VCQkFBakE0R0dBQVFBWEhXdnJrSXF5NnBGZXMxT1E4MmQ2NDYwZUxaOQo5UFdCWGdmaHBLRU1nY2NNamZtQ3FncUV5TGY2YjE3WUVJNEQxdGZKVTFvR3pXQm0zOUhsTDVYVm95OEJyZlBSCm1SRWQ5ZEJOMmg5YWVJYjZtMVFKWDdYdGVPWHljNklobi81dU1Za1Fnb3RpRlkwaVRqeitSaGQwbi9xN3krTlYKL3NCYTlNcFVjdEgvanpIRkQ5Zz0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JSGNBZ0VCQkVJQlNwRlprcnorTzAzK3ErdnlOdUJPMng2S3JKR1NVSzNQT1kyQkdaR0RpUUV3b3lkK1llS1EKNWVwdjJDL2puVEJlc1lVeXhrck5MMHF4VTZpamthdE44bmlnQndZRks0RUVBQ09oZ1lrRGdZWUFCQUJjZGErdQpRaXJMcWtWNnpVNUR6WjNyanJSNHRuMzA5WUZlQitHa29ReUJ4d3lOK1lLcUNvVEl0L3B2WHRnUWpnUFcxOGxUCldnYk5ZR2JmMGVVdmxkV2pMd0d0ODlHWkVSMzEwRTNhSDFwNGh2cWJWQWxmdGUxNDVmSnpvaUdmL200eGlSQ0MKaTJJVmpTSk9QUDVHRjNTZitydkw0MVgrd0ZyMHlsUnkwZitQTWNVUDJBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha384: ECDSA with P-521", + "signature": "308188024200d109e56087e3be2bc3379f08975e761a8f870c7b0f5f42dccb412ff21fa6561d1147f65a1ee5a7cb789b17c7adf69c92c8aa6d4c3e3654564050879ed2e99ee668024201448bbbd2a65d79e8b28af154042770cb3a5f17ec6d896d1141d7cb77de702516daae4c54498c7df21d2f3fa83e1ff7693ef2cc8b1e0eb2d367cd20ad584b53dc15", + "scheme": "sha384" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IUUNBUUVFSURGNlh2OFN2Ly93R1VXRCtjNzgwcHBHclUwUWRaV0NBenhBUVBRWDhyL3VvQWNHQlN1QkJBQUsKb1VRRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUmlqYTRlL3FFTWlrT0hKYWk3Z2VlVXJlVQpyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBFQyBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha512: ecdsa with sha512", + "signature": "3045022074d03c4a00437dd687b46ee24cfadbd0a5f1f0fd958d0e10a24615d1bb8ecb6d02210097b8d1150efe3fa846d61ae46127f3bf2584db5e97d43bff27c8660e49db499d", + "scheme": "sha512" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUVrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRRURNZ0FFWFBFMExldVdhSVhyWXlPbGwvTDlwdlhTVTJJOQpvNHY5MTZUMWZMNzB6ZlNoUW45U09CQVhBNUdlQ3A2d3dNN1AKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQVE9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1GOENBUUVFR0kvYmg3bldaUVJBcDBBSXhCTnFzTVh6K0R3SlZLb00vYUFLQmdncWhrak9QUU1CQWFFMEF6SUEKQkZ6eE5DM3JsbWlGNjJNanBaZnkvYWIxMGxOaVBhT0wvZGVrOVh5KzlNMzBvVUovVWpnUUZ3T1JuZ3Flc01ETwp6dz09Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha512: ecdsa with p192 key with sha512", + "signature": "3034021863b1399238e0b2bd59e057911b172ee4a3868a7db17178d70218398c10513ebb431a14a5e874a58e69a3cfae6eceac95f8ad", + "scheme": "sha512" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUU0d0VBWUhLb1pJemowQ0FRWUZLNEVFQUNFRE9nQUVnZFdMVDZaSWJoUEd3M29wWC93WFVmUmdJMndTeDVJOApyUEY2N0lzZ1BKc1J4MjZYZG1zWFpLOXNhMnA4MWNVSzNXYkZ0bHF5SzhrPQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdVcmdRUUFJUT09Ci0tLS0tRU5EIEVDIFBBUkFNRVRFUlMtLS0tLQotLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUdnQ0FRRUVIR1E5aGlhenluZ1J2SjJFYW5Ja2FyMG5YTnZXOG1pTUxKS3JGNjZnQndZRks0RUVBQ0doUEFNNgpBQVNCMVl0UHBraHVFOGJEZWlsZi9CZFI5R0FqYkJMSGtqeXM4WHJzaXlBOG14SEhicGQyYXhka3IyeHJhbnpWCnhRcmRac1cyV3JJcnlRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha512: ecdsa with p224 key with sha512", + "signature": "303d021c2569465de9fd7384d82c9a0bf1220da0fdef563331d2da488b3ae743021d00d4b70fe006632a7dec1017ab05284c1c1af8553c48b181ae847bf4e2", + "scheme": "sha512" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1NgpqeWJLOVl1Qm56V0VHMllHREVPVTFma3NTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQQVJBTUVURVJTLS0tLS0KQmdncWhrak9QUU1CQnc9PQotLS0tLUVORCBFQyBQQVJBTUVURVJTLS0tLS0KLS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1hQXE4bktUM0lxVmFZODcxTUpTM3lZUDBYUER3RU1ON2R0UlR3U1FXaDBvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWWpHaCtJdHJUL3Z1dWZ6MkRhYlZ3dmJEbDV1Nmp5Yks5WXVCbnpXRUcyWUdERU9VMWZrcwpTcHo2YlVsWXV5Y0ZUMDcybzNuRHF4NXFSTG9XcHg4R2pnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha512: ecdsa with p256 key with sha512", + "signature": "3046022100c2f6d5ef3d6c89f3c549c9d739ae42319a13e5c8d6f888bc207033a1e1608ea6022100caee880f5f5d19f8c6e04d0d3ac98c875c6f5f88ff1c59027fa0dea0590a5840", + "scheme": "sha512" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUFvRFFnQUVJWmVvd0R5bGxzNEsvd2ZCak8xOGJZbzdnR3g4bllRUgppamE0ZS9xRU1pa09ISmFpN2dlZVVyZVVyNVhreS9BeDdzMmRHdGVnc1BOc1BnR2U1TXBRdmc9PQotLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0K", + "private": "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLQpNSUhlTUVrR0NTcUdTSWIzRFFFRkRUQThNQnNHQ1NxR1NJYjNEUUVGRERBT0JBaTlMcVpReDRKRlhBSUNDQUF3CkhRWUpZSVpJQVdVREJBRUNCQkEranMxZkc0UnYveVJON29adnhiZ3lCSUdRL0Q0eWo4Nk0xeDhsTXNuQUhRL0sKNy9yeWIvYmFETkhxTjlMVFphbkVHQnV5eGdyVHp0MDhTaUwraDkxeUZHTW9hbHkwMjlLMVZnRUk4THh1NU5wLwpBK0xLN2V3aDczQUJ6c2J1eFlkY1hJK3JLbnJ2TE45VHQ2dmVEczRHbHFUVHNXd3E1d0YwQys2Z2FZUkJYQTc0ClQxYjZOeWtHaDJVTkw1VTVwSFpFWWRPVkx6K2xSSkw3Z1lxbHdlTkhQL1MzCi0tLS0tRU5EIEVOQ1JZUFRFRCBQUklWQVRFIEtFWS0tLS0tCg==", + "message": "sha512: ecdsa with password", + "signature": "3045022046c7079f0c8eb8b219ad905a6d6594f550fa2d56bdb505a864db046c88bca510022100a112bd975aa01133926899070d01209ef2b94a9d797e79d6350d4e62d76d1655", + "scheme": "sha512", + "passphrase": "bard" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVXVUIzL0RwOVZSWGR5VjhZY3lqRVFVWGRkMEFzUHh3bwpQTVpBRzJQbG1SVlhuRmMyZWhuT0tOVDVxdklGeXJTb0JYS285ckNmZi9CN0kwR3hpNzBNOHVML0JRS2Z5MWpBCkRvSEp1WndWVXpMa0RkZU1lL2ZiK1dXNFF1YUFVbHBDCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JR2tBZ0VCQkRBME5VbVMzOHoxcU1QK2R6Sjk4Y3J4bFkzZXhzN0tOVVlqZ25zODZzZ0ZBTmhPd3YyT09uVVgKcTcvbHZZUW1QN1NnQndZRks0RUVBQ0toWkFOaUFBUlpRSGY4T24xVkZkM0pYeGh6S01SQlJkMTNRQ3cvSENnOAp4a0FiWStXWkZWZWNWelo2R2M0bzFQbXE4Z1hLdEtnRmNxajJzSjkvOEhzalFiR0x2UXp5NHY4RkFwL0xXTUFPCmdjbTVuQlZUTXVRTjE0eDc5OXY1WmJoQzVvQlNXa0k9Ci0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0K", + "message": "sha512: ECDSA with P-384", + "signature": "306402304f61fd4cb02dc367a09d158484a9f4a505b9dab2d9600aa233aef5a64e1ae0d80851254c1a0757c33de2505f5fa9af160230764dded6f16ef2c4ad94dd7d374b5adc1cbeebb7ccc236b74d63a6c2421182b83fc2ee3cfaca267d41f1f2b22a91ca5d", + "scheme": "sha512" + }, + { + "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHYk1CQUdCeXFHU000OUFnRUdCU3VCQkFBakE0R0dBQVFBWEhXdnJrSXF5NnBGZXMxT1E4MmQ2NDYwZUxaOQo5UFdCWGdmaHBLRU1nY2NNamZtQ3FncUV5TGY2YjE3WUVJNEQxdGZKVTFvR3pXQm0zOUhsTDVYVm95OEJyZlBSCm1SRWQ5ZEJOMmg5YWVJYjZtMVFKWDdYdGVPWHljNklobi81dU1Za1Fnb3RpRlkwaVRqeitSaGQwbi9xN3krTlYKL3NCYTlNcFVjdEgvanpIRkQ5Zz0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==", + "private": "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1JSGNBZ0VCQkVJQlNwRlprcnorTzAzK3ErdnlOdUJPMng2S3JKR1NVSzNQT1kyQkdaR0RpUUV3b3lkK1llS1EKNWVwdjJDL2puVEJlc1lVeXhrck5MMHF4VTZpamthdE44bmlnQndZRks0RUVBQ09oZ1lrRGdZWUFCQUJjZGErdQpRaXJMcWtWNnpVNUR6WjNyanJSNHRuMzA5WUZlQitHa29ReUJ4d3lOK1lLcUNvVEl0L3B2WHRnUWpnUFcxOGxUCldnYk5ZR2JmMGVVdmxkV2pMd0d0ODlHWkVSMzEwRTNhSDFwNGh2cWJWQWxmdGUxNDVmSnpvaUdmL200eGlSQ0MKaTJJVmpTSk9QUDVHRjNTZitydkw0MVgrd0ZyMHlsUnkwZitQTWNVUDJBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=", + "message": "sha512: ECDSA with P-521", + "signature": "308188024200dd355b43c77589aff66933c3e3d43d7bdfb0f28308e0fdbaa65fd083ad10b39516c22207a29fb385b17f1085fc8e85bbb132109e7213e05908bab39d4594701d07024201cc0590599ba443f7ea73913b3df7b7e5ae60538053f94b91bd98674411c0b1d82aa95d65c413e0aa994bb55203aad15a222df490f3a7539773785e14f334332d49", + "scheme": "sha512" } ], "rsa": [ @@ -408,9 +608,9 @@ { "public": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZ3d0RRWUpLb1pJaHZjTkFRRUJCUUFEU3dBd1NBSkJBS011enIzZ0VLWHE5VDRka3RkVnV6NHpxclIyenZzbwpCbEg0S1NDRkovNTBvNVNNWkZPa01rZ0pzeDgveVEyb0pzdDBncWVqb3dEWEFLY1lqbUlGNTJVQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=", "private": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUJWQUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQVQ0d2dnRTZBZ0VBQWtFQW95N092ZUFRcGVyMVBoMlMKMTFXN1BqT3F0SGJPK3lnR1VmZ3BJSVVuL25TamxJeGtVNlF5U0Ftekh6L0pEYWdteTNTQ3A2T2pBTmNBcHhpTwpZZ1huWlFJREFRQUJBa0I3ZUl0TitDQWdxcXR0bUlybkRDTmxhVXFjeWRqTENQbmZROW82bFFZeDdYRjdCdkQ2CmZaeEtlODJXK21UMW1BQ2hKeGdITG5MS0wrOUpjNmdMUzljQkFpRUEyYzFyTklTM0ZLTTNmbXNLajdKU2FmbVEKNnZ3anVsdjVvbEpNL2N0M1IvRUNJUUMvelNoRkRNZmVoQXlBT2xTc3NCNlhGZ2syQU9xanBnY1lSMXQ5R1lxcQp0UUlnUTBWeFFVMWtodGxLd0o4cktlcjREWWRwdlVxWGRtNEdFcDY4N1A2MUh1RUNJUUNRSzdndlh4SUZzcUJxCjZtMm5lS01sMGt5T0tWWTJPS0J3b1lLbG9FTlpXUUlnWWRlYWVBY2RIMzg0c2pZa202M05jMzFzQnJyUE5SeGsKSnBVYk9SZzFiNjA9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K", - "message":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDMyMDQyNTQ3fQ", + "message": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDMyMDQyNTQ3fQ", "scheme": "RSA-SHA256", - "signature":"0f4dd91274567cc3242fa4ed172a577ed68b9108894e8e71d4b8638c29cc941f5fb8346cbe7a475b6b01df99d7d5d951a9178af8055a75fe2b2c26cc0142258e" + "signature": "0f4dd91274567cc3242fa4ed172a577ed68b9108894e8e71d4b8638c29cc941f5fb8346cbe7a475b6b01df99d7d5d951a9178af8055a75fe2b2c26cc0142258e" } ], "kvectors": [ @@ -605,4 +805,4 @@ } ] } -} +} \ No newline at end of file diff --git a/test/index.js b/test/index.js index 991f2ef..f94f932 100644 --- a/test/index.js +++ b/test/index.js @@ -1,114 +1,218 @@ -var asn1 = require('parse-asn1/asn1') -var fixtures = require('./fixtures') -var myCrypto = require('../browser') -var nodeCrypto = require('crypto') -var test = require('tape') +'use strict'; -function isNode10 () { - return process.version && process.version.split('.').length === 3 && parseInt(process.version.split('.')[0].slice(1), 10) < 1 && parseInt(process.version.split('.')[1], 10) <= 10 -} +var Buffer = require('safe-buffer').Buffer; +var asn1 = require('parse-asn1/asn1'); +var test = require('tape').test; +var nCrypto = require('crypto'); +var semver = require('semver'); +var BN = require('bn.js'); +var parseKeys = require('parse-asn1'); + +var bCrypto = require('../browser'); +var fixtures = require('./fixtures'); fixtures.valid.rsa.forEach(function (f) { - var message = new Buffer(f.message) - var pub = new Buffer(f.public, 'base64') - var priv + var message = Buffer.from(f.message); + var pub = Buffer.from(f['public'], 'base64'); + var priv; if (f.passphrase) { priv = { - key: new Buffer(f.private, 'base64'), + key: Buffer.from(f['private'], 'base64'), passphrase: f.passphrase - } + }; } else { - priv = new Buffer(f.private, 'base64') + priv = Buffer.from(f['private'], 'base64'); } - // skip passphrase tests in node 10 - if (f.passphrase && isNode10()) return - - test(f.message, function (t) { - t.plan(7) - - var mySign = myCrypto.createSign(f.scheme) - var nodeSign = nodeCrypto.createSign(f.scheme) - var mySig = mySign.update(message).sign(priv) - var nodeSig = nodeSign.update(message).sign(priv) + (nCrypto.getHashes().indexOf(f.scheme) >= 0 ? test : test.skip)(f.message, function (t) { + var bSign; + try { + bSign = bCrypto.createSign(f.scheme); + } catch (e) { + console.info('skipping unsupported browserify-sign scheme', f.scheme); + t.end(); + return; + } - t.equals(mySig.length, nodeSig.length, 'correct length') - t.equals(mySig.toString('hex'), nodeSig.toString('hex'), 'equal sigs') - t.equals(mySig.toString('hex'), f.signature, 'compare to known') + try { + var nSign = nCrypto.createSign(f.scheme); + } catch (e) { + console.info('skipping unsupported node scheme', f.scheme); + t.end(); + return; + } - var myVer = myCrypto.createVerify(f.scheme) - var nodeVer = nodeCrypto.createVerify(f.scheme) - t.ok(nodeVer.update(message).verify(pub, mySig), 'node validate my sig') - t.ok(myVer.update(message).verify(pub, nodeSig), 'me validate node sig') - myVer = myCrypto.createVerify(f.scheme) - nodeVer = nodeCrypto.createVerify(f.scheme) - t.ok(nodeVer.update(message).verify(pub, nodeSig), 'node validate node sig') - t.ok(myVer.update(message).verify(pub, mySig), 'me validate my sig') - }) -}) + var bSig = bSign.update(message).sign(priv); + var nSig = nSign.update(message).sign(priv); + + t.equals(bSig.length, nSig.length, 'correct length'); + t.equals(bSig.toString('hex'), nSig.toString('hex'), 'equal sigs'); + t.equals(bSig.toString('hex'), f.signature, 'compare to known'); + + t.ok(nCrypto.createVerify(f.scheme).update(message).verify(pub, nSig), 'node validate node sig'); + t.ok(nCrypto.createVerify(f.scheme).update(message).verify(pub, bSig), 'node validate browser sig'); + + t.ok(bCrypto.createVerify(f.scheme).update(message).verify(pub, nSig), 'browser validate node sig'); + t.ok(bCrypto.createVerify(f.scheme).update(message).verify(pub, bSig), 'browser validate browser sig'); + + t.end(); + }); +}); + +// node has padding support since 8.0 +// TODO: figure out why node v8.0 - v8.6 is broken +(semver.satisfies(process.versions.node, '>= 8.6') ? test : test.skip)('padding option', function (t) { + var f = fixtures.valid.rsa[0]; + var message = Buffer.from(f.message); + var priv = { + key: Buffer.from(f['private'], 'base64'), + padding: 11646841 // Some invalid value + }; + + t.test('invalid padding option', function (st) { + var bSign = bCrypto.createSign(f.scheme); + var nSign = nCrypto.createSign(f.scheme); + st['throws']( + function () { bSign.update(message).sign(priv); }, + /illegal or unsupported padding mode/, + 'browser throws exception with proper message' + ); + st['throws']( + function () { nSign.update(message).sign(priv); }, + /illegal or unsupported padding mode/, + 'node throws exception with proper message' + ); + + st.end(); + }); + + t.end(); +}); fixtures.valid.ec.forEach(function (f) { - var message = new Buffer(f.message) - var pub = new Buffer(f.public, 'base64') - var priv + var message = Buffer.from(f.message); + var pub = Buffer.from(f['public'], 'base64'); + var priv; if (f.passphrase) { priv = { - key: new Buffer(f.private, 'base64'), + key: Buffer.from(f['private'], 'base64'), passphrase: f.passphrase - } + }; } else { - priv = new Buffer(f.private, 'base64') + priv = Buffer.from(f['private'], 'base64'); } - // skip passphrase tests in node 10 - if (f.passphrase && isNode10()) return + (nCrypto.getHashes().indexOf(f.scheme) >= 0 ? test : test.skip)(f.message, function (t) { + var nSign; + try { + nSign = nCrypto.createSign(f.scheme); + } catch (e) { + console.info('skipping unsupported browserify-sign scheme', f.scheme); + t.end(); + return; + } + + var bSign; + try { + bSign = bCrypto.createSign(f.scheme); + } catch (e) { + console.info('skipping unsupported node scheme', f.scheme); + t.end(); + return; + } - test(f.message, function (t) { - t.plan(4) + var bSig = bSign.update(message).sign(priv); + var nSig = nSign.update(message).sign(priv); + t.notEqual(bSig.toString('hex'), nSig.toString('hex'), 'not equal sigs'); + t.equals(bSig.toString('hex'), f.signature, 'sig is determanistic'); - var nodeSign = nodeCrypto.createSign(f.scheme) - var mySign = myCrypto.createSign(f.scheme) + var nVer = nCrypto.createVerify(f.scheme); + t.ok(nVer.update(message).verify(pub, bSig), 'node validate browser sig'); - var mySig = mySign.update(message).sign(priv) - var nodeSig = nodeSign.update(message).sign(priv) - t.notEqual(mySig.toString('hex'), nodeSig.toString('hex'), 'not equal sigs') - t.equals(mySig.toString('hex'), f.signature) + var bVer = bCrypto.createVerify(f.scheme); + t.ok(bVer.update(message).verify(pub, nSig), 'browser validate node sig'); - var myVer = myCrypto.createVerify(f.scheme) - var nodeVer = nodeCrypto.createVerify(f.scheme) - t.ok(nodeVer.update(message).verify(pub, mySig), 'node validate my sig') - t.ok(myVer.update(message).verify(pub, nodeSig), 'me validate node sig') - }) -}) + t.end(); + }); + + if (f.scheme !== 'DSA' && f.scheme.toLowerCase().indexOf('dsa') === -1) { + test(f.message + ' named rsa through', function (t) { + var scheme = 'RSA-' + f.scheme.toUpperCase(); + var nSign = nCrypto.createSign(scheme); + var bSign = bCrypto.createSign(scheme); + + var bSig = bSign.update(message).sign(priv); + var nSig = nSign.update(message).sign(priv); + t.notEqual(bSig.toString('hex'), nSig.toString('hex'), 'not equal sigs'); + t.equals(bSig.toString('hex'), f.signature, 'sig is determanistic'); + + var nVer = nCrypto.createVerify(f.scheme); + t.ok(nVer.update(message).verify(pub, bSig), 'node validate browser sig'); + + var bVer = bCrypto.createVerify(f.scheme); + t.ok(bVer.update(message).verify(pub, nSig), 'browser validate node sig'); + + t.end(); + }); + } + + var s = parseKeys(pub).data.q; + test( + f.message + ' against a fake signature', + { skip: !s || '(this test only applies to DSA signatures and not EC signatures, this is ' + f.scheme + ')' }, + function (t) { + var messageBase64 = Buffer.from(f.message, 'base64'); + + // forge a fake signature + var r = new BN('1'); + + try { + var fakeSig = asn1.signature.encode({ r: r, s: s }, 'der'); + } catch (e) { + t.ifError(e); + t.end(); + return; + } + + var bVer = bCrypto.createVerify(f.scheme); + t['throws']( + function () { bVer.update(messageBase64).verify(pub, fakeSig); }, + Error, + 'fake signature is invalid' + ); + + t.end(); + } + ); +}); fixtures.valid.kvectors.forEach(function (f) { test('kvector algo: ' + f.algo + ' key len: ' + f.key.length + ' msg: ' + f.msg, function (t) { - var key = new Buffer(f.key, 'base64') + var key = Buffer.from(f.key, 'base64'); + + var bSig = bCrypto.createSign(f.algo).update(f.msg).sign(key); + var bRS = asn1.signature.decode(bSig, 'der'); + t.equals(bRS.r.toString(16), f.r.toLowerCase(), 'r'); + t.equals(bRS.s.toString(16), f.s.toLowerCase(), 's'); - t.plan(2) - var sig = myCrypto.createSign(f.algo).update(f.msg).sign(key) - var rs = asn1.signature.decode(sig, 'der') - t.equals(rs.r.toString(16), f.r.toLowerCase(), 'r') - t.equals(rs.s.toString(16), f.s.toLowerCase(), 's') - }) -}) + t.end(); + }); +}); fixtures.invalid.verify.forEach(function (f) { test(f.description, function (t) { - t.plan(2) + var sign = Buffer.from(f.signature, 'hex'); + var pub = Buffer.from(f['public'], 'base64'); + var message = Buffer.from(f.message); - var sign = new Buffer(f.signature, 'hex') - var pub = new Buffer(f.public, 'base64') - var message = new Buffer(f.message) + var nVerify = nCrypto.createVerify(f.scheme).update(message).verify(pub, sign); + t.notOk(nVerify, 'node rejects it'); - t.notOk(nodeCrypto.createVerify(f.scheme) - .update(message) - .verify(pub, sign), 'node rejects it') + var bVerify = bCrypto.createVerify(f.scheme).update(message).verify(pub, sign); + t.notOk(bVerify, 'We reject it'); - t.notOk(myCrypto.createVerify(f.scheme) - .update(message) - .verify(pub, sign), 'We reject it') - }) -}) + t.end(); + }); +}); diff --git a/verify.js b/verify.js deleted file mode 100644 index cc5e7fe..0000000 --- a/verify.js +++ /dev/null @@ -1,103 +0,0 @@ -// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js -var curves = require('./curves') -var elliptic = require('elliptic') -var parseKeys = require('parse-asn1') - -var BN = require('bn.js') -var EC = elliptic.ec - -function verify (sig, hash, key, signType) { - var pub = parseKeys(key) - if (pub.type === 'ec') { - if (signType !== 'ecdsa') { - throw new Error('wrong public key type') - } - return ecVerify(sig, hash, pub) - } else if (pub.type === 'dsa') { - if (signType !== 'dsa') { - throw new Error('wrong public key type') - } - return dsaVerify(sig, hash, pub) - } else { - if (signType !== 'rsa') { - throw new Error('wrong public key type') - } - } - var len = pub.modulus.byteLength() - var pad = [ 1 ] - var padNum = 0 - while (hash.length + pad.length + 2 < len) { - pad.push(0xff) - padNum++ - } - pad.push(0x00) - var i = -1 - while (++i < hash.length) { - pad.push(hash[i]) - } - pad = new Buffer(pad) - var red = BN.mont(pub.modulus) - sig = new BN(sig).toRed(red) - - sig = sig.redPow(new BN(pub.publicExponent)) - - sig = new Buffer(sig.fromRed().toArray()) - var out = 0 - if (padNum < 8) { - out = 1 - } - len = Math.min(sig.length, pad.length) - if (sig.length !== pad.length) { - out = 1 - } - - i = -1 - while (++i < len) { - out |= (sig[i] ^ pad[i]) - } - return out === 0 -} - -function ecVerify (sig, hash, pub) { - var curveId = curves[pub.data.algorithm.curve.join('.')] - if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.')) - - var curve = new EC(curveId) - var pubkey = pub.data.subjectPrivateKey.data - - return curve.verify(hash, sig, pubkey) -} - -function dsaVerify (sig, hash, pub) { - var p = pub.data.p - var q = pub.data.q - var g = pub.data.g - var y = pub.data.pub_key - var unpacked = parseKeys.signature.decode(sig, 'der') - var s = unpacked.s - var r = unpacked.r - checkValue(s, q) - checkValue(r, q) - var montp = BN.mont(p) - var w = s.invm(q) - var v = g.toRed(montp) - .redPow(new BN(hash).mul(w).mod(q)) - .fromRed() - .mul( - y.toRed(montp) - .redPow(r.mul(w).mod(q)) - .fromRed() - ).mod(p).mod(q) - return !v.cmp(r) -} - -function checkValue (b, q) { - if (b.cmpn(0) <= 0) { - throw new Error('invalid sig') - } - if (b.cmp(q) >= q) { - throw new Error('invalid sig') - } -} - -module.exports = verify