├── .editorconfig
├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.md
├── docs
├── images
│ ├── bg_hr.png
│ ├── blacktocat.png
│ ├── icon_download.png
│ └── sprite_download.png
├── index.html
├── javascripts
│ └── main.js
├── params.json
└── stylesheets
│ ├── github-light.css
│ └── stylesheet.css
├── examples
├── encrypt.js
├── mac.js
├── sign-rs.js
└── sign.js
├── lib
├── common.js
├── encrypt.js
├── index.js
├── mac.js
└── sign.js
├── package-lock.json
├── package.json
└── test
├── aes-ccm-examples.js
├── aes-gcm-examples.js
├── cbc-mac-examples.js
├── common.js
├── ecdh-direct-examples.js
├── encrypted-tests.js
├── enveloped-tests.js
├── hmac-examples.js
├── mac-tests.js
├── mac0-tests.js
├── rsa-pkcs-examples.js
├── rsa-pkcs-examples
└── rsa-pkcs-01.json
├── sign-performance-tests.js
├── sign-tests.js
├── sign1-tests.js
└── util.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .DS_Store
3 | npm-debug.log
4 | .nyc_output/
5 | coverage/
6 | tmp/
7 | .vscode/
8 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "test/Examples"]
2 | path = test/Examples
3 | url = https://github.com/cose-wg/Examples.git
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - '12'
5 | env:
6 | - CXX=g++-4.8
7 | addons:
8 | apt:
9 | sources:
10 | - ubuntu-toolchain-r-test
11 | packages:
12 | - g++-4.8
13 | install:
14 | - npm install
15 | - npm install coveralls
16 | script:
17 | - npm run coverage
18 | after_success:
19 | - npm run coveralls
20 | cache:
21 | directories:
22 | - node_modules
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://app.travis-ci.com/erdtman/cose-js)
2 | [](https://coveralls.io/github/erdtman/cose-js?branch=master)
3 | # cose-js
4 | JavaScript implementation of [COSE](https://tools.ietf.org/html/rfc8152), [RFC8152](https://tools.ietf.org/html/rfc8152)
5 | ## MAC
6 | ```js
7 | const cose = require('cose-js');
8 | try {
9 | const plaintext = 'Important message!';
10 | const headers = {
11 | p: { alg: 'SHA-256_64' },
12 | u: { kid: 'our-secret' }
13 | };
14 | const recipent = {
15 | key: Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex')
16 | };
17 | const buf = await cose.mac.create(headers, plaintext, recipent);
18 | console.log('MACed message: ' + buf.toString('hex'));
19 | } catch (error) {
20 | console.log(error);
21 | }
22 | ```
23 | ## Verify MAC
24 | ```js
25 | const cose = require('cose-js');
26 | try {
27 | const key = Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex');
28 | const COSEMessage = Buffer.from('d18443a10104a1044a6f75722d73656372657472496d706f7274616e74206d65737361676521488894981d4aa5d614', 'hex');
29 | const buf = await cose.mac.read(COSEMessage, key);
30 | console.log('Verified message: ' + buf.toString('utf8'));
31 | } catch (error) {
32 | console.log(error);
33 | }
34 | ```
35 | ## Sign
36 | ```js
37 | const cose = require('cose-js');
38 | try {
39 | const plaintext = 'Important message!';
40 | const headers = {
41 | p: { alg: 'ES256' },
42 | u: { kid: '11' }
43 | };
44 | const signer = {
45 | key: {
46 | d: Buffer.from('6c1382765aec5358f117733d281c1c7bdc39884d04a45a1e6c67c858bc206c19', 'hex')
47 | }
48 | };
49 | const buf = await cose.sign.create(headers, plaintext, signer);
50 | console.log('Signed message: ' + buf.toString('hex'));
51 | } catch (error) {
52 | console.log(error);
53 | }
54 | ```
55 | ## Verify Signature
56 | ```js
57 | const cose = require('cose-js');
58 | try {
59 | const verifier = {
60 | key: {
61 | x: Buffer.from('143329cce7868e416927599cf65a34f3ce2ffda55a7eca69ed8919a394d42f0f', 'hex'),
62 | y: Buffer.from('60f7f1a780d8a783bfb7a2dd6b2796e8128dbbcef9d3d168db9529971a36e7b9', 'hex')
63 | }
64 | };
65 | const COSEMessage = Buffer.from('d28443a10126a10442313172496d706f7274616e74206d6573736167652158404c2b6b66dfedc4cfef0f221cf7ac7f95087a4c4245fef0063a0fd4014b670f642d31e26d38345bb4efcdc7ded3083ab4fe71b62a23f766d83785f044b20534f9', 'hex');
66 | const buf = await cose.sign.verify(COSEMessage, verifier);
67 | console.log('Verified message: ' + buf.toString('utf8'));
68 | } catch (error) {
69 | console.log(error);
70 | }
71 | ```
72 | ## Encrypt
73 | ```js
74 | const cose = require('cose-js');
75 | try {
76 | const plaintext = 'Secret message!';
77 | const headers = {
78 | p: { alg: 'A128GCM' },
79 | u: { kid: 'our-secret' }
80 | };
81 | const recipient = {
82 | key: Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex')
83 | };
84 | const buf = await cose.encrypt.create(headers, plaintext, recipient);
85 | console.log('Encrypted message: ' + buf.toString('hex'));
86 | } catch (error) {
87 | console.log(error);
88 | }
89 | ```
90 | ## Decrypt
91 | ```js
92 | const cose = require('cose-js');
93 | try {
94 | const key = Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex');
95 | const COSEMessage = Buffer.from('d8608443a10101a2044a6f75722d736563726574054c291a40271067ff57b1623c30581f23b663aaf9dfb91c5a39a175118ad7d72d416385b1b610e28b3b3fd824a397818340a040', 'hex');
96 | const buf = await cose.encrypt.read(COSEMessage, key);
97 | console.log('Protected message: ' + buf.toString('utf8'));
98 | } catch (error) {
99 | console.log(error);
100 | }
101 | ```
102 | ## Install
103 | ```
104 | npm install cose-js --save
105 | ```
106 | ## Test
107 | ```
108 | npm test
109 | ```
110 |
--------------------------------------------------------------------------------
/docs/images/bg_hr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdtman/cose-js/c9e6d4d288392aa20fd9b8b434123f905e7449b0/docs/images/bg_hr.png
--------------------------------------------------------------------------------
/docs/images/blacktocat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdtman/cose-js/c9e6d4d288392aa20fd9b8b434123f905e7449b0/docs/images/blacktocat.png
--------------------------------------------------------------------------------
/docs/images/icon_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdtman/cose-js/c9e6d4d288392aa20fd9b8b434123f905e7449b0/docs/images/icon_download.png
--------------------------------------------------------------------------------
/docs/images/sprite_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdtman/cose-js/c9e6d4d288392aa20fd9b8b434123f905e7449b0/docs/images/sprite_download.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | cose-js
12 |
13 |
14 |
15 |
16 |
17 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | cose-js
39 |
40 | JavaScript implementation of COSE
41 |
42 |
43 | install
44 |
45 | npm install cose-js --save
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/docs/javascripts/main.js:
--------------------------------------------------------------------------------
1 | console.log('This would be the main JS file.');
2 |
--------------------------------------------------------------------------------
/docs/params.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cose-js",
3 | "tagline": "JavaScript implementation of COSE",
4 | "body": "[](https://travis-ci.org/erdtman/cose-js)\r\n[](https://coveralls.io/github/erdtman/cose-js?branch=master)\r\n# cose-js\r\nJavaScript implementation of [COSE](https://tools.ietf.org/html/draft-ietf-cose-msg)\r\n\r\n## install\r\n```\r\nnpm install cose-js --save\r\n```\r\n",
5 | "note": "Don't delete this file! It's used internally to help with page regeneration."
6 | }
--------------------------------------------------------------------------------
/docs/stylesheets/github-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2016 GitHub, Inc.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
24 | */
25 |
26 | .pl-c /* comment */ {
27 | color: #969896;
28 | }
29 |
30 | .pl-c1 /* constant, variable.other.constant, support, meta.property-name, support.constant, support.variable, meta.module-reference, markup.raw, meta.diff.header */,
31 | .pl-s .pl-v /* string variable */ {
32 | color: #0086b3;
33 | }
34 |
35 | .pl-e /* entity */,
36 | .pl-en /* entity.name */ {
37 | color: #795da3;
38 | }
39 |
40 | .pl-smi /* variable.parameter.function, storage.modifier.package, storage.modifier.import, storage.type.java, variable.other */,
41 | .pl-s .pl-s1 /* string source */ {
42 | color: #333;
43 | }
44 |
45 | .pl-ent /* entity.name.tag */ {
46 | color: #63a35c;
47 | }
48 |
49 | .pl-k /* keyword, storage, storage.type */ {
50 | color: #a71d5d;
51 | }
52 |
53 | .pl-s /* string */,
54 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */,
55 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */,
56 | .pl-sr /* string.regexp */,
57 | .pl-sr .pl-cce /* string.regexp constant.character.escape */,
58 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */,
59 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */ {
60 | color: #183691;
61 | }
62 |
63 | .pl-v /* variable */ {
64 | color: #ed6a43;
65 | }
66 |
67 | .pl-id /* invalid.deprecated */ {
68 | color: #b52a1d;
69 | }
70 |
71 | .pl-ii /* invalid.illegal */ {
72 | color: #f8f8f8;
73 | background-color: #b52a1d;
74 | }
75 |
76 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ {
77 | font-weight: bold;
78 | color: #63a35c;
79 | }
80 |
81 | .pl-ml /* markup.list */ {
82 | color: #693a17;
83 | }
84 |
85 | .pl-mh /* markup.heading */,
86 | .pl-mh .pl-en /* markup.heading entity.name */,
87 | .pl-ms /* meta.separator */ {
88 | font-weight: bold;
89 | color: #1d3e81;
90 | }
91 |
92 | .pl-mq /* markup.quote */ {
93 | color: #008080;
94 | }
95 |
96 | .pl-mi /* markup.italic */ {
97 | font-style: italic;
98 | color: #333;
99 | }
100 |
101 | .pl-mb /* markup.bold */ {
102 | font-weight: bold;
103 | color: #333;
104 | }
105 |
106 | .pl-md /* markup.deleted, meta.diff.header.from-file */ {
107 | color: #bd2c00;
108 | background-color: #ffecec;
109 | }
110 |
111 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ {
112 | color: #55a532;
113 | background-color: #eaffea;
114 | }
115 |
116 | .pl-mdr /* meta.diff.range */ {
117 | font-weight: bold;
118 | color: #795da3;
119 | }
120 |
121 | .pl-mo /* meta.output */ {
122 | color: #1d3e81;
123 | }
124 |
125 |
--------------------------------------------------------------------------------
/docs/stylesheets/stylesheet.css:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | Slate Theme for GitHub Pages
3 | by Jason Costello, @jsncostello
4 | *******************************************************************************/
5 |
6 | @import url(github-light.css);
7 |
8 | /*******************************************************************************
9 | MeyerWeb Reset
10 | *******************************************************************************/
11 |
12 | html, body, div, span, applet, object, iframe,
13 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
14 | a, abbr, acronym, address, big, cite, code,
15 | del, dfn, em, img, ins, kbd, q, s, samp,
16 | small, strike, strong, sub, sup, tt, var,
17 | b, u, i, center,
18 | dl, dt, dd, ol, ul, li,
19 | fieldset, form, label, legend,
20 | table, caption, tbody, tfoot, thead, tr, th, td,
21 | article, aside, canvas, details, embed,
22 | figure, figcaption, footer, header, hgroup,
23 | menu, nav, output, ruby, section, summary,
24 | time, mark, audio, video {
25 | margin: 0;
26 | padding: 0;
27 | border: 0;
28 | font: inherit;
29 | vertical-align: baseline;
30 | }
31 |
32 | /* HTML5 display-role reset for older browsers */
33 | article, aside, details, figcaption, figure,
34 | footer, header, hgroup, menu, nav, section {
35 | display: block;
36 | }
37 |
38 | ol, ul {
39 | list-style: none;
40 | }
41 |
42 | table {
43 | border-collapse: collapse;
44 | border-spacing: 0;
45 | }
46 |
47 | /*******************************************************************************
48 | Theme Styles
49 | *******************************************************************************/
50 |
51 | body {
52 | box-sizing: border-box;
53 | color:#373737;
54 | background: #212121;
55 | font-size: 16px;
56 | font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
57 | line-height: 1.5;
58 | -webkit-font-smoothing: antialiased;
59 | }
60 |
61 | h1, h2, h3, h4, h5, h6 {
62 | margin: 10px 0;
63 | font-weight: 700;
64 | color:#222222;
65 | font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
66 | letter-spacing: -1px;
67 | }
68 |
69 | h1 {
70 | font-size: 36px;
71 | font-weight: 700;
72 | }
73 |
74 | h2 {
75 | padding-bottom: 10px;
76 | font-size: 32px;
77 | background: url('../images/bg_hr.png') repeat-x bottom;
78 | }
79 |
80 | h3 {
81 | font-size: 24px;
82 | }
83 |
84 | h4 {
85 | font-size: 21px;
86 | }
87 |
88 | h5 {
89 | font-size: 18px;
90 | }
91 |
92 | h6 {
93 | font-size: 16px;
94 | }
95 |
96 | p {
97 | margin: 10px 0 15px 0;
98 | }
99 |
100 | footer p {
101 | color: #f2f2f2;
102 | }
103 |
104 | a {
105 | text-decoration: none;
106 | color: #007edf;
107 | text-shadow: none;
108 |
109 | transition: color 0.5s ease;
110 | transition: text-shadow 0.5s ease;
111 | -webkit-transition: color 0.5s ease;
112 | -webkit-transition: text-shadow 0.5s ease;
113 | -moz-transition: color 0.5s ease;
114 | -moz-transition: text-shadow 0.5s ease;
115 | -o-transition: color 0.5s ease;
116 | -o-transition: text-shadow 0.5s ease;
117 | -ms-transition: color 0.5s ease;
118 | -ms-transition: text-shadow 0.5s ease;
119 | }
120 |
121 | a:hover, a:focus {text-decoration: underline;}
122 |
123 | footer a {
124 | color: #F2F2F2;
125 | text-decoration: underline;
126 | }
127 |
128 | em {
129 | font-style: italic;
130 | }
131 |
132 | strong {
133 | font-weight: bold;
134 | }
135 |
136 | img {
137 | position: relative;
138 | margin: 0 auto;
139 | max-width: 739px;
140 | padding: 5px;
141 | margin: 10px 0 10px 0;
142 | border: 1px solid #ebebeb;
143 |
144 | box-shadow: 0 0 5px #ebebeb;
145 | -webkit-box-shadow: 0 0 5px #ebebeb;
146 | -moz-box-shadow: 0 0 5px #ebebeb;
147 | -o-box-shadow: 0 0 5px #ebebeb;
148 | -ms-box-shadow: 0 0 5px #ebebeb;
149 | }
150 |
151 | p img {
152 | display: inline;
153 | margin: 0;
154 | padding: 0;
155 | vertical-align: middle;
156 | text-align: center;
157 | border: none;
158 | }
159 |
160 | pre, code {
161 | width: 100%;
162 | color: #222;
163 | background-color: #fff;
164 |
165 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
166 | font-size: 14px;
167 |
168 | border-radius: 2px;
169 | -moz-border-radius: 2px;
170 | -webkit-border-radius: 2px;
171 | }
172 |
173 | pre {
174 | width: 100%;
175 | padding: 10px;
176 | box-shadow: 0 0 10px rgba(0,0,0,.1);
177 | overflow: auto;
178 | }
179 |
180 | code {
181 | padding: 3px;
182 | margin: 0 3px;
183 | box-shadow: 0 0 10px rgba(0,0,0,.1);
184 | }
185 |
186 | pre code {
187 | display: block;
188 | box-shadow: none;
189 | }
190 |
191 | blockquote {
192 | color: #666;
193 | margin-bottom: 20px;
194 | padding: 0 0 0 20px;
195 | border-left: 3px solid #bbb;
196 | }
197 |
198 |
199 | ul, ol, dl {
200 | margin-bottom: 15px
201 | }
202 |
203 | ul {
204 | list-style-position: inside;
205 | list-style: disc;
206 | padding-left: 20px;
207 | }
208 |
209 | ol {
210 | list-style-position: inside;
211 | list-style: decimal;
212 | padding-left: 20px;
213 | }
214 |
215 | dl dt {
216 | font-weight: bold;
217 | }
218 |
219 | dl dd {
220 | padding-left: 20px;
221 | font-style: italic;
222 | }
223 |
224 | dl p {
225 | padding-left: 20px;
226 | font-style: italic;
227 | }
228 |
229 | hr {
230 | height: 1px;
231 | margin-bottom: 5px;
232 | border: none;
233 | background: url('../images/bg_hr.png') repeat-x center;
234 | }
235 |
236 | table {
237 | border: 1px solid #373737;
238 | margin-bottom: 20px;
239 | text-align: left;
240 | }
241 |
242 | th {
243 | font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
244 | padding: 10px;
245 | background: #373737;
246 | color: #fff;
247 | }
248 |
249 | td {
250 | padding: 10px;
251 | border: 1px solid #373737;
252 | }
253 |
254 | form {
255 | background: #f2f2f2;
256 | padding: 20px;
257 | }
258 |
259 | /*******************************************************************************
260 | Full-Width Styles
261 | *******************************************************************************/
262 |
263 | .outer {
264 | width: 100%;
265 | }
266 |
267 | .inner {
268 | position: relative;
269 | max-width: 640px;
270 | padding: 20px 10px;
271 | margin: 0 auto;
272 | }
273 |
274 | #forkme_banner {
275 | display: block;
276 | position: absolute;
277 | top:0;
278 | right: 10px;
279 | z-index: 10;
280 | padding: 10px 50px 10px 10px;
281 | color: #fff;
282 | background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
283 | font-weight: 700;
284 | box-shadow: 0 0 10px rgba(0,0,0,.5);
285 | border-bottom-left-radius: 2px;
286 | border-bottom-right-radius: 2px;
287 | }
288 |
289 | #header_wrap {
290 | background: #212121;
291 | background: -moz-linear-gradient(top, #373737, #212121);
292 | background: -webkit-linear-gradient(top, #373737, #212121);
293 | background: -ms-linear-gradient(top, #373737, #212121);
294 | background: -o-linear-gradient(top, #373737, #212121);
295 | background: linear-gradient(top, #373737, #212121);
296 | }
297 |
298 | #header_wrap .inner {
299 | padding: 50px 10px 30px 10px;
300 | }
301 |
302 | #project_title {
303 | margin: 0;
304 | color: #fff;
305 | font-size: 42px;
306 | font-weight: 700;
307 | text-shadow: #111 0px 0px 10px;
308 | }
309 |
310 | #project_tagline {
311 | color: #fff;
312 | font-size: 24px;
313 | font-weight: 300;
314 | background: none;
315 | text-shadow: #111 0px 0px 10px;
316 | }
317 |
318 | #downloads {
319 | position: absolute;
320 | width: 210px;
321 | z-index: 10;
322 | bottom: -40px;
323 | right: 0;
324 | height: 70px;
325 | background: url('../images/icon_download.png') no-repeat 0% 90%;
326 | }
327 |
328 | .zip_download_link {
329 | display: block;
330 | float: right;
331 | width: 90px;
332 | height:70px;
333 | text-indent: -5000px;
334 | overflow: hidden;
335 | background: url(../images/sprite_download.png) no-repeat bottom left;
336 | }
337 |
338 | .tar_download_link {
339 | display: block;
340 | float: right;
341 | width: 90px;
342 | height:70px;
343 | text-indent: -5000px;
344 | overflow: hidden;
345 | background: url(../images/sprite_download.png) no-repeat bottom right;
346 | margin-left: 10px;
347 | }
348 |
349 | .zip_download_link:hover {
350 | background: url(../images/sprite_download.png) no-repeat top left;
351 | }
352 |
353 | .tar_download_link:hover {
354 | background: url(../images/sprite_download.png) no-repeat top right;
355 | }
356 |
357 | #main_content_wrap {
358 | background: #f2f2f2;
359 | border-top: 1px solid #111;
360 | border-bottom: 1px solid #111;
361 | }
362 |
363 | #main_content {
364 | padding-top: 40px;
365 | }
366 |
367 | #footer_wrap {
368 | background: #212121;
369 | }
370 |
371 |
372 |
373 | /*******************************************************************************
374 | Small Device Styles
375 | *******************************************************************************/
376 |
377 | @media screen and (max-width: 480px) {
378 | body {
379 | font-size:14px;
380 | }
381 |
382 | #downloads {
383 | display: none;
384 | }
385 |
386 | .inner {
387 | min-width: 320px;
388 | max-width: 480px;
389 | }
390 |
391 | #project_title {
392 | font-size: 32px;
393 | }
394 |
395 | h1 {
396 | font-size: 28px;
397 | }
398 |
399 | h2 {
400 | font-size: 24px;
401 | }
402 |
403 | h3 {
404 | font-size: 21px;
405 | }
406 |
407 | h4 {
408 | font-size: 18px;
409 | }
410 |
411 | h5 {
412 | font-size: 14px;
413 | }
414 |
415 | h6 {
416 | font-size: 12px;
417 | }
418 |
419 | code, pre {
420 | min-width: 320px;
421 | max-width: 480px;
422 | font-size: 11px;
423 | }
424 |
425 | }
426 |
--------------------------------------------------------------------------------
/examples/encrypt.js:
--------------------------------------------------------------------------------
1 | const cose = require('../');
2 |
3 | async function run () {
4 | try {
5 | const plaintext = 'Secret message!';
6 | const headers = {
7 | p: { alg: 'A128GCM' },
8 | u: { kid: 'our-secret' }
9 | };
10 | const recipient = {
11 | key: Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex')
12 | };
13 | const buf = await cose.encrypt.create(headers, plaintext, recipient);
14 | console.log('Encrypted message: ' + buf.toString('hex'));
15 | } catch (error) {
16 | console.log(error);
17 | }
18 |
19 | try {
20 | const key = Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex');
21 | const COSEMessage = Buffer.from('d8608443a10101a2044a6f75722d736563726574054c291a40271067ff57b1623c30581f23b663aaf9dfb91c5a39a175118ad7d72d416385b1b610e28b3b3fd824a397818340a040', 'hex');
22 | const buf = await cose.encrypt.read(COSEMessage, key);
23 | console.log('Protected message: ' + buf.toString('utf8'));
24 | } catch (error) {
25 | console.log(error);
26 | }
27 | }
28 | run();
29 |
--------------------------------------------------------------------------------
/examples/mac.js:
--------------------------------------------------------------------------------
1 | const cose = require('../');
2 |
3 | async function run () {
4 | try {
5 | const plaintext = 'Important message!';
6 | const headers = {
7 | p: { alg: 'SHA-256_64' },
8 | u: { kid: 'our-secret' }
9 | };
10 | const recipent = {
11 | key: Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex')
12 | };
13 | const buf = await cose.mac.create(headers, plaintext, recipent);
14 | console.log('MACed message: ' + buf.toString('hex'));
15 | } catch (error) {
16 | console.log(error);
17 | }
18 |
19 | try {
20 | const key = Buffer.from('231f4c4d4d3051fdc2ec0a3851d5b383', 'hex');
21 | const COSEMessage = Buffer.from('d18443a10104a1044a6f75722d73656372657472496d706f7274616e74206d65737361676521488894981d4aa5d614', 'hex');
22 | const buf = await cose.mac.read(COSEMessage, key);
23 | console.log('Verified message: ' + buf.toString('utf8'));
24 | } catch (error) {
25 | console.log(error);
26 | }
27 | }
28 | run();
29 |
--------------------------------------------------------------------------------
/examples/sign-rs.js:
--------------------------------------------------------------------------------
1 | const crypto = require('crypto');
2 | const cose = require('../lib');
3 |
4 | async function sample () {
5 | const plaintext = 'Important message!';
6 | const headers = {
7 | p: { alg: 'RS256' },
8 | u: { kid: '11' }
9 | };
10 | const keys = crypto.generateKeyPairSync('rsa', {
11 | modulusLength: 2048,
12 | publicKeyEncoding: {
13 | type: 'spki',
14 | format: 'pem'
15 | },
16 | privateKeyEncoding: {
17 | type: 'pkcs8',
18 | format: 'pem'
19 | }
20 | });
21 | const signer = {
22 | key: keys.privateKey
23 | };
24 |
25 | const msg = await cose.sign.create(headers, plaintext, signer);
26 | console.log('Signed message: ' + msg.toString('hex'));
27 |
28 | const verifier = {
29 | key: keys.publicKey
30 | };
31 |
32 | const plaintext2 = await cose.sign.verify(msg, verifier);
33 | console.log('Verified message: ' + plaintext2.toString('utf8'));
34 | }
35 | sample();
36 |
--------------------------------------------------------------------------------
/examples/sign.js:
--------------------------------------------------------------------------------
1 | const cose = require('../');
2 |
3 | async function run () {
4 | try {
5 | const plaintext = 'Important message!';
6 | const headers = {
7 | p: { alg: 'ES256' },
8 | u: { kid: '11' }
9 | };
10 | const signer = {
11 | key: {
12 | d: Buffer.from('6c1382765aec5358f117733d281c1c7bdc39884d04a45a1e6c67c858bc206c19', 'hex')
13 | }
14 | };
15 | const buf = await cose.sign.create(headers, plaintext, signer);
16 | console.log('Signed message: ' + buf.toString('hex'));
17 | } catch (error) {
18 | console.log(error);
19 | }
20 |
21 | try {
22 | const verifier = {
23 | key: {
24 | x: Buffer.from('143329cce7868e416927599cf65a34f3ce2ffda55a7eca69ed8919a394d42f0f', 'hex'),
25 | y: Buffer.from('60f7f1a780d8a783bfb7a2dd6b2796e8128dbbcef9d3d168db9529971a36e7b9', 'hex')
26 | }
27 | };
28 | const COSEMessage = Buffer.from('d28443a10126a10442313172496d706f7274616e74206d6573736167652158404c2b6b66dfedc4cfef0f221cf7ac7f95087a4c4245fef0063a0fd4014b670f642d31e26d38345bb4efcdc7ded3083ab4fe71b62a23f766d83785f044b20534f9', 'hex');
29 | const buf = await cose.sign.verify(COSEMessage, verifier);
30 | console.log('Verified message: ' + buf.toString('utf8'));
31 | } catch (error) {
32 | console.log(error);
33 | }
34 | }
35 | run();
36 |
--------------------------------------------------------------------------------
/lib/common.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const AlgToTags = {
6 | PS512: -39,
7 | PS384: -38,
8 | PS256: -37,
9 | RS512: -259,
10 | RS384: -258,
11 | RS256: -257,
12 | 'ECDH-SS-512': -28,
13 | 'ECDH-SS': -27,
14 | 'ECDH-ES-512': -26,
15 | 'ECDH-ES': -25,
16 | ES256: -7,
17 | ES384: -35,
18 | ES512: -36,
19 | direct: -6,
20 | A128GCM: 1,
21 | A192GCM: 2,
22 | A256GCM: 3,
23 | 'SHA-256_64': 4,
24 | 'SHA-256-64': 4,
25 | 'HS256/64': 4,
26 | 'SHA-256': 5,
27 | HS256: 5,
28 | 'SHA-384': 6,
29 | HS384: 6,
30 | 'SHA-512': 7,
31 | HS512: 7,
32 | 'AES-CCM-16-64-128': 10,
33 | 'AES-CCM-16-128/64': 10,
34 | 'AES-CCM-16-64-256': 11,
35 | 'AES-CCM-16-256/64': 11,
36 | 'AES-CCM-64-64-128': 12,
37 | 'AES-CCM-64-128/64': 12,
38 | 'AES-CCM-64-64-256': 13,
39 | 'AES-CCM-64-256/64': 13,
40 | 'AES-MAC-128/64': 14,
41 | 'AES-MAC-256/64': 15,
42 | 'AES-MAC-128/128': 25,
43 | 'AES-MAC-256/128': 26,
44 | 'AES-CCM-16-128-128': 30,
45 | 'AES-CCM-16-128/128': 30,
46 | 'AES-CCM-16-128-256': 31,
47 | 'AES-CCM-16-256/128': 31,
48 | 'AES-CCM-64-128-128': 32,
49 | 'AES-CCM-64-128/128': 32,
50 | 'AES-CCM-64-128-256': 33,
51 | 'AES-CCM-64-256/128': 33
52 | };
53 |
54 | const Translators = {
55 | kid: (value) => {
56 | return Buffer.from(value, 'utf8');
57 | },
58 | alg: (value) => {
59 | if (!(AlgToTags[value])) {
60 | throw new Error('Unknown \'alg\' parameter, ' + value);
61 | }
62 | return AlgToTags[value];
63 | }
64 | };
65 |
66 | const HeaderParameters = {
67 | partyUNonce: -22,
68 | static_key_id: -3,
69 | static_key: -2,
70 | ephemeral_key: -1,
71 | alg: 1,
72 | crit: 2,
73 | content_type: 3,
74 | ctyp: 3, // one could question this but it makes testing easier
75 | kid: 4,
76 | IV: 5,
77 | Partial_IV: 6,
78 | counter_signature: 7,
79 | x5chain: 33
80 | };
81 |
82 | exports.EMPTY_BUFFER = Buffer.alloc(0);
83 |
84 | exports.TranslateHeaders = function (header) {
85 | const result = new Map();
86 | for (const param in header) {
87 | if (!HeaderParameters[param]) {
88 | throw new Error('Unknown parameter, \'' + param + '\'');
89 | }
90 | let value = header[param];
91 | if (Translators[param]) {
92 | value = Translators[param](header[param]);
93 | }
94 | if (value !== undefined && value !== null) {
95 | result.set(HeaderParameters[param], value);
96 | }
97 | }
98 | return result;
99 | };
100 |
101 | const KeyParameters = {
102 | crv: -1,
103 | k: -1,
104 | x: -2,
105 | y: -3,
106 | d: -4,
107 | kty: 1
108 | };
109 |
110 | const KeyTypes = {
111 | OKP: 1,
112 | EC2: 2,
113 | RSA: 3,
114 | Symmetric: 4
115 | };
116 |
117 | const KeyCrv = {
118 | 'P-256': 1,
119 | 'P-384': 2,
120 | 'P-521': 3,
121 | X25519: 4,
122 | X448: 5,
123 | Ed25519: 6,
124 | Ed448: 7
125 | };
126 |
127 | const KeyTranslators = {
128 | kty: (value) => {
129 | if (!(KeyTypes[value])) {
130 | throw new Error('Unknown \'kty\' parameter, ' + value);
131 | }
132 | return KeyTypes[value];
133 | },
134 | crv: (value) => {
135 | if (!(KeyCrv[value])) {
136 | throw new Error('Unknown \'crv\' parameter, ' + value);
137 | }
138 | return KeyCrv[value];
139 | }
140 | };
141 |
142 | exports.TranslateKey = function (key) {
143 | const result = new Map();
144 | for (const param in key) {
145 | if (!KeyParameters[param]) {
146 | throw new Error('Unknown parameter, \'' + param + '\'');
147 | }
148 | let value = key[param];
149 | if (KeyTranslators[param]) {
150 | value = KeyTranslators[param](value);
151 | }
152 | result.set(KeyParameters[param], value);
153 | }
154 | return result;
155 | };
156 |
157 | module.exports.xor = function (a, b) {
158 | const buffer = Buffer.alloc(Math.max(a.length, b.length));
159 | for (let i = 1; i <= buffer.length; ++i) {
160 | const av = (a.length - i) < 0 ? 0 : a[a.length - i];
161 | const bv = (b.length - i) < 0 ? 0 : b[b.length - i];
162 | buffer[buffer.length - i] = av ^ bv;
163 | }
164 | return buffer;
165 | };
166 |
167 | exports.HeaderParameters = HeaderParameters;
168 |
169 | exports.runningInNode = function () {
170 | return Object.prototype.toString.call(global.process) === '[object process]';
171 | };
172 |
--------------------------------------------------------------------------------
/lib/encrypt.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cbor = require('cbor');
6 | const crypto = require('crypto');
7 | const Promise = require('any-promise');
8 | const common = require('./common');
9 | const HKDF = require('node-hkdf-sync');
10 |
11 | const Tagged = cbor.Tagged;
12 |
13 | const EMPTY_BUFFER = common.EMPTY_BUFFER;
14 | const EncryptTag = exports.EncryptTag = 96;
15 | const Encrypt0Tag = exports.Encrypt0Tag = 16;
16 |
17 | const runningInNode = common.runningInNode;
18 |
19 | const TagToAlg = {
20 | 1: 'A128GCM',
21 | 2: 'A192GCM',
22 | 3: 'A256GCM',
23 | 10: 'AES-CCM-16-64-128',
24 | 11: 'AES-CCM-16-64-256',
25 | 12: 'AES-CCM-64-64-128',
26 | 13: 'AES-CCM-64-64-256',
27 | 30: 'AES-CCM-16-128-128',
28 | 31: 'AES-CCM-16-128-256',
29 | 32: 'AES-CCM-64-128-128',
30 | 33: 'AES-CCM-64-128-256'
31 | };
32 |
33 | const COSEAlgToNodeAlg = {
34 | A128GCM: 'aes-128-gcm',
35 | A192GCM: 'aes-192-gcm',
36 | A256GCM: 'aes-256-gcm',
37 |
38 | 'AES-CCM-16-64-128': 'aes-128-ccm',
39 | 'AES-CCM-16-64-256': 'aes-256-ccm',
40 | 'AES-CCM-64-64-128': 'aes-128-ccm',
41 | 'AES-CCM-64-64-256': 'aes-256-ccm',
42 | 'AES-CCM-16-128-128': 'aes-128-ccm',
43 | 'AES-CCM-16-128-256': 'aes-256-ccm',
44 | 'AES-CCM-64-128-128': 'aes-128-ccm',
45 | 'AES-CCM-64-128-256': 'aes-256-ccm'
46 | };
47 |
48 | const isNodeAlg = {
49 | 1: true, // A128GCM
50 | 2: true, // A192GCM
51 | 3: true // A256GCM
52 | };
53 |
54 | const isCCMAlg = {
55 | 10: true, // AES-CCM-16-64-128
56 | 11: true, // AES-CCM-16-64-256
57 | 12: true, // AES-CCM-64-64-128
58 | 13: true, // AES-CCM-64-64-256
59 | 30: true, // AES-CCM-16-128-128
60 | 31: true, // AES-CCM-16-128-256
61 | 32: true, // AES-CCM-64-128-128
62 | 33: true // AES-CCM-64-128-256
63 | };
64 |
65 | const authTagLength = {
66 | 1: 16,
67 | 2: 16,
68 | 3: 16,
69 | 10: 8, // AES-CCM-16-64-128
70 | 11: 8, // AES-CCM-16-64-256
71 | 12: 8, // AES-CCM-64-64-128
72 | 13: 8, // AES-CCM-64-64-256
73 | 30: 16, // AES-CCM-16-128-128
74 | 31: 16, // AES-CCM-16-128-256
75 | 32: 16, // AES-CCM-64-128-128
76 | 33: 16 // AES-CCM-64-128-256
77 | };
78 |
79 | const ivLenght = {
80 | 1: 12, // A128GCM
81 | 2: 12, // A192GCM
82 | 3: 12, // A256GCM
83 | 10: 13, // AES-CCM-16-64-128
84 | 11: 13, // AES-CCM-16-64-256
85 | 12: 7, // AES-CCM-64-64-128
86 | 13: 7, // AES-CCM-64-64-256
87 | 30: 13, // AES-CCM-16-128-128
88 | 31: 13, // AES-CCM-16-128-256
89 | 32: 7, // AES-CCM-64-128-128
90 | 33: 7 // AES-CCM-64-128-256
91 | };
92 |
93 | const keyLength = {
94 | 1: 16, // A128GCM
95 | 2: 24, // A192GCM
96 | 3: 32, // A256GCM
97 | 10: 16, // AES-CCM-16-64-128
98 | 11: 32, // AES-CCM-16-64-256
99 | 12: 16, // AES-CCM-64-64-128
100 | 13: 32, // AES-CCM-64-64-256
101 | 30: 16, // AES-CCM-16-128-128
102 | 31: 32, // AES-CCM-16-128-256
103 | 32: 16, // AES-CCM-64-128-128
104 | 33: 32, // AES-CCM-64-128-256
105 | 'P-521': 66,
106 | 'P-256': 32
107 | };
108 |
109 | const HKDFAlg = {
110 | 'ECDH-ES': 'sha256',
111 | 'ECDH-ES-512': 'sha512',
112 | 'ECDH-SS': 'sha256',
113 | 'ECDH-SS-512': 'sha512'
114 | };
115 |
116 | const nodeCRV = {
117 | 'P-521': 'secp521r1',
118 | 'P-256': 'prime256v1'
119 | };
120 |
121 | function createAAD (p, context, externalAAD) {
122 | p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
123 | const encStructure = [
124 | context,
125 | p,
126 | externalAAD
127 | ];
128 | return cbor.encode(encStructure);
129 | }
130 |
131 | function _randomSource (bytes) {
132 | return crypto.randomBytes(bytes);
133 | }
134 |
135 | function nodeEncrypt (payload, key, alg, iv, aad, ccm = false) {
136 | const nodeAlg = COSEAlgToNodeAlg[TagToAlg[alg]];
137 | const chiperOptions = ccm ? { authTagLength: authTagLength[alg] } : null;
138 | const aadOptions = ccm ? { plaintextLength: Buffer.byteLength(payload) } : null;
139 | const cipher = crypto.createCipheriv(nodeAlg, key, iv, chiperOptions);
140 | cipher.setAAD(aad, aadOptions);
141 | return Buffer.concat([
142 | cipher.update(payload),
143 | cipher.final(),
144 | cipher.getAuthTag()
145 | ]);
146 | }
147 |
148 | function createContext (rp, alg, partyUNonce) {
149 | return cbor.encode([
150 | alg, // AlgorithmID
151 | [ // PartyUInfo
152 | null, // identity
153 | (partyUNonce || null), // nonce
154 | null // other
155 | ],
156 | [ // PartyVInfo
157 | null, // identity
158 | null, // nonce
159 | null // other
160 | ],
161 | [
162 | keyLength[alg] * 8, // keyDataLength
163 | rp // protected
164 | ]
165 | ]);
166 | }
167 |
168 | exports.create = function (headers, payload, recipients, options) {
169 | return new Promise((resolve, reject) => {
170 | options = options || {};
171 | const externalAAD = options.externalAAD || EMPTY_BUFFER;
172 | const randomSource = options.randomSource || _randomSource;
173 | let u = headers.u || {};
174 | let p = headers.p || {};
175 |
176 | p = common.TranslateHeaders(p);
177 | u = common.TranslateHeaders(u);
178 |
179 | const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
180 |
181 | if (!alg) {
182 | throw new Error('Missing mandatory parameter \'alg\'');
183 | }
184 |
185 | if (Array.isArray(recipients)) {
186 | if (recipients.length === 0) {
187 | throw new Error('There has to be at least one recipent');
188 | }
189 | if (recipients.length > 1) {
190 | throw new Error('Encrypting with multiple recipents is not implemented');
191 | }
192 |
193 | let iv;
194 | if (options.contextIv) {
195 | const partialIv = randomSource(2);
196 | iv = common.xor(partialIv, options.contextIv);
197 | u.set(common.HeaderParameters.Partial_IV, partialIv);
198 | } else {
199 | iv = randomSource(ivLenght[alg]);
200 | u.set(common.HeaderParameters.IV, iv);
201 | }
202 |
203 | const aad = createAAD(p, 'Encrypt', externalAAD);
204 |
205 | let key;
206 | let recipientStruct;
207 | // TODO do a more accurate check
208 | if (recipients[0] && recipients[0].p &&
209 | (recipients[0].p.alg === 'ECDH-ES' ||
210 | recipients[0].p.alg === 'ECDH-ES-512' ||
211 | recipients[0].p.alg === 'ECDH-SS' ||
212 | recipients[0].p.alg === 'ECDH-SS-512')) {
213 | const recipient = crypto.createECDH(nodeCRV[recipients[0].key.crv]);
214 | const generated = crypto.createECDH(nodeCRV[recipients[0].key.crv]);
215 | recipient.setPrivateKey(recipients[0].key.d);
216 | let pk = randomSource(keyLength[recipients[0].key.crv]);
217 | if (recipients[0].p.alg === 'ECDH-ES' ||
218 | recipients[0].p.alg === 'ECDH-ES-512') {
219 | pk = randomSource(keyLength[recipients[0].key.crv]);
220 | pk[0] = (recipients[0].key.crv !== 'P-521' || pk[0] === 1) ? pk[0] : 0;
221 | } else {
222 | pk = recipients[0].sender.d;
223 | }
224 |
225 | generated.setPrivateKey(pk);
226 | const senderPublicKey = generated.getPublicKey();
227 | const recipientPublicKey = Buffer.concat([
228 | Buffer.from('04', 'hex'),
229 | recipients[0].key.x,
230 | recipients[0].key.y
231 | ]);
232 |
233 | const generatedKey = common.TranslateKey({
234 | crv: recipients[0].key.crv,
235 | x: senderPublicKey.slice(1, keyLength[recipients[0].key.crv] + 1), // TODO slice based on key length
236 | y: senderPublicKey.slice(keyLength[recipients[0].key.crv] + 1),
237 | kty: 'EC2' // TODO use real value
238 | });
239 | const rp = cbor.encode(common.TranslateHeaders(recipients[0].p));
240 | const ikm = generated.computeSecret(recipientPublicKey);
241 | let partyUNonce = null;
242 | if (recipients[0].p.alg === 'ECDH-SS' || recipients[0].p.alg === 'ECDH-SS-512') {
243 | partyUNonce = randomSource(64); // TODO use real value
244 | }
245 | const context = createContext(rp, alg, partyUNonce);
246 | const nrBytes = keyLength[alg];
247 | const hkdf = new HKDF(HKDFAlg[recipients[0].p.alg], undefined, ikm);
248 | key = hkdf.derive(context, nrBytes);
249 | let ru = recipients[0].u;
250 |
251 | if (recipients[0].p.alg === 'ECDH-ES' ||
252 | recipients[0].p.alg === 'ECDH-ES-512') {
253 | ru.ephemeral_key = generatedKey;
254 | } else {
255 | ru.static_key = generatedKey;
256 | }
257 |
258 | ru.partyUNonce = partyUNonce;
259 | ru = common.TranslateHeaders(ru);
260 |
261 | recipientStruct = [[rp, ru, EMPTY_BUFFER]];
262 | } else {
263 | key = recipients[0].key;
264 | const ru = common.TranslateHeaders(recipients[0].u);
265 | recipientStruct = [[EMPTY_BUFFER, ru, EMPTY_BUFFER]];
266 | }
267 |
268 | let ciphertext;
269 | if (isNodeAlg[alg]) {
270 | ciphertext = nodeEncrypt(payload, key, alg, iv, aad);
271 | } else if (isCCMAlg[alg] && runningInNode()) {
272 | ciphertext = nodeEncrypt(payload, key, alg, iv, aad, true);
273 | } else {
274 | throw new Error('No implementation for algorithm, ' + alg);
275 | }
276 |
277 | if (p.size === 0 && options.encodep === 'empty') {
278 | p = EMPTY_BUFFER;
279 | } else {
280 | p = cbor.encode(p);
281 | }
282 |
283 | const encrypted = [p, u, ciphertext, recipientStruct];
284 | resolve(cbor.encode(options.excludetag ? encrypted : new Tagged(EncryptTag, encrypted)));
285 | } else {
286 | let iv;
287 | if (options.contextIv) {
288 | const partialIv = randomSource(2);
289 | iv = common.xor(partialIv, options.contextIv);
290 | u.set(common.HeaderParameters.Partial_IV, partialIv);
291 | } else {
292 | iv = randomSource(ivLenght[alg]);
293 | u.set(common.HeaderParameters.IV, iv);
294 | }
295 |
296 | const key = recipients.key;
297 |
298 | const aad = createAAD(p, 'Encrypt0', externalAAD);
299 | let ciphertext;
300 | if (isNodeAlg[alg]) {
301 | ciphertext = nodeEncrypt(payload, key, alg, iv, aad);
302 | } else if (isCCMAlg[alg] && runningInNode()) {
303 | ciphertext = nodeEncrypt(payload, key, alg, iv, aad, true);
304 | } else {
305 | throw new Error('No implementation for algorithm, ' + alg);
306 | }
307 |
308 | if (p.size === 0 && options.encodep === 'empty') {
309 | p = EMPTY_BUFFER;
310 | } else {
311 | p = cbor.encode(p);
312 | }
313 | const encrypted = [p, u, ciphertext];
314 | resolve(cbor.encode(options.excludetag ? encrypted : new Tagged(Encrypt0Tag, encrypted)));
315 | }
316 | });
317 | };
318 |
319 | function nodeDecrypt (ciphertext, key, alg, iv, tag, aad, ccm = false) {
320 | const nodeAlg = COSEAlgToNodeAlg[TagToAlg[alg]];
321 | const chiperOptions = ccm ? { authTagLength: authTagLength[alg] } : null;
322 | const aadOptions = ccm ? { plaintextLength: Buffer.byteLength(ciphertext) } : null;
323 | const decipher = crypto.createDecipheriv(nodeAlg, key, iv, chiperOptions);
324 | decipher.setAuthTag(tag);
325 | decipher.setAAD(aad, aadOptions);
326 | return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
327 | }
328 |
329 | exports.read = async function (data, key, options) {
330 | options = options || {};
331 | const externalAAD = options.externalAAD || EMPTY_BUFFER;
332 | let obj = await cbor.decodeFirst(data);
333 | let msgTag = options.defaultType ? options.defaultType : EncryptTag;
334 | if (obj instanceof Tagged) {
335 | if (obj.tag !== EncryptTag && obj.tag !== Encrypt0Tag) {
336 | throw new Error('Unknown tag, ' + obj.tag);
337 | }
338 | msgTag = obj.tag;
339 | obj = obj.value;
340 | }
341 |
342 | if (!Array.isArray(obj)) {
343 | throw new Error('Expecting Array');
344 | }
345 |
346 | if (msgTag === EncryptTag && obj.length !== 4) {
347 | throw new Error('Expecting Array of lenght 4 for COSE Encrypt message');
348 | }
349 |
350 | if (msgTag === Encrypt0Tag && obj.length !== 3) {
351 | throw new Error('Expecting Array of lenght 4 for COSE Encrypt0 message');
352 | }
353 |
354 | let [p, u, ciphertext] = obj;
355 |
356 | p = (p.length === 0) ? EMPTY_BUFFER : cbor.decodeFirstSync(p);
357 | p = (!p.size) ? EMPTY_BUFFER : p;
358 | u = (!u.size) ? EMPTY_BUFFER : u;
359 |
360 | const alg = (p !== EMPTY_BUFFER) ? p.get(common.HeaderParameters.alg) : (u !== EMPTY_BUFFER) ? u.get(common.HeaderParameters.alg) : undefined;
361 | if (!TagToAlg[alg]) {
362 | throw new Error('Unknown or unsupported algorithm ' + alg);
363 | }
364 |
365 | let iv = u.get(common.HeaderParameters.IV);
366 | const partialIv = u.get(common.HeaderParameters.Partial_IV);
367 | if (iv && partialIv) {
368 | throw new Error('IV and Partial IV parameters MUST NOT both be present in the same security layer');
369 | }
370 | if (partialIv && !options.contextIv) {
371 | throw new Error('Context IV must be provided when Partial IV is used');
372 | }
373 | if (partialIv && options.contextIv) {
374 | iv = common.xor(partialIv, options.contextIv);
375 | }
376 |
377 | const tagLength = authTagLength[alg];
378 | const tag = ciphertext.slice(ciphertext.length - tagLength, ciphertext.length);
379 | ciphertext = ciphertext.slice(0, ciphertext.length - tagLength);
380 |
381 | const aad = createAAD(p, (msgTag === EncryptTag ? 'Encrypt' : 'Encrypt0'), externalAAD);
382 | if (isNodeAlg[alg]) {
383 | return nodeDecrypt(ciphertext, key, alg, iv, tag, aad);
384 | } else if (isCCMAlg[alg] && runningInNode()) {
385 | return nodeDecrypt(ciphertext, key, alg, iv, tag, aad, true);
386 | } else {
387 | throw new Error('No implementation for algorithm, ' + alg);
388 | }
389 | };
390 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | exports.common = require('./common');
6 | exports.mac = require('./mac');
7 | exports.sign = require('./sign');
8 | exports.encrypt = require('./encrypt');
9 |
--------------------------------------------------------------------------------
/lib/mac.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cbor = require('cbor');
6 | const aesCbcMac = require('aes-cbc-mac');
7 | const crypto = require('crypto');
8 | const Promise = require('any-promise');
9 | const common = require('./common');
10 | const Tagged = cbor.Tagged;
11 | const EMPTY_BUFFER = common.EMPTY_BUFFER;
12 |
13 | const MAC0Tag = exports.MAC0Tag = 17;
14 | const MACTag = exports.MACTag = 97;
15 |
16 | const AlgFromTags = {
17 | 4: 'SHA-256_64',
18 | 5: 'SHA-256',
19 | 6: 'SHA-384',
20 | 7: 'SHA-512',
21 | 14: 'AES-MAC-128/64',
22 | 15: 'AES-MAC-256/64',
23 | 25: 'AES-MAC-128/128',
24 | 26: 'AES-MAC-256/128'
25 | };
26 |
27 | const COSEAlgToNodeAlg = {
28 | 'SHA-256_64': 'sha256',
29 | 'SHA-256': 'sha256',
30 | HS256: 'sha256',
31 | 'SHA-384': 'sha384',
32 | 'SHA-512': 'sha512',
33 | 'AES-MAC-128/64': 'aes-cbc-mac-64',
34 | 'AES-MAC-128/128': 'aes-cbc-mac-128',
35 | 'AES-MAC-256/64': 'aes-cbc-mac-64',
36 | 'AES-MAC-256/128': 'aes-cbc-mac-128'
37 | };
38 |
39 | const CutTo = {
40 | 4: 8,
41 | 5: 32,
42 | 6: 48,
43 | 7: 64
44 | };
45 |
46 | const context = {};
47 | context[MAC0Tag] = 'MAC0';
48 | context[MACTag] = 'MAC';
49 |
50 | function doMac (context, p, externalAAD, payload, alg, key) {
51 | return new Promise((resolve, reject) => {
52 | const MACstructure = [
53 | context, // 'MAC0' or 'MAC1', // context
54 | p, // protected
55 | externalAAD, // bstr,
56 | payload // bstr
57 | ];
58 |
59 | const toBeMACed = cbor.encode(MACstructure);
60 | if (alg === 'aes-cbc-mac-64') {
61 | const mac = aesCbcMac.create(key, toBeMACed, 8);
62 | resolve(mac);
63 | } else if (alg === 'aes-cbc-mac-128') {
64 | const mac = aesCbcMac.create(key, toBeMACed, 16);
65 | resolve(mac);
66 | } else {
67 | const hmac = crypto.createHmac(alg, key);
68 | hmac.end(toBeMACed, function () {
69 | resolve(hmac.read());
70 | });
71 | }
72 | });
73 | }
74 |
75 | exports.create = async function (headers, payload, recipents, externalAAD, options) {
76 | options = options || {};
77 | externalAAD = externalAAD || EMPTY_BUFFER;
78 | let u = headers.u || {};
79 | let p = headers.p || {};
80 |
81 | p = common.TranslateHeaders(p);
82 | u = common.TranslateHeaders(u);
83 |
84 | const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
85 |
86 | if (!alg) {
87 | throw new Error('Missing mandatory parameter \'alg\'');
88 | }
89 |
90 | if (recipents.length === 0) {
91 | throw new Error('There has to be at least one recipent');
92 | }
93 |
94 | const predictableP = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
95 | if (p.size === 0 && options.encodep === 'empty') {
96 | p = EMPTY_BUFFER;
97 | } else {
98 | p = cbor.encode(p);
99 | }
100 | // TODO check crit headers
101 | if (Array.isArray(recipents)) {
102 | if (recipents.length > 1) {
103 | throw new Error('MACing with multiple recipents is not implemented');
104 | }
105 | const recipent = recipents[0];
106 | let tag = await doMac('MAC', predictableP, externalAAD, payload, COSEAlgToNodeAlg[AlgFromTags[alg]], recipent.key);
107 | tag = tag.slice(0, CutTo[alg]);
108 | const ru = common.TranslateHeaders(recipent.u);
109 | const rp = EMPTY_BUFFER;
110 | const maced = [p, u, payload, tag, [[rp, ru, EMPTY_BUFFER]]];
111 | return cbor.encode(options.excludetag ? maced : new Tagged(MACTag, maced));
112 | } else {
113 | let tag = await doMac('MAC0', predictableP, externalAAD, payload, COSEAlgToNodeAlg[AlgFromTags[alg]], recipents.key);
114 | tag = tag.slice(0, CutTo[alg]);
115 | const maced = [p, u, payload, tag];
116 | return cbor.encode(options.excludetag ? maced : new Tagged(MAC0Tag, maced));
117 | }
118 | };
119 |
120 | exports.read = async function (data, key, externalAAD, options) {
121 | options = options || {};
122 | externalAAD = externalAAD || EMPTY_BUFFER;
123 |
124 | let obj = await cbor.decodeFirst(data);
125 |
126 | let type = options.defaultType ? options.defaultType : MAC0Tag;
127 | if (obj instanceof Tagged) {
128 | if (obj.tag !== MAC0Tag && obj.tag !== MACTag) {
129 | throw new Error('Unexpected cbor tag, \'' + obj.tag + '\'');
130 | }
131 | type = obj.tag;
132 | obj = obj.value;
133 | }
134 |
135 | if (!Array.isArray(obj)) {
136 | throw new Error('Expecting Array');
137 | }
138 |
139 | if (type === MAC0Tag && obj.length !== 4) {
140 | throw new Error('Expecting Array of lenght 4');
141 | }
142 | if (type === MACTag && obj.length !== 5) {
143 | throw new Error('Expecting Array of lenght 5');
144 | }
145 |
146 | let [p, u, payload, tag] = obj;
147 | p = (!p.length) ? EMPTY_BUFFER : cbor.decode(p);
148 | p = (!p.size) ? EMPTY_BUFFER : p;
149 | u = (!u.size) ? EMPTY_BUFFER : u;
150 |
151 | // TODO validate protected header
152 | const alg = (p !== EMPTY_BUFFER) ? p.get(common.HeaderParameters.alg) : (u !== EMPTY_BUFFER) ? u.get(common.HeaderParameters.alg) : undefined;
153 | p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
154 | if (!AlgFromTags[alg]) {
155 | throw new Error('Unknown algorithm, ' + alg);
156 | }
157 | if (!COSEAlgToNodeAlg[AlgFromTags[alg]]) {
158 | throw new Error('Unsupported algorithm, ' + AlgFromTags[alg]);
159 | }
160 |
161 | let calcTag = await doMac(context[type], p, externalAAD, payload, COSEAlgToNodeAlg[AlgFromTags[alg]], key);
162 | calcTag = calcTag.slice(0, CutTo[alg]);
163 | if (tag.toString('hex') !== calcTag.toString('hex')) {
164 | throw new Error('Tag mismatch');
165 | }
166 | return payload;
167 | };
168 |
--------------------------------------------------------------------------------
/lib/sign.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cbor = require('cbor');
6 | const EC = require('elliptic').ec;
7 | const crypto = require('crypto');
8 | const NodeRSA = require('node-rsa');
9 | const common = require('./common');
10 | const EMPTY_BUFFER = common.EMPTY_BUFFER;
11 | const Tagged = cbor.Tagged;
12 |
13 | const SignTag = exports.SignTag = 98;
14 | const Sign1Tag = exports.Sign1Tag = 18;
15 |
16 | const AlgFromTags = {};
17 | AlgFromTags[-7] = { sign: 'ES256', digest: 'SHA-256' };
18 | AlgFromTags[-35] = { sign: 'ES384', digest: 'SHA-384' };
19 | AlgFromTags[-36] = { sign: 'ES512', digest: 'SHA-512' };
20 | AlgFromTags[-37] = { sign: 'PS256', digest: 'SHA-256' };
21 | AlgFromTags[-38] = { sign: 'PS384', digest: 'SHA-384' };
22 | AlgFromTags[-39] = { sign: 'PS512', digest: 'SHA-512' };
23 | AlgFromTags[-257] = { sign: 'RS256', digest: 'SHA-256' };
24 | AlgFromTags[-258] = { sign: 'RS384', digest: 'SHA-384' };
25 | AlgFromTags[-259] = { sign: 'RS512', digest: 'SHA-512' };
26 |
27 | const COSEAlgToNodeAlg = {
28 | ES256: { sign: 'p256', digest: 'sha256' },
29 | ES384: { sign: 'p384', digest: 'sha384' },
30 | ES512: { sign: 'p521', digest: 'sha512' },
31 | RS256: { sign: 'RSA-SHA256' },
32 | RS384: { sign: 'RSA-SHA384' },
33 | RS512: { sign: 'RSA-SHA512' },
34 | PS256: { alg: 'pss-sha256', saltLen: 32 },
35 | PS384: { alg: 'pss-sha384', saltLen: 48 },
36 | PS512: { alg: 'pss-sha512', saltLen: 64 }
37 | };
38 |
39 | function doSign (SigStructure, signer, alg) {
40 | if (!AlgFromTags[alg]) {
41 | throw new Error('Unknown algorithm, ' + alg);
42 | }
43 | if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) {
44 | throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign);
45 | }
46 |
47 | let ToBeSigned = cbor.encode(SigStructure);
48 |
49 | let sig;
50 | if (AlgFromTags[alg].sign.startsWith('ES')) {
51 | const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest);
52 | hash.update(ToBeSigned);
53 | ToBeSigned = hash.digest();
54 | const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
55 | const key = ec.keyFromPrivate(signer.key.d);
56 | const signature = key.sign(ToBeSigned);
57 | const bitLength = Math.ceil(ec.curve._bitLength / 8);
58 | sig = Buffer.concat([signature.r.toArrayLike(Buffer, undefined, bitLength), signature.s.toArrayLike(Buffer, undefined, bitLength)]);
59 | } else if (AlgFromTags[alg].sign.startsWith('PS')) {
60 | signer.key.dmp1 = signer.key.dp;
61 | signer.key.dmq1 = signer.key.dq;
62 | signer.key.coeff = signer.key.qi;
63 | const key = new NodeRSA().importKey(signer.key, 'components-private');
64 | key.setOptions({
65 | signingScheme: {
66 | scheme: COSEAlgToNodeAlg[AlgFromTags[alg].sign].alg.split('-')[0],
67 | hash: COSEAlgToNodeAlg[AlgFromTags[alg].sign].alg.split('-')[1],
68 | saltLength: COSEAlgToNodeAlg[AlgFromTags[alg].sign].saltLen
69 | }
70 | });
71 | sig = key.sign(ToBeSigned);
72 | } else {
73 | const sign = crypto.createSign(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign);
74 | sign.update(ToBeSigned);
75 | sign.end();
76 | sig = sign.sign(signer.key);
77 | }
78 | return sig;
79 | }
80 |
81 | exports.create = function (headers, payload, signers, options) {
82 | options = options || {};
83 | let u = headers.u || {};
84 | let p = headers.p || {};
85 |
86 | p = common.TranslateHeaders(p);
87 | u = common.TranslateHeaders(u);
88 | let bodyP = p || {};
89 | bodyP = (bodyP.size === 0) ? EMPTY_BUFFER : cbor.encode(bodyP);
90 | if (Array.isArray(signers)) {
91 | if (signers.length === 0) {
92 | throw new Error('There has to be at least one signer');
93 | }
94 | if (signers.length > 1) {
95 | throw new Error('Only one signer is supported');
96 | }
97 | // TODO handle multiple signers
98 | const signer = signers[0];
99 | const externalAAD = signer.externalAAD || EMPTY_BUFFER;
100 | let signerP = signer.p || {};
101 | let signerU = signer.u || {};
102 |
103 | signerP = common.TranslateHeaders(signerP);
104 | signerU = common.TranslateHeaders(signerU);
105 | const alg = signerP.get(common.HeaderParameters.alg);
106 | signerP = (signerP.size === 0) ? EMPTY_BUFFER : cbor.encode(signerP);
107 |
108 | const SigStructure = [
109 | 'Signature',
110 | bodyP,
111 | signerP,
112 | externalAAD,
113 | payload
114 | ];
115 |
116 | const sig = doSign(SigStructure, signer, alg);
117 | if (p.size === 0 && options.encodep === 'empty') {
118 | p = EMPTY_BUFFER;
119 | } else {
120 | p = cbor.encode(p);
121 | }
122 | const signed = [p, u, payload, [[signerP, signerU, sig]]];
123 | return cbor.encodeAsync(options.excludetag ? signed : new Tagged(SignTag, signed));
124 | } else {
125 | const signer = signers;
126 | const externalAAD = signer.externalAAD || EMPTY_BUFFER;
127 | const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
128 | const SigStructure = [
129 | 'Signature1',
130 | bodyP,
131 | externalAAD,
132 | payload
133 | ];
134 | const sig = doSign(SigStructure, signer, alg);
135 | if (p.size === 0 && options.encodep === 'empty') {
136 | p = EMPTY_BUFFER;
137 | } else {
138 | p = cbor.encode(p);
139 | }
140 | const signed = [p, u, payload, sig];
141 | return cbor.encodeAsync(options.excludetag ? signed : new Tagged(Sign1Tag, signed), { canonical: true });
142 | }
143 | };
144 |
145 | function doVerify (SigStructure, verifier, alg, sig) {
146 | if (!AlgFromTags[alg]) {
147 | throw new Error('Unknown algorithm, ' + alg);
148 | }
149 | const nodeAlg = COSEAlgToNodeAlg[AlgFromTags[alg].sign];
150 | if (!nodeAlg) {
151 | throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign);
152 | }
153 | const ToBeSigned = cbor.encode(SigStructure);
154 |
155 | if (AlgFromTags[alg].sign.startsWith('ES')) {
156 | const hash = crypto.createHash(nodeAlg.digest);
157 | hash.update(ToBeSigned);
158 | const msgHash = hash.digest();
159 |
160 | const pub = { x: verifier.key.x, y: verifier.key.y };
161 | const ec = new EC(nodeAlg.sign);
162 | const key = ec.keyFromPublic(pub);
163 | sig = { r: sig.slice(0, sig.length / 2), s: sig.slice(sig.length / 2) };
164 | if (!key.verify(msgHash, sig)) {
165 | throw new Error('Signature missmatch');
166 | }
167 | } else if (AlgFromTags[alg].sign.startsWith('PS')) {
168 | const key = new NodeRSA().importKey(verifier.key, 'components-public');
169 | key.setOptions({
170 | signingScheme: {
171 | scheme: COSEAlgToNodeAlg[AlgFromTags[alg].sign].alg.split('-')[0],
172 | hash: COSEAlgToNodeAlg[AlgFromTags[alg].sign].alg.split('-')[1],
173 | saltLength: COSEAlgToNodeAlg[AlgFromTags[alg].sign].saltLen
174 | }
175 | });
176 | if (!key.verify(ToBeSigned, sig, 'buffer', 'buffer')) {
177 | throw new Error('Signature missmatch');
178 | }
179 | } else {
180 | const verify = crypto.createVerify(nodeAlg.sign);
181 | verify.update(ToBeSigned);
182 | if (!verify.verify(verifier.key, sig)) {
183 | throw new Error('Signature missmatch');
184 | }
185 | }
186 | }
187 |
188 | function getSigner (signers, verifier) {
189 | for (let i = 0; i < signers.length; i++) {
190 | const kid = signers[i][1].get(common.HeaderParameters.kid); // TODO create constant for header locations
191 | if (kid.equals(Buffer.from(verifier.key.kid, 'utf8'))) {
192 | return signers[i];
193 | }
194 | }
195 | }
196 |
197 | function getCommonParameter (first, second, parameter) {
198 | let result;
199 | if (first.get) {
200 | result = first.get(parameter);
201 | }
202 | if (!result && second.get) {
203 | result = second.get(parameter);
204 | }
205 | return result;
206 | }
207 |
208 | exports.verify = async function (payload, verifier, options) {
209 | options = options || {};
210 | const obj = await cbor.decodeFirst(payload);
211 | return verifyInternal(verifier, options, obj);
212 | };
213 |
214 | exports.verifySync = function (payload, verifier, options) {
215 | options = options || {};
216 | const obj = cbor.decodeFirstSync(payload);
217 | return verifyInternal(verifier, options, obj);
218 | };
219 |
220 | function verifyInternal (verifier, options, obj) {
221 | options = options || {};
222 | let type = options.defaultType ? options.defaultType : SignTag;
223 | if (obj instanceof Tagged) {
224 | if (obj.tag !== SignTag && obj.tag !== Sign1Tag) {
225 | throw new Error('Unexpected cbor tag, \'' + obj.tag + '\'');
226 | }
227 | type = obj.tag;
228 | obj = obj.value;
229 | }
230 |
231 | if (!Array.isArray(obj)) {
232 | throw new Error('Expecting Array');
233 | }
234 |
235 | if (obj.length !== 4) {
236 | throw new Error('Expecting Array of lenght 4');
237 | }
238 |
239 | let [p, u, plaintext, signers] = obj;
240 |
241 | if (type === SignTag && !Array.isArray(signers)) {
242 | throw new Error('Expecting signature Array');
243 | }
244 |
245 | p = (!p.length) ? EMPTY_BUFFER : cbor.decodeFirstSync(p);
246 | u = (!u.size) ? EMPTY_BUFFER : u;
247 |
248 | const signer = (type === SignTag ? getSigner(signers, verifier) : signers);
249 |
250 | if (!signer) {
251 | throw new Error('Failed to find signer with kid' + verifier.key.kid);
252 | }
253 |
254 | if (type === SignTag) {
255 | const externalAAD = verifier.externalAAD || EMPTY_BUFFER;
256 | let [signerP, , sig] = signer;
257 | signerP = (!signerP.length) ? EMPTY_BUFFER : signerP;
258 | p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
259 | const signerPMap = cbor.decode(signerP);
260 | const alg = signerPMap.get(common.HeaderParameters.alg);
261 | const SigStructure = [
262 | 'Signature',
263 | p,
264 | signerP,
265 | externalAAD,
266 | plaintext
267 | ];
268 | doVerify(SigStructure, verifier, alg, sig);
269 | return plaintext;
270 | } else {
271 | const externalAAD = verifier.externalAAD || EMPTY_BUFFER;
272 |
273 | const alg = getCommonParameter(p, u, common.HeaderParameters.alg);
274 | p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
275 | const SigStructure = [
276 | 'Signature1',
277 | p,
278 | externalAAD,
279 | plaintext
280 | ];
281 | doVerify(SigStructure, verifier, alg, signer);
282 | return plaintext;
283 | }
284 | }
285 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cose-js",
3 | "version": "0.8.3",
4 | "description": "JavaScript COSE implementation",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "clean": "rm -rf coverage/ .nyc_output/",
8 | "pretest": "semistandard --fix",
9 | "test": "pwd & ava ./test/*.js",
10 | "coverage": "nyc npm test",
11 | "coveragehtml": "nyc report -r html",
12 | "precoveragehtml": "npm run coverage",
13 | "coveralls": "nyc report --reporter=text-lcov | coveralls",
14 | "live": "live-server -q --port=4003 --ignorePattern='(js|css|png)$' coverage",
15 | "watch": "watch 'npm run coveragehtml' test lib",
16 | "dev": "npm-run-all -p --silent watch live"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/erdtman/COSE-JS.git"
21 | },
22 | "keywords": [
23 | "COSE",
24 | "Signing",
25 | "MAC",
26 | "Encrypt",
27 | "IoT"
28 | ],
29 | "author": "Samuel Erdtman",
30 | "contributors": [
31 | {
32 | "name": "Joe Hildebrand",
33 | "email": "joe-github@cursive.net"
34 | }
35 | ],
36 | "license": "Apache-2.0",
37 | "bugs": {
38 | "url": "https://github.com/erdtman/cose-js/issues"
39 | },
40 | "homepage": "https://github.com/erdtman/cose-js#readme",
41 | "dependencies": {
42 | "aes-cbc-mac": "^1.0.1",
43 | "any-promise": "^1.3.0",
44 | "cbor": "^8.1.0",
45 | "elliptic": "^6.4.0",
46 | "node-hkdf-sync": "^1.0.0",
47 | "node-rsa": "^1.1.1"
48 | },
49 | "devDependencies": {
50 | "ava": "^3.15.0",
51 | "base64url": "^3.0.1",
52 | "jsonfile": "^2.4.0",
53 | "jwk-to-pem": "^2.0.5",
54 | "live-server": "*",
55 | "npm-run-all": "*",
56 | "nyc": "^15.1.0",
57 | "semistandard": "^16.0.1",
58 | "watch": "*"
59 | },
60 | "engines": {
61 | "node": ">=12.0"
62 | },
63 | "semistandard": {
64 | "ignore": "tmp/**"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/test/aes-ccm-examples.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | function randomSource (bytes) {
13 | if (bytes === 12) {
14 | return Buffer.from('02D1F7E6F26C43D4868D87CE', 'hex');
15 | } else if (bytes === 2) {
16 | return Buffer.from('61A7', 'hex');
17 | } else if (bytes === 13) {
18 | return Buffer.from('89F52F65A1C580933B5261A72F', 'hex');
19 | } else if (bytes === 7) {
20 | return Buffer.from('89F52F65A1C580', 'hex');
21 | }
22 | }
23 |
24 | test('create aes-ccm-enc-01', async t => {
25 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-01.json');
26 | const p = example.input.encrypted.protected;
27 | const u = example.input.encrypted.unprotected;
28 | const plaintext = Buffer.from(example.input.plaintext);
29 |
30 | const recipient = {
31 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
32 | u: example.input.encrypted.recipients[0].unprotected
33 | };
34 |
35 | const options = {
36 | randomSource: randomSource
37 | };
38 | const header = { p: p, u: u };
39 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
40 | t.true(Buffer.isBuffer(buf));
41 | t.true(buf.length > 0);
42 | const actual = cbor.decodeFirstSync(buf);
43 | const expected = cbor.decodeFirstSync(example.output.cbor);
44 | t.true(deepEqual(actual, expected));
45 | });
46 |
47 | test('create aes-ccm-enc-02', async t => {
48 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-02.json');
49 | const p = example.input.encrypted.protected;
50 | const u = example.input.encrypted.unprotected;
51 | const plaintext = Buffer.from(example.input.plaintext);
52 |
53 | const recipient = {
54 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
55 | u: example.input.encrypted.recipients[0].unprotected
56 | };
57 |
58 | const options = {
59 | randomSource: randomSource
60 | };
61 | const header = { p: p, u: u };
62 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
63 | t.true(Buffer.isBuffer(buf));
64 | t.true(buf.length > 0);
65 | const actual = cbor.decodeFirstSync(buf);
66 | const expected = cbor.decodeFirstSync(example.output.cbor);
67 | t.true(deepEqual(actual, expected));
68 | });
69 |
70 | test('create aes-ccm-enc-03', async t => {
71 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-03.json');
72 | const p = example.input.encrypted.protected;
73 | const u = example.input.encrypted.unprotected;
74 | const plaintext = Buffer.from(example.input.plaintext);
75 |
76 | const recipient = {
77 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
78 | u: example.input.encrypted.recipients[0].unprotected
79 | };
80 |
81 | const options = {
82 | randomSource: randomSource
83 | };
84 | const header = { p: p, u: u };
85 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
86 |
87 | t.true(Buffer.isBuffer(buf));
88 | t.true(buf.length > 0);
89 | const actual = cbor.decodeFirstSync(buf);
90 | const expected = cbor.decodeFirstSync(example.output.cbor);
91 | t.true(deepEqual(actual, expected));
92 | });
93 |
94 | test('create aes-ccm-enc-04', async t => {
95 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-04.json');
96 | const p = example.input.encrypted.protected;
97 | const u = example.input.encrypted.unprotected;
98 | const plaintext = Buffer.from(example.input.plaintext);
99 |
100 | const recipient = {
101 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
102 | u: example.input.encrypted.recipients[0].unprotected
103 | };
104 |
105 | const options = {
106 | randomSource: randomSource
107 | };
108 | const header = { p: p, u: u };
109 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
110 |
111 | t.true(Buffer.isBuffer(buf));
112 | t.true(buf.length > 0);
113 | const actual = cbor.decodeFirstSync(buf);
114 | const expected = cbor.decodeFirstSync(example.output.cbor);
115 | t.true(deepEqual(actual, expected));
116 | });
117 |
118 | test('create aes-ccm-enc-05', async t => {
119 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-05.json');
120 | const p = example.input.encrypted.protected;
121 | const u = example.input.encrypted.unprotected;
122 | const plaintext = Buffer.from(example.input.plaintext);
123 |
124 | const recipient = {
125 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
126 | u: example.input.encrypted.recipients[0].unprotected
127 | };
128 |
129 | const options = {
130 | randomSource: randomSource
131 | };
132 | const header = { p: p, u: u };
133 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
134 |
135 | t.true(Buffer.isBuffer(buf));
136 | t.true(buf.length > 0);
137 | const actual = cbor.decodeFirstSync(buf);
138 | const expected = cbor.decodeFirstSync(example.output.cbor);
139 | t.true(deepEqual(actual, expected));
140 | });
141 |
142 | test('create aes-ccm-enc-06', async t => {
143 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-06.json');
144 | const p = example.input.encrypted.protected;
145 | const u = example.input.encrypted.unprotected;
146 | const plaintext = Buffer.from(example.input.plaintext);
147 |
148 | const recipient = {
149 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
150 | u: example.input.encrypted.recipients[0].unprotected
151 | };
152 |
153 | const options = {
154 | randomSource: randomSource
155 | };
156 | const header = { p: p, u: u };
157 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
158 |
159 | t.true(Buffer.isBuffer(buf));
160 | t.true(buf.length > 0);
161 | const actual = cbor.decodeFirstSync(buf);
162 | const expected = cbor.decodeFirstSync(example.output.cbor);
163 | t.true(deepEqual(actual, expected));
164 | });
165 |
166 | test('create aes-ccm-enc-07', async t => {
167 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-07.json');
168 | const p = example.input.encrypted.protected;
169 | const u = example.input.encrypted.unprotected;
170 | const plaintext = Buffer.from(example.input.plaintext);
171 |
172 | const recipient = {
173 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
174 | u: example.input.encrypted.recipients[0].unprotected
175 | };
176 |
177 | const options = {
178 | randomSource: randomSource
179 | };
180 | const header = { p: p, u: u };
181 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
182 |
183 | t.true(Buffer.isBuffer(buf));
184 | t.true(buf.length > 0);
185 | const actual = cbor.decodeFirstSync(buf);
186 | const expected = cbor.decodeFirstSync(example.output.cbor);
187 | t.true(deepEqual(actual, expected));
188 | });
189 |
190 | test('create aes-ccm-enc-08', async t => {
191 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-08.json');
192 | const p = example.input.encrypted.protected;
193 | const u = example.input.encrypted.unprotected;
194 | const plaintext = Buffer.from(example.input.plaintext);
195 |
196 | const recipient = {
197 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
198 | u: example.input.encrypted.recipients[0].unprotected
199 | };
200 |
201 | const options = {
202 | randomSource: randomSource
203 | };
204 | const header = { p: p, u: u };
205 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
206 |
207 | t.true(Buffer.isBuffer(buf));
208 | t.true(buf.length > 0);
209 | const actual = cbor.decodeFirstSync(buf);
210 | const expected = cbor.decodeFirstSync(example.output.cbor);
211 | t.true(deepEqual(actual, expected));
212 | });
213 |
214 | test('decrypt aes-ccm-enc-01', async t => {
215 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-01.json');
216 | const plaintext = example.input.plaintext;
217 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
218 | const data = example.output.cbor;
219 | const buf = await cose.encrypt.read(data, key);
220 | t.true(Buffer.isBuffer(buf));
221 | t.true(buf.length > 0);
222 | t.is(buf.toString('utf8'), plaintext);
223 | });
224 |
225 | test('decrypt aes-ccm-enc-02', async t => {
226 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-02.json');
227 | const plaintext = example.input.plaintext;
228 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
229 | const data = example.output.cbor;
230 | const buf = await cose.encrypt.read(data, key);
231 | t.true(Buffer.isBuffer(buf));
232 | t.true(buf.length > 0);
233 | t.is(buf.toString('utf8'), plaintext);
234 | });
235 |
236 | test('decrypt aes-ccm-enc-03', async t => {
237 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-03.json');
238 | const plaintext = example.input.plaintext;
239 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
240 | const data = example.output.cbor;
241 | const buf = await cose.encrypt.read(data, key);
242 | t.true(Buffer.isBuffer(buf));
243 | t.true(buf.length > 0);
244 | t.is(buf.toString('utf8'), plaintext);
245 | });
246 |
247 | test('decrypt aes-ccm-enc-04', async t => {
248 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-04.json');
249 | const plaintext = example.input.plaintext;
250 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
251 | const data = example.output.cbor;
252 | const buf = await cose.encrypt.read(data, key);
253 | t.true(Buffer.isBuffer(buf));
254 | t.true(buf.length > 0);
255 | t.is(buf.toString('utf8'), plaintext);
256 | });
257 |
258 | test('decrypt aes-ccm-enc-05', async t => {
259 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-05.json');
260 | const plaintext = example.input.plaintext;
261 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
262 | const data = example.output.cbor;
263 | const buf = await cose.encrypt.read(data, key);
264 | t.true(Buffer.isBuffer(buf));
265 | t.true(buf.length > 0);
266 | t.is(buf.toString('utf8'), plaintext);
267 | });
268 |
269 | test('decrypt aes-ccm-enc-06', async t => {
270 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-06.json');
271 | const plaintext = example.input.plaintext;
272 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
273 | const data = example.output.cbor;
274 | const buf = await cose.encrypt.read(data, key);
275 | t.true(Buffer.isBuffer(buf));
276 | t.true(buf.length > 0);
277 | t.is(buf.toString('utf8'), plaintext);
278 | });
279 |
280 | test('decrypt aes-ccm-enc-07', async t => {
281 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-07.json');
282 | const plaintext = example.input.plaintext;
283 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
284 | const data = example.output.cbor;
285 | const buf = await cose.encrypt.read(data, key);
286 | t.true(Buffer.isBuffer(buf));
287 | t.true(buf.length > 0);
288 | t.is(buf.toString('utf8'), plaintext);
289 | });
290 |
291 | test('decrypt aes-ccm-enc-08', async t => {
292 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-enc-08.json');
293 | const plaintext = example.input.plaintext;
294 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
295 | const data = example.output.cbor;
296 | const buf = await cose.encrypt.read(data, key);
297 | t.true(Buffer.isBuffer(buf));
298 | t.true(buf.length > 0);
299 | t.is(buf.toString('utf8'), plaintext);
300 | });
301 |
302 | test('create aes-ccm-01', async t => {
303 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-01.json');
304 | const p = example.input.enveloped.protected;
305 | const u = example.input.enveloped.unprotected;
306 | const plaintext = Buffer.from(example.input.plaintext);
307 |
308 | const recipient = [{
309 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
310 | u: example.input.enveloped.recipients[0].unprotected
311 | }];
312 |
313 | const options = {
314 | randomSource: randomSource
315 | };
316 | const header = { p: p, u: u };
317 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
318 |
319 | t.true(Buffer.isBuffer(buf));
320 | t.true(buf.length > 0);
321 | t.is(buf.toString('hex'), example.output.cbor.toLowerCase());
322 | });
323 |
324 | test('create aes-ccm-02', async t => {
325 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-02.json');
326 | const p = example.input.enveloped.protected;
327 | const u = example.input.enveloped.unprotected;
328 | const plaintext = Buffer.from(example.input.plaintext);
329 |
330 | const recipient = [{
331 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
332 | u: example.input.enveloped.recipients[0].unprotected
333 | }];
334 |
335 | const options = {
336 | randomSource: randomSource
337 | };
338 | const header = { p: p, u: u };
339 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
340 |
341 | t.true(Buffer.isBuffer(buf));
342 | t.true(buf.length > 0);
343 | const actual = cbor.decodeFirstSync(buf);
344 | const expected = cbor.decodeFirstSync(example.output.cbor);
345 | t.true(deepEqual(actual, expected));
346 | });
347 |
348 | test('create aes-ccm-03', async t => {
349 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-03.json');
350 | const p = example.input.enveloped.protected;
351 | const u = example.input.enveloped.unprotected;
352 | const plaintext = Buffer.from(example.input.plaintext);
353 |
354 | const recipient = [{
355 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
356 | u: example.input.enveloped.recipients[0].unprotected
357 | }];
358 |
359 | const options = {
360 | randomSource: randomSource
361 | };
362 | const header = { p: p, u: u };
363 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
364 |
365 | t.true(Buffer.isBuffer(buf));
366 | t.true(buf.length > 0);
367 | const actual = cbor.decodeFirstSync(buf);
368 | const expected = cbor.decodeFirstSync(example.output.cbor);
369 | t.true(deepEqual(actual, expected));
370 | });
371 |
372 | test('create aes-ccm-04', async t => {
373 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-04.json');
374 | const p = example.input.enveloped.protected;
375 | const u = example.input.enveloped.unprotected;
376 | const plaintext = Buffer.from(example.input.plaintext);
377 |
378 | const recipient = [{
379 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
380 | u: example.input.enveloped.recipients[0].unprotected
381 | }];
382 |
383 | const options = {
384 | randomSource: randomSource
385 | };
386 | const header = { p: p, u: u };
387 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
388 |
389 | t.true(Buffer.isBuffer(buf));
390 | t.true(buf.length > 0);
391 | const actual = cbor.decodeFirstSync(buf);
392 | const expected = cbor.decodeFirstSync(example.output.cbor);
393 | t.true(deepEqual(actual, expected));
394 | });
395 |
396 | test('create aes-ccm-05', async t => {
397 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-05.json');
398 | const p = example.input.enveloped.protected;
399 | const u = example.input.enveloped.unprotected;
400 | const plaintext = Buffer.from(example.input.plaintext);
401 |
402 | const recipient = [{
403 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
404 | u: example.input.enveloped.recipients[0].unprotected
405 | }];
406 |
407 | const options = {
408 | randomSource: randomSource
409 | };
410 | const header = { p: p, u: u };
411 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
412 |
413 | t.true(Buffer.isBuffer(buf));
414 | t.true(buf.length > 0);
415 | const actual = cbor.decodeFirstSync(buf);
416 | const expected = cbor.decodeFirstSync(example.output.cbor);
417 | t.true(deepEqual(actual, expected));
418 | });
419 |
420 | test('create aes-ccm-06', async t => {
421 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-06.json');
422 | const p = example.input.enveloped.protected;
423 | const u = example.input.enveloped.unprotected;
424 | const plaintext = Buffer.from(example.input.plaintext);
425 |
426 | const recipient = [{
427 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
428 | u: example.input.enveloped.recipients[0].unprotected
429 | }];
430 |
431 | const options = {
432 | randomSource: randomSource
433 | };
434 | const header = { p: p, u: u };
435 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
436 |
437 | t.true(Buffer.isBuffer(buf));
438 | t.true(buf.length > 0);
439 | const actual = cbor.decodeFirstSync(buf);
440 | const expected = cbor.decodeFirstSync(example.output.cbor);
441 | t.true(deepEqual(actual, expected));
442 | });
443 |
444 | test('create aes-ccm-07', async t => {
445 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-07.json');
446 | const p = example.input.enveloped.protected;
447 | const u = example.input.enveloped.unprotected;
448 | const plaintext = Buffer.from(example.input.plaintext);
449 |
450 | const recipient = [{
451 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
452 | u: example.input.enveloped.recipients[0].unprotected
453 | }];
454 |
455 | const options = {
456 | randomSource: randomSource
457 | };
458 | const header = { p: p, u: u };
459 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
460 |
461 | t.true(Buffer.isBuffer(buf));
462 | t.true(buf.length > 0);
463 | const actual = cbor.decodeFirstSync(buf);
464 | const expected = cbor.decodeFirstSync(example.output.cbor);
465 | t.true(deepEqual(actual, expected));
466 | });
467 |
468 | test('create aes-ccm-08', async t => {
469 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-08.json');
470 | const p = example.input.enveloped.protected;
471 | const u = example.input.enveloped.unprotected;
472 | const plaintext = Buffer.from(example.input.plaintext);
473 |
474 | const recipient = [{
475 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
476 | u: example.input.enveloped.recipients[0].unprotected
477 | }];
478 |
479 | const options = {
480 | randomSource: randomSource
481 | };
482 | const header = { p: p, u: u };
483 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
484 |
485 | t.true(Buffer.isBuffer(buf));
486 | t.true(buf.length > 0);
487 | const actual = cbor.decodeFirstSync(buf);
488 | const expected = cbor.decodeFirstSync(example.output.cbor);
489 | t.true(deepEqual(actual, expected));
490 | });
491 |
492 | test('decrypt aes-ccm-01', async t => {
493 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-01.json');
494 | const plaintext = example.input.plaintext;
495 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
496 | const data = example.output.cbor;
497 | const buf = await cose.encrypt.read(data, key);
498 | t.true(Buffer.isBuffer(buf));
499 | t.true(buf.length > 0);
500 | t.is(buf.toString('utf8'), plaintext);
501 | });
502 |
503 | test('decrypt aes-ccm-02', async t => {
504 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-02.json');
505 | const plaintext = example.input.plaintext;
506 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
507 | const data = example.output.cbor;
508 | const buf = await cose.encrypt.read(data, key);
509 | t.true(Buffer.isBuffer(buf));
510 | t.true(buf.length > 0);
511 | t.is(buf.toString('utf8'), plaintext);
512 | });
513 |
514 | test('decrypt aes-ccm-03', async t => {
515 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-03.json');
516 | const plaintext = example.input.plaintext;
517 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
518 | const data = example.output.cbor;
519 | const buf = await cose.encrypt.read(data, key);
520 | t.true(Buffer.isBuffer(buf));
521 | t.true(buf.length > 0);
522 | t.is(buf.toString('utf8'), plaintext);
523 | });
524 |
525 | test('decrypt aes-ccm-04', async t => {
526 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-04.json');
527 | const plaintext = example.input.plaintext;
528 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
529 | const data = example.output.cbor;
530 | const buf = await cose.encrypt.read(data, key);
531 | t.true(Buffer.isBuffer(buf));
532 | t.true(buf.length > 0);
533 | t.is(buf.toString('utf8'), plaintext);
534 | });
535 |
536 | test('decrypt aes-ccm-05', async t => {
537 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-05.json');
538 | const plaintext = example.input.plaintext;
539 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
540 | const data = example.output.cbor;
541 | const buf = await cose.encrypt.read(data, key);
542 | t.true(Buffer.isBuffer(buf));
543 | t.true(buf.length > 0);
544 | t.is(buf.toString('utf8'), plaintext);
545 | });
546 |
547 | test('decrypt aes-ccm-06', async t => {
548 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-06.json');
549 | const plaintext = example.input.plaintext;
550 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
551 | const data = example.output.cbor;
552 | const buf = await cose.encrypt.read(data, key);
553 | t.true(Buffer.isBuffer(buf));
554 | t.true(buf.length > 0);
555 | t.is(buf.toString('utf8'), plaintext);
556 | });
557 |
558 | test('decrypt aes-ccm-07', async t => {
559 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-07.json');
560 | const plaintext = example.input.plaintext;
561 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
562 | const data = example.output.cbor;
563 | const buf = await cose.encrypt.read(data, key);
564 | t.true(Buffer.isBuffer(buf));
565 | t.true(buf.length > 0);
566 | t.is(buf.toString('utf8'), plaintext);
567 | });
568 |
569 | test('decrypt aes-ccm-08', async t => {
570 | const example = jsonfile.readFileSync('test/Examples/aes-ccm-examples/aes-ccm-08.json');
571 | const plaintext = example.input.plaintext;
572 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
573 | const data = example.output.cbor;
574 | const buf = await cose.encrypt.read(data, key);
575 | t.true(Buffer.isBuffer(buf));
576 | t.true(buf.length > 0);
577 | t.is(buf.toString('utf8'), plaintext);
578 | });
579 |
--------------------------------------------------------------------------------
/test/aes-gcm-examples.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | function randomSource (bytes) {
13 | if (bytes === 12) {
14 | return Buffer.from('02D1F7E6F26C43D4868D87CE', 'hex');
15 | } else {
16 | return Buffer.from('61A7', 'hex');
17 | }
18 | }
19 |
20 | test('create aes-gcm-01', async t => {
21 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-01.json');
22 | const p = example.input.enveloped.protected;
23 | const u = example.input.enveloped.unprotected;
24 | const plaintext = Buffer.from(example.input.plaintext);
25 |
26 | const recipients = [{
27 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
28 | u: example.input.enveloped.recipients[0].unprotected
29 | }];
30 |
31 | const options = {
32 | randomSource: randomSource
33 | };
34 | const header = { p: p, u: u };
35 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
36 | t.true(Buffer.isBuffer(buf));
37 | t.true(buf.length > 0);
38 | const actual = cbor.decodeFirstSync(buf);
39 | const expected = cbor.decodeFirstSync(example.output.cbor);
40 | t.true(deepEqual(actual, expected));
41 | });
42 |
43 | test('create aes-gcm-02', async t => {
44 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-02.json');
45 | const p = example.input.enveloped.protected;
46 | const u = example.input.enveloped.unprotected;
47 | const plaintext = Buffer.from(example.input.plaintext);
48 |
49 | const recipients = [{
50 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
51 | u: example.input.enveloped.recipients[0].unprotected
52 | }];
53 |
54 | const options = {
55 | randomSource: randomSource
56 | };
57 | const header = { p: p, u: u };
58 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
59 | t.true(Buffer.isBuffer(buf));
60 | t.true(buf.length > 0);
61 | const actual = cbor.decodeFirstSync(buf);
62 | const expected = cbor.decodeFirstSync(example.output.cbor);
63 | t.true(deepEqual(actual, expected));
64 | });
65 |
66 | test('create aes-gcm-03', async t => {
67 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-03.json');
68 | const p = example.input.enveloped.protected;
69 | const u = example.input.enveloped.unprotected;
70 | const plaintext = Buffer.from(example.input.plaintext);
71 |
72 | const recipients = [{
73 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
74 | u: example.input.enveloped.recipients[0].unprotected
75 | }];
76 |
77 | const options = {
78 | randomSource: randomSource
79 | };
80 | const header = { p: p, u: u };
81 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
82 | t.true(Buffer.isBuffer(buf));
83 | t.true(buf.length > 0);
84 | const actual = cbor.decodeFirstSync(buf);
85 | const expected = cbor.decodeFirstSync(example.output.cbor);
86 | t.true(deepEqual(actual, expected));
87 | });
88 |
89 | // aes-gcm-04 is an error example and cannot be recreated
90 |
91 | test('create aes-gcm-05', async t => {
92 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-05.json');
93 | const p = example.input.enveloped.protected;
94 | const u = example.input.enveloped.unprotected;
95 | const plaintext = Buffer.from(example.input.plaintext);
96 |
97 | const recipients = [{
98 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
99 | u: example.input.enveloped.recipients[0].unprotected
100 | }];
101 |
102 | example.input.enveloped.unprotected.Partial_IV = Buffer.from(example.input.enveloped.unprotected.partialIV_hex, 'hex');
103 | delete example.input.enveloped.unprotected.partialIV_hex;
104 |
105 | const contextIv = Buffer.from(example.input.enveloped.unsent.IV_hex, 'hex');
106 | contextIv[10] = 0;
107 | contextIv[11] = 0;
108 |
109 | const options = {
110 | randomSource: randomSource,
111 | contextIv: contextIv
112 | };
113 | const header = { p: p, u: u };
114 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
115 | t.true(Buffer.isBuffer(buf));
116 | t.true(buf.length > 0);
117 | const actual = cbor.decodeFirstSync(buf);
118 | const expected = cbor.decodeFirstSync(example.output.cbor);
119 | t.true(deepEqual(actual, expected));
120 | });
121 |
122 | test('decrypt aes-gcm-01', async t => {
123 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-01.json');
124 | const plaintext = example.input.plaintext;
125 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
126 | const data = example.output.cbor;
127 | const buf = await cose.encrypt.read(data, key);
128 | t.true(Buffer.isBuffer(buf));
129 | t.true(buf.length > 0);
130 | t.is(buf.toString('utf8'), plaintext);
131 | });
132 |
133 | test('decrypt aes-gcm-02', async t => {
134 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-02.json');
135 | const plaintext = example.input.plaintext;
136 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
137 | const data = example.output.cbor;
138 | const buf = await cose.encrypt.read(data, key);
139 | t.true(Buffer.isBuffer(buf));
140 | t.true(buf.length > 0);
141 | t.is(buf.toString('utf8'), plaintext);
142 | });
143 |
144 | test('decrypt aes-gcm-03', async t => {
145 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-03.json');
146 | const plaintext = example.input.plaintext;
147 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
148 | const data = example.output.cbor;
149 | const buf = await cose.encrypt.read(data, key);
150 | t.true(Buffer.isBuffer(buf));
151 | t.true(buf.length > 0);
152 | t.is(buf.toString('utf8'), plaintext);
153 | });
154 |
155 | test('decrypt aes-gcm-04', async t => {
156 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-04.json');
157 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
158 | const data = example.output.cbor;
159 | try {
160 | await cose.encrypt.read(data, key);
161 | t.fail('Unsupported state or unable to authenticate data');
162 | } catch (error) {
163 | t.is(error.message, 'Unsupported state or unable to authenticate data');
164 | }
165 | });
166 |
167 | test('decrypt aes-gcm-05', async t => {
168 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-05.json');
169 | const plaintext = example.input.plaintext;
170 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
171 | const data = example.output.cbor;
172 | const contextIv = Buffer.from(example.input.enveloped.unsent.IV_hex, 'hex');
173 | contextIv[10] = 0;
174 | contextIv[11] = 0;
175 | const options = { contextIv: contextIv };
176 | const buf = await cose.encrypt.read(data, key, options);
177 | t.true(Buffer.isBuffer(buf));
178 | t.true(buf.length > 0);
179 | t.is(buf.toString('utf8'), plaintext);
180 | });
181 |
182 | test('create aes-gcm-enc-01', async t => {
183 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-01.json');
184 | const p = example.input.encrypted.protected;
185 | const u = example.input.encrypted.unprotected;
186 | const plaintext = Buffer.from(example.input.plaintext);
187 |
188 | const recipient = {
189 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
190 | u: example.input.encrypted.recipients[0].unprotected
191 | };
192 |
193 | const options = {
194 | randomSource: randomSource
195 | };
196 | const header = { p: p, u: u };
197 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
198 | t.true(Buffer.isBuffer(buf));
199 | t.true(buf.length > 0);
200 | const actual = cbor.decodeFirstSync(buf);
201 | const expected = cbor.decodeFirstSync(example.output.cbor);
202 | t.true(deepEqual(actual, expected));
203 | });
204 |
205 | test('create aes-gcm-enc-02', async t => {
206 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-02.json');
207 | const p = example.input.encrypted.protected;
208 | const u = example.input.encrypted.unprotected;
209 | const plaintext = Buffer.from(example.input.plaintext);
210 |
211 | const recipient = {
212 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
213 | u: example.input.encrypted.recipients[0].unprotected
214 | };
215 |
216 | const options = {
217 | randomSource: randomSource
218 | };
219 | const header = { p: p, u: u };
220 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
221 | t.true(Buffer.isBuffer(buf));
222 | t.true(buf.length > 0);
223 | const actual = cbor.decodeFirstSync(buf);
224 | const expected = cbor.decodeFirstSync(example.output.cbor);
225 | t.true(deepEqual(actual, expected));
226 | });
227 |
228 | test('create aes-gcm-enc-03', async t => {
229 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-03.json');
230 | const p = example.input.encrypted.protected;
231 | const u = example.input.encrypted.unprotected;
232 | const plaintext = Buffer.from(example.input.plaintext);
233 |
234 | const recipient = {
235 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
236 | u: example.input.encrypted.recipients[0].unprotected
237 | };
238 |
239 | const options = {
240 | randomSource: randomSource
241 | };
242 | const header = { p: p, u: u };
243 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
244 | t.true(Buffer.isBuffer(buf));
245 | t.true(buf.length > 0);
246 | const actual = cbor.decodeFirstSync(buf);
247 | const expected = cbor.decodeFirstSync(example.output.cbor);
248 | t.true(deepEqual(actual, expected));
249 | });
250 |
251 | // create aes-gcm-enc-04 is an error example and cannot be recreated
252 |
253 | test('decrypt aes-gcm-enc-01', async t => {
254 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-01.json');
255 | const plaintext = example.input.plaintext;
256 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
257 | const data = example.output.cbor;
258 | const buf = await cose.encrypt.read(data, key);
259 | t.true(Buffer.isBuffer(buf));
260 | t.true(buf.length > 0);
261 | t.is(buf.toString('utf8'), plaintext);
262 | });
263 |
264 | test('decrypt aes-gcm-enc-02', async t => {
265 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-02.json');
266 | const plaintext = example.input.plaintext;
267 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
268 | const data = example.output.cbor;
269 | const buf = await cose.encrypt.read(data, key);
270 | t.true(Buffer.isBuffer(buf));
271 | t.true(buf.length > 0);
272 | t.is(buf.toString('utf8'), plaintext);
273 | });
274 |
275 | test('decrypt aes-gcm-enc-03', async t => {
276 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-03.json');
277 | const plaintext = example.input.plaintext;
278 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
279 | const data = example.output.cbor;
280 | const buf = await cose.encrypt.read(data, key);
281 | t.true(Buffer.isBuffer(buf));
282 | t.true(buf.length > 0);
283 | t.is(buf.toString('utf8'), plaintext);
284 | });
285 |
286 | test('decrypt aes-gcm-enc-04', async t => {
287 | const example = jsonfile.readFileSync('test/Examples/aes-gcm-examples/aes-gcm-enc-04.json');
288 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
289 | const data = example.output.cbor;
290 | try {
291 | await cose.encrypt.read(data, key);
292 | t.fail('Unsupported state or unable to authenticate data');
293 | } catch (error) {
294 | t.is(error.message, 'Unsupported state or unable to authenticate data');
295 | }
296 | });
297 |
--------------------------------------------------------------------------------
/test/cbc-mac-examples.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | test('create cbc-mac-01', async t => {
13 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-01.json');
14 | const p = example.input.mac.protected;
15 | const u = example.input.mac.recipients[0].unprotected;
16 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
17 | const plaintext = Buffer.from(example.input.plaintext);
18 |
19 | const header = { p: p };
20 | const recipents = [{ key: key, u: u }];
21 | const buf = await cose.mac.create(header, plaintext, recipents);
22 |
23 | t.true(Buffer.isBuffer(buf));
24 | t.true(buf.length > 0);
25 | const actual = cbor.decodeFirstSync(buf);
26 | const expected = cbor.decodeFirstSync(example.output.cbor);
27 | t.true(deepEqual(actual, expected));
28 | });
29 |
30 | test('create cbc-mac-02', async t => {
31 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-02.json');
32 | const p = example.input.mac.protected;
33 | const u = example.input.mac.recipients[0].unprotected;
34 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
35 | const plaintext = Buffer.from(example.input.plaintext);
36 |
37 | const header = { p: p };
38 | const recipents = [{ key: key, u: u }];
39 | const buf = await cose.mac.create(header, plaintext, recipents);
40 |
41 | t.true(Buffer.isBuffer(buf));
42 | t.true(buf.length > 0);
43 | const actual = cbor.decodeFirstSync(buf);
44 | const expected = cbor.decodeFirstSync(example.output.cbor);
45 |
46 | t.true(deepEqual(actual, expected));
47 | });
48 |
49 | test('create cbc-mac-03', async t => {
50 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-03.json');
51 | const p = example.input.mac.protected;
52 | const u = example.input.mac.recipients[0].unprotected;
53 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
54 | const plaintext = Buffer.from(example.input.plaintext);
55 |
56 | const header = { p: p };
57 | const recipents = [{ key: key, u: u }];
58 | const buf = await cose.mac.create(header, plaintext, recipents);
59 |
60 | t.true(Buffer.isBuffer(buf));
61 | t.true(buf.length > 0);
62 | const actual = cbor.decodeFirstSync(buf);
63 | const expected = cbor.decodeFirstSync(example.output.cbor);
64 |
65 | t.true(deepEqual(actual, expected));
66 | });
67 |
68 | test('create cbc-mac-04', async t => {
69 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-04.json');
70 | const p = example.input.mac.protected;
71 | const u = example.input.mac.recipients[0].unprotected;
72 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
73 | const plaintext = Buffer.from(example.input.plaintext);
74 |
75 | const header = { p: p };
76 | const recipents = [{ key: key, u: u }];
77 | const buf = await cose.mac.create(header, plaintext, recipents);
78 |
79 | t.true(Buffer.isBuffer(buf));
80 | t.true(buf.length > 0);
81 | const actual = cbor.decodeFirstSync(buf);
82 | const expected = cbor.decodeFirstSync(example.output.cbor);
83 |
84 | t.true(deepEqual(actual, expected));
85 | });
86 |
87 | test('create cbc-mac-enc-01', async t => {
88 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-01.json');
89 | const p = example.input.mac0.protected;
90 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
91 | const plaintext = Buffer.from(example.input.plaintext);
92 |
93 | const header = { p: p };
94 | const recipents = { key: key };
95 | const buf = await cose.mac.create(header, plaintext, recipents);
96 |
97 | t.true(Buffer.isBuffer(buf));
98 | t.true(buf.length > 0);
99 |
100 | const actual = cbor.decodeFirstSync(buf);
101 | const expected = cbor.decodeFirstSync(example.output.cbor);
102 |
103 | t.true(deepEqual(actual, expected));
104 | });
105 |
106 | test('create cbc-mac-enc-02', async t => {
107 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-02.json');
108 | const p = example.input.mac0.protected;
109 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
110 | const plaintext = Buffer.from(example.input.plaintext);
111 |
112 | const header = { p: p };
113 | const recipent = { key: key };
114 | const buf = await cose.mac.create(header, plaintext, recipent);
115 |
116 | t.true(Buffer.isBuffer(buf));
117 | t.true(buf.length > 0);
118 |
119 | const actual = cbor.decodeFirstSync(buf);
120 | const expected = cbor.decodeFirstSync(example.output.cbor);
121 |
122 | t.true(deepEqual(actual, expected));
123 | });
124 |
125 | test('create cbc-mac-enc-03', async t => {
126 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-03.json');
127 | const p = example.input.mac0.protected;
128 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
129 | const plaintext = Buffer.from(example.input.plaintext);
130 |
131 | const header = { p: p };
132 | const recipent = { key: key };
133 | const buf = await cose.mac.create(header, plaintext, recipent);
134 |
135 | t.true(Buffer.isBuffer(buf));
136 | t.true(buf.length > 0);
137 |
138 | const actual = cbor.decodeFirstSync(buf);
139 | const expected = cbor.decodeFirstSync(example.output.cbor);
140 |
141 | t.true(deepEqual(actual, expected));
142 | });
143 |
144 | test('create cbc-mac-enc-04', async t => {
145 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-04.json');
146 | const p = example.input.mac0.protected;
147 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
148 | const plaintext = Buffer.from(example.input.plaintext);
149 |
150 | const header = { p: p };
151 | const recipent = { key: key };
152 | const buf = await cose.mac.create(header, plaintext, recipent);
153 |
154 | t.true(Buffer.isBuffer(buf));
155 | t.true(buf.length > 0);
156 |
157 | const actual = cbor.decodeFirstSync(buf);
158 | const expected = cbor.decodeFirstSync(example.output.cbor);
159 |
160 | t.true(deepEqual(actual, expected));
161 | });
162 |
163 | test('verify cbc-mac-01', async t => {
164 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-01.json');
165 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
166 |
167 | const data = example.output.cbor;
168 | const buf = await cose.mac.read(data, key);
169 | t.true(Buffer.isBuffer(buf));
170 | t.true(buf.length > 0);
171 | t.is(buf.toString('utf8'), example.input.plaintext);
172 | });
173 |
174 | test('verify cbc-mac-02', async t => {
175 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-02.json');
176 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
177 |
178 | const data = example.output.cbor;
179 | const buf = await cose.mac.read(data, key);
180 | t.true(Buffer.isBuffer(buf));
181 | t.true(buf.length > 0);
182 | t.is(buf.toString('utf8'), example.input.plaintext);
183 | });
184 |
185 | test('verify cbc-mac-03', async t => {
186 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-03.json');
187 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
188 |
189 | const data = example.output.cbor;
190 | const buf = await cose.mac.read(data, key);
191 | t.true(Buffer.isBuffer(buf));
192 | t.true(buf.length > 0);
193 | t.is(buf.toString('utf8'), example.input.plaintext);
194 | });
195 |
196 | test('verify cbc-mac-04', async t => {
197 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-04.json');
198 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
199 |
200 | const data = example.output.cbor;
201 | const buf = await cose.mac.read(data, key);
202 | t.true(Buffer.isBuffer(buf));
203 | t.true(buf.length > 0);
204 | t.is(buf.toString('utf8'), example.input.plaintext);
205 | });
206 |
207 | test('verify cbc-mac-enc-01', async t => {
208 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-02.json');
209 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
210 |
211 | const data = example.output.cbor;
212 | const buf = await cose.mac.read(data, key);
213 | t.true(Buffer.isBuffer(buf));
214 | t.true(buf.length > 0);
215 | t.is(buf.toString('utf8'), example.input.plaintext);
216 | });
217 |
218 | test('verify cbc-mac-enc-02', async t => {
219 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-02.json');
220 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
221 |
222 | const data = example.output.cbor;
223 | const buf = await cose.mac.read(data, key);
224 | t.true(Buffer.isBuffer(buf));
225 | t.true(buf.length > 0);
226 | t.is(buf.toString('utf8'), example.input.plaintext);
227 | });
228 |
229 | test('verify cbc-mac-enc-03', async t => {
230 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-03.json');
231 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
232 |
233 | const data = example.output.cbor;
234 | const buf = await cose.mac.read(data, key);
235 | t.true(Buffer.isBuffer(buf));
236 | t.true(buf.length > 0);
237 | t.is(buf.toString('utf8'), example.input.plaintext);
238 | });
239 |
240 | test('verify cbc-mac-enc-04', async t => {
241 | const example = jsonfile.readFileSync('test/Examples/cbc-mac-examples/cbc-mac-enc-04.json');
242 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
243 |
244 | const data = example.output.cbor;
245 | const buf = await cose.mac.read(data, key);
246 | t.true(Buffer.isBuffer(buf));
247 | t.true(buf.length > 0);
248 | t.is(buf.toString('utf8'), example.input.plaintext);
249 | });
250 |
--------------------------------------------------------------------------------
/test/common.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 | const test = require('ava');
5 | const cose = require('../');
6 |
7 | test('translate headers', (t) => {
8 | let h = cose.common.TranslateHeaders({});
9 | t.is(h.constructor.name, 'Map');
10 | h = cose.common.TranslateHeaders({ alg: 'SHA-256', crit: 2 });
11 | t.is(h.constructor.name, 'Map');
12 | t.is(h.size, 2);
13 | t.is(h.get(cose.common.HeaderParameters.alg), 5);
14 | t.is(h.get(cose.common.HeaderParameters.crit), 2);
15 | });
16 |
17 | /*
18 | test('translate headers', (t) => {
19 | const result = cose.common.TranslateHeaders({
20 | 'ephemeral_key': Buffer.from('beef', 'hex'),
21 | 'partyUNonce': Buffer.from('dead', 'hex'),
22 | 'kid': Buffer.from('0b0b', 'hex'),
23 | });
24 | console.log(result);
25 | });
26 | */
27 |
28 | test('invalid', (t) => {
29 | t.throws(() => {
30 | cose.common.TranslateHeaders({ 'fizzle stomp': 12 });
31 | });
32 | });
33 |
34 | test('xor1', (t) => {
35 | const a = Buffer.from('00ff0f', 'hex');
36 | const b = Buffer.from('f0f0', 'hex');
37 | const actual = cose.common.xor(a, b);
38 | const expected = '000fff';
39 | t.is(actual.toString('hex'), expected);
40 | });
41 |
42 | test('xor2', (t) => {
43 | const a = Buffer.from('f0f0', 'hex');
44 | const b = Buffer.from('00ff0f', 'hex');
45 | const actual = cose.common.xor(a, b);
46 | const expected = '000fff';
47 | t.is(actual.toString('hex'), expected);
48 | });
49 |
50 | test('xor3', (t) => {
51 | const a = Buffer.from('f0f0f0', 'hex');
52 | const b = Buffer.from('00ff0f', 'hex');
53 | const actual = cose.common.xor(a, b);
54 | const expected = 'f00fff';
55 | t.is(actual.toString('hex'), expected);
56 | });
57 |
--------------------------------------------------------------------------------
/test/ecdh-direct-examples.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | function randomSource (bytes) {
13 | if (bytes === 12) {
14 | return Buffer.from('C9CF4DF2FE6C632BF7886413', 'hex');
15 | } else {
16 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3', 'hex');
17 | }
18 | }
19 |
20 | test('create p256-hkdf-256-01', async t => {
21 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p256-hkdf-256-01.json');
22 | const p = example.input.enveloped.protected;
23 | const u = example.input.enveloped.unprotected;
24 | const plaintext = Buffer.from(example.input.plaintext);
25 |
26 | const recipient = [{
27 | key: {
28 | kty: example.input.enveloped.recipients[0].key.kty,
29 | kid: example.input.enveloped.recipients[0].key.kid,
30 | crv: example.input.enveloped.recipients[0].key.crv,
31 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
32 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
33 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
34 | },
35 | p: example.input.enveloped.recipients[0].protected,
36 | u: example.input.enveloped.recipients[0].unprotected
37 | }];
38 |
39 | const options = {
40 | randomSource: randomSource
41 | };
42 |
43 | const header = { p: p, u: u };
44 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
45 | t.true(Buffer.isBuffer(buf));
46 | t.true(buf.length > 0);
47 | const actual = cbor.decodeFirstSync(buf);
48 | const expected = cbor.decodeFirstSync(example.output.cbor);
49 | t.true(deepEqual(actual, expected));
50 | });
51 |
52 | test('create p256-hkdf-256-02', async t => {
53 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p256-hkdf-256-02.json');
54 | const p = example.input.enveloped.protected;
55 | const u = example.input.enveloped.unprotected;
56 | const plaintext = Buffer.from(example.input.plaintext);
57 |
58 | const recipient = [{
59 | key: {
60 | kty: example.input.enveloped.recipients[0].key.kty,
61 | kid: example.input.enveloped.recipients[0].key.kid,
62 | crv: example.input.enveloped.recipients[0].key.crv,
63 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
64 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
65 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
66 | },
67 | p: example.input.enveloped.recipients[0].protected,
68 | u: example.input.enveloped.recipients[0].unprotected
69 | }];
70 |
71 | const options = {
72 | randomSource: randomSource
73 | };
74 |
75 | const header = { p: p, u: u };
76 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
77 | t.true(Buffer.isBuffer(buf));
78 | t.true(buf.length > 0);
79 | const actual = cbor.decodeFirstSync(buf);
80 | const expected = cbor.decodeFirstSync(example.output.cbor);
81 | t.true(deepEqual(actual, expected));
82 | });
83 |
84 | // create p256-hkdf-256-03
85 |
86 | test('create p256-hkdf-512-01', async t => {
87 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p256-hkdf-512-01.json');
88 | const p = example.input.enveloped.protected;
89 | const u = example.input.enveloped.unprotected;
90 | const plaintext = Buffer.from(example.input.plaintext);
91 |
92 | const recipient = [{
93 | key: {
94 | kty: example.input.enveloped.recipients[0].key.kty,
95 | kid: example.input.enveloped.recipients[0].key.kid,
96 | crv: example.input.enveloped.recipients[0].key.crv,
97 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
98 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
99 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
100 | },
101 | p: example.input.enveloped.recipients[0].protected,
102 | u: example.input.enveloped.recipients[0].unprotected
103 | }];
104 |
105 | const options = {
106 | randomSource: randomSource
107 | };
108 |
109 | const header = { p: p, u: u };
110 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
111 | t.true(Buffer.isBuffer(buf));
112 | t.true(buf.length > 0);
113 | const actual = cbor.decodeFirstSync(buf);
114 | const expected = cbor.decodeFirstSync(example.output.cbor);
115 | t.true(deepEqual(actual, expected));
116 | });
117 |
118 | test('create p256-hkdf-512-02', async t => {
119 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p256-hkdf-512-02.json');
120 | const p = example.input.enveloped.protected;
121 | const u = example.input.enveloped.unprotected;
122 | const plaintext = Buffer.from(example.input.plaintext);
123 |
124 | const recipient = [{
125 | key: {
126 | kty: example.input.enveloped.recipients[0].key.kty,
127 | kid: example.input.enveloped.recipients[0].key.kid,
128 | crv: example.input.enveloped.recipients[0].key.crv,
129 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
130 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
131 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
132 | },
133 | p: example.input.enveloped.recipients[0].protected,
134 | u: example.input.enveloped.recipients[0].unprotected
135 | }];
136 |
137 | const options = {
138 | randomSource: (bytes) => {
139 | if (bytes === 12) {
140 | return Buffer.from('C9CF4DF2FE6C632BF7886413', 'hex');
141 | } else {
142 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3', 'hex');
143 | }
144 | }
145 | };
146 |
147 | const header = { p: p, u: u };
148 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
149 | t.true(Buffer.isBuffer(buf));
150 | t.true(buf.length > 0);
151 | const actual = cbor.decodeFirstSync(buf);
152 | const expected = cbor.decodeFirstSync(example.output.cbor);
153 | t.true(deepEqual(actual, expected));
154 | });
155 |
156 | // create p256-hkdf-512-03
157 |
158 | test('create p256-ss-hkdf-256-01', async t => {
159 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p256-ss-hkdf-256-01.json');
160 | const p = example.input.enveloped.protected;
161 | const u = example.input.enveloped.unprotected;
162 | const plaintext = Buffer.from(example.input.plaintext);
163 |
164 | const recipient = [{
165 | key: {
166 | kty: example.input.enveloped.recipients[0].key.kty,
167 | kid: example.input.enveloped.recipients[0].key.kid,
168 | crv: example.input.enveloped.recipients[0].key.crv,
169 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
170 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
171 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
172 | },
173 | sender: {
174 | kty: example.input.enveloped.recipients[0].sender_key.kty,
175 | crv: example.input.enveloped.recipients[0].sender_key.crv,
176 | x: base64url.toBuffer(example.input.enveloped.recipients[0].sender_key.x),
177 | y: base64url.toBuffer(example.input.enveloped.recipients[0].sender_key.y),
178 | d: base64url.toBuffer(example.input.enveloped.recipients[0].sender_key.d)
179 | },
180 | p: example.input.enveloped.recipients[0].protected,
181 | u: example.input.enveloped.recipients[0].unprotected
182 | }];
183 |
184 | const options = {
185 | randomSource: (bytes) => {
186 | if (bytes === 12) {
187 | return Buffer.from('D7923E677B71A3F40A179643', 'hex');
188 | } else {
189 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3C9CF4DF2FE6C632BF7886413F76E88523A8260B857D70B350027FD842B5E5947', 'hex');
190 | }
191 | }
192 | };
193 |
194 | const header = { p: p, u: u };
195 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
196 | t.true(Buffer.isBuffer(buf));
197 | t.true(buf.length > 0);
198 | const actual = cbor.decodeFirstSync(buf);
199 | const expected = cbor.decodeFirstSync(example.output.cbor);
200 | t.true(deepEqual(actual, expected));
201 | });
202 |
203 | // create p256-ss-hkdf-256-02
204 |
205 | // create p256-ss-hkdf-256-03
206 |
207 | // create p256-ss-hkdf-512-01
208 |
209 | // create p256-ss-hkdf-512-02
210 |
211 | // create p256-ss-hkdf-512-03
212 |
213 | test('create p521-hkdf-256-01', async t => {
214 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p521-hkdf-256-01.json');
215 | const p = example.input.enveloped.protected;
216 | const u = example.input.enveloped.unprotected;
217 | const plaintext = Buffer.from(example.input.plaintext);
218 |
219 | const recipient = [{
220 | key: {
221 | kty: example.input.enveloped.recipients[0].key.kty,
222 | kid: example.input.enveloped.recipients[0].key.kid,
223 | crv: example.input.enveloped.recipients[0].key.crv,
224 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
225 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
226 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
227 | },
228 | p: example.input.enveloped.recipients[0].protected,
229 | u: example.input.enveloped.recipients[0].unprotected
230 | }];
231 |
232 | const options = {
233 | randomSource: (bytes) => {
234 | if (bytes === 12) {
235 | return Buffer.from('3082660901A9B9CD87AACB71', 'hex');
236 | } else {
237 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3C9CF4DF2FE6C632BF7886413F76E885252908DF901D1581A045444DD996E1704B9B6', 'hex');
238 | }
239 | }
240 | };
241 |
242 | const header = { p: p, u: u };
243 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
244 | t.true(Buffer.isBuffer(buf));
245 | t.true(buf.length > 0);
246 | const actual = cbor.decodeFirstSync(buf);
247 | const expected = cbor.decodeFirstSync(example.output.cbor);
248 | t.true(deepEqual(actual, expected));
249 | });
250 |
251 | test('create p521-hkdf-256-02', async t => {
252 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p521-hkdf-256-02.json');
253 | const p = example.input.enveloped.protected;
254 | const u = example.input.enveloped.unprotected;
255 | const plaintext = Buffer.from(example.input.plaintext);
256 |
257 | const recipient = [{
258 | key: {
259 | kty: example.input.enveloped.recipients[0].key.kty,
260 | kid: example.input.enveloped.recipients[0].key.kid,
261 | crv: example.input.enveloped.recipients[0].key.crv,
262 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
263 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
264 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
265 | },
266 | p: example.input.enveloped.recipients[0].protected,
267 | u: example.input.enveloped.recipients[0].unprotected
268 | }];
269 |
270 | const options = {
271 | randomSource: (bytes) => {
272 | if (bytes === 12) {
273 | return Buffer.from('512C9CC879517ADCF0FA768E', 'hex');
274 | } else {
275 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3C9CF4DF2FE6C632BF7886413F76E88527FAC271A4C7EA34B7E28D7BBB54C682BED7A', 'hex');
276 | }
277 | }
278 | };
279 |
280 | const header = { p: p, u: u };
281 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
282 | t.true(Buffer.isBuffer(buf));
283 | t.true(buf.length > 0);
284 | const actual = cbor.decodeFirstSync(buf);
285 | const expected = cbor.decodeFirstSync(example.output.cbor);
286 | t.true(deepEqual(actual, expected));
287 | });
288 |
289 | // create p521-hkdf-256-03
290 |
291 | test('create p521-hkdf-512-01', async t => {
292 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p521-hkdf-512-01.json');
293 | const p = example.input.enveloped.protected;
294 | const u = example.input.enveloped.unprotected;
295 | const plaintext = Buffer.from(example.input.plaintext);
296 |
297 | const recipient = [{
298 | key: {
299 | kty: example.input.enveloped.recipients[0].key.kty,
300 | kid: example.input.enveloped.recipients[0].key.kid,
301 | crv: example.input.enveloped.recipients[0].key.crv,
302 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
303 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
304 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
305 | },
306 | p: example.input.enveloped.recipients[0].protected,
307 | u: example.input.enveloped.recipients[0].unprotected
308 | }];
309 |
310 | const options = {
311 | randomSource: (bytes) => {
312 | if (bytes === 12) {
313 | return Buffer.from('CFDC1CA6D690CF1964458D42', 'hex');
314 | } else {
315 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3C9CF4DF2FE6C632BF7886413F76E88526B37FD0B58734CA925A389AD361ECEF28358', 'hex');
316 | }
317 | }
318 | };
319 |
320 | const header = { p: p, u: u };
321 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
322 | t.true(Buffer.isBuffer(buf));
323 | t.true(buf.length > 0);
324 | const actual = cbor.decodeFirstSync(buf);
325 | const expected = cbor.decodeFirstSync(example.output.cbor);
326 | t.true(deepEqual(actual, expected));
327 | });
328 |
329 | test('create p521-hkdf-512-02', async t => {
330 | const example = jsonfile.readFileSync('test/Examples/ecdh-direct-examples/p521-hkdf-512-02.json');
331 | const p = example.input.enveloped.protected;
332 | const u = example.input.enveloped.unprotected;
333 | const plaintext = Buffer.from(example.input.plaintext);
334 |
335 | const recipient = [{
336 | key: {
337 | kty: example.input.enveloped.recipients[0].key.kty,
338 | kid: example.input.enveloped.recipients[0].key.kid,
339 | crv: example.input.enveloped.recipients[0].key.crv,
340 | x: base64url.toBuffer(example.input.enveloped.recipients[0].key.x),
341 | y: base64url.toBuffer(example.input.enveloped.recipients[0].key.y),
342 | d: base64url.toBuffer(example.input.enveloped.recipients[0].key.d)
343 | },
344 | p: example.input.enveloped.recipients[0].protected,
345 | u: example.input.enveloped.recipients[0].unprotected
346 | }];
347 |
348 | const options = {
349 | randomSource: (bytes) => {
350 | if (bytes === 12) {
351 | return Buffer.from('E89FD3534E1ABAF69C65CFE0', 'hex');
352 | } else {
353 | return Buffer.from('02D1F7E6F26C43D4868D87CEB2353161740AACF1F7163647984B522A848DF1C3C9CF4DF2FE6C632BF7886413F76E885238FB137F6C20764D89E26452937675B5E3B4', 'hex');
354 | }
355 | }
356 | };
357 |
358 | const header = { p: p, u: u };
359 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
360 | t.true(Buffer.isBuffer(buf));
361 | t.true(buf.length > 0);
362 | const actual = cbor.decodeFirstSync(buf);
363 | const expected = cbor.decodeFirstSync(example.output.cbor);
364 | t.true(deepEqual(actual, expected));
365 | });
366 |
367 | // create p521-hkdf-512-03
368 |
369 | // create p521-ss-hkdf-256-01
370 |
371 | // create p521-ss-hkdf-256-02
372 |
373 | // create p521-ss-hkdf-256-03
374 |
375 | // create p521-ss-hkdf-512-01
376 |
377 | // create p521-ss-hkdf-512-02
378 |
379 | // create p521-ss-hkdf-512-03
380 |
--------------------------------------------------------------------------------
/test/encrypted-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | function randomSource (bytes) {
13 | if (bytes === 12) {
14 | return Buffer.from('02D1F7E6F26C43D4868D87CE', 'hex');
15 | } else {
16 | return Buffer.from('61A7', 'hex');
17 | }
18 | }
19 |
20 | test('create aes-gcm-01', async t => {
21 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/aes-gcm-01.json');
22 | const p = example.input.encrypted.protected;
23 | const u = example.input.encrypted.unprotected;
24 | const plaintext = Buffer.from(example.input.plaintext);
25 |
26 | const recipient = {
27 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
28 | u: example.input.encrypted.recipients[0].unprotected
29 | };
30 |
31 | const options = {
32 | randomSource: randomSource
33 | };
34 |
35 | const header = { p: p, u: u };
36 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
37 | t.true(Buffer.isBuffer(buf));
38 | t.true(buf.length > 0);
39 | const actual = cbor.decodeFirstSync(buf);
40 | const expected = cbor.decodeFirstSync(example.output.cbor);
41 | t.true(deepEqual(actual, expected));
42 | });
43 |
44 | test('create enc-pass-01', async t => {
45 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-pass-01.json');
46 | const p = example.input.encrypted.protected;
47 | const u = example.input.encrypted.unprotected;
48 | const plaintext = Buffer.from(example.input.plaintext);
49 |
50 | const recipient = {
51 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
52 | u: example.input.encrypted.recipients[0].unprotected
53 | };
54 |
55 | const options = {
56 | randomSource: randomSource
57 | };
58 | const header = { p: p, u: u };
59 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
60 | t.true(Buffer.isBuffer(buf));
61 | t.true(buf.length > 0);
62 | const actual = cbor.decodeFirstSync(buf);
63 | const expected = cbor.decodeFirstSync(example.output.cbor);
64 | t.true(deepEqual(actual, expected));
65 | });
66 |
67 | test('create enc-pass-02', async t => {
68 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-pass-02.json');
69 | const p = example.input.encrypted.protected;
70 | const u = example.input.encrypted.unprotected;
71 | const plaintext = Buffer.from(example.input.plaintext);
72 | const external = Buffer.from(example.input.encrypted.external, 'hex');
73 |
74 | const recipient = {
75 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
76 | u: example.input.encrypted.recipients[0].unprotected
77 | };
78 |
79 | const options = {
80 | randomSource: randomSource,
81 | externalAAD: external,
82 | encodep: 'empty'
83 | };
84 |
85 | const header = { p: p, u: u };
86 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
87 | t.true(Buffer.isBuffer(buf));
88 | t.true(buf.length > 0);
89 | const actual = cbor.decodeFirstSync(buf);
90 | const expected = cbor.decodeFirstSync(example.output.cbor);
91 | t.true(deepEqual(actual, expected));
92 | });
93 |
94 | test('create enc-pass-03', async t => {
95 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-pass-03.json');
96 | const p = example.input.encrypted.protected;
97 | const u = example.input.encrypted.unprotected;
98 | const plaintext = Buffer.from(example.input.plaintext);
99 |
100 | const recipient = {
101 | key: base64url.toBuffer(example.input.encrypted.recipients[0].key.k),
102 | u: example.input.encrypted.recipients[0].unprotected
103 | };
104 |
105 | const options = {
106 | randomSource: randomSource,
107 | excludetag: true,
108 | encodep: 'empty'
109 | };
110 |
111 | const header = { p: p, u: u };
112 | const buf = await cose.encrypt.create(header, plaintext, recipient, options);
113 | t.true(Buffer.isBuffer(buf));
114 | t.true(buf.length > 0);
115 | const actual = cbor.decodeFirstSync(buf);
116 | const expected = cbor.decodeFirstSync(example.output.cbor);
117 | t.true(deepEqual(actual, expected));
118 | });
119 |
120 | test('decrypt aes-gcm-01', async t => {
121 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/aes-gcm-01.json');
122 | const plaintext = example.input.plaintext;
123 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
124 |
125 | const data = example.output.cbor;
126 | const buf = await cose.encrypt.read(data, key);
127 | t.true(Buffer.isBuffer(buf));
128 | t.true(buf.length > 0);
129 | t.is(buf.toString('utf8'), plaintext);
130 | });
131 |
132 | test('decrypt enc-pass-01', async t => {
133 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-pass-01.json');
134 | const plaintext = example.input.plaintext;
135 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
136 |
137 | const data = example.output.cbor;
138 | const buf = await cose.encrypt.read(data, key);
139 | t.true(Buffer.isBuffer(buf));
140 | t.true(buf.length > 0);
141 | t.is(buf.toString('utf8'), plaintext);
142 | });
143 |
144 | test('decrypt enc-pass-02', async t => {
145 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-pass-02.json');
146 | const plaintext = example.input.plaintext;
147 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
148 | const options = {
149 | externalAAD: Buffer.from(example.input.encrypted.external, 'hex')
150 | };
151 |
152 | const data = example.output.cbor;
153 | const buf = await cose.encrypt.read(data, key, options);
154 | t.true(Buffer.isBuffer(buf));
155 | t.true(buf.length > 0);
156 | t.is(buf.toString('utf8'), plaintext);
157 | });
158 |
159 | test('decrypt enc-pass-03', async t => {
160 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-pass-03.json');
161 | const plaintext = example.input.plaintext;
162 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
163 | const options = {
164 | defaultType: cose.encrypt.Encrypt0Tag
165 | };
166 | const data = example.output.cbor;
167 | const buf = await cose.encrypt.read(data, key, options);
168 | t.true(Buffer.isBuffer(buf));
169 | t.true(buf.length > 0);
170 | t.is(buf.toString('utf8'), plaintext);
171 | });
172 |
173 | test('decrypt enc-fail-01', async t => {
174 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-fail-01.json');
175 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
176 | const data = example.output.cbor;
177 | try {
178 | await cose.encrypt.read(data, key);
179 | t.fail('Unknown tag, 995');
180 | } catch (error) {
181 | t.is(error.message, 'Unknown tag, 995');
182 | }
183 | });
184 |
185 | test('decrypt enc-fail-02', async t => {
186 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-fail-02.json');
187 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
188 | const data = example.output.cbor;
189 | try {
190 | await cose.encrypt.read(data, key);
191 | t.fail('Unsupported state or unable to authenticate data');
192 | } catch (error) {
193 | t.is(error.message, 'Unsupported state or unable to authenticate data');
194 | }
195 | });
196 |
197 | test('decrypt enc-fail-03', async t => {
198 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-fail-03.json');
199 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
200 | const data = example.output.cbor;
201 | try {
202 | await cose.encrypt.read(data, key);
203 | t.fail('Unknown or unsupported algorithm -999');
204 | } catch (error) {
205 | t.is(error.message, 'Unknown or unsupported algorithm -999');
206 | }
207 | });
208 |
209 | test('decrypt enc-fail-04', async t => {
210 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-fail-04.json');
211 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
212 | const data = example.output.cbor;
213 | try {
214 | await cose.encrypt.read(data, key);
215 | t.fail('Unknown or unsupported algorithm Unknown');
216 | } catch (error) {
217 | t.is(error.message, 'Unknown or unsupported algorithm Unknown');
218 | }
219 | });
220 |
221 | test('decrypt enc-fail-06', async t => {
222 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-fail-06.json');
223 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
224 | const data = example.output.cbor;
225 | try {
226 | await cose.encrypt.read(data, key);
227 | t.fail('Unsupported state or unable to authenticate data');
228 | } catch (error) {
229 | t.is(error.message, 'Unsupported state or unable to authenticate data');
230 | }
231 | });
232 |
233 | test('decrypt enc-fail-07', async t => {
234 | const example = jsonfile.readFileSync('test/Examples/encrypted-tests/enc-fail-07.json');
235 | const key = base64url.toBuffer(example.input.encrypted.recipients[0].key.k);
236 | const data = example.output.cbor;
237 | try {
238 | await cose.encrypt.read(data, key);
239 | t.fail('Unsupported state or unable to authenticate data');
240 | } catch (error) {
241 | t.is(error.message, 'Unsupported state or unable to authenticate data');
242 | }
243 | });
244 |
--------------------------------------------------------------------------------
/test/enveloped-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | function randomSource (bytes) {
13 | if (bytes === 12) {
14 | return Buffer.from('02D1F7E6F26C43D4868D87CE', 'hex');
15 | } else {
16 | return Buffer.from('61A7', 'hex');
17 | }
18 | }
19 |
20 | test('create aes-gcm-01', async t => {
21 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/aes-gcm-01.json');
22 | const p = example.input.enveloped.protected;
23 | const u = example.input.enveloped.unprotected;
24 | const plaintext = Buffer.from(example.input.plaintext);
25 |
26 | const recipients = [{
27 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
28 | u: example.input.enveloped.recipients[0].unprotected
29 | }];
30 |
31 | const options = {
32 | randomSource: randomSource
33 | };
34 | const header = { p: p, u: u };
35 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
36 | t.true(Buffer.isBuffer(buf));
37 | t.true(buf.length > 0);
38 | const actual = cbor.decodeFirstSync(buf);
39 | const expected = cbor.decodeFirstSync(example.output.cbor);
40 | t.true(deepEqual(actual, expected));
41 | });
42 |
43 | test('create env-pass-01', async t => {
44 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-pass-01.json');
45 | const p = example.input.enveloped.protected;
46 | const u = example.input.enveloped.unprotected;
47 | const plaintext = Buffer.from(example.input.plaintext);
48 |
49 | const recipients = [{
50 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
51 | u: example.input.enveloped.recipients[0].unprotected
52 | }];
53 |
54 | const options = {
55 | randomSource: randomSource
56 | };
57 |
58 | const header = { p: p, u: u };
59 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
60 | t.true(Buffer.isBuffer(buf));
61 | t.true(buf.length > 0);
62 | const actual = cbor.decodeFirstSync(buf);
63 | const expected = cbor.decodeFirstSync(example.output.cbor);
64 | t.true(deepEqual(actual, expected));
65 | });
66 |
67 | test('create env-pass-02', async t => {
68 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-pass-02.json');
69 | const p = example.input.enveloped.protected;
70 | const u = example.input.enveloped.unprotected;
71 | const plaintext = Buffer.from(example.input.plaintext);
72 |
73 | const recipients = [{
74 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
75 | u: example.input.enveloped.recipients[0].unprotected
76 | }];
77 |
78 | const options = {
79 | randomSource: randomSource,
80 | externalAAD: Buffer.from(example.input.enveloped.external, 'hex')
81 | };
82 | const header = { p: p, u: u };
83 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
84 | t.true(Buffer.isBuffer(buf));
85 | t.true(buf.length > 0);
86 | const actual = cbor.decodeFirstSync(buf);
87 | const expected = cbor.decodeFirstSync(example.output.cbor);
88 | t.true(deepEqual(actual, expected));
89 | });
90 |
91 | test('create env-pass-03', async t => {
92 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-pass-03.json');
93 | const p = example.input.enveloped.protected;
94 | const u = example.input.enveloped.unprotected;
95 | const plaintext = Buffer.from(example.input.plaintext);
96 |
97 | const recipients = [{
98 | key: base64url.toBuffer(example.input.enveloped.recipients[0].key.k),
99 | u: example.input.enveloped.recipients[0].unprotected
100 | }];
101 |
102 | const options = {
103 | randomSource: randomSource,
104 | excludetag: true,
105 | encodep: 'empty'
106 | };
107 | const header = { p: p, u: u };
108 | const buf = await cose.encrypt.create(header, plaintext, recipients, options);
109 | t.true(Buffer.isBuffer(buf));
110 | t.true(buf.length > 0);
111 | const actual = cbor.decodeFirstSync(buf);
112 | const expected = cbor.decodeFirstSync(example.output.cbor);
113 | t.true(deepEqual(actual, expected));
114 | });
115 |
116 | test('decrypt aes-gcm-01', async t => {
117 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/aes-gcm-01.json');
118 | const plaintext = example.input.plaintext;
119 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
120 |
121 | const data = example.output.cbor;
122 | const buf = await cose.encrypt.read(data, key);
123 | t.true(Buffer.isBuffer(buf));
124 | t.true(buf.length > 0);
125 | t.is(buf.toString('utf8'), plaintext);
126 | });
127 |
128 | test('decrypt enc-pass-01', async t => {
129 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-pass-01.json');
130 | const plaintext = example.input.plaintext;
131 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
132 | const data = example.output.cbor;
133 | const buf = await cose.encrypt.read(data, key);
134 | t.true(Buffer.isBuffer(buf));
135 | t.true(buf.length > 0);
136 | t.is(buf.toString('utf8'), plaintext);
137 | });
138 |
139 | test('decrypt enc-pass-02', async t => {
140 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-pass-02.json');
141 | const plaintext = example.input.plaintext;
142 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
143 | const options = {
144 | externalAAD: Buffer.from(example.input.enveloped.external, 'hex')
145 | };
146 | const data = example.output.cbor;
147 | const buf = await cose.encrypt.read(data, key, options);
148 | t.true(Buffer.isBuffer(buf));
149 | t.true(buf.length > 0);
150 | t.is(buf.toString('utf8'), plaintext);
151 | });
152 |
153 | test('decrypt enc-pass-03', async t => {
154 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-pass-03.json');
155 | const plaintext = example.input.plaintext;
156 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
157 | const data = example.output.cbor;
158 | const buf = await cose.encrypt.read(data, key);
159 | t.true(Buffer.isBuffer(buf));
160 | t.true(buf.length > 0);
161 | t.is(buf.toString('utf8'), plaintext);
162 | });
163 |
164 | test('decrypt enc-fail-01', async t => {
165 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-fail-01.json');
166 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
167 | const data = example.output.cbor;
168 |
169 | try {
170 | await cose.encrypt.read(data, key);
171 | t.fail('Unknown tag, 995');
172 | } catch (error) {
173 | t.is(error.message, 'Unknown tag, 995');
174 | }
175 | });
176 |
177 | test('decrypt enc-fail-02', async t => {
178 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-fail-02.json');
179 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
180 | const data = example.output.cbor;
181 |
182 | try {
183 | await cose.encrypt.read(data, key);
184 | t.fail('Unsupported state or unable to authenticate data');
185 | } catch (error) {
186 | t.is(error.message, 'Unsupported state or unable to authenticate data');
187 | }
188 | });
189 |
190 | test('decrypt enc-fail-03', async t => {
191 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-fail-03.json');
192 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
193 | const data = example.output.cbor;
194 |
195 | try {
196 | await cose.encrypt.read(data, key);
197 | t.fail('Unknown or unsupported algorithm -999');
198 | } catch (error) {
199 | t.is(error.message, 'Unknown or unsupported algorithm -999');
200 | }
201 | });
202 |
203 | test('decrypt enc-fail-04', async t => {
204 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-fail-04.json');
205 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
206 | const data = example.output.cbor;
207 |
208 | try {
209 | await cose.encrypt.read(data, key);
210 | t.fail('Unknown or unsupported algorithm Unknown');
211 | } catch (error) {
212 | t.is(error.message, 'Unknown or unsupported algorithm Unknown');
213 | }
214 | });
215 |
216 | test('decrypt enc-fail-06', async t => {
217 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-fail-06.json');
218 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
219 | const data = example.output.cbor;
220 |
221 | try {
222 | await cose.encrypt.read(data, key);
223 | t.fail('Unsupported state or unable to authenticate data');
224 | } catch (error) {
225 | t.is(error.message, 'Unsupported state or unable to authenticate data');
226 | }
227 | });
228 |
229 | test('decrypt enc-fail-07', async t => {
230 | const example = jsonfile.readFileSync('test/Examples/enveloped-tests/env-fail-07.json');
231 | const key = base64url.toBuffer(example.input.enveloped.recipients[0].key.k);
232 | const data = example.output.cbor;
233 |
234 | try {
235 | await cose.encrypt.read(data, key);
236 | t.fail('Unsupported state or unable to authenticate data');
237 | } catch (error) {
238 | t.is(error.message, 'Unsupported state or unable to authenticate data');
239 | }
240 | });
241 |
--------------------------------------------------------------------------------
/test/hmac-examples.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | test('create HMac-enc-01', async t => {
13 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-01.json');
14 | const p = example.input.mac0.protected;
15 | const u = example.input.mac0.unprotected;
16 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
17 | const plaintext = Buffer.from(example.input.plaintext);
18 | const header = { p: p, u: u };
19 | const recipeient = { key: key };
20 | const buf = await cose.mac.create(header, plaintext, recipeient);
21 | t.true(Buffer.isBuffer(buf));
22 | t.true(buf.length > 0);
23 | const actual = cbor.decodeFirstSync(buf);
24 | const expected = cbor.decodeFirstSync(example.output.cbor);
25 | t.true(deepEqual(actual, expected));
26 | });
27 |
28 | test('create HMac-enc-02', async t => {
29 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-02.json');
30 | const p = example.input.mac0.protected;
31 | const u = example.input.mac0.unprotected;
32 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
33 | const plaintext = Buffer.from(example.input.plaintext);
34 | const header = { p: p, u: u };
35 | const recipient = { key: key };
36 | const buf = await cose.mac.create(header, plaintext, recipient);
37 | t.true(Buffer.isBuffer(buf));
38 | t.true(buf.length > 0);
39 | const actual = cbor.decodeFirstSync(buf);
40 | const expected = cbor.decodeFirstSync(example.output.cbor);
41 | t.true(deepEqual(actual, expected));
42 | });
43 |
44 | test('create HMac-enc-03', async t => {
45 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-03.json');
46 | const p = example.input.mac0.protected;
47 | const u = example.input.mac0.unprotected;
48 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
49 | const plaintext = Buffer.from(example.input.plaintext);
50 | const header = { p: p, u: u };
51 | const recipient = { key: key };
52 | const buf = await cose.mac.create(header, plaintext, recipient);
53 | t.true(Buffer.isBuffer(buf));
54 | t.true(buf.length > 0);
55 | const actual = cbor.decodeFirstSync(buf);
56 | const expected = cbor.decodeFirstSync(example.output.cbor);
57 | t.true(deepEqual(actual, expected));
58 | });
59 |
60 | // HMac-enc-04 is a negative test and cannot be recreated
61 |
62 | test('create HMac-enc-05', async t => {
63 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-05.json');
64 | const p = example.input.mac0.protected;
65 | const u = example.input.mac0.unprotected;
66 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
67 | const plaintext = Buffer.from(example.input.plaintext);
68 | const header = { p: p, u: u };
69 | const recipeint = { key: key };
70 | const buf = await cose.mac.create(header, plaintext, recipeint);
71 | t.true(Buffer.isBuffer(buf));
72 | t.true(buf.length > 0);
73 | const actual = cbor.decodeFirstSync(buf);
74 | const expected = cbor.decodeFirstSync(example.output.cbor);
75 | t.true(deepEqual(actual, expected));
76 | });
77 |
78 | test('verify HMac-enc-01', async t => {
79 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-01.json');
80 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
81 | const data = example.output.cbor;
82 | const buf = await cose.mac.read(data, key);
83 | t.true(Buffer.isBuffer(buf));
84 | t.true(buf.length > 0);
85 | t.is(buf.toString('utf8'), example.input.plaintext);
86 | });
87 |
88 | test('verify HMac-enc-02', async t => {
89 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-02.json');
90 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
91 |
92 | const data = example.output.cbor;
93 | const buf = await cose.mac.read(data, key);
94 | t.true(Buffer.isBuffer(buf));
95 | t.true(buf.length > 0);
96 | t.is(buf.toString('utf8'), example.input.plaintext);
97 | });
98 |
99 | test('verify HMac-enc-03', async t => {
100 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-03.json');
101 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
102 | const data = example.output.cbor;
103 | const buf = await cose.mac.read(data, key);
104 | t.true(Buffer.isBuffer(buf));
105 | t.true(buf.length > 0);
106 | t.is(buf.toString('utf8'), example.input.plaintext);
107 | });
108 |
109 | test('verify HMac-enc-04', async t => {
110 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-04.json');
111 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
112 | const data = example.output.cbor;
113 | try {
114 | await cose.mac.read(data, key);
115 | t.fail('Tag mismatch');
116 | } catch (error) {
117 | t.is(error.message, 'Tag mismatch');
118 | }
119 | });
120 |
121 | test('verify HMac-enc-05', async t => {
122 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-enc-05.json');
123 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
124 | const data = example.output.cbor;
125 | const buf = await cose.mac.read(data, key);
126 | t.true(Buffer.isBuffer(buf));
127 | t.true(buf.length > 0);
128 | t.is(buf.toString('utf8'), example.input.plaintext);
129 | });
130 |
131 | test('create HMac-01', async t => {
132 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-01.json');
133 | const p = example.input.mac.protected;
134 | const u = example.input.mac.recipients[0].unprotected;
135 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
136 | const plaintext = Buffer.from(example.input.plaintext);
137 | const recipents = [{ key: key, u: u }];
138 | const header = { p: p };
139 | const buf = await cose.mac.create(header, plaintext, recipents);
140 | t.true(Buffer.isBuffer(buf));
141 | t.true(buf.length > 0);
142 | const actual = cbor.decodeFirstSync(buf);
143 | const expected = cbor.decodeFirstSync(example.output.cbor);
144 | t.true(deepEqual(actual, expected));
145 | });
146 |
147 | test('create HMac-02', async t => {
148 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-02.json');
149 | const p = example.input.mac.protected;
150 | const u = example.input.mac.recipients[0].unprotected;
151 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
152 | const plaintext = Buffer.from(example.input.plaintext);
153 | const recipents = [{ key: key, u: u }];
154 | const header = { p: p };
155 | const buf = await cose.mac.create(header, plaintext, recipents);
156 | t.true(Buffer.isBuffer(buf));
157 | t.true(buf.length > 0);
158 | const actual = cbor.decodeFirstSync(buf);
159 | const expected = cbor.decodeFirstSync(example.output.cbor);
160 | t.true(deepEqual(actual, expected));
161 | });
162 |
163 | test('create HMac-03', async t => {
164 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-03.json');
165 | const p = example.input.mac.protected;
166 | const u = example.input.mac.recipients[0].unprotected;
167 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
168 | const plaintext = Buffer.from(example.input.plaintext);
169 | const recipents = [{ key: key, u: u }];
170 | const header = { p: p };
171 | const buf = await cose.mac.create(header, plaintext, recipents);
172 | t.true(Buffer.isBuffer(buf));
173 | t.true(buf.length > 0);
174 | const actual = cbor.decodeFirstSync(buf);
175 | const expected = cbor.decodeFirstSync(example.output.cbor);
176 | t.true(deepEqual(actual, expected));
177 | });
178 |
179 | // HMac-04 is a negative test and cannot be recreated
180 |
181 | test('create HMac-05', async t => {
182 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-05.json');
183 | const p = example.input.mac.protected;
184 | const u = example.input.mac.recipients[0].unprotected;
185 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
186 | const plaintext = Buffer.from(example.input.plaintext);
187 | const recipents = [{ key: key, u: u }];
188 | const header = { p: p };
189 | const buf = await cose.mac.create(header, plaintext, recipents);
190 | t.true(Buffer.isBuffer(buf));
191 | t.true(buf.length > 0);
192 | const actual = cbor.decodeFirstSync(buf);
193 | const expected = cbor.decodeFirstSync(example.output.cbor);
194 | t.true(deepEqual(actual, expected));
195 | });
196 |
197 | test('verify HMac-01', async t => {
198 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-01.json');
199 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
200 | const data = example.output.cbor;
201 | const buf = await cose.mac.read(data, key);
202 | t.true(Buffer.isBuffer(buf));
203 | t.true(buf.length > 0);
204 | t.is(buf.toString('utf8'), example.input.plaintext);
205 | });
206 |
207 | test('verify HMac-02', async t => {
208 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-02.json');
209 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
210 | const data = example.output.cbor;
211 | const buf = await cose.mac.read(data, key);
212 | t.true(Buffer.isBuffer(buf));
213 | t.true(buf.length > 0);
214 | t.is(buf.toString('utf8'), example.input.plaintext);
215 | });
216 |
217 | test('verify HMac-03', async t => {
218 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-03.json');
219 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
220 | const data = example.output.cbor;
221 | const buf = await cose.mac.read(data, key);
222 | t.true(Buffer.isBuffer(buf));
223 | t.true(buf.length > 0);
224 | t.is(buf.toString('utf8'), example.input.plaintext);
225 | });
226 |
227 | test('verify HMac-04', async t => {
228 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-04.json');
229 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
230 | const data = example.output.cbor;
231 | try {
232 | await cose.mac.read(data, key);
233 | t.fail('Tag mismatch');
234 | } catch (error) {
235 | t.is(error.message, 'Tag mismatch');
236 | }
237 | });
238 |
239 | test('verify HMac-05', async t => {
240 | const example = jsonfile.readFileSync('test/Examples/hmac-examples/HMac-05.json');
241 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
242 | const data = example.output.cbor;
243 | const buf = await cose.mac.read(data, key);
244 | t.true(Buffer.isBuffer(buf));
245 | t.true(buf.length > 0);
246 | t.is(buf.toString('utf8'), example.input.plaintext);
247 | });
248 |
--------------------------------------------------------------------------------
/test/mac-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | test('create HMac-01', async t => {
13 | const example = jsonfile.readFileSync('test/Examples/mac-tests/HMac-01.json');
14 | const p = example.input.mac.protected;
15 | const u = example.input.mac.recipients[0].unprotected;
16 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
17 | const plaintext = Buffer.from(example.input.plaintext);
18 |
19 | const recipents = [{ key: key, u: u }];
20 | const header = { p: p };
21 | const buf = await cose.mac.create(header, plaintext, recipents);
22 | t.true(Buffer.isBuffer(buf));
23 | t.true(buf.length > 0);
24 | const actual = cbor.decodeFirstSync(buf);
25 | const expected = cbor.decodeFirstSync(example.output.cbor);
26 | t.true(deepEqual(actual, expected));
27 | });
28 |
29 | test('verify HMac-01', async t => {
30 | const example = jsonfile.readFileSync('test/Examples/mac-tests/HMac-01.json');
31 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
32 |
33 | const data = example.output.cbor;
34 | const buf = await cose.mac.read(data, key);
35 | t.true(Buffer.isBuffer(buf));
36 | t.true(buf.length > 0);
37 | t.is(buf.toString('utf8'), example.input.plaintext);
38 | });
39 |
40 | test('create mac-pass-01', async t => {
41 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-pass-01.json');
42 | const p = example.input.mac.protected;
43 | const u = example.input.mac.unprotected;
44 | const ru = example.input.mac.recipients[0].unprotected;
45 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
46 | const plaintext = Buffer.from(example.input.plaintext);
47 | const recipents = [{ key: key, u: ru }];
48 | const header = { p: p, u: u };
49 | const buf = await cose.mac.create(header, plaintext, recipents);
50 | t.true(Buffer.isBuffer(buf));
51 | t.true(buf.length > 0);
52 | t.is(buf.toString('hex'), example.output.cbor.toLowerCase());
53 | const actual = cbor.decodeFirstSync(buf);
54 | const expected = cbor.decodeFirstSync(example.output.cbor);
55 | t.true(deepEqual(actual, expected));
56 | });
57 |
58 | test('create mac-pass-02', async t => {
59 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-pass-02.json');
60 | const p = example.input.mac.protected;
61 | const u = example.input.mac.unprotected;
62 | const ru = example.input.mac.recipients[0].unprotected;
63 | const external = Buffer.from(example.input.mac.external, 'hex');
64 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
65 | const plaintext = Buffer.from(example.input.plaintext);
66 | const options = { encodep: 'empty' };
67 | const header = { p: p, u: u };
68 | const recipents = [{ key: key, u: ru }];
69 | const buf = await cose.mac.create(header, plaintext, recipents, external, options);
70 | t.true(Buffer.isBuffer(buf));
71 | t.true(buf.length > 0);
72 | const actual = cbor.decodeFirstSync(buf);
73 | const expected = cbor.decodeFirstSync(example.output.cbor);
74 | t.true(deepEqual(actual, expected));
75 | });
76 |
77 | test('create mac-pass-03', async t => {
78 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-pass-03.json');
79 | const p = example.input.mac.protected;
80 | const u = example.input.mac.unprotected;
81 | const ru = example.input.mac.recipients[0].unprotected;
82 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
83 | const plaintext = Buffer.from(example.input.plaintext);
84 | const options = { encodep: 'empty', excludetag: true };
85 | const header = { p: p, u: u };
86 | const recipents = [{ key: key, u: ru }];
87 | const external = null;
88 | const buf = await cose.mac.create(header, plaintext, recipents, external, options);
89 | t.true(Buffer.isBuffer(buf));
90 | t.true(buf.length > 0);
91 | const actual = cbor.decodeFirstSync(buf);
92 | const expected = cbor.decodeFirstSync(example.output.cbor);
93 | t.true(deepEqual(actual, expected));
94 | });
95 |
96 | test('verify mac-pass-01', async t => {
97 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-pass-01.json');
98 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
99 | const data = example.output.cbor;
100 | const buf = await cose.mac.read(data, key);
101 | t.true(Buffer.isBuffer(buf));
102 | t.true(buf.length > 0);
103 | t.is(buf.toString('utf8'), example.input.plaintext);
104 | });
105 |
106 | test('verify mac-pass-02', async t => {
107 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-pass-02.json');
108 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
109 | const external = Buffer.from(example.input.mac.external, 'hex');
110 | const data = example.output.cbor;
111 | const buf = await cose.mac.read(data, key, external);
112 | t.true(Buffer.isBuffer(buf));
113 | t.true(buf.length > 0);
114 | t.is(buf.toString('utf8'), example.input.plaintext);
115 | });
116 |
117 | test('verify mac-pass-03', async t => {
118 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-pass-03.json');
119 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
120 | const options = { defaultType: cose.mac.MACTag };
121 | const external = null;
122 | const data = example.output.cbor;
123 | const buf = await cose.mac.read(data, key, external, options);
124 | t.true(Buffer.isBuffer(buf));
125 | t.true(buf.length > 0);
126 | t.is(buf.toString('utf8'), example.input.plaintext);
127 | });
128 |
129 | test('verify mac-fail-01', async t => {
130 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-fail-01.json');
131 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
132 | const data = example.output.cbor;
133 | try {
134 | await cose.mac.read(data, key);
135 | t.fail('Expecting Array of lenght 4');
136 | } catch (error) {
137 | t.is(error.message, 'Expecting Array of lenght 4');
138 | }
139 | });
140 |
141 | test('verify mac-fail-02', async t => {
142 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-fail-02.json');
143 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
144 | const data = example.output.cbor;
145 | try {
146 | await cose.mac.read(data, key);
147 | t.fail('Tag mismatch');
148 | } catch (error) {
149 | t.is(error.message, 'Tag mismatch');
150 | }
151 | });
152 |
153 | test('verify mac-fail-03', async t => {
154 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-fail-03.json');
155 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
156 | const data = example.output.cbor;
157 | try {
158 | await cose.mac.read(data, key);
159 | t.fail('Unknown algorithm, -999');
160 | } catch (error) {
161 | t.is(error.message, 'Unknown algorithm, -999');
162 | }
163 | });
164 |
165 | test('verify mac-fail-04', async t => {
166 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-fail-04.json');
167 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
168 | const data = example.output.cbor;
169 | try {
170 | await cose.mac.read(data, key);
171 | t.fail('Unknown algorithm, Unknown');
172 | } catch (error) {
173 | t.is(error.message, 'Unknown algorithm, Unknown');
174 | }
175 | });
176 |
177 | test('verify mac-fail-06', async t => {
178 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-fail-06.json');
179 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
180 | const data = example.output.cbor;
181 | try {
182 | await cose.mac.read(data, key);
183 | t.fail('Tag mismatch');
184 | } catch (error) {
185 | t.is(error.message, 'Tag mismatch');
186 | }
187 | });
188 |
189 | test('verify mac-fail-07', async t => {
190 | const example = jsonfile.readFileSync('test/Examples/mac-tests/mac-fail-07.json');
191 | const key = base64url.toBuffer(example.input.mac.recipients[0].key.k);
192 | const data = example.output.cbor;
193 | try {
194 | await cose.mac.read(data, key);
195 | t.fail('Tag mismatch');
196 | } catch (error) {
197 | t.is(error.message, 'Tag mismatch');
198 | }
199 | });
200 |
--------------------------------------------------------------------------------
/test/mac0-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | test('create HMac-01', async t => {
13 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/HMac-01.json');
14 | const p = example.input.mac0.protected;
15 | const u = example.input.mac0.unprotected;
16 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
17 | const plaintext = Buffer.from(example.input.plaintext);
18 |
19 | const header = { p: p, u: u };
20 | const recipents = { key: key };
21 | const buf = await cose.mac.create(header, plaintext, recipents);
22 | t.true(Buffer.isBuffer(buf));
23 | t.true(buf.length > 0);
24 | const actual = cbor.decodeFirstSync(buf);
25 | const expected = cbor.decodeFirstSync(example.output.cbor);
26 | t.true(deepEqual(actual, expected));
27 | });
28 |
29 | test('verify HMac-01', async t => {
30 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/HMac-01.json');
31 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
32 |
33 | const data = example.output.cbor;
34 | const buf = await cose.mac.read(data, key);
35 | t.true(Buffer.isBuffer(buf));
36 | t.true(buf.length > 0);
37 | t.is(buf.toString('utf8'), example.input.plaintext);
38 | });
39 |
40 | test('create mac-pass-01', async t => {
41 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-pass-01.json');
42 |
43 | const u = example.input.mac0.unprotected;
44 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
45 | const plaintext = Buffer.from(example.input.plaintext);
46 | const header = { u: u };
47 | const recipents = { key: key };
48 | const buf = await cose.mac.create(header, plaintext, recipents);
49 | t.true(Buffer.isBuffer(buf));
50 | t.true(buf.length > 0);
51 | const actual = cbor.decodeFirstSync(buf);
52 | const expected = cbor.decodeFirstSync(example.output.cbor);
53 | t.true(deepEqual(actual, expected));
54 | });
55 |
56 | test('create mac-pass-02', async t => {
57 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-pass-02.json');
58 | const p = undefined;
59 | const u = example.input.mac0.unprotected;
60 | const external = Buffer.from(example.input.mac0.external, 'hex');
61 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
62 | const plaintext = Buffer.from(example.input.plaintext);
63 | const options = { encodep: 'empty' };
64 |
65 | const header = { p: p, u: u };
66 | const recipents = { key: key };
67 | const buf = await cose.mac.create(header, plaintext, recipents, external, options);
68 | t.true(Buffer.isBuffer(buf));
69 | t.true(buf.length > 0);
70 | const actual = cbor.decodeFirstSync(buf);
71 | const expected = cbor.decodeFirstSync(example.output.cbor);
72 | t.true(deepEqual(actual, expected));
73 | });
74 |
75 | test('create mac-pass-03', async t => {
76 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-pass-03.json');
77 | const p = undefined;
78 | const u = example.input.mac0.unprotected;
79 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
80 | const plaintext = Buffer.from(example.input.plaintext);
81 | const options = { encodep: 'empty', excludetag: true };
82 |
83 | const recipents = { key: key };
84 | const header = { p: p, u: u };
85 | const external = null;
86 | const buf = await cose.mac.create(header, plaintext, recipents, external, options);
87 |
88 | t.true(Buffer.isBuffer(buf));
89 | t.true(buf.length > 0);
90 | const actual = cbor.decodeFirstSync(buf);
91 | const expected = cbor.decodeFirstSync(example.output.cbor);
92 | t.true(deepEqual(actual, expected));
93 | });
94 |
95 | test('verify mac-pass-01', async t => {
96 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-pass-01.json');
97 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
98 |
99 | const data = example.output.cbor;
100 | const buf = await cose.mac.read(data, key);
101 |
102 | t.true(Buffer.isBuffer(buf));
103 | t.true(buf.length > 0);
104 | t.is(buf.toString('utf8'), example.input.plaintext);
105 | });
106 |
107 | test('verify mac-pass-02', async t => {
108 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-pass-02.json');
109 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
110 | const external = Buffer.from(example.input.mac0.external, 'hex');
111 |
112 | const data = example.output.cbor;
113 | const buf = await cose.mac.read(data, key, external);
114 | t.true(Buffer.isBuffer(buf));
115 | t.true(buf.length > 0);
116 | t.is(buf.toString('utf8'), example.input.plaintext);
117 | });
118 |
119 | test('verify mac-pass-03', async t => {
120 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-pass-03.json');
121 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
122 |
123 | const data = example.output.cbor;
124 | const buf = await cose.mac.read(data, key);
125 |
126 | t.true(Buffer.isBuffer(buf));
127 | t.true(buf.length > 0);
128 | t.is(buf.toString('utf8'), example.input.plaintext);
129 | });
130 |
131 | test('verify mac-fail-01', async t => {
132 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-fail-01.json');
133 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
134 | const data = example.output.cbor;
135 |
136 | try {
137 | await cose.mac.read(data, key);
138 | t.fail('Unexpected cbor tag, \'992\'');
139 | } catch (error) {
140 | t.is(error.message, 'Unexpected cbor tag, \'992\'');
141 | }
142 | });
143 |
144 | test('verify mac-fail-02', async t => {
145 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-fail-02.json');
146 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
147 | const data = example.output.cbor;
148 |
149 | try {
150 | await cose.mac.read(data, key);
151 | t.fail('Tag mismatch');
152 | } catch (error) {
153 | t.is(error.message, 'Tag mismatch');
154 | }
155 | });
156 |
157 | test('verify mac-fail-03', async t => {
158 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-fail-03.json');
159 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
160 | const data = example.output.cbor;
161 |
162 | try {
163 | await cose.mac.read(data, key);
164 | t.fail('Unknown algorithm, -999');
165 | } catch (error) {
166 | t.is(error.message, 'Unknown algorithm, -999');
167 | }
168 | });
169 |
170 | test('verify mac-fail-04', async t => {
171 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-fail-04.json');
172 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
173 | const data = example.output.cbor;
174 |
175 | try {
176 | await cose.mac.read(data, key);
177 | t.fail('Unknown algorithm, Unknown');
178 | } catch (error) {
179 | t.is(error.message, 'Unknown algorithm, Unknown');
180 | }
181 | });
182 |
183 | test('verify mac-fail-06', async t => {
184 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-fail-06.json');
185 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
186 | const data = example.output.cbor;
187 |
188 | try {
189 | await cose.mac.read(data, key);
190 | t.fail('Tag mismatch');
191 | } catch (error) {
192 | t.is(error.message, 'Tag mismatch');
193 | }
194 | });
195 |
196 | test('verify mac-fail-07', async t => {
197 | const example = jsonfile.readFileSync('test/Examples/mac0-tests/mac-fail-07.json');
198 | const key = base64url.toBuffer(example.input.mac0.recipients[0].key.k);
199 | const data = example.output.cbor;
200 |
201 | try {
202 | await cose.mac.read(data, key);
203 | t.fail('Tag mismatch');
204 | } catch (error) {
205 | t.is(error.message, 'Tag mismatch');
206 | }
207 | });
208 |
--------------------------------------------------------------------------------
/test/rsa-pkcs-examples.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const jwkToPem = require('jwk-to-pem');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | function hexToB64 (hex) {
13 | return Buffer.from(hex, 'hex').toString('base64');
14 | }
15 |
16 | test('create rsa-pkcs-01', async (t) => {
17 | const example = jsonfile.readFileSync('test/rsa-pkcs-examples/rsa-pkcs-01.json');
18 | const p = example.input.sign0.protected;
19 | const u = example.input.sign0.unprotected;
20 | const plaintext = Buffer.from(example.input.plaintext);
21 |
22 | const testKey = example.input.sign0.key;
23 | const signer = {
24 | key: jwkToPem({
25 | kty: testKey.kty,
26 | n: hexToB64(testKey.n_hex),
27 | e: hexToB64(testKey.e_hex),
28 | d: hexToB64(testKey.d_hex),
29 | p: hexToB64(testKey.p_hex),
30 | q: hexToB64(testKey.q_hex),
31 | dp: hexToB64(testKey.dP_hex),
32 | dq: hexToB64(testKey.dQ_hex),
33 | qi: hexToB64(testKey.qi_hex)
34 | }, { private: true })
35 | };
36 | const header = { p: p, u: u };
37 | const options = { excludetag: true };
38 | const buf = await cose.sign.create(header, plaintext, signer, options);
39 | t.true(Buffer.isBuffer(buf));
40 | t.true(buf.length > 0);
41 | const actual = cbor.decodeFirstSync(buf);
42 | const expected = cbor.decodeFirstSync(example.output.cbor);
43 | t.true(deepEqual(actual, expected));
44 | });
45 |
46 | test('create rsa-pkcs-01 Sync', async (t) => {
47 | const example = jsonfile.readFileSync('test/rsa-pkcs-examples/rsa-pkcs-01.json');
48 | const p = example.input.sign0.protected;
49 | const u = example.input.sign0.unprotected;
50 | const plaintext = Buffer.from(example.input.plaintext);
51 |
52 | const testKey = example.input.sign0.key;
53 | const signer = {
54 | key: jwkToPem({
55 | kty: testKey.kty,
56 | n: hexToB64(testKey.n_hex),
57 | e: hexToB64(testKey.e_hex),
58 | d: hexToB64(testKey.d_hex),
59 | p: hexToB64(testKey.p_hex),
60 | q: hexToB64(testKey.q_hex),
61 | dp: hexToB64(testKey.dP_hex),
62 | dq: hexToB64(testKey.dQ_hex),
63 | qi: hexToB64(testKey.qi_hex)
64 | }, { private: true })
65 | };
66 | const header = { p: p, u: u };
67 | const options = { excludetag: true };
68 | const buf = await cose.sign.create(header, plaintext, signer, options);
69 | t.true(Buffer.isBuffer(buf));
70 | t.true(buf.length > 0);
71 | const actual = cbor.decodeFirstSync(buf);
72 | const expected = cbor.decodeFirstSync(example.output.cbor);
73 | t.true(deepEqual(actual, expected));
74 | });
75 |
76 | test('verify rsa-pkcs-01', async (t) => {
77 | const example = jsonfile.readFileSync('test/rsa-pkcs-examples/rsa-pkcs-01.json');
78 |
79 | const testKey = example.input.sign0.key;
80 |
81 | const verifier = {
82 | key: jwkToPem({
83 | kty: testKey.kty,
84 | n: hexToB64(testKey.n_hex),
85 | e: hexToB64(testKey.e_hex)
86 | })
87 | };
88 |
89 | const signature = Buffer.from(example.output.cbor, 'hex');
90 |
91 | const options = { defaultType: cose.sign.Sign1Tag };
92 | const buf = await cose.sign.verify(signature, verifier, options);
93 | t.true(Buffer.isBuffer(buf));
94 | t.true(buf.length > 0);
95 | t.is(buf.toString('utf8'), example.input.plaintext);
96 | });
97 |
98 | test('verify rsa-pkcs-01 Sync', async (t) => {
99 | const example = jsonfile.readFileSync('test/rsa-pkcs-examples/rsa-pkcs-01.json');
100 |
101 | const testKey = example.input.sign0.key;
102 |
103 | const verifier = {
104 | key: jwkToPem({
105 | kty: testKey.kty,
106 | n: hexToB64(testKey.n_hex),
107 | e: hexToB64(testKey.e_hex)
108 | })
109 | };
110 |
111 | const signature = Buffer.from(example.output.cbor, 'hex');
112 | const options = { defaultType: cose.sign.Sign1Tag };
113 | const buf = await cose.sign.verify(signature, verifier, options);
114 | t.true(Buffer.isBuffer(buf));
115 | t.true(buf.length > 0);
116 | t.is(buf.toString('utf8'), example.input.plaintext);
117 | });
118 |
--------------------------------------------------------------------------------
/test/rsa-pkcs-examples/rsa-pkcs-01.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "RSA-PKCS1-v1_5 w/ SHA-256",
3 | "input": {
4 | "plaintext": "This is the content.",
5 | "sign0": {
6 | "key": {
7 | "kty": "RSA",
8 | "n_hex": "BC7E29D0DF7E20CC9DC8D509E0F68895922AF0EF452190D402C61B554334A7BF91C9A570240F994FAE1B69035BCFAD4F7E249EB26087C2665E7C958C967B1517413DC3F97A431691A5999B257CC6CD356BAD168D929B8BAE9020750E74CF60F6FD35D6BB3FC93FC28900478694F508B33E7C00E24F90EDF37457FC3E8EFCFD2F42306301A8205AB740515331D5C18F0C64D4A43BE52FC440400F6BFC558A6E32884C2AF56F29E5C52780CEA7285F5C057FC0DFDA232D0ADA681B01495D9D0E32196633588E289E59035FF664F056189F2F10FE05827B796C326E3E748FFA7C589ED273C9C43436CDDB4A6A22523EF8BCB2221615B799966F1ABA5BC84B7A27CF",
9 | "e_hex": "010001",
10 | "d_hex": "0969FF04FCC1E1647C20402CF3F736D4CAE33F264C1C6EE3252CFCC77CDEF533D700570AC09A50D7646EDFB1F86A13BCABCF00BD659F27813D08843597271838BC46ED4743FE741D9BC38E0BF36D406981C7B81FCE54861CEBFB85AD23A8B4833C1BEE18C05E4E436A869636980646EECB839E4DAF434C9C6DFBF3A55CE1DB73E4902F89384BD6F9ECD3399FB1ED4B83F28D356C8E619F1F0DC96BBE8B75C1812CA58F360259EAEB1D17130C3C0A2715A99BE49898E871F6088A29570DC2FFA0CEFFFA27F1F055CBAABFD8894E0CC24F176E34EBAD32278A466F8A34A685ACC8207D9EC1FCBBD094996DC73C6305FCA31668BE57B1699D0BB456CC8871BFFBCD",
11 | "p_hex": "F331593E147FD3A3235675F0D36A06E5426F7C5E78E49B2ACD3E268BA50E48ED2A52F3B4FA492D6BCF70EB3F915A716078A113652E3FA4C6D50AF8606C2D2C28ECAF083B712D6CEE1263C1205DA03BBBFA6F5C2D8B1A96194089CACB306C844A832E2B032B5F96A7EAB6CFE1107299013C8B0E9F089BBABBC504DD8BC138BA4B",
12 | "q_hex": "C66B5DDCAB7017E14083F2854F61997F35636C86F2F92B172D2555588EE1ED899BA6B6ADEC0A02024B2E78A91C891256A8571E0EFB3BAC3F41724DE036EC8FA0F93E2CFBDDA59C6FF1816EB3DC938D4E45912423F3F34B7E96C39E2E4D65A3DCD6DFD2B4EF527841001272F77855B6D75D40D54BB65BD1DF8538E96EC4DAD60D",
13 | "dP_hex": "1F677CFDBE49EF7B7EA1B8A33BB9D260229F20F1562D373864BEA4DD9D97E5A4F2B53991624CB6D7D836DDBA1CBC102E0405D0EA5CF98CFEBC1E298AD20D5749859EE8B23C604053D1FE1DBF5F37C4DEF66D10FB349E5F49AD82DDB435719DF7BD4EE5F107D5D52FA3E8AD9983B538BAE72591E2C98ACAA75ABED1192DFF7457",
14 | "dQ_hex": "2CCC9F13ACCD9146B57755318E3BBE197FA7642090097C162E86485FC75AF173E965D9C7290D1569092A83E9C2DC9BFC5EE3D490935EE4C41F75BC698C5D1B0CC059AE746B95F1DD408CF5BEBC65C038D4F23153C0C7C4DADF1569C890870B5958568ECF755D8C73389DF1C138353A242414F853B0E7C85A0C4D4E3F4949139D",
15 | "qi_hex": "7B6E2406FD03BC75EA22AB94A8D242506A6BBFE36BC8132DBBCE50B8425425062B697AFA180F5685E90E11EB5712D2E6E2B24E2A1E7C75D5940E08301E824470EF38561BE3E9D05F9FCA8E6F69A028A928E85E58212E789BA577B80378D7A995FA6AFEA74BE364661A679F82776C5905F43F7A35692986271E594E1D11F9668D",
16 | "kid": "meriadoc.brandybuck@rsa.example"
17 | },
18 | "unprotected": {
19 | "kid": "meriadoc.brandybuck@rsa.example"
20 | },
21 | "protected": {
22 | "alg": "RS256"
23 | }
24 | }
25 | },
26 | "output": {
27 | "cbor": "8445a101390100a104581f6d65726961646f632e6272616e64796275636b407273612e6578616d706c6554546869732069732074686520636f6e74656e742e590100a533c0490c109e639b3325c457675ba692debf20ef4f56b6cec37e28739b21d2af824eb93975aaac5e3292660ebeefcaa1a8bf0bab8e6611a4c2fcf2d0bba499f84c7eb7079e04eb9c2bb797191ba1ef1b13cf39617fe6fccb1018aec54414c14f93666db86cac66421d053ab2171c225172e5fec4009e7a3c0fa4a05d8c483434f6fb19679f34b7ef773f8aee1d73ae5661905f6c7f1c66b506895c4048fc4d4b851a851e64489e051088bfd0df95a887095acb5037dc4c2db814b77d044ac22aea062694400755dfee253d83714a868d2d7b809b0902aaf18ae6dbc25cab3f04d3f3d1d9e40d1c501da02b3e54144a9392fe92d8cde0050febd1df8a69e3d9"
28 | }
29 | }
--------------------------------------------------------------------------------
/test/sign-performance-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const base64url = require('base64url');
8 | const cbor = require('cbor');
9 | const jsonfile = require('jsonfile');
10 |
11 | test('create and verify really huge payload', async (t) => {
12 | // uses the keys from here but it has nothing to do with the test
13 | const example = jsonfile.readFileSync('test/Examples/sign-tests/ecdsa-01.json');
14 | const BIG_LENGHT = 100 * 1000;
15 | const p = example.input.sign.protected;
16 | const u = example.input.sign.unprotected;
17 | const signers = [{
18 | key: {
19 | d: base64url.toBuffer(example.input.sign.signers[0].key.d)
20 | },
21 | u: example.input.sign.signers[0].unprotected,
22 | p: example.input.sign.signers[0].protected
23 | }];
24 | const plaintext = Buffer.from('a'.repeat(BIG_LENGHT));
25 |
26 | const verifier = {
27 | key: {
28 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
29 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
30 | kid: example.input.sign.signers[0].key.kid
31 | }
32 | };
33 |
34 | const header = { p: p, u: u };
35 | const buf = await cose.sign.create(header, plaintext, signers);
36 | t.true(Buffer.isBuffer(buf));
37 | t.true(buf.length > 0);
38 |
39 | const actual = await cbor.decodeFirst(buf);
40 | t.is(actual.value[2].length, BIG_LENGHT);
41 |
42 | const verifiedBuf = await cose.sign.verify(buf, verifier);
43 | t.true(Buffer.isBuffer(verifiedBuf));
44 | t.true(verifiedBuf.length > 0);
45 | t.is(verifiedBuf.toString('utf8'), plaintext.toString('utf8'));
46 | });
47 |
--------------------------------------------------------------------------------
/test/sign-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const deepEqual = require('./util.js').deepEqual;
11 |
12 | test('ecdsa-examples verify ecdsa-01', async (t) => {
13 | const example = jsonfile.readFileSync('test/Examples/ecdsa-examples/ecdsa-01.json');
14 |
15 | const verifier = {
16 | key: {
17 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
18 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
19 | kid: example.input.sign.signers[0].key.kid
20 | }
21 | };
22 |
23 | const signature = Buffer.from(example.output.cbor, 'hex');
24 |
25 | const buf = await cose.sign.verify(signature, verifier);
26 | t.true(Buffer.isBuffer(buf));
27 | t.true(buf.length > 0);
28 | t.is(buf.toString('utf8'), example.input.plaintext);
29 | });
30 |
31 | test('ecdsa-examples verify ecdsa-02', async (t) => {
32 | const example = jsonfile.readFileSync('test/Examples/ecdsa-examples/ecdsa-02.json');
33 |
34 | const verifier = {
35 | key: {
36 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
37 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
38 | kid: example.input.sign.signers[0].key.kid
39 | }
40 | };
41 |
42 | const signature = Buffer.from(example.output.cbor, 'hex');
43 |
44 | const buf = await cose.sign.verify(signature, verifier);
45 | t.true(Buffer.isBuffer(buf));
46 | t.true(buf.length > 0);
47 | t.is(buf.toString('utf8'), example.input.plaintext);
48 | });
49 |
50 | test('create ecdsa-01', async (t) => {
51 | const example = jsonfile.readFileSync('test/Examples/sign-tests/ecdsa-01.json');
52 | const p = example.input.sign.protected;
53 | const u = example.input.sign.unprotected;
54 | const plaintext = Buffer.from(example.input.plaintext);
55 | const signers = [{
56 | key: {
57 | d: base64url.toBuffer(example.input.sign.signers[0].key.d)
58 | },
59 | u: example.input.sign.signers[0].unprotected,
60 | p: example.input.sign.signers[0].protected
61 | }];
62 |
63 | const header = { p: p, u: u };
64 | const buf = await cose.sign.create(header, plaintext, signers);
65 | t.true(Buffer.isBuffer(buf));
66 | t.true(buf.length > 0);
67 | const actual = cbor.decodeFirstSync(buf);
68 | const expected = cbor.decodeFirstSync(example.output.cbor);
69 | t.true(deepEqual(actual, expected));
70 | });
71 |
72 | test('sign+verify rsa-pss-01', async (t) => {
73 | const example = jsonfile.readFileSync('test/Examples/rsa-pss-examples/rsa-pss-01.json');
74 | const p = example.input.sign.protected;
75 |
76 | const u = example.input.sign.unprotected;
77 | const plaintext = Buffer.from(example.input.plaintext);
78 | const signers = [{
79 | key: {
80 | n: Buffer.from(example.input.sign.signers[0].key.n_hex, 'hex'),
81 | d: Buffer.from(example.input.sign.signers[0].key.d_hex, 'hex'),
82 | p: Buffer.from(example.input.sign.signers[0].key.p_hex, 'hex'),
83 | q: Buffer.from(example.input.sign.signers[0].key.q_hex, 'hex'),
84 | dp: Buffer.from(example.input.sign.signers[0].key.dP_hex, 'hex'),
85 | dq: Buffer.from(example.input.sign.signers[0].key.dQ_hex, 'hex'),
86 | qi: Buffer.from(example.input.sign.signers[0].key.qi_hex, 'hex'),
87 | e: Buffer.from(example.input.sign.signers[0].key.e_hex, 'hex'),
88 | kid: example.input.sign.signers[0].key.kid
89 | },
90 | u: example.input.sign.signers[0].unprotected,
91 | p: example.input.sign.signers[0].protected
92 | }];
93 | signers[0].p.alg = 'PS256';
94 |
95 | const header = { p: p, u: u };
96 | const buf = await cose.sign.create(header, plaintext, signers);
97 | t.true(Buffer.isBuffer(buf));
98 | t.true(buf.length > 0);
99 |
100 | const verifiedBuf = await cose.sign.verify(buf, signers[0]);
101 | t.true(Buffer.isBuffer(verifiedBuf));
102 | t.true(verifiedBuf.length > 0);
103 | t.is(verifiedBuf.toString('utf8'), example.input.plaintext);
104 | });
105 |
106 | test('sign+verify rsa-pss-02', async (t) => {
107 | const example = jsonfile.readFileSync('test/Examples/rsa-pss-examples/rsa-pss-02.json');
108 | const p = example.input.sign.protected;
109 |
110 | const u = example.input.sign.unprotected;
111 | const plaintext = Buffer.from(example.input.plaintext);
112 | const signers = [{
113 | key: {
114 | n: Buffer.from(example.input.sign.signers[0].key.n_hex, 'hex'),
115 | d: Buffer.from(example.input.sign.signers[0].key.d_hex, 'hex'),
116 | p: Buffer.from(example.input.sign.signers[0].key.p_hex, 'hex'),
117 | q: Buffer.from(example.input.sign.signers[0].key.q_hex, 'hex'),
118 | dp: Buffer.from(example.input.sign.signers[0].key.dP_hex, 'hex'),
119 | dq: Buffer.from(example.input.sign.signers[0].key.dQ_hex, 'hex'),
120 | qi: Buffer.from(example.input.sign.signers[0].key.qi_hex, 'hex'),
121 | e: Buffer.from(example.input.sign.signers[0].key.e_hex, 'hex'),
122 | kid: example.input.sign.signers[0].key.kid
123 | },
124 | u: example.input.sign.signers[0].unprotected,
125 | p: example.input.sign.signers[0].protected
126 | }];
127 | signers[0].p.alg = 'PS384';
128 |
129 | const header = { p: p, u: u };
130 | const buf = await cose.sign.create(header, plaintext, signers);
131 | t.true(Buffer.isBuffer(buf));
132 | t.true(buf.length > 0);
133 |
134 | const verifiedBuf = await cose.sign.verify(buf, signers[0]);
135 | t.true(Buffer.isBuffer(buf));
136 | t.true(verifiedBuf.length > 0);
137 | t.is(verifiedBuf.toString('utf8'), example.input.plaintext);
138 | });
139 | test('sign+verify rsa-pss-03', async (t) => {
140 | const example = jsonfile.readFileSync('test/Examples/rsa-pss-examples/rsa-pss-03.json');
141 | const p = example.input.sign.protected;
142 |
143 | const u = example.input.sign.unprotected;
144 | const plaintext = Buffer.from(example.input.plaintext);
145 | const signers = [{
146 | key: {
147 | n: Buffer.from(example.input.sign.signers[0].key.n_hex, 'hex'),
148 | d: Buffer.from(example.input.sign.signers[0].key.d_hex, 'hex'),
149 | p: Buffer.from(example.input.sign.signers[0].key.p_hex, 'hex'),
150 | q: Buffer.from(example.input.sign.signers[0].key.q_hex, 'hex'),
151 | dp: Buffer.from(example.input.sign.signers[0].key.dP_hex, 'hex'),
152 | dq: Buffer.from(example.input.sign.signers[0].key.dQ_hex, 'hex'),
153 | qi: Buffer.from(example.input.sign.signers[0].key.qi_hex, 'hex'),
154 | e: Buffer.from(example.input.sign.signers[0].key.e_hex, 'hex'),
155 | kid: example.input.sign.signers[0].key.kid
156 | },
157 | u: example.input.sign.signers[0].unprotected,
158 | p: example.input.sign.signers[0].protected
159 | }];
160 | signers[0].p.alg = 'PS512';
161 |
162 | const header = { p: p, u: u };
163 | const buf = await cose.sign.create(header, plaintext, signers);
164 | t.true(Buffer.isBuffer(buf));
165 | t.true(buf.length > 0);
166 |
167 | const verifiedBuf = await cose.sign.verify(buf, signers[0]);
168 | t.true(Buffer.isBuffer(verifiedBuf));
169 | t.true(verifiedBuf.length > 0);
170 | t.is(verifiedBuf.toString('utf8'), example.input.plaintext);
171 | });
172 |
173 | test('verify ecdsa-01', async (t) => {
174 | const example = jsonfile.readFileSync('test/Examples/sign-tests/ecdsa-01.json');
175 |
176 | const verifier = {
177 | key: {
178 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
179 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
180 | kid: example.input.sign.signers[0].key.kid
181 | }
182 | };
183 |
184 | const signature = Buffer.from(example.output.cbor, 'hex');
185 |
186 | const buf = await cose.sign.verify(signature, verifier);
187 | t.true(Buffer.isBuffer(buf));
188 | t.true(buf.length > 0);
189 | t.is(buf.toString('utf8'), example.input.plaintext);
190 | });
191 |
192 | test('create sign-pass-01', async (t) => {
193 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-01.json');
194 | const p = example.input.sign.protected;
195 | const u = example.input.sign.unprotected;
196 | const plaintext = Buffer.from(example.input.plaintext);
197 |
198 | const signers = [{
199 | key: {
200 | d: base64url.toBuffer(example.input.sign.signers[0].key.d)
201 | },
202 | u: example.input.sign.signers[0].unprotected,
203 | p: example.input.sign.signers[0].protected
204 | }];
205 |
206 | const header = { p: p, u: u };
207 | const buf = await cose.sign.create(header, plaintext, signers);
208 | t.true(Buffer.isBuffer(buf));
209 | t.true(buf.length > 0);
210 | const actual = cbor.decodeFirstSync(buf);
211 | const expected = cbor.decodeFirstSync(example.output.cbor);
212 | t.true(deepEqual(actual, expected));
213 | });
214 |
215 | test('create sign-pass-01 Sync', async (t) => {
216 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-01.json');
217 | const p = example.input.sign.protected;
218 | const u = example.input.sign.unprotected;
219 | const plaintext = Buffer.from(example.input.plaintext);
220 |
221 | const signers = [{
222 | key: {
223 | d: base64url.toBuffer(example.input.sign.signers[0].key.d)
224 | },
225 | u: example.input.sign.signers[0].unprotected,
226 | p: example.input.sign.signers[0].protected
227 | }];
228 |
229 | const header = { p: p, u: u };
230 | const buf = await cose.sign.create(header, plaintext, signers);
231 | t.true(Buffer.isBuffer(buf));
232 | t.true(buf.length > 0);
233 | const actual = cbor.decodeFirstSync(buf);
234 | const expected = cbor.decodeFirstSync(example.output.cbor);
235 | t.true(deepEqual(actual, expected));
236 | });
237 |
238 | test('create sign-pass-02', async (t) => {
239 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-02.json');
240 | const p = example.input.sign.protected;
241 | const u = example.input.sign.unprotected;
242 | const plaintext = Buffer.from(example.input.plaintext);
243 |
244 | const signers = [{
245 | key: { d: base64url.toBuffer(example.input.sign.signers[0].key.d) },
246 | u: example.input.sign.signers[0].unprotected,
247 | p: example.input.sign.signers[0].protected,
248 | externalAAD: Buffer.from(example.input.sign.signers[0].external, 'hex')
249 | }];
250 |
251 | const header = { p: p, u: u };
252 | const options = { encodep: 'empty' };
253 | const buf = await cose.sign.create(header, plaintext, signers, options);
254 | t.true(Buffer.isBuffer(buf));
255 | t.true(buf.length > 0);
256 | const actual = cbor.decodeFirstSync(buf);
257 | const expected = cbor.decodeFirstSync(example.output.cbor);
258 | t.true(deepEqual(actual, expected));
259 | });
260 |
261 | test('create sign-pass-03', async (t) => {
262 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-03.json');
263 | const p = example.input.sign.protected;
264 | const u = example.input.sign.unprotected;
265 | const plaintext = Buffer.from(example.input.plaintext);
266 |
267 | const signers = [{
268 | key: {
269 | d: base64url.toBuffer(example.input.sign.signers[0].key.d)
270 | },
271 | u: example.input.sign.signers[0].unprotected,
272 | p: example.input.sign.signers[0].protected
273 | }];
274 |
275 | const header = { p: p, u: u };
276 | const options = { encodep: 'empty', excludetag: true };
277 | const buf = await cose.sign.create(header, plaintext, signers, options);
278 | t.true(Buffer.isBuffer(buf));
279 | t.true(buf.length > 0);
280 | const actual = cbor.decodeFirstSync(buf);
281 | const expected = cbor.decodeFirstSync(example.output.cbor);
282 | t.true(deepEqual(actual, expected));
283 | });
284 |
285 | test('verify sign-pass-01', async (t) => {
286 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-01.json');
287 |
288 | const verifier = {
289 | key: {
290 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
291 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
292 | kid: example.input.sign.signers[0].key.kid
293 | }
294 | };
295 |
296 | const signature = Buffer.from(example.output.cbor, 'hex');
297 |
298 | const buf = await cose.sign.verify(signature, verifier);
299 | t.true(Buffer.isBuffer(buf));
300 | t.true(buf.length > 0);
301 | t.is(buf.toString('utf8'), example.input.plaintext);
302 | });
303 |
304 | test('verify sign-pass-01 Sync', async (t) => {
305 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-01.json');
306 |
307 | const verifier = {
308 | key: {
309 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
310 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
311 | kid: example.input.sign.signers[0].key.kid
312 | }
313 | };
314 |
315 | const signature = Buffer.from(example.output.cbor, 'hex');
316 |
317 | const buf = await cose.sign.verify(signature, verifier);
318 | t.true(Buffer.isBuffer(buf));
319 | t.true(buf.length > 0);
320 | t.is(buf.toString('utf8'), example.input.plaintext);
321 | });
322 |
323 | test('verify sign-pass-02', async (t) => {
324 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-02.json');
325 |
326 | const verifier = {
327 | key: {
328 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
329 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
330 | kid: example.input.sign.signers[0].key.kid
331 | },
332 | externalAAD: Buffer.from(example.input.sign.signers[0].external, 'hex')
333 | };
334 |
335 | const signature = Buffer.from(example.output.cbor, 'hex');
336 |
337 | const buf = await cose.sign.verify(signature, verifier);
338 | t.true(Buffer.isBuffer(buf));
339 | t.true(buf.length > 0);
340 | t.is(buf.toString('utf8'), example.input.plaintext);
341 | });
342 |
343 | test('verify sign-pass-03', async (t) => {
344 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-pass-03.json');
345 |
346 | const verifier = {
347 | key: {
348 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
349 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
350 | kid: example.input.sign.signers[0].key.kid
351 | }
352 | };
353 |
354 | const signature = Buffer.from(example.output.cbor, 'hex');
355 |
356 | const buf = await cose.sign.verify(signature, verifier);
357 | t.true(Buffer.isBuffer(buf));
358 | t.true(buf.length > 0);
359 | t.is(buf.toString('utf8'), example.input.plaintext);
360 | });
361 |
362 | test('verify sign-fail-01', async (t) => {
363 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-fail-01.json');
364 |
365 | const verifier = {
366 | key: {
367 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
368 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
369 | kid: example.input.sign.signers[0].key.kid
370 | }
371 | };
372 |
373 | const signature = Buffer.from(example.output.cbor, 'hex');
374 |
375 | try {
376 | await cose.sign.verify(signature, verifier);
377 | t.fail('Unexpected cbor tag, \'998\'');
378 | } catch (error) {
379 | t.is(error.message, 'Unexpected cbor tag, \'998\'');
380 | }
381 | });
382 |
383 | test('verify sign-fail-02', async (t) => {
384 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-fail-02.json');
385 |
386 | const verifier = {
387 | key: {
388 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
389 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
390 | kid: example.input.sign.signers[0].key.kid
391 | }
392 | };
393 |
394 | const signature = Buffer.from(example.output.cbor, 'hex');
395 |
396 | try {
397 | await cose.sign.verify(signature, verifier);
398 | t.fail('Signature missmatch');
399 | } catch (error) {
400 | t.is(error.message, 'Signature missmatch');
401 | }
402 | });
403 |
404 | test('verify sign-fail-03', async (t) => {
405 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-fail-03.json');
406 |
407 | const verifier = {
408 | key: {
409 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
410 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
411 | kid: example.input.sign.signers[0].key.kid
412 | }
413 | };
414 |
415 | const signature = Buffer.from(example.output.cbor, 'hex');
416 | try {
417 | await cose.sign.verify(signature, verifier);
418 | t.fail('Unknown algorithm, -999');
419 | } catch (error) {
420 | t.is(error.message, 'Unknown algorithm, -999');
421 | }
422 | });
423 |
424 | test('verify sign-fail-04', async (t) => {
425 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-fail-04.json');
426 |
427 | const verifier = {
428 | key: {
429 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
430 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
431 | kid: example.input.sign.signers[0].key.kid
432 | }
433 | };
434 |
435 | const signature = Buffer.from(example.output.cbor, 'hex');
436 | try {
437 | await cose.sign.verify(signature, verifier);
438 | t.fail('Unknown algorithm, unknown');
439 | } catch (error) {
440 | t.is(error.message, 'Unknown algorithm, unknown');
441 | }
442 | });
443 |
444 | test('verify sign-fail-06', async (t) => {
445 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-fail-06.json');
446 |
447 | const verifier = {
448 | key: {
449 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
450 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
451 | kid: example.input.sign.signers[0].key.kid
452 | }
453 | };
454 |
455 | const signature = Buffer.from(example.output.cbor, 'hex');
456 |
457 | try {
458 | await cose.sign.verify(signature, verifier);
459 | t.fail('Signature missmatch');
460 | } catch (error) {
461 | t.is(error.message, 'Signature missmatch');
462 | }
463 | });
464 |
465 | test('verify sign-fail-07', async (t) => {
466 | const example = jsonfile.readFileSync('test/Examples/sign-tests/sign-fail-07.json');
467 |
468 | const verifier = {
469 | key: {
470 | x: base64url.toBuffer(example.input.sign.signers[0].key.x),
471 | y: base64url.toBuffer(example.input.sign.signers[0].key.y),
472 | kid: example.input.sign.signers[0].key.kid
473 | }
474 | };
475 |
476 | const signature = Buffer.from(example.output.cbor, 'hex');
477 |
478 | try {
479 | await cose.sign.verify(signature, verifier);
480 | t.fail('Signature missmatch');
481 | } catch (error) {
482 | t.is(error.message, 'Signature missmatch');
483 | }
484 | });
485 |
486 | test('verify rsa-pss-01', async (t) => {
487 | const example = jsonfile.readFileSync('test/Examples/rsa-pss-examples/rsa-pss-01.json');
488 |
489 | const verifier = {
490 | key: {
491 | n: Buffer.from(example.input.sign.signers[0].key.n_hex, 'hex'),
492 | e: Buffer.from(example.input.sign.signers[0].key.e_hex, 'hex'),
493 | kid: example.input.sign.signers[0].key.kid
494 | }
495 | };
496 |
497 | const signature = Buffer.from(example.output.cbor, 'hex');
498 |
499 | const buf = await cose.sign.verify(signature, verifier);
500 | t.true(Buffer.isBuffer(buf));
501 | t.true(buf.length > 0);
502 | t.is(buf.toString('utf8'), example.input.plaintext);
503 | });
504 |
505 | test('verify rsa-pss-02', async (t) => {
506 | const example = jsonfile.readFileSync('test/Examples/rsa-pss-examples/rsa-pss-02.json');
507 |
508 | const verifier = {
509 | key: {
510 | n: Buffer.from(example.input.sign.signers[0].key.n_hex, 'hex'),
511 | e: Buffer.from(example.input.sign.signers[0].key.e_hex, 'hex'),
512 | kid: example.input.sign.signers[0].key.kid
513 | }
514 | };
515 |
516 | const signature = Buffer.from(example.output.cbor, 'hex');
517 |
518 | const buf = await cose.sign.verify(signature, verifier);
519 | t.true(Buffer.isBuffer(buf));
520 | t.true(buf.length > 0);
521 | t.is(buf.toString('utf8'), example.input.plaintext);
522 | });
523 |
524 | test('verify rsa-pss-03', async (t) => {
525 | const example = jsonfile.readFileSync('test/Examples/rsa-pss-examples/rsa-pss-03.json');
526 |
527 | const verifier = {
528 | key: {
529 | n: Buffer.from(example.input.sign.signers[0].key.n_hex, 'hex'),
530 | e: Buffer.from(example.input.sign.signers[0].key.e_hex, 'hex'),
531 | kid: example.input.sign.signers[0].key.kid
532 | }
533 | };
534 |
535 | const signature = Buffer.from(example.output.cbor, 'hex');
536 |
537 | const buf = await cose.sign.verify(signature, verifier);
538 | t.true(Buffer.isBuffer(buf));
539 | t.true(buf.length > 0);
540 | t.is(buf.toString('utf8'), example.input.plaintext);
541 | });
542 |
--------------------------------------------------------------------------------
/test/sign1-tests.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const cose = require('../');
6 | const test = require('ava');
7 | const jsonfile = require('jsonfile');
8 | const base64url = require('base64url');
9 | const cbor = require('cbor');
10 | const { deepEqual } = require('./util.js');
11 |
12 | test('create sign-pass-01', async (t) => {
13 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-pass-01.json');
14 | const u = example.input.sign0.unprotected;
15 | const plaintext = Buffer.from(example.input.plaintext);
16 |
17 | const signer = {
18 | key: {
19 | d: base64url.toBuffer(example.input.sign0.key.d)
20 | }
21 | };
22 |
23 | const header = { u: u };
24 | const buf = await cose.sign.create(header, plaintext, signer);
25 | t.true(Buffer.isBuffer(buf));
26 | t.true(buf.length > 0);
27 | const actual = cbor.decodeFirstSync(buf);
28 | const expected = cbor.decodeFirstSync(example.output.cbor);
29 | t.true(deepEqual(actual, expected));
30 | });
31 |
32 | test('create sign-pass-02', async (t) => {
33 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-pass-02.json');
34 | const p = example.input.sign0.protected;
35 | const u = example.input.sign0.unprotected;
36 | const plaintext = Buffer.from(example.input.plaintext);
37 |
38 | const signer = {
39 | key: {
40 | d: base64url.toBuffer(example.input.sign0.key.d)
41 | },
42 | externalAAD: Buffer.from(example.input.sign0.external, 'hex')
43 | };
44 |
45 | const header = { p: p, u: u };
46 | const buf = await cose.sign.create(header, plaintext, signer);
47 | t.true(Buffer.isBuffer(buf));
48 | t.true(buf.length > 0);
49 | const actual = cbor.decodeFirstSync(buf);
50 | const expected = cbor.decodeFirstSync(example.output.cbor);
51 | t.true(deepEqual(actual, expected));
52 | });
53 |
54 | test('create sign-pass-03', async (t) => {
55 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-pass-03.json');
56 | const p = example.input.sign0.protected;
57 | const u = example.input.sign0.unprotected;
58 | const plaintext = Buffer.from(example.input.plaintext);
59 |
60 | const signer = {
61 | key: {
62 | d: base64url.toBuffer(example.input.sign0.key.d)
63 | }
64 | };
65 |
66 | const header = { p: p, u: u };
67 | const options = { excludetag: true };
68 | const buf = await cose.sign.create(header, plaintext, signer, options);
69 | t.true(Buffer.isBuffer(buf));
70 | t.true(buf.length > 0);
71 | const actual = cbor.decodeFirstSync(buf);
72 | const expected = cbor.decodeFirstSync(example.output.cbor);
73 | t.true(deepEqual(actual, expected));
74 | });
75 |
76 | test('verify sign-pass-01', async (t) => {
77 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-pass-01.json');
78 |
79 | const verifier = {
80 | key: {
81 | x: base64url.toBuffer(example.input.sign0.key.x),
82 | y: base64url.toBuffer(example.input.sign0.key.y)
83 | }
84 | };
85 |
86 | const signature = Buffer.from(example.output.cbor, 'hex');
87 |
88 | const buf = await cose.sign.verify(signature, verifier);
89 | t.true(Buffer.isBuffer(buf));
90 | t.true(buf.length > 0);
91 | t.is(buf.toString('utf8'), example.input.plaintext);
92 | });
93 |
94 | test('verify sign-pass-02', async (t) => {
95 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-pass-02.json');
96 |
97 | const verifier = {
98 | key: {
99 | x: base64url.toBuffer(example.input.sign0.key.x),
100 | y: base64url.toBuffer(example.input.sign0.key.y)
101 | },
102 | externalAAD: Buffer.from(example.input.sign0.external, 'hex')
103 | };
104 |
105 | const signature = Buffer.from(example.output.cbor, 'hex');
106 |
107 | const buf = await cose.sign.verify(signature, verifier);
108 | t.true(Buffer.isBuffer(buf));
109 | t.true(buf.length > 0);
110 | t.is(buf.toString('utf8'), example.input.plaintext);
111 | });
112 |
113 | test('verify sign-pass-03', async (t) => {
114 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-pass-03.json');
115 |
116 | const verifier = {
117 | key: {
118 | x: base64url.toBuffer(example.input.sign0.key.x),
119 | y: base64url.toBuffer(example.input.sign0.key.y)
120 | }
121 | };
122 |
123 | const signature = Buffer.from(example.output.cbor, 'hex');
124 |
125 | const options = { defaultType: cose.sign.Sign1Tag };
126 | const buf = await cose.sign.verify(signature, verifier, options);
127 | t.true(Buffer.isBuffer(buf));
128 | t.true(buf.length > 0);
129 | t.is(buf.toString('utf8'), example.input.plaintext);
130 | });
131 |
132 | test('verify sign-fail-01', async (t) => {
133 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-fail-01.json');
134 |
135 | const verifier = {
136 | key: {
137 | x: base64url.toBuffer(example.input.sign0.key.x),
138 | y: base64url.toBuffer(example.input.sign0.key.y)
139 | }
140 | };
141 |
142 | const signature = Buffer.from(example.output.cbor, 'hex');
143 | try {
144 | await cose.sign.verify(signature, verifier);
145 | t.fail('Unexpected cbor tag, \'998\'');
146 | } catch (error) {
147 | t.is(error.message, 'Unexpected cbor tag, \'998\'');
148 | }
149 | });
150 |
151 | test('verify sign-fail-02', async (t) => {
152 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-fail-02.json');
153 |
154 | const verifier = {
155 | key: {
156 | x: base64url.toBuffer(example.input.sign0.key.x),
157 | y: base64url.toBuffer(example.input.sign0.key.y)
158 | }
159 | };
160 |
161 | const signature = Buffer.from(example.output.cbor, 'hex');
162 | try {
163 | await cose.sign.verify(signature, verifier);
164 | t.fail('Signature missmatch');
165 | } catch (error) {
166 | t.is(error.message, 'Signature missmatch');
167 | }
168 | });
169 |
170 | test('verify sign-fail-03', async (t) => {
171 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-fail-03.json');
172 |
173 | const verifier = {
174 | key: {
175 | x: base64url.toBuffer(example.input.sign0.key.x),
176 | y: base64url.toBuffer(example.input.sign0.key.y)
177 | }
178 | };
179 |
180 | const signature = Buffer.from(example.output.cbor, 'hex');
181 | try {
182 | await cose.sign.verify(signature, verifier);
183 | t.fail('Unknown algorithm, -999');
184 | } catch (error) {
185 | t.is(error.message, 'Unknown algorithm, -999');
186 | }
187 | });
188 |
189 | test('verify sign-fail-04', async (t) => {
190 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-fail-04.json');
191 |
192 | const verifier = {
193 | key: {
194 | x: base64url.toBuffer(example.input.sign0.key.x),
195 | y: base64url.toBuffer(example.input.sign0.key.y)
196 | }
197 | };
198 |
199 | const signature = Buffer.from(example.output.cbor, 'hex');
200 | try {
201 | await cose.sign.verify(signature, verifier);
202 | t.fail('Unknown algorithm, unknown');
203 | } catch (error) {
204 | t.is(error.message, 'Unknown algorithm, unknown');
205 | }
206 | });
207 |
208 | test('verify sign-fail-06', async (t) => {
209 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-fail-06.json');
210 |
211 | const verifier = {
212 | key: {
213 | x: base64url.toBuffer(example.input.sign0.key.x),
214 | y: base64url.toBuffer(example.input.sign0.key.y)
215 | }
216 | };
217 |
218 | const signature = Buffer.from(example.output.cbor, 'hex');
219 | try {
220 | await cose.sign.verify(signature, verifier);
221 | t.fail('Signature missmatch');
222 | } catch (error) {
223 | t.is(error.message, 'Signature missmatch');
224 | }
225 | });
226 |
227 | test('verify sign-fail-07', async (t) => {
228 | const example = jsonfile.readFileSync('test/Examples/sign1-tests/sign-fail-07.json');
229 |
230 | const verifier = {
231 | key: {
232 | x: base64url.toBuffer(example.input.sign0.key.x),
233 | y: base64url.toBuffer(example.input.sign0.key.y)
234 | }
235 | };
236 |
237 | const signature = Buffer.from(example.output.cbor, 'hex');
238 | try {
239 | await cose.sign.verify(signature, verifier);
240 | t.fail('Signature missmatch');
241 | } catch (error) {
242 | t.is(error.message, 'Signature missmatch');
243 | }
244 | });
245 |
--------------------------------------------------------------------------------
/test/util.js:
--------------------------------------------------------------------------------
1 | /* jshint esversion: 6 */
2 | /* jslint node: true */
3 | 'use strict';
4 |
5 | const test = require('ava');
6 |
7 | function isObject (item) {
8 | return item && typeof item === 'object' && !Array.isArray(item);
9 | }
10 |
11 | function mapDeepEqual (actual, expected, depth) {
12 | const sortedActualKeys = [...actual.keys()].sort();
13 | const sortedExpectedKeys = [...expected.keys()].sort();
14 | if (sortedActualKeys.length !== sortedExpectedKeys.length) {
15 | return false;
16 | }
17 | for (let i = 0; i < sortedActualKeys.length; i++) {
18 | const actualKey = sortedActualKeys[i];
19 | const expectedKey = sortedExpectedKeys[i];
20 | if (actualKey !== expectedKey) {
21 | return false;
22 | }
23 | if (!deepEqual(actual.get(actualKey), expected.get(expectedKey), depth + 1)) {
24 | return false;
25 | }
26 | }
27 | return true;
28 | }
29 |
30 | function objectDeepEqual (actual, expected, depth) {
31 | const sortedActualKeys = Object.keys(actual).sort();
32 | const sortedExpectedKeys = Object.keys(expected).sort();
33 | if (sortedActualKeys.length !== sortedExpectedKeys.length) {
34 | return false;
35 | }
36 | for (let i = 0; i < sortedActualKeys.length; i++) {
37 | const actualKey = sortedActualKeys[i];
38 | const expectedKey = sortedExpectedKeys[i];
39 | if (actualKey !== expectedKey) {
40 | return false;
41 | }
42 | if (!deepEqual(actual[actualKey], expected[expectedKey], depth + 1)) {
43 | return false;
44 | }
45 | }
46 | return true;
47 | }
48 |
49 | function arrayDeepEqual (actual, expected, depth) {
50 | if (actual.length !== expected.length) {
51 | return false;
52 | }
53 | for (let i = 0; i < actual.length; i++) {
54 | if (!deepEqual(actual[i], expected[i], depth + 1)) {
55 | return false;
56 | }
57 | }
58 | return true;
59 | }
60 |
61 | function deepEqual (actual, expected, depth) {
62 | const currentDepth = (depth !== undefined ? depth : 0);
63 | if (currentDepth === 50) {
64 | throw new Error('Structure is to deeply nested.');
65 | }
66 |
67 | if (actual instanceof Map && expected instanceof Map) {
68 | return mapDeepEqual(actual, expected, currentDepth);
69 | } else if (actual instanceof Set && expected instanceof Set) {
70 | throw new Error('Set is not supported.');
71 | } else if (isObject(actual) && isObject(expected)) {
72 | return objectDeepEqual(actual, expected, currentDepth);
73 | } else if (Array.isArray(actual) && Array.isArray(expected)) {
74 | return arrayDeepEqual(actual, expected, currentDepth);
75 | } else {
76 | return actual === expected;
77 | }
78 | }
79 |
80 | exports.deepEqual = deepEqual;
81 |
82 | test('deep equal array', (t) => {
83 | const actual = [1, 2, 3, '4', [1, 2, 3], { hello: 'world', world: 'hello' }];
84 | const expected = [1, 2, 3, '4', [1, 2, 3], { hello: 'world', world: 'hello' }];
85 | t.true(deepEqual(actual, expected));
86 | expected.push(4);
87 | t.false(deepEqual(actual, expected));
88 | });
89 |
90 | test('deep equal deep array', (t) => {
91 | const actual = [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, 1]]]]]]]]]]]]];
92 | const expected = [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, [1, 1]]]]]]]]]]]]];
93 | t.true(deepEqual(actual, expected));
94 | });
95 |
96 | test('deep equal objects', (t) => {
97 | const actual = {
98 | world: 'hello',
99 | hello: 'world',
100 | complex: {
101 | world: 'hello',
102 | hello: 'world'
103 | }
104 | };
105 | const expected = {
106 | hello: 'world',
107 | world: 'hello',
108 | complex: {
109 | hello: 'world',
110 | world: 'hello'
111 | }
112 | };
113 | t.true(deepEqual(actual, expected));
114 | expected.test = 'test';
115 | t.false(deepEqual(actual, expected));
116 | });
117 |
118 | test('deep equal Map', (t) => {
119 | const actual = new Map();
120 | actual.set(1, 1);
121 | actual.set('hello', 'world');
122 | actual.set('object', { hello: 'world', world: 'hello' });
123 | const expected = new Map();
124 | expected.set(1, 1);
125 | expected.set('hello', 'world');
126 | expected.set('object', { hello: 'world', world: 'hello' });
127 | t.true(deepEqual(actual, expected));
128 | expected.set(2, 2);
129 | t.false(deepEqual(actual, expected));
130 | });
131 |
--------------------------------------------------------------------------------