├── w3c.json ├── .pr-preview.json ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── .github └── workflows │ └── auto-publish.yml ├── README.md ├── CONTRIBUTING.md ├── explainer.md └── index.html /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [80485] 3 | , "contacts": ["yoavweiss"] 4 | , "repo-type": "cg-report" 5 | } 6 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.html", 3 | "type": "respec", 4 | "params": { 5 | "force": 1 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors under the 2 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 3 | Contributions to Specifications are made under the [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 4 | -------------------------------------------------------------------------------- /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | jobs: 7 | main: 8 | name: Build, Validate, Deploy 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: w3c/spec-prod@v2 13 | with: 14 | GH_PAGES_BRANCH: gh-pages 15 | TOOLCHAIN: respec 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Secure Curves in the Web Cryptography API 2 | 3 | This repository contains a proposal to add support for [Curve25519 and 4 | Curve448](https://tools.ietf.org/html/rfc7748) in the Web Cryptography API. 5 | 6 | There is an [explainer](./explainer.md) and a [draft specification](https://WICG.github.io/webcrypto-secure-curves/). 7 | 8 | See the [implementation status](https://github.com/WICG/webcrypto-secure-curves/issues/20). 9 | 10 | Acknowledgement: this proposal was based on [a previous proposal by Qingsi Wang 11 | to include Curve25519 in WebCrypto](https://github.com/tQsW/webcrypto-curve25519). 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Secure Curves in the Web Cryptography API 2 | 3 | This repository is being used for work on Secure Curves in the W3C Web Cryptography API, governed by the [W3C Community License 4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions, 5 | you must join the [WICG](https://www.w3.org/community/wicg/). 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request comment. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | -------------------------------------------------------------------------------- /explainer.md: -------------------------------------------------------------------------------- 1 | # Secure Curves in WebCrypto 2 | 3 | ## Problem Statement 4 | 5 | The Web Cryptography API currently only specifies the [NIST P-256, P-384, and 6 | P-521 curves][nist-186-4], and does not specify any ["safe curves"][safecurves]. 7 | Among the safe curves, Curve25519 and Curve448 have gained the most traction, 8 | and have been specified for use in TLS 1.3, for example. They have also been 9 | [recommended][rfc7748] by the Crypto Forum Research Group (CFRG) of the Internet 10 | Research Task Force (IRTF), and are [expected to be approved by 11 | NIST][nist-186-5]. 12 | 13 | In addition, Node.js [has implemented][node-webcrypto] a nonstandard extension 14 | to Web Crypto, adding Curve25519 and Curve448 under a vendor-prefixed name. 15 | We would like to avoid other implementations doing the same, and encourage 16 | intercompatibility going forward by providing a standard specification. 17 | 18 | Today, web developers are getting around the unavailability of Curve25519 and 19 | Curve448 in the browser either by using less secure curves, or by including an 20 | implementation of Curve25519 and/or Curve448 in JavaScript or WebAssembly. In 21 | addition to wasting bandwidth shipping algorithms that are already included in 22 | browsers that implement TLS 1.3, this practice also has security implications, 23 | e.g. side-channel attacks as studied by [Daniel Genkin et al][key-extraction]. 24 | 25 | ## Support Curve25519 and Curve448 in the Web Cryptography API 26 | 27 | We solve the above problem by adding support for Curve25519 and Curve448 28 | algorithms in the Web Cryptography API, namely the signature algorithms 29 | [Ed25519 and Ed448][rfc8032], and the key agreement algorithms 30 | [X25519 and X448][rfc7748]. 31 | 32 | ## Alternatives Considered and Security Implications 33 | 34 | Shipping cryptographic algorithms in JavaScript or WebAssembly, including 35 | Curve25519 or Curve448, has been an alternative solution to using 36 | implementations provided by the browser. In addition to the vulnerability to 37 | side-channel attacks as noted in the problem statement, these alternatives are 38 | also potentially more susceptible to attacks like cross-site scripting, as the 39 | private key material must be available to JavaScript. An implementation in 40 | WebCrypto can solve this issue through the availability of non-extractable key 41 | handles (though applications should note that as a general security 42 | consideration in WebCrypto, a persistent oracle can be allowed if CryptoKey 43 | objects are shared between origins such as through the use of postMessage). 44 | 45 | Once the [constant-time proposal for WebAssembly][ct-wasm] is accepted and 46 | implemented, it will become possible to implement Curve25519 and/or Curve448 in 47 | WebAssembly while protecting against timing attacks. However, this still 48 | requires the private key material to be accessible to script, potentially 49 | exposing it to cross-site scripting and other attacks. In addition, the ready 50 | availability of Web Crypto, compared to a WebAssembly library, may encourage 51 | developers to continue to use the curves available in Web Crypto only. To 52 | encourage the use of modern and secure curves like Curve25519 and Curve448, we 53 | believe it would be good to implement them in Web Crypto. 54 | 55 | ## Supported algorithms 56 | 57 | ### Ed25519 and Ed448 58 | 59 | The following operations are supported with the recognized algorithm names 60 | "Ed25519" and "Ed448": 61 | 62 | 1. generateKey 63 | 2. sign 64 | 3. verify 65 | 4. importKey 66 | 5. exportKey 67 | 68 | ### X25519 and X448 69 | 70 | The following operations are supported with the recognized algorithm names 71 | "X25519" and "X448": 72 | 73 | 1. generateKey 74 | 2. deriveKey 75 | 3. deriveBits 76 | 4. importKey 77 | 5. exportKey 78 | 79 | ### Import and export formats 80 | 81 | For key serialization and deserialization, the supported formats include the raw 82 | format for public keys as an ArrayBuffer containing the raw bytes, as well as 83 | the SPKI format for public keys, the PKCS#8 format for private keys, and the JWK 84 | format for public and private keys. 85 | 86 | ## Code Examples 87 | 88 | ### Key generation 89 | 90 | ```js 91 | // Pass a string of the recognized algorithm name. 92 | const ed25519_key = await crypto.subtle.generateKey('Ed25519', 93 | true /* extractable */, ['sign', 'verify']); 94 | // Or pass an object with only the name property. 95 | const x25519_key = await crypto.subtle.generateKey({ name: 'X25519' }, 96 | true /* extractable */, ['deriveKey', 'deriveBits']); 97 | ``` 98 | 99 | ### Signing and verification using Ed25519 100 | 101 | ```js 102 | // Some message to be signed. 103 | const data = new TextEncoder().encode('Some message'); 104 | // Pass a string or an object with only the name property, as above. 105 | const signature = await crypto.subtle.sign('Ed25519', ed25519_key.privateKey, 106 | data); 107 | const verified = await crypto.subtle.verify('Ed25519', ed25519_key.publicKey, 108 | signature, data); 109 | ``` 110 | 111 | ### Signing and verification using Ed448 with a context 112 | 113 | ```js 114 | // Some message to be signed. 115 | const data = new TextEncoder().encode('Some message'); 116 | // Some context for the message, to provide domain separation. 117 | const context = new TextEncoder().encode('Some context'); 118 | // The context is optional, and defaults to the empty octet string. 119 | // If the context is not needed, the string 'Ed448' can be passed as well, 120 | // instead of an object. 121 | const signature = await crypto.subtle.sign( 122 | { name: 'Ed448', context }, ed448_key.privateKey, data); 123 | const verified = await crypto.subtle.verify( 124 | { name: 'Ed448', context }, ed448_key.publicKey, signature, data); 125 | ``` 126 | 127 | ### Key agreement using X25519 or X448 128 | 129 | ```js 130 | const private_x25519_key = x25519_key.privateKey; 131 | // Assume we received the peer's public key, |peer_public_x25519_key|. 132 | // 133 | // The key derivation parameters: 134 | // name, a string that should be set to 'X25519' or 'X448'. 135 | // public, a CryptoKey object representing the public key of the peer. 136 | const key_derive_params = { name: 'X25519', public: peer_public_x25519_key }; 137 | const result = await crypto.subtle.deriveBits( 138 | key_derive_params, private_x25519_key, 256 /* number of bits to derive */); 139 | ``` 140 | 141 | ### Export and import of keys 142 | 143 | ```js 144 | // An example using the raw format for X25519 public keys. 145 | const raw_public_key = 146 | await crypto.subtle.exportKey('raw', x25519_key.publicKey); 147 | // Pass a string or an object with only the name property, 148 | // which should be set to 'Ed25519', 'Ed448', 'X25519' or 'X448'. 149 | const result = await subtle.importKey('raw', raw_public_key, 'X25519', 150 | true /* extractable */, ['deriveKey', 'deriveBits']); 151 | 152 | // An example using the SPKI format. An example for the PKCS#8 format would be 153 | // similar. 154 | const spki_public_key = 155 | await crypto.subtle.exportKey('spki', x25519_key.publicKey); 156 | const result = await subtle.importKey('spki', spki_public_key, 'X25519', 157 | true /* extractable */, ['deriveKey', 'deriveBits']); 158 | 159 | // An example using the JWK format. 160 | const jwk_private_key = 161 | await crypto.subtle.exportKey('jwk', ed25519_key.privateKey); 162 | const result = await subtle.importKey( 163 | 'jwk', jwk_private_key, 'Ed25519', true /* extractable */, ['sign']); 164 | ``` 165 | 166 | ## References 167 | 168 | 1. [RFC 7748, Elliptic Curves for Security][rfc7748] 169 | 2. [RFC 8032, Edwards-Curve Digital Signature Algorithm (EdDSA)][rfc8032] 170 | 3. [FIPS 186-4: Digital Signature Standard (DSS)][nist-186-4] 171 | 4. [FIPS 186-5 (Draft): Digital Signature Standard (DSS)][nist-186-5] 172 | 5. [Daniel J. Bernstein and Tanja Lange, SafeCurves: choosing safe curves for elliptic-curve cryptography][safecurves] 173 | 6. [Daniel Genkin et al, Drive-By Key-Extraction Cache Attacks from Portable Code][key-extraction]. 174 | 7. [Node.js Web Crypto API][node-webcrypto] 175 | 8. [Constant-time Proposal for WebAssembly][ct-wasm] 176 | 177 | 178 | [rfc7748]: https://tools.ietf.org/html/rfc7748 179 | [rfc8032]: https://datatracker.ietf.org/doc/html/rfc8032 180 | [nist-186-4]: https://csrc.nist.gov/publications/detail/fips/186/4/final 181 | [nist-186-5]: https://csrc.nist.gov/publications/detail/fips/186/5/draft 182 | [safecurves]: https://safecurves.cr.yp.to/ 183 | [key-extraction]: https://www.cs.tau.ac.il/~tromer/drivebycache/ 184 | [node-webcrypto]: https://nodejs.org/api/webcrypto.html 185 | [ct-wasm]: https://github.com/WebAssembly/constant-time 186 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |38 | This specification defines a number of algorithms for the [[webcrypto | Web Cryptography API]], 39 | namely X25519 and X448 [[RFC7748]], and Ed25519 and Ed448 [[RFC8032]]. 40 |
41 |44 | This is an unofficial proposal. 45 |
46 |50 | The [[webcrypto | Web Cryptography API]] currently does not specify any "safe curves" [[SafeCurves]]. 51 | Among the safe curves, Curve25519 and Curve448 have gained the most traction, and 52 | have been specified for use in TLS 1.3, among others. This specification aims to 53 | expose these algorithms to the web platform. 54 | To this end, this specification defines a number of algorithms and operations for 55 | the [[webcrypto | Web Cryptography API]], namely key agreement using X25519 and X448 [[RFC7748]], and 56 | signing and verifying using Ed25519 and Ed448 [[RFC8032]]. 57 |
58 |62 | This specification follows the conventions 63 | laid out in Section 18.3 of [[webcrypto]]. None of the algorithms defined here 64 | are required to be implemented, but if a conforming User Agent implements an 65 | algorithm, it MUST implement all of the supported operations specified in this 66 | document, and must perform the steps to define an algorithm 67 | specified in section 18.4.3 of [[webcrypto]] for each of the supported operations. 68 |
69 |76 | The "`X25519`" algorithm identifier is used to perform 77 | key agreement using the X25519 algorithm specified in 78 | [[RFC7748]]. 79 |
80 |84 | The recognized algorithm name 85 | for this algorithm is "`X25519`". 86 |
87 || Operation | 91 |Parameters | 92 |Result | 93 |
|---|---|---|
| deriveBits | 98 |{{EcdhKeyDeriveParams}} | 99 |octet string | 100 |
| generateKey | 103 |None | 104 |{{CryptoKeyPair}} | 105 |
| importKey | 108 |None | 109 |{{CryptoKey}} | 110 |
| exportKey | 113 |None | 114 |object | 115 |
128 | If the [[\type]] internal slot of 129 | |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 130 |
131 |134 | Let |publicKey| be the 135 | {{EcdhKeyDeriveParams/public}} member of 136 | |normalizedAlgorithm|. 137 |
138 |141 | If the [[\type]] internal slot of 142 | |publicKey| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 143 |
144 |147 | If the {{KeyAlgorithm/name}} attribute of 148 | the [[\algorithm]] internal slot of 149 | |publicKey| is not equal to the {{KeyAlgorithm/name}} property of the [[\algorithm]] internal slot of 150 | |key|, then [= exception/throw =] an {{InvalidAccessError}}. 151 |
152 |155 | Let |secret| be the result of performing the X25519 function specified in 156 | [[RFC7748]] Section 5 with |key| as the X25519 private key |k| 157 | and the X25519 public key represented by the [[\handle]] 158 | internal slot of |publicKey| as the X25519 public key |u|. 159 |
160 |163 | If |secret| is the all-zero value, 164 | then [= exception/throw =] a {{OperationError}}. 165 | This check must be performed in constant-time, as per [[RFC7748]] Section 6.1. 166 |
167 |198 | If |usages| contains an entry which is not 199 | "`deriveKey`" or "`deriveBits`" 200 | then [= exception/throw =] a 201 | {{SyntaxError}}. 202 |
203 |206 | Generate an X25519 key pair, with the private key being 32 random bytes, 207 | and the public key being `X25519(a, 9)`, 208 | as defined in [[RFC7748]], section 6.1. 209 |
210 |213 | Let |algorithm| be a new {{KeyAlgorithm}} object. 214 |
215 |218 | Set the {{KeyAlgorithm/name}} attribute of 219 | |algorithm| to "`X25519`". 220 |
221 |224 | Let |publicKey| be a new {{CryptoKey}} associated with the 225 | [= relevant global object =] 226 | of `this` [[HTML]], and 227 | representing the public key of the generated key pair. 228 |
229 |232 | Set the [[\type]] internal slot of 233 | |publicKey| to "`public`" 234 |
235 |238 | Set the [[\algorithm]] internal 239 | slot of |publicKey| to |algorithm|. 240 |
241 |244 | Set the [[\extractable]] internal 245 | slot of |publicKey| to true. 246 |
247 |250 | Set the [[\usages]] internal slot of 251 | |publicKey| to be the empty list. 252 |
253 |256 | Let |privateKey| be a new {{CryptoKey}} associated with the 257 | [= relevant global object =] 258 | of `this` [[HTML]], and 259 | representing the private key of the generated key pair. 260 |
261 |264 | Set the [[\type]] internal slot of 265 | |privateKey| to {{KeyType/"private"}} 266 |
267 |270 | Set the [[\algorithm]] internal 271 | slot of |privateKey| to |algorithm|. 272 |
273 |276 | Set the [[\extractable]] internal 277 | slot of |privateKey| to |extractable|. 278 |
279 |282 | Set the [[\usages]] internal slot of 283 | |privateKey| to be the 284 | usage intersection of 285 | |usages| and `[ "deriveKey", "deriveBits" ]`. 286 |
287 |290 | Let |result| be a new {{CryptoKeyPair}} 291 | dictionary. 292 |
293 |296 | Set the {{CryptoKeyPair/publicKey}} attribute 297 | of |result| to be |publicKey|. 298 |
299 |302 | Set the {{CryptoKeyPair/privateKey}} attribute 303 | of |result| to be |privateKey|. 304 |
305 |308 | Return the result of converting |result| to an ECMAScript Object, as 309 | defined by [[WebIDL]]. 310 |
311 |Let |keyData| be the key data to be imported.
320 |328 | If |usages| is not empty 329 | then [= exception/throw =] a 330 | {{SyntaxError}}. 331 |
332 |335 | Let |spki| be the result of running the 336 | parse a subjectPublicKeyInfo 337 | algorithm over |keyData|. 338 |
339 |342 | If an error occurred while parsing, 343 | then [= exception/throw =] a 344 | {{DataError}}. 345 |
346 |349 | If the `algorithm` object identifier field of the 350 | `algorithm` AlgorithmIdentifier field of |spki| is 351 | not equal to the `id-X25519` 352 | object identifier defined in [[RFC8410]], 353 | then [= exception/throw =] a 354 | {{DataError}}. 355 |
356 |359 | If the `parameters` field of the `algorithm` 360 | AlgorithmIdentifier field of |spki| is present, 361 | then [= exception/throw =] a 362 | {{DataError}}. 363 |
364 |367 | Let |publicKey| be the X25519 public key identified by 368 | the `subjectPublicKey` field of |spki|. 369 |
370 |373 | Let |key| be a new {{CryptoKey}} associated with the 374 | [= relevant global object =] 375 | of `this` [[HTML]], and 376 | that represents |publicKey|. 377 |
378 |381 | Set the [[\type]] internal slot 382 | of |key| to "`public`" 383 |
384 |387 | Let |algorithm| be a new {{KeyAlgorithm}}. 388 |
389 |392 | Set the {{KeyAlgorithm/name}} attribute of 393 | |algorithm| to "`X25519`". 394 |
395 |398 | Set the [[\algorithm]] 399 | internal slot of |key| to |algorithm|. 400 |
401 |409 | If |usages| contains an entry which is not 410 | "`deriveKey`" or "`deriveBits`" 411 | then [= exception/throw =] a 412 | {{SyntaxError}}. 413 |
414 |417 | Let |privateKeyInfo| be the result of running the 418 | parse a privateKeyInfo 419 | algorithm over |keyData|. 420 |
421 |424 | If an error occurs while parsing, 425 | then [= exception/throw =] a 426 | {{DataError}}. 427 |
428 |431 | If the `algorithm` object identifier field of the 432 | `privateKeyAlgorithm` PrivateKeyAlgorithm field of 433 | |privateKeyInfo| is not equal to the 434 | `id-X25519` object identifier defined in [[RFC8410]], 435 | then [= exception/throw =] a 436 | {{DataError}}. 437 |
438 |441 | If the `parameters` field of the 442 | `privateKeyAlgorithm` PrivateKeyAlgorithmIdentifier field 443 | of |privateKeyInfo| is present, 444 | then [= exception/throw =] a 445 | {{DataError}}. 446 |
447 |450 | Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure 451 | algorithm, with |data| as the `privateKey` field 452 | of |privateKeyInfo|, |structure| as the ASN.1 453 | `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. 454 |
455 |458 | If an error occurred while parsing, 459 | then [= exception/throw =] a 460 | {{DataError}}. 461 |
462 |465 | Let |key| be a new {{CryptoKey}} associated with the 466 | [= relevant global object =] 467 | of `this` [[HTML]], and 468 | that represents the X25519 private key identified by |curvePrivateKey|. 469 |
470 |473 | Set the [[\type]] internal slot 474 | of |key| to {{KeyType/"private"}} 475 |
476 |479 | Let |algorithm| be a new {{KeyAlgorithm}}. 480 |
481 |484 | Set the {{KeyAlgorithm/name}} attribute of 485 | |algorithm| to "`X25519`". 486 |
487 |490 | Set the [[\algorithm]] 491 | internal slot of |key| to |algorithm|. 492 |
493 |Let |jwk| equal |keyData|.
[= exception/Throw =] a {{DataError}}.
509 | If the {{JsonWebKey/d}} field is present and if |usages| 510 | contains an entry which is not 511 | "`deriveKey`" or "`deriveBits`" 512 | then [= exception/throw =] a 513 | {{SyntaxError}}. 514 |
515 |518 | If the {{JsonWebKey/d}} field is not present and if |usages| is not 519 | empty 520 | then [= exception/throw =] a 521 | {{SyntaxError}}. 522 |
523 |526 | If the {{JsonWebKey/kty}} field of |jwk| is not 527 | "`OKP`", 528 | then [= exception/throw =] a 529 | {{DataError}}. 530 |
531 |534 | If the {{JsonWebKey/crv}} field of |jwk| is not 535 | "`X25519`", 536 | then [= exception/throw =] a 537 | {{DataError}}. 538 |
539 |542 | If |usages| is non-empty and the {{JsonWebKey/use}} field of |jwk| is present 543 | and is not equal to "`enc`" then [= exception/throw =] a 544 | {{DataError}}. 545 |
546 |549 | If the {{JsonWebKey/key_ops}} field of |jwk| is present, and 550 | is invalid according to the requirements of JSON Web 551 | Key [[JWK]], or it does not contain all of the specified |usages| 552 | values, 553 | then [= exception/throw =] a 554 | {{DataError}}. 555 |
556 |559 | If the {{JsonWebKey/ext}} field of |jwk| is present and 560 | has the value false and |extractable| is true, 561 | then [= exception/throw =] a 562 | {{DataError}}. 563 |
564 |572 | If |jwk| does not meet the requirements of 573 | the JWK private key format described in Section 2 574 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 575 |
576 |579 | Let |key| be a new {{CryptoKey}} object that represents the 580 | X25519 private key identified by interpreting 581 | |jwk| according to Section 2 of [[RFC8037]]. 582 |
583 |586 | Set the [[\type]] 587 | internal slot of |Key| to {{KeyType/"private"}}. 588 |
589 |597 | If |jwk| does not meet the requirements of 598 | the JWK public key format described in Section 2 599 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 600 |
601 |604 | Let |key| be a new {{CryptoKey}} object that represents the 605 | X25519 public key identified by interpreting 606 | |jwk| according to Section 2 of [[RFC8037]]. 607 |
608 |611 | Set the [[\type]] 612 | internal slot of |Key| to {{KeyType/"public"}}. 613 |
614 |621 | Let |algorithm| be a new instance of a {{KeyAlgorithm}} object. 622 |
623 |626 | Set the {{KeyAlgorithm/name}} attribute of 627 | |algorithm| to "`X25519`". 628 |
629 |632 | Set the [[\algorithm]] 633 | internal slot of |key| to |algorithm|. 634 |
635 |643 | If |usages| is not empty 644 | then [= exception/throw =] a 645 | {{SyntaxError}}. 646 |
647 |650 | Let |data| be |keyData|. 651 |
652 |655 | If the length in bits of |data| is not 256 then [= exception/throw =] a {{DataError}}. 656 |
657 |660 | Let |algorithm| be a new {{KeyAlgorithm}} object. 661 |
662 |665 | Set the {{KeyAlgorithm/name}} attribute of 666 | |algorithm| to "`X25519`". 667 |
668 |671 | Let |key| be a new {{CryptoKey}} associated with the 672 | [= relevant global object =] 673 | of `this` [[HTML]], and that represents |data|. 674 |
675 |678 | Set the [[\type]] internal slot 679 | of |key| to "`public`" 680 |
681 |684 | Set the [[\algorithm]] 685 | internal slot of |key| to |algorithm|. 686 |
687 |693 | [= exception/throw =] a 694 | {{NotSupportedError}}. 695 |
696 |701 | Return |key| 702 |
703 |712 | Let |key| be the {{CryptoKey}} to be 713 | exported. 714 |
715 |718 | If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| 719 | cannot be accessed, then [= exception/throw =] an {{OperationError}}. 720 |
721 |729 | If the [[\type]] internal slot 730 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 731 |
732 |735 | Let |data| be an instance of the `subjectPublicKeyInfo` 736 | ASN.1 structure defined in [[RFC5280]] 737 | with the following properties: 738 |
739 |742 | Set the |algorithm| field to an 743 | `AlgorithmIdentifier` ASN.1 type with the following 744 | properties: 745 |
746 |749 | Set the |algorithm| object identifier to the 750 | `id-X25519` OID defined in [[RFC8410]]. 751 |
752 |757 | Set the |subjectPublicKey| field to |keyData|. 758 |
759 |764 | Let |result| be a new {{ArrayBuffer}} associated with the 765 | [= relevant global object =] 766 | of `this` [[HTML]], and containing 767 | |data|. 768 |
769 |777 | If the [[\type]] internal slot 778 | of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 779 |
780 |783 | Let |data| be an instance of the `privateKeyInfo` 784 | ASN.1 structure defined in [[RFC5208]] 785 | with the following properties: 786 |
787 |790 | Set the |version| field to `0`. 791 |
792 |795 | Set the |privateKeyAlgorithm| field to a 796 | `PrivateKeyAlgorithmIdentifier` ASN.1 type with the 797 | following properties: 798 |
799 |802 | Set the |algorithm| object identifier to the 803 | `id-X25519` OID defined in [[RFC8410]]. 804 |
805 |810 | Set the |privateKey| field to the result of DER-encoding 811 | a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the 812 | X25519 private key represented by the [[\handle]] internal slot of 813 | |key| 814 |
815 |820 | Let |result| be a new {{ArrayBuffer}} associated with the 821 | [= relevant global object =] 822 | of `this` [[HTML]], and containing 823 | |data|. 824 |
825 |833 | Let |jwk| be a new {{JsonWebKey}} 834 | dictionary. 835 |
836 |839 | Set the `kty` attribute of |jwk| to 840 | "`OKP`". 841 |
842 |845 | Set the `crv` attribute of |jwk| to 846 | "`X25519`". 847 |
848 |851 | Set the {{JsonWebKey/x}} attribute of |jwk| according to the 852 | definition in Section 2 of [[RFC8037]]. 853 |
854 |869 | Set the `key_ops` attribute of |jwk| to the {{CryptoKey/usages}} attribute of |key|. 870 |
871 |874 | Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot 875 | of |key|. 876 |
877 |880 | Let |result| be the result of converting |jwk| 881 | to an ECMAScript Object, as defined by [[WebIDL]]. 882 |
883 |893 | If the [[\type]] internal slot 894 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 895 |
896 |899 | Let |data| be an octet string representing the X25519 900 | public key represented by the [[\handle]] internal slot of 901 | |key|. 902 |
903 |906 | Let |result| be a new {{ArrayBuffer}} associated with the 907 | [= relevant global object =] 908 | of `this` [[HTML]], and containing 909 | |data|. 910 |
911 |917 | [= exception/throw =] a 918 | {{NotSupportedError}}. 919 |
920 |925 | Return |result|. 926 |
927 |939 | The "`X448`" algorithm identifier is used to perform 940 | key agreement using the X448 algorithm specified in 941 | [[RFC7748]]. 942 |
943 |947 | The recognized algorithm name 948 | for this algorithm is "`X448`". 949 |
950 || Operation | 954 |Parameters | 955 |Result | 956 |
|---|---|---|
| deriveBits | 961 |{{EcdhKeyDeriveParams}} | 962 |octet string | 963 |
| generateKey | 966 |None | 967 |{{CryptoKeyPair}} | 968 |
| importKey | 971 |None | 972 |{{CryptoKey}} | 973 |
| exportKey | 976 |None | 977 |object | 978 |
991 | If the [[\type]] internal slot of 992 | |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 993 |
994 |997 | Let |publicKey| be the 998 | {{EcdhKeyDeriveParams/public}} member of 999 | |normalizedAlgorithm|. 1000 |
1001 |1004 | If the [[\type]] internal slot of 1005 | |publicKey| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 1006 |
1007 |1010 | If the {{KeyAlgorithm/name}} attribute of 1011 | the [[\algorithm]] internal slot of 1012 | |publicKey| is not equal to the {{KeyAlgorithm/name}} property of the [[\algorithm]] internal slot of 1013 | |key|, then [= exception/throw =] an {{InvalidAccessError}}. 1014 |
1015 |1018 | Let |secret| be the result of performing the X448 function specified in 1019 | [[RFC7748]] Section 5 with |key| as the X448 private key |k| 1020 | and the X448 public key represented by the [[\handle]] 1021 | internal slot of |publicKey| as the X448 public key |u|. 1022 |
1023 |1026 | If |secret| is the all-zero value, 1027 | then [= exception/throw =] a {{OperationError}}. 1028 | This check must be performed in constant-time, as per [[RFC7748]] Section 6.2. 1029 |
1030 |1061 | If |usages| contains an entry which is not 1062 | "`deriveKey`" or "`deriveBits`" 1063 | then [= exception/throw =] a 1064 | {{SyntaxError}}. 1065 |
1066 |1069 | Generate an X448 key pair, with the private key being 56 random bytes, 1070 | and the public key being `X448(a, 5)`, 1071 | as defined in [[RFC7748]], section 6.2. 1072 |
1073 |1076 | Let |algorithm| be a new {{KeyAlgorithm}} object. 1077 |
1078 |1081 | Set the {{KeyAlgorithm/name}} attribute of 1082 | |algorithm| to "`X448`". 1083 |
1084 |1087 | Let |publicKey| be a new {{CryptoKey}} associated with the 1088 | [= relevant global object =] 1089 | of `this` [[HTML]], and 1090 | representing the public key of the generated key pair. 1091 |
1092 |1095 | Set the [[\type]] internal slot of 1096 | |publicKey| to "`public`" 1097 |
1098 |1101 | Set the [[\algorithm]] internal 1102 | slot of |publicKey| to |algorithm|. 1103 |
1104 |1107 | Set the [[\extractable]] internal 1108 | slot of |publicKey| to true. 1109 |
1110 |1113 | Set the [[\usages]] internal slot of 1114 | |publicKey| to be the empty list. 1115 |
1116 |1119 | Let |privateKey| be a new {{CryptoKey}} associated with the 1120 | [= relevant global object =] 1121 | of `this` [[HTML]], and 1122 | representing the private key of the generated key pair. 1123 |
1124 |1127 | Set the [[\type]] internal slot of 1128 | |privateKey| to {{KeyType/"private"}} 1129 |
1130 |1133 | Set the [[\algorithm]] internal 1134 | slot of |privateKey| to |algorithm|. 1135 |
1136 |1139 | Set the [[\extractable]] internal 1140 | slot of |privateKey| to |extractable|. 1141 |
1142 |1145 | Set the [[\usages]] internal slot of 1146 | |privateKey| to be the 1147 | usage intersection of 1148 | |usages| and `[ "deriveKey", "deriveBits" ]`. 1149 |
1150 |1153 | Let |result| be a new {{CryptoKeyPair}} 1154 | dictionary. 1155 |
1156 |1159 | Set the {{CryptoKeyPair/publicKey}} attribute 1160 | of |result| to be |publicKey|. 1161 |
1162 |1165 | Set the {{CryptoKeyPair/privateKey}} attribute 1166 | of |result| to be |privateKey|. 1167 |
1168 |1171 | Return the result of converting |result| to an ECMAScript Object, as 1172 | defined by [[WebIDL]]. 1173 |
1174 |Let |keyData| be the key data to be imported.
1183 |1191 | If |usages| is not empty 1192 | then [= exception/throw =] a 1193 | {{SyntaxError}}. 1194 |
1195 |1198 | Let |spki| be the result of running the 1199 | parse a subjectPublicKeyInfo 1200 | algorithm over |keyData|. 1201 |
1202 |1205 | If an error occurred while parsing, 1206 | then [= exception/throw =] a 1207 | {{DataError}}. 1208 |
1209 |1212 | If the `algorithm` object identifier field of the 1213 | `algorithm` AlgorithmIdentifier field of |spki| is 1214 | not equal to the `id-X448` 1215 | object identifier defined in [[RFC8410]], 1216 | then [= exception/throw =] a 1217 | {{DataError}}. 1218 |
1219 |1222 | If the `parameters` field of the `algorithm` 1223 | AlgorithmIdentifier field of |spki| is present, 1224 | then [= exception/throw =] a 1225 | {{DataError}}. 1226 |
1227 |1230 | Let |publicKey| be the X448 public key identified by 1231 | the `subjectPublicKey` field of |spki|. 1232 |
1233 |1236 | Let |key| be a new {{CryptoKey}} associated with the 1237 | [= relevant global object =] 1238 | of `this` [[HTML]], and 1239 | that represents |publicKey|. 1240 |
1241 |1244 | Set the [[\type]] internal slot 1245 | of |key| to "`public`" 1246 |
1247 |1250 | Let |algorithm| be a new {{KeyAlgorithm}}. 1251 |
1252 |1255 | Set the {{KeyAlgorithm/name}} attribute of 1256 | |algorithm| to "`X448`". 1257 |
1258 |1261 | Set the [[\algorithm]] 1262 | internal slot of |key| to |algorithm|. 1263 |
1264 |1272 | If |usages| contains an entry which is not 1273 | "`deriveKey`" or "`deriveBits`" 1274 | then [= exception/throw =] a 1275 | {{SyntaxError}}. 1276 |
1277 |1280 | Let |privateKeyInfo| be the result of running the 1281 | parse a privateKeyInfo 1282 | algorithm over |keyData|. 1283 |
1284 |1287 | If an error occurs while parsing, 1288 | then [= exception/throw =] a 1289 | {{DataError}}. 1290 |
1291 |1294 | If the `algorithm` object identifier field of the 1295 | `privateKeyAlgorithm` PrivateKeyAlgorithm field of 1296 | |privateKeyInfo| is not equal to the 1297 | `id-X448` object identifier defined in [[RFC8410]], 1298 | then [= exception/throw =] a 1299 | {{DataError}}. 1300 |
1301 |1304 | If the `parameters` field of the 1305 | `privateKeyAlgorithm` PrivateKeyAlgorithmIdentifier field 1306 | of |privateKeyInfo| is present, 1307 | then [= exception/throw =] a 1308 | {{DataError}}. 1309 |
1310 |1313 | Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure 1314 | algorithm, with |data| as the `privateKey` field 1315 | of |privateKeyInfo|, |structure| as the ASN.1 1316 | `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. 1317 |
1318 |1321 | If an error occurred while parsing, 1322 | then [= exception/throw =] a 1323 | {{DataError}}. 1324 |
1325 |1328 | Let |key| be a new {{CryptoKey}} associated with the 1329 | [= relevant global object =] 1330 | of `this` [[HTML]], and 1331 | that represents the X448 private key identified by |curvePrivateKey|. 1332 |
1333 |1336 | Set the [[\type]] internal slot 1337 | of |key| to {{KeyType/"private"}} 1338 |
1339 |1342 | Let |algorithm| be a new {{KeyAlgorithm}}. 1343 |
1344 |1347 | Set the {{KeyAlgorithm/name}} attribute of 1348 | |algorithm| to "`X448`". 1349 |
1350 |1353 | Set the [[\algorithm]] 1354 | internal slot of |key| to |algorithm|. 1355 |
1356 |Let |jwk| equal |keyData|.
[= exception/Throw =] a {{DataError}}.
1372 | If the {{JsonWebKey/d}} field is present and if |usages| 1373 | contains an entry which is not 1374 | "`deriveKey`" or "`deriveBits`" 1375 | then [= exception/throw =] a 1376 | {{SyntaxError}}. 1377 |
1378 |1381 | If the {{JsonWebKey/d}} field is not present and if |usages| is not 1382 | empty 1383 | then [= exception/throw =] a 1384 | {{SyntaxError}}. 1385 |
1386 |1389 | If the {{JsonWebKey/kty}} field of |jwk| is not 1390 | "`OKP`", 1391 | then [= exception/throw =] a 1392 | {{DataError}}. 1393 |
1394 |1397 | If the {{JsonWebKey/crv}} field of |jwk| is not 1398 | "`X448`", 1399 | then [= exception/throw =] a 1400 | {{DataError}}. 1401 |
1402 |1405 | If |usages| is non-empty and the {{JsonWebKey/use}} field of |jwk| is present 1406 | and is not equal to "`enc`" then [= exception/throw =] a 1407 | {{DataError}}. 1408 |
1409 |1412 | If the {{JsonWebKey/key_ops}} field of |jwk| is present, and 1413 | is invalid according to the requirements of JSON Web 1414 | Key [[JWK]], or it does not contain all of the specified |usages| 1415 | values, 1416 | then [= exception/throw =] a 1417 | {{DataError}}. 1418 |
1419 |1422 | If the {{JsonWebKey/ext}} field of |jwk| is present and 1423 | has the value false and |extractable| is true, 1424 | then [= exception/throw =] a 1425 | {{DataError}}. 1426 |
1427 |1435 | If |jwk| does not meet the requirements of 1436 | the JWK private key format described in Section 2 1437 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 1438 |
1439 |1442 | Let |key| be a new {{CryptoKey}} object that represents the 1443 | X448 private key identified by interpreting 1444 | |jwk| according to Section 2 of [[RFC8037]]. 1445 |
1446 |1449 | Set the [[\type]] 1450 | internal slot of |Key| to {{KeyType/"private"}}. 1451 |
1452 |1460 | If |jwk| does not meet the requirements of 1461 | the JWK public key format described in Section 2 1462 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 1463 |
1464 |1467 | Let |key| be a new {{CryptoKey}} object that represents the 1468 | X448 public key identified by interpreting 1469 | |jwk| according to Section 2 of [[RFC8037]]. 1470 |
1471 |1474 | Set the [[\type]] 1475 | internal slot of |Key| to {{KeyType/"public"}}. 1476 |
1477 |1484 | Let |algorithm| be a new instance of a {{KeyAlgorithm}} object. 1485 |
1486 |1489 | Set the {{KeyAlgorithm/name}} attribute of 1490 | |algorithm| to "`X448`". 1491 |
1492 |1495 | Set the [[\algorithm]] 1496 | internal slot of |key| to |algorithm|. 1497 |
1498 |1506 | If |usages| is not empty 1507 | then [= exception/throw =] a 1508 | {{SyntaxError}}. 1509 |
1510 |1513 | Let |data| be |keyData|. 1514 |
1515 |1518 | If the length in bits of |data| is not 448 then [= exception/throw =] a {{DataError}}. 1519 |
1520 |1523 | Let |algorithm| be a new {{KeyAlgorithm}} object. 1524 |
1525 |1528 | Set the {{KeyAlgorithm/name}} attribute of 1529 | |algorithm| to "`X448`". 1530 |
1531 |1534 | Let |key| be a new {{CryptoKey}} associated with the 1535 | [= relevant global object =] 1536 | of `this` [[HTML]], and that represents |data|. 1537 |
1538 |1541 | Set the [[\type]] internal slot 1542 | of |key| to "`public`" 1543 |
1544 |1547 | Set the [[\algorithm]] 1548 | internal slot of |key| to |algorithm|. 1549 |
1550 |1556 | [= exception/throw =] a 1557 | {{NotSupportedError}}. 1558 |
1559 |1564 | Return |key| 1565 |
1566 |1575 | Let |key| be the {{CryptoKey}} to be 1576 | exported. 1577 |
1578 |1581 | If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| 1582 | cannot be accessed, then [= exception/throw =] an {{OperationError}}. 1583 |
1584 |1592 | If the [[\type]] internal slot 1593 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 1594 |
1595 |1598 | Let |data| be an instance of the `subjectPublicKeyInfo` 1599 | ASN.1 structure defined in [[RFC5280]] 1600 | with the following properties: 1601 |
1602 |1605 | Set the |algorithm| field to an 1606 | `AlgorithmIdentifier` ASN.1 type with the following 1607 | properties: 1608 |
1609 |1612 | Set the |algorithm| object identifier to the 1613 | `id-X448` OID defined in [[RFC8410]]. 1614 |
1615 |1620 | Set the |subjectPublicKey| field to |keyData|. 1621 |
1622 |1627 | Let |result| be a new {{ArrayBuffer}} associated with the 1628 | [= relevant global object =] 1629 | of `this` [[HTML]], and containing 1630 | |data|. 1631 |
1632 |1640 | If the [[\type]] internal slot 1641 | of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 1642 |
1643 |1646 | Let |data| be an instance of the `privateKeyInfo` 1647 | ASN.1 structure defined in [[RFC5208]] 1648 | with the following properties: 1649 |
1650 |1653 | Set the |version| field to `0`. 1654 |
1655 |1658 | Set the |privateKeyAlgorithm| field to a 1659 | `PrivateKeyAlgorithmIdentifier` ASN.1 type with the 1660 | following properties: 1661 |
1662 |1665 | Set the |algorithm| object identifier to the 1666 | `id-X448` OID defined in [[RFC8410]]. 1667 |
1668 |1673 | Set the |privateKey| field to the result of DER-encoding 1674 | a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the 1675 | X448 private key represented by the [[\handle]] internal slot of 1676 | |key| 1677 |
1678 |1683 | Let |result| be a new {{ArrayBuffer}} associated with the 1684 | [= relevant global object =] 1685 | of `this` [[HTML]], and containing 1686 | |data|. 1687 |
1688 |1696 | Let |jwk| be a new {{JsonWebKey}} 1697 | dictionary. 1698 |
1699 |1702 | Set the `kty` attribute of |jwk| to 1703 | "`OKP`". 1704 |
1705 |1708 | Set the `crv` attribute of |jwk| to 1709 | "`X448`". 1710 |
1711 |1714 | Set the {{JsonWebKey/x}} attribute of |jwk| according to the 1715 | definition in Section 2 of [[RFC8037]]. 1716 |
1717 |1732 | Set the `key_ops` attribute of |jwk| to the {{CryptoKey/usages}} attribute of |key|. 1733 |
1734 |1737 | Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot 1738 | of |key|. 1739 |
1740 |1743 | Let |result| be the result of converting |jwk| 1744 | to an ECMAScript Object, as defined by [[WebIDL]]. 1745 |
1746 |1756 | If the [[\type]] internal slot 1757 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 1758 |
1759 |1762 | Let |data| be an octet string representing the X448 1763 | public key represented by the [[\handle]] internal slot of 1764 | |key|. 1765 |
1766 |1769 | Let |result| be a new {{ArrayBuffer}} associated with the 1770 | [= relevant global object =] 1771 | of `this` [[HTML]], and containing 1772 | |data|. 1773 |
1774 |1780 | [= exception/throw =] a 1781 | {{NotSupportedError}}. 1782 |
1783 |1788 | Return |result|. 1789 |
1790 |1802 | The "`Ed25519`" algorithm identifier is used to perform signing 1803 | and verification using the Ed25519 algorithm specified in 1804 | [[RFC8032]]. 1805 |
1806 |1810 | The recognized algorithm name 1811 | for this algorithm is "`Ed25519`". 1812 |
1813 || Operation | 1817 |Parameters | 1818 |Result | 1819 |
|---|---|---|
| sign | 1824 |None | 1825 |{{ArrayBuffer}} | 1826 |
| verify | 1829 |None | 1830 |boolean | 1831 |
| generateKey | 1834 |None | 1835 |{{CryptoKeyPair}} | 1836 |
| importKey | 1839 |None | 1840 |{{CryptoKey}} | 1841 |
| exportKey | 1844 |None | 1845 |object | 1846 |
1860 | If the [[\type]] internal slot of 1861 | |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 1862 |
1863 |1866 | Perform the Ed25519 signing process, as specified in [[RFC8032]], 1867 | Section 5.1.6, with |message| as |M|, 1868 | using the Ed25519 private key associated with |key|. 1869 |
1870 |1871 | Some implementations may (wish to) generate randomized signatures 1872 | as per draft-irtf-cfrg-det-sigs-with-noise 1873 | instead of deterministic signatures as per [[RFC8032]]. 1874 |
1875 |1878 | Return a new {{ArrayBuffer}} associated with the 1879 | [= relevant global object =] 1880 | of `this` [[HTML]], and containing the 1881 | bytes of the signature resulting from performing 1882 | the Ed25519 signing process. 1883 |
1884 |1893 | If the [[\type]] internal slot of 1894 | |key| is not {{KeyType/"public"}}, then [= exception/throw =] an {{InvalidAccessError}}. 1895 |
1896 |1899 | If the key data of |key| represents an invalid point or a small-order element 1900 | on the Elliptic Curve of Ed25519, return `false`. 1901 |
1902 |1903 | Not all implementations perform this check. 1904 |
1905 |1908 | If the point R, encoded in the first half of |signature|, 1909 | represents an invalid point or a small-order element 1910 | on the Elliptic Curve of Ed25519, return `false`. 1911 |
1912 |1913 | Not all implementations perform this check. 1914 |
1915 |1918 | Perform the Ed25519 verification steps, as specified in [[RFC8032]], 1919 | Section 5.1.7, using the cofactorless (unbatched) equation, 1920 | `[S]B = R + [k]A'`, on the |signature|, with |message| as |M|, 1921 | using the Ed25519 public key associated with |key|. 1922 |
1923 |1926 | Let |result| be a boolean with the value `true` if the signature is valid 1927 | and the value `false` otherwise. 1928 |
1929 |1932 | Return |result|. 1933 |
1934 |1942 | If |usages| contains a value which is not 1943 | one of "`sign`" or "`verify`", 1944 | then [= exception/throw =] a 1945 | {{SyntaxError}}. 1946 |
1947 |1950 | Generate an Ed25519 key pair, as defined in [[RFC8032]], section 5.1.5. 1951 |
1952 |1955 | Let |algorithm| be a new {{KeyAlgorithm}} object. 1956 |
1957 |1960 | Set the {{KeyAlgorithm/name}} attribute of 1961 | |algorithm| to "`Ed25519`". 1962 |
1963 |1966 | Let |publicKey| be a new {{CryptoKey}} associated with the 1967 | [= relevant global object =] 1968 | of `this` [[HTML]], and 1969 | representing the public key of the generated key pair. 1970 |
1971 |1974 | Set the [[\type]] internal slot of 1975 | |publicKey| to "`public`" 1976 |
1977 |1980 | Set the [[\algorithm]] internal 1981 | slot of |publicKey| to |algorithm|. 1982 |
1983 |1986 | Set the [[\extractable]] internal 1987 | slot of |publicKey| to true. 1988 |
1989 |1992 | Set the [[\usages]] internal slot of 1993 | |publicKey| to be the usage intersection 1994 | of |usages| and `[ "verify" ]`. 1995 |
1996 |1999 | Let |privateKey| be a new {{CryptoKey}} associated with the 2000 | [= relevant global object =] 2001 | of `this` [[HTML]], and 2002 | representing the private key of the generated key pair. 2003 |
2004 |2007 | Set the [[\type]] internal slot of 2008 | |privateKey| to {{KeyType/"private"}} 2009 |
2010 |2013 | Set the [[\algorithm]] internal 2014 | slot of |privateKey| to |algorithm|. 2015 |
2016 |2019 | Set the [[\extractable]] internal 2020 | slot of |privateKey| to |extractable|. 2021 |
2022 |2025 | Set the [[\usages]] internal slot of 2026 | |privateKey| to be the usage intersection 2027 | of |usages| and `[ "sign" ]`. 2028 |
2029 |2032 | Let |result| be a new {{CryptoKeyPair}} 2033 | dictionary. 2034 |
2035 |2038 | Set the {{CryptoKeyPair/publicKey}} attribute 2039 | of |result| to be |publicKey|. 2040 |
2041 |2044 | Set the {{CryptoKeyPair/privateKey}} attribute 2045 | of |result| to be |privateKey|. 2046 |
2047 |2050 | Return the result of converting |result| to an ECMAScript Object, as 2051 | defined by [[WebIDL]]. 2052 |
2053 |Let |keyData| be the key data to be imported.
2062 |2070 | If |usages| contains a value which is not 2071 | "`verify`" 2072 | then [= exception/throw =] a 2073 | {{SyntaxError}}. 2074 |
2075 |2078 | Let |spki| be the result of running the 2079 | parse a subjectPublicKeyInfo 2080 | algorithm over |keyData|. 2081 |
2082 |2085 | If an error occurred while parsing, 2086 | then [= exception/throw =] a 2087 | {{DataError}}. 2088 |
2089 |2092 | If the `algorithm` object identifier field of the 2093 | `algorithm` AlgorithmIdentifier field of |spki| is 2094 | not equal to the `id-Ed25519` 2095 | object identifier defined in [[RFC8410]], 2096 | then [= exception/throw =] a 2097 | {{DataError}}. 2098 |
2099 |2102 | If the `parameters` field of the `algorithm` 2103 | AlgorithmIdentifier field of |spki| is present, 2104 | then [= exception/throw =] a 2105 | {{DataError}}. 2106 |
2107 |2110 | Let |publicKey| be the Ed25519 public key identified by 2111 | the `subjectPublicKey` field of |spki|. 2112 |
2113 |2116 | Let |key| be a new {{CryptoKey}} associated with the 2117 | [= relevant global object =] 2118 | of `this` [[HTML]], and 2119 | that represents |publicKey|. 2120 |
2121 |2124 | Set the [[\type]] internal slot 2125 | of |key| to "`public`" 2126 |
2127 |2130 | Let |algorithm| be a new {{KeyAlgorithm}}. 2131 |
2132 |2135 | Set the {{KeyAlgorithm/name}} attribute of 2136 | |algorithm| to "`Ed25519`". 2137 |
2138 |2141 | Set the [[\algorithm]] 2142 | internal slot of |key| to |algorithm|. 2143 |
2144 |2152 | If |usages| contains a value which is not 2153 | "`sign`" 2154 | then [= exception/throw =] a 2155 | {{SyntaxError}}. 2156 |
2157 |2160 | Let |privateKeyInfo| be the result of running the 2161 | parse a privateKeyInfo 2162 | algorithm over |keyData|. 2163 |
2164 |2167 | If an error occurs while parsing, 2168 | then [= exception/throw =] a 2169 | {{DataError}}. 2170 |
2171 |2174 | If the `algorithm` object identifier field of the 2175 | `privateKeyAlgorithm` PrivateKeyAlgorithm field of 2176 | |privateKeyInfo| is not equal to the 2177 | `id-Ed25519` object identifier defined in [[RFC8410]], 2178 | then [= exception/throw =] a 2179 | {{DataError}}. 2180 |
2181 |2184 | If the `parameters` field of the 2185 | `privateKeyAlgorithm` PrivateKeyAlgorithmIdentifier field 2186 | of |privateKeyInfo| is present, 2187 | then [= exception/throw =] a 2188 | {{DataError}}. 2189 |
2190 |2193 | Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure 2194 | algorithm, with |data| as the `privateKey` field 2195 | of |privateKeyInfo|, |structure| as the ASN.1 2196 | `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. 2197 |
2198 |2201 | If an error occurred while parsing, 2202 | then [= exception/throw =] a 2203 | {{DataError}}. 2204 |
2205 |2208 | Let |key| be a new {{CryptoKey}} associated with the 2209 | [= relevant global object =] 2210 | of `this` [[HTML]], and 2211 | that represents the Ed25519 private key identified by |curvePrivateKey|. 2212 |
2213 |2216 | Set the [[\type]] internal slot 2217 | of |key| to {{KeyType/"private"}} 2218 |
2219 |2222 | Let |algorithm| be a new {{KeyAlgorithm}}. 2223 |
2224 |2227 | Set the {{KeyAlgorithm/name}} attribute of 2228 | |algorithm| to "`Ed25519`". 2229 |
2230 |2233 | Set the [[\algorithm]] 2234 | internal slot of |key| to |algorithm|. 2235 |
2236 |Let |jwk| equal |keyData|.
[= exception/Throw =] a {{DataError}}.
2252 | If the {{JsonWebKey/d}} field is present and |usages| contains 2253 | a value which is not 2254 | "`sign`", or, 2255 | if the {{JsonWebKey/d}} field is not present and |usages| contains 2256 | a value which is not 2257 | "`verify`" 2258 | then [= exception/throw =] a 2259 | {{SyntaxError}}. 2260 |
2261 |2264 | If the {{JsonWebKey/kty}} field of |jwk| is not 2265 | "`OKP`", 2266 | then [= exception/throw =] a 2267 | {{DataError}}. 2268 |
2269 |2272 | If the {{JsonWebKey/crv}} field of |jwk| is not 2273 | "`Ed25519`", 2274 | then [= exception/throw =] a 2275 | {{DataError}}. 2276 |
2277 |2280 | If the {{JsonWebKey/alg}} field of |jwk| is present and is 2281 | not "`Ed25519`" or "`EdDSA`", 2282 | then [= exception/throw =] a 2283 | {{DataError}}. 2284 |
2285 |2288 | If |usages| is non-empty and the {{JsonWebKey/use}} field of |jwk| is present and is 2289 | not "`sig`", 2290 | then [= exception/throw =] a 2291 | {{DataError}}. 2292 |
2293 |2296 | If the {{JsonWebKey/key_ops}} field of |jwk| is present, and 2297 | is invalid according to the requirements of JSON Web 2298 | Key [[JWK]], or it does not contain all of the specified |usages| 2299 | values, 2300 | then [= exception/throw =] a 2301 | {{DataError}}. 2302 |
2303 |2306 | If the {{JsonWebKey/ext}} field of |jwk| is present and 2307 | has the value false and |extractable| is true, 2308 | then [= exception/throw =] a 2309 | {{DataError}}. 2310 |
2311 |2319 | If |jwk| does not meet the requirements of 2320 | the JWK private key format described in Section 2 2321 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 2322 |
2323 |2326 | Let |key| be a new {{CryptoKey}} object that represents the 2327 | Ed25519 private key identified by interpreting 2328 | |jwk| according to Section 2 of [[RFC8037]]. 2329 |
2330 |2333 | Set the [[\type]] 2334 | internal slot of |Key| to {{KeyType/"private"}}. 2335 |
2336 |2344 | If |jwk| does not meet the requirements of 2345 | the JWK public key format described in Section 2 2346 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 2347 |
2348 |2351 | Let |key| be a new {{CryptoKey}} object that represents the 2352 | Ed25519 public key identified by interpreting 2353 | |jwk| according to Section 2 of [[RFC8037]]. 2354 |
2355 |2358 | Set the [[\type]] 2359 | internal slot of |Key| to {{KeyType/"public"}}. 2360 |
2361 |2368 | Let |algorithm| be a new instance of a {{KeyAlgorithm}} object. 2369 |
2370 |2373 | Set the {{KeyAlgorithm/name}} attribute of 2374 | |algorithm| to "`Ed25519`". 2375 |
2376 |2379 | Set the [[\algorithm]] 2380 | internal slot of |key| to |algorithm|. 2381 |
2382 |2390 | If |usages| contains a value which is not 2391 | "`verify`" 2392 | then [= exception/throw =] a 2393 | {{SyntaxError}}. 2394 |
2395 |2398 | Let |data| be |keyData|. 2399 |
2400 |2403 | If the length in bits of |data| is not 256 then [= exception/throw =] a {{DataError}}. 2404 |
2405 |2408 | Let |algorithm| be a new {{KeyAlgorithm}} object. 2409 |
2410 |2413 | Set the {{KeyAlgorithm/name}} attribute of 2414 | |algorithm| to "`Ed25519`". 2415 |
2416 |2419 | Let |key| be a new {{CryptoKey}} associated with the 2420 | [= relevant global object =] 2421 | of `this` [[HTML]], and that represents |data|. 2422 |
2423 |2426 | Set the [[\type]] internal slot 2427 | of |key| to "`public`" 2428 |
2429 |2432 | Set the [[\algorithm]] 2433 | internal slot of |key| to |algorithm|. 2434 |
2435 |2441 | [= exception/throw =] a 2442 | {{NotSupportedError}}. 2443 |
2444 |2449 | Return |key| 2450 |
2451 |2460 | Let |key| be the {{CryptoKey}} to be 2461 | exported. 2462 |
2463 |2466 | If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| 2467 | cannot be accessed, then [= exception/throw =] an {{OperationError}}. 2468 |
2469 |2477 | If the [[\type]] internal slot 2478 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 2479 |
2480 |2483 | Let |data| be an instance of the `subjectPublicKeyInfo` 2484 | ASN.1 structure defined in [[RFC5280]] 2485 | with the following properties: 2486 |
2487 |2490 | Set the |algorithm| field to an 2491 | `AlgorithmIdentifier` ASN.1 type with the following 2492 | properties: 2493 |
2494 |2497 | Set the |algorithm| object identifier to the 2498 | `id-Ed25519` OID defined in [[RFC8410]]. 2499 |
2500 |2505 | Set the |subjectPublicKey| field to |keyData|. 2506 |
2507 |2512 | Let |result| be a new {{ArrayBuffer}} associated with the 2513 | [= relevant global object =] 2514 | of `this` [[HTML]], and containing 2515 | |data|. 2516 |
2517 |2525 | If the [[\type]] internal slot 2526 | of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 2527 |
2528 |2531 | Let |data| be an instance of the `privateKeyInfo` 2532 | ASN.1 structure defined in [[RFC5208]] 2533 | with the following properties: 2534 |
2535 |2538 | Set the |version| field to `0`. 2539 |
2540 |2543 | Set the |privateKeyAlgorithm| field to a 2544 | `PrivateKeyAlgorithmIdentifier` ASN.1 type with the 2545 | following properties: 2546 |
2547 |2550 | Set the |algorithm| object identifier to the 2551 | `id-Ed25519` OID defined in [[RFC8410]]. 2552 |
2553 |2558 | Set the |privateKey| field to the result of DER-encoding 2559 | a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the 2560 | Ed25519 private key represented by the [[\handle]] internal slot of 2561 | |key| 2562 |
2563 |2568 | Let |result| be a new {{ArrayBuffer}} associated with the 2569 | [= relevant global object =] 2570 | of `this` [[HTML]], and containing 2571 | |data|. 2572 |
2573 |2581 | Let |jwk| be a new {{JsonWebKey}} 2582 | dictionary. 2583 |
2584 |2587 | Set the `kty` attribute of |jwk| to 2588 | "`OKP`". 2589 |
2590 |2593 | Set the `alg` attribute of |jwk| to 2594 | "`Ed25519`". 2595 |
2596 |2599 | Set the `crv` attribute of |jwk| to 2600 | "`Ed25519`". 2601 |
2602 |2605 | Set the {{JsonWebKey/x}} attribute of |jwk| according to the 2606 | definition in Section 2 of [[RFC8037]]. 2607 |
2608 |2623 | Set the `key_ops` attribute of |jwk| to the {{CryptoKey/usages}} attribute of |key|. 2624 |
2625 |2628 | Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot 2629 | of |key|. 2630 |
2631 |2634 | Let |result| be the result of converting |jwk| 2635 | to an ECMAScript Object, as defined by [[WebIDL]]. 2636 |
2637 |2647 | If the [[\type]] internal slot 2648 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 2649 |
2650 |2653 | Let |data| be an octet string representing the Ed25519 2654 | public key represented by the [[\handle]] internal slot of 2655 | |key|. 2656 |
2657 |2660 | Let |result| be a new {{ArrayBuffer}} associated with the 2661 | [= relevant global object =] 2662 | of `this` [[HTML]], and containing 2663 | |data|. 2664 |
2665 |2671 | [= exception/throw =] a 2672 | {{NotSupportedError}}. 2673 |
2674 |2679 | Return |result|. 2680 |
2681 |2693 | The "`Ed448`" algorithm identifier is used to perform signing 2694 | and verification using the Ed448 algorithm specified in 2695 | [[RFC8032]]. 2696 |
2697 |2701 | The recognized algorithm name 2702 | for this algorithm is "`Ed448`". 2703 |
2704 || Operation | 2708 |Parameters | 2709 |Result | 2710 |
|---|---|---|
| sign | 2715 |{{Ed448Params}} | 2716 |{{ArrayBuffer}} | 2717 |
| verify | 2720 |{{Ed448Params}} | 2721 |boolean | 2722 |
| generateKey | 2725 |None | 2726 |{{CryptoKeyPair}} | 2727 |
| importKey | 2730 |None | 2731 |{{CryptoKey}} | 2732 |
| exportKey | 2735 |None | 2736 |object | 2737 |
2745 | dictionary Ed448Params : Algorithm {
2746 | BufferSource context;
2747 | };
2748 |
2749 | The context member represents the optional context data to associate with the message.
2750 |2760 | If the [[\type]] internal slot of 2761 | |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 2762 |
2763 |2766 | Let |context| be the contents of 2767 | the {{Ed448Params/context}} member of |normalizedAlgorithm| 2768 | or the empty octet string if the {{Ed448Params/context}} member of 2769 | |normalizedAlgorithm| is not present. 2770 |
2771 |2774 | If |context| has a length greater than 255 bytes, 2775 | then [= exception/throw =] an {{OperationError}}. 2776 |
2777 |2780 | Perform the Ed448 signing process, as specified in [[RFC8032]], 2781 | Section 5.2.6, with |message| as |M| 2782 | and |context| as |C|, 2783 | using the Ed448 private key associated with |key|. 2784 |
2785 |2786 | Some implementations may (wish to) generate randomized signatures 2787 | as per draft-irtf-cfrg-det-sigs-with-noise 2788 | instead of deterministic signatures as per [[RFC8032]]. 2789 |
2790 |2793 | Return a new {{ArrayBuffer}} associated with the 2794 | [= relevant global object =] 2795 | of `this` [[HTML]], and containing the 2796 | bytes of the signature resulting from performing 2797 | the Ed448 signing process. 2798 |
2799 |2808 | If the [[\type]] internal slot of 2809 | |key| is not {{KeyType/"public"}}, then [= exception/throw =] an {{InvalidAccessError}}. 2810 |
2811 |2814 | Let |context| be the contents of 2815 | the {{Ed448Params/context}} member of |normalizedAlgorithm| 2816 | or the empty octet string if the {{Ed448Params/context}} member of 2817 | |normalizedAlgorithm| is not present. 2818 |
2819 |2822 | If |context| has a length greater than 255 bytes, 2823 | then [= exception/throw =] an {{OperationError}}. 2824 |
2825 |2828 | If the key data of |key| represents an invalid point or a small-order element 2829 | on the Elliptic Curve of Ed448, return `false`. 2830 |
2831 |2832 | Not all implementations perform this check. 2833 |
2834 |2837 | If the point R, encoded in the first half of |signature|, 2838 | represents an invalid point or a small-order element 2839 | on the Elliptic Curve of Ed448, return `false`. 2840 |
2841 |2842 | Not all implementations perform this check. 2843 |
2844 |2847 | Perform the Ed448 verification steps, as specified in [[RFC8032]], 2848 | Section 5.2.7, using the cofactorless (unbatched) equation, 2849 | `[S]B = R + [k]A'`, on the |signature|, with |message| as |M| 2850 | and |context| as |C|, 2851 | using the Ed448 public key associated with |key|. 2852 |
2853 |2856 | Let |result| be a boolean with the value `true` if the signature is valid 2857 | and the value `false` otherwise. 2858 |
2859 |2862 | Return |result|. 2863 |
2864 |2872 | If |usages| contains a value which is not 2873 | one of "`sign`" or "`verify`", 2874 | then [= exception/throw =] a 2875 | {{SyntaxError}}. 2876 |
2877 |2880 | Generate an Ed448 key pair, as defined in [[RFC8032]], section 5.1.5. 2881 |
2882 |2885 | Let |algorithm| be a new {{KeyAlgorithm}} object. 2886 |
2887 |2890 | Set the {{KeyAlgorithm/name}} attribute of 2891 | |algorithm| to "`Ed448`". 2892 |
2893 |2896 | Let |publicKey| be a new {{CryptoKey}} associated with the 2897 | [= relevant global object =] 2898 | of `this` [[HTML]], and 2899 | representing the public key of the generated key pair. 2900 |
2901 |2904 | Set the [[\type]] internal slot of 2905 | |publicKey| to "`public`" 2906 |
2907 |2910 | Set the [[\algorithm]] internal 2911 | slot of |publicKey| to |algorithm|. 2912 |
2913 |2916 | Set the [[\extractable]] internal 2917 | slot of |publicKey| to true. 2918 |
2919 |2922 | Set the [[\usages]] internal slot of 2923 | |publicKey| to be the usage intersection 2924 | of |usages| and `[ "verify" ]`. 2925 |
2926 |2929 | Let |privateKey| be a new {{CryptoKey}} associated with the 2930 | [= relevant global object =] 2931 | of `this` [[HTML]], and 2932 | representing the private key of the generated key pair. 2933 |
2934 |2937 | Set the [[\type]] internal slot of 2938 | |privateKey| to {{KeyType/"private"}} 2939 |
2940 |2943 | Set the [[\algorithm]] internal 2944 | slot of |privateKey| to |algorithm|. 2945 |
2946 |2949 | Set the [[\extractable]] internal 2950 | slot of |privateKey| to |extractable|. 2951 |
2952 |2955 | Set the [[\usages]] internal slot of 2956 | |privateKey| to be the usage intersection 2957 | of |usages| and `[ "sign" ]`. 2958 |
2959 |2962 | Let |result| be a new {{CryptoKeyPair}} 2963 | dictionary. 2964 |
2965 |2968 | Set the {{CryptoKeyPair/publicKey}} attribute 2969 | of |result| to be |publicKey|. 2970 |
2971 |2974 | Set the {{CryptoKeyPair/privateKey}} attribute 2975 | of |result| to be |privateKey|. 2976 |
2977 |2980 | Return the result of converting |result| to an ECMAScript Object, as 2981 | defined by [[WebIDL]]. 2982 |
2983 |Let |keyData| be the key data to be imported.
2992 |3000 | If |usages| contains a value which is not 3001 | "`verify`" 3002 | then [= exception/throw =] a 3003 | {{SyntaxError}}. 3004 |
3005 |3008 | Let |spki| be the result of running the 3009 | parse a subjectPublicKeyInfo 3010 | algorithm over |keyData|. 3011 |
3012 |3015 | If an error occurred while parsing, 3016 | then [= exception/throw =] a 3017 | {{DataError}}. 3018 |
3019 |3022 | If the `algorithm` object identifier field of the 3023 | `algorithm` AlgorithmIdentifier field of |spki| is 3024 | not equal to the `id-Ed448` 3025 | object identifier defined in [[RFC8410]], 3026 | then [= exception/throw =] a 3027 | {{DataError}}. 3028 |
3029 |3032 | If the `parameters` field of the `algorithm` 3033 | AlgorithmIdentifier field of |spki| is present, 3034 | then [= exception/throw =] a 3035 | {{DataError}}. 3036 |
3037 |3040 | Let |publicKey| be the Ed448 public key identified by 3041 | the `subjectPublicKey` field of |spki|. 3042 |
3043 |3046 | Let |key| be a new {{CryptoKey}} associated with the 3047 | [= relevant global object =] 3048 | of `this` [[HTML]], and 3049 | that represents |publicKey|. 3050 |
3051 |3054 | Set the [[\type]] internal slot 3055 | of |key| to "`public`" 3056 |
3057 |3060 | Let |algorithm| be a new {{KeyAlgorithm}}. 3061 |
3062 |3065 | Set the {{KeyAlgorithm/name}} attribute of 3066 | |algorithm| to "`Ed448`". 3067 |
3068 |3071 | Set the [[\algorithm]] 3072 | internal slot of |key| to |algorithm|. 3073 |
3074 |3082 | If |usages| contains a value which is not 3083 | "`sign`" 3084 | then [= exception/throw =] a 3085 | {{SyntaxError}}. 3086 |
3087 |3090 | Let |privateKeyInfo| be the result of running the 3091 | parse a privateKeyInfo 3092 | algorithm over |keyData|. 3093 |
3094 |3097 | If an error occurs while parsing, 3098 | then [= exception/throw =] a 3099 | {{DataError}}. 3100 |
3101 |3104 | If the `algorithm` object identifier field of the 3105 | `privateKeyAlgorithm` PrivateKeyAlgorithm field of 3106 | |privateKeyInfo| is not equal to the 3107 | `id-Ed448` object identifier defined in [[RFC8410]], 3108 | then [= exception/throw =] a 3109 | {{DataError}}. 3110 |
3111 |3114 | If the `parameters` field of the 3115 | `privateKeyAlgorithm` PrivateKeyAlgorithmIdentifier field 3116 | of |privateKeyInfo| is present, 3117 | then [= exception/throw =] a 3118 | {{DataError}}. 3119 |
3120 |3123 | Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure 3124 | algorithm, with |data| as the `privateKey` field 3125 | of |privateKeyInfo|, |structure| as the ASN.1 3126 | `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. 3127 |
3128 |3131 | If an error occurred while parsing, 3132 | then [= exception/throw =] a 3133 | {{DataError}}. 3134 |
3135 |3138 | Let |key| be a new {{CryptoKey}} associated with the 3139 | [= relevant global object =] 3140 | of `this` [[HTML]], and 3141 | that represents the Ed448 private key identified by |curvePrivateKey|. 3142 |
3143 |3146 | Set the [[\type]] internal slot 3147 | of |key| to {{KeyType/"private"}} 3148 |
3149 |3152 | Let |algorithm| be a new {{KeyAlgorithm}}. 3153 |
3154 |3157 | Set the {{KeyAlgorithm/name}} attribute of 3158 | |algorithm| to "`Ed448`". 3159 |
3160 |3163 | Set the [[\algorithm]] 3164 | internal slot of |key| to |algorithm|. 3165 |
3166 |Let |jwk| equal |keyData|.
[= exception/Throw =] a {{DataError}}.
3182 | If the {{JsonWebKey/d}} field is present and |usages| contains 3183 | a value which is not 3184 | "`sign`", or, 3185 | if the {{JsonWebKey/d}} field is not present and |usages| contains 3186 | a value which is not 3187 | "`verify`" 3188 | then [= exception/throw =] a 3189 | {{SyntaxError}}. 3190 |
3191 |3194 | If the {{JsonWebKey/kty}} field of |jwk| is not 3195 | "`OKP`", 3196 | then [= exception/throw =] a 3197 | {{DataError}}. 3198 |
3199 |3202 | If the {{JsonWebKey/crv}} field of |jwk| is not 3203 | "`Ed448`", 3204 | then [= exception/throw =] a 3205 | {{DataError}}. 3206 |
3207 |3210 | If the {{JsonWebKey/alg}} field of |jwk| is present and is 3211 | not "`Ed448`" or "`EdDSA`", 3212 | then [= exception/throw =] a 3213 | {{DataError}}. 3214 |
3215 |3218 | If |usages| is non-empty and the {{JsonWebKey/use}} field of |jwk| is present and is 3219 | not "`sig`", 3220 | then [= exception/throw =] a 3221 | {{DataError}}. 3222 |
3223 |3226 | If the {{JsonWebKey/key_ops}} field of |jwk| is present, and 3227 | is invalid according to the requirements of JSON Web 3228 | Key [[JWK]], or it does not contain all of the specified |usages| 3229 | values, 3230 | then [= exception/throw =] a 3231 | {{DataError}}. 3232 |
3233 |3236 | If the {{JsonWebKey/ext}} field of |jwk| is present and 3237 | has the value false and |extractable| is true, 3238 | then [= exception/throw =] a 3239 | {{DataError}}. 3240 |
3241 |3249 | If |jwk| does not meet the requirements of 3250 | the JWK private key format described in Section 2 3251 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 3252 |
3253 |3256 | Let |key| be a new {{CryptoKey}} object that represents the 3257 | Ed448 private key identified by interpreting 3258 | |jwk| according to Section 2 of [[RFC8037]]. 3259 |
3260 |3263 | Set the [[\type]] 3264 | internal slot of |Key| to {{KeyType/"private"}}. 3265 |
3266 |3274 | If |jwk| does not meet the requirements of 3275 | the JWK public key format described in Section 2 3276 | of [[RFC8037]], then [= exception/throw =] a {{DataError}}. 3277 |
3278 |3281 | Let |key| be a new {{CryptoKey}} object that represents the 3282 | Ed448 public key identified by interpreting 3283 | |jwk| according to Section 2 of [[RFC8037]]. 3284 |
3285 |3288 | Set the [[\type]] 3289 | internal slot of |Key| to {{KeyType/"public"}}. 3290 |
3291 |3298 | Let |algorithm| be a new instance of a {{KeyAlgorithm}} object. 3299 |
3300 |3303 | Set the {{KeyAlgorithm/name}} attribute of 3304 | |algorithm| to "`Ed448`". 3305 |
3306 |3309 | Set the [[\algorithm]] 3310 | internal slot of |key| to |algorithm|. 3311 |
3312 |3320 | If |usages| contains a value which is not 3321 | "`verify`" 3322 | then [= exception/throw =] a 3323 | {{SyntaxError}}. 3324 |
3325 |3328 | Let |data| be |keyData|. 3329 |
3330 |3333 | If the length in bits of |data| is not 448 then [= exception/throw =] a {{DataError}}. 3334 |
3335 |3338 | Let |algorithm| be a new {{KeyAlgorithm}} object. 3339 |
3340 |3343 | Set the {{KeyAlgorithm/name}} attribute of 3344 | |algorithm| to "`Ed448`". 3345 |
3346 |3349 | Let |key| be a new {{CryptoKey}} associated with the 3350 | [= relevant global object =] 3351 | of `this` [[HTML]], and that represents |data|. 3352 |
3353 |3356 | Set the [[\type]] internal slot 3357 | of |key| to "`public`" 3358 |
3359 |3362 | Set the [[\algorithm]] 3363 | internal slot of |key| to |algorithm|. 3364 |
3365 |3371 | [= exception/throw =] a 3372 | {{NotSupportedError}}. 3373 |
3374 |3379 | Return |key| 3380 |
3381 |3390 | Let |key| be the {{CryptoKey}} to be 3391 | exported. 3392 |
3393 |3396 | If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| 3397 | cannot be accessed, then [= exception/throw =] an {{OperationError}}. 3398 |
3399 |3407 | If the [[\type]] internal slot 3408 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 3409 |
3410 |3413 | Let |data| be an instance of the `subjectPublicKeyInfo` 3414 | ASN.1 structure defined in [[RFC5280]] 3415 | with the following properties: 3416 |
3417 |3420 | Set the |algorithm| field to an 3421 | `AlgorithmIdentifier` ASN.1 type with the following 3422 | properties: 3423 |
3424 |3427 | Set the |algorithm| object identifier to the 3428 | `id-Ed448` OID defined in [[RFC8410]]. 3429 |
3430 |3435 | Set the |subjectPublicKey| field to |keyData|. 3436 |
3437 |3442 | Let |result| be a new {{ArrayBuffer}} associated with the 3443 | [= relevant global object =] 3444 | of `this` [[HTML]], and containing 3445 | |data|. 3446 |
3447 |3455 | If the [[\type]] internal slot 3456 | of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. 3457 |
3458 |3461 | Let |data| be an instance of the `privateKeyInfo` 3462 | ASN.1 structure defined in [[RFC5208]] 3463 | with the following properties: 3464 |
3465 |3468 | Set the |version| field to `0`. 3469 |
3470 |3473 | Set the |privateKeyAlgorithm| field to a 3474 | `PrivateKeyAlgorithmIdentifier` ASN.1 type with the 3475 | following properties: 3476 |
3477 |3480 | Set the |algorithm| object identifier to the 3481 | `id-Ed448` OID defined in [[RFC8410]]. 3482 |
3483 |3488 | Set the |privateKey| field to the result of DER-encoding 3489 | a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the 3490 | Ed448 private key represented by the [[\handle]] internal slot of 3491 | |key| 3492 |
3493 |3498 | Let |result| be a new {{ArrayBuffer}} associated with the 3499 | [= relevant global object =] 3500 | of `this` [[HTML]], and containing 3501 | |data|. 3502 |
3503 |3511 | Let |jwk| be a new {{JsonWebKey}} 3512 | dictionary. 3513 |
3514 |3517 | Set the `kty` attribute of |jwk| to 3518 | "`OKP`". 3519 |
3520 |3523 | Set the `alg` attribute of |jwk| to 3524 | "`Ed448`". 3525 |
3526 |3529 | Set the `crv` attribute of |jwk| to 3530 | "`Ed448`". 3531 |
3532 |3535 | Set the {{JsonWebKey/x}} attribute of |jwk| according to the 3536 | definition in Section 2 of [[RFC8037]]. 3537 |
3538 |3553 | Set the `key_ops` attribute of |jwk| to the {{CryptoKey/usages}} attribute of |key|. 3554 |
3555 |3558 | Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot 3559 | of |key|. 3560 |
3561 |3564 | Let |result| be the result of converting |jwk| 3565 | to an ECMAScript Object, as defined by [[WebIDL]]. 3566 |
3567 |3577 | If the [[\type]] internal slot 3578 | of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. 3579 |
3580 |3583 | Let |data| be an octet string 3584 | representing the Ed448 public key represented by the [[\handle]] 3585 | internal slot of |key|. 3586 |
3587 |3590 | Let |result| be a new {{ArrayBuffer}} associated with the 3591 | [= relevant global object =] 3592 | of `this` [[HTML]], and containing 3593 | |data|. 3594 |
3595 |3601 | [= exception/throw =] a 3602 | {{NotSupportedError}}. 3603 |
3604 |3609 | Return |result|. 3610 |
3611 |3621 | This example generates two X25519 key pairs, one for Alice and one for Bob, performs 3622 | a key agreement between them, derives a 256-bit AES-GCM key from the result using 3623 | HKDF with SHA-256, and encrypts and decrypts some data with it. 3624 |
3625 |
3626 | // Generate a key pair for Alice.
3627 | const alice_x25519_key = await crypto.subtle.generateKey('X25519', false /* extractable */, ['deriveKey']);
3628 | const alice_private_key = alice_x25519_key.privateKey;
3629 |
3630 | // Normally, the public key would be sent by Bob to Alice in advance over some authenticated channel.
3631 | // In this example, we'll generate another key pair and use its public key instead.
3632 | const bob_x25519_key = await crypto.subtle.generateKey('X25519', false /* extractable */, ['deriveKey']);
3633 | const bob_public_key = bob_x25519_key.publicKey;
3634 |
3635 | // Perform the key agreement.
3636 | const alice_x25519_params = { name: 'X25519', public: bob_public_key };
3637 | const alice_shared_key = await crypto.subtle.deriveKey(alice_x25519_params, alice_private_key, 'HKDF', false /* extractable */, ['deriveKey']);
3638 |
3639 | // Derive a symmetric key from the result.
3640 | const salt = crypto.getRandomValues(new Uint8Array(32));
3641 | const info = new TextEncoder().encode('X25519 key agreement for an AES-GCM-256 key');
3642 | const hkdf_params = { name: 'HKDF', hash: 'SHA-256', salt, info };
3643 | const gcm_params = { name: 'AES-GCM', length: 256 };
3644 | const alice_symmetric_key = await crypto.subtle.deriveKey(hkdf_params, alice_shared_key, gcm_params, false /* extractable */, ['encrypt', 'decrypt']);
3645 |
3646 | // Encrypt some data with the symmetric key, and send it to Bob. The IV must be passed along as well.
3647 | const iv = crypto.getRandomValues(new Uint8Array(12));
3648 | const message = new TextEncoder().encode('Hi Bob!');
3649 | const encrypted = await crypto.subtle.encrypt({ ...gcm_params, iv }, alice_symmetric_key, message);
3650 |
3651 | // On Bob's side, Alice's public key and Bob's private key are used, instead.
3652 | // To get the same result, Alice and Bob must agree on using the same salt and info.
3653 | const alice_public_key = alice_x25519_key.publicKey;
3654 | const bob_private_key = bob_x25519_key.privateKey;
3655 | const bob_x25519_params = { name: 'X25519', public: alice_public_key };
3656 | const bob_shared_key = await crypto.subtle.deriveKey(bob_x25519_params, bob_private_key, 'HKDF', false /* extractable */, ['deriveKey']);
3657 | const bob_symmetric_key = await crypto.subtle.deriveKey(hkdf_params, bob_shared_key, gcm_params, false /* extractable */, ['encrypt', 'decrypt']);
3658 |
3659 | // On Bob's side, the data can be decrypted.
3660 | const decrypted = await crypto.subtle.decrypt({ ...gcm_params, iv }, bob_symmetric_key, encrypted);
3661 | const decrypted_message = new TextDecoder().decode(decrypted);
3662 |
3663 | 3668 | Refer to algorithm-specific sections for the 3669 | normative requirements of importing and exporting JWK. 3670 |
3671 || JSON Web Key | 3676 |AlgorithmIdentifier | 3677 |
|---|---|
3682 |
3683 | { kty: "OKP",
3684 | crv: "X25519" }
3685 |
3686 | |
3687 |
3688 |
3689 | { name: "X25519" }
3690 |
3691 | |
3692 |
3695 |
3696 | { kty: "OKP",
3697 | crv: "X448" }
3698 |
3699 | |
3700 |
3701 |
3702 | { name: "X448" }
3703 |
3704 | |
3705 |
3707 |
3708 | { kty: "OKP",
3709 | crv: "Ed25519",
3710 | alg: "Ed25519" }
3711 |
3712 | |
3713 |
3714 |
3715 | { name: "Ed25519" }
3716 |
3717 | |
3718 |
3719 |
3721 |
3722 | { kty: "OKP",
3723 | crv: "Ed448",
3724 | alg: "Ed448" }
3725 |
3726 | |
3727 |
3728 |
3729 | { name: "Ed448" }
3730 |
3731 | |
3732 |
3739 | Refer to algorithm-specific sections for the 3740 | normative requirements of importing and exporting SPKI. 3741 |
3742 || Algorithm OID | 3746 |subjectPublicKey ASN.1 structure | 3747 |AlgorithmIdentifier | 3748 |Reference | 3749 |
|---|---|---|---|
| id-X25519 (1.3.101.110) | 3754 |BIT STRING | 3755 |3756 | "`X25519`" 3757 | | 3758 |3759 | [[RFC8410]] 3760 | | 3761 |
| id-X448 (1.3.101.111) | 3764 |BIT STRING | 3765 |3766 | "`X448`" 3767 | | 3768 |3769 | [[RFC8410]] 3770 | | 3771 |
| id-Ed25519 (1.3.101.112) | 3774 |BIT STRING | 3775 |3776 | "`Ed25519`" 3777 | | 3778 |3779 | [[RFC8410]] 3780 | | 3781 |
| id-Ed448 (1.3.101.113) | 3784 |BIT STRING | 3785 |3786 | "`Ed448`" 3787 | | 3788 |3789 | [[RFC8410]] 3790 | | 3791 |
3798 | Refer to algorithm-specific sections for the 3799 | normative requirements of importing and exporting PKCS#8 PrivateKeyInfo. 3800 |
3801 || privateKeyAlgorithm | 3805 |privateKey format | 3806 |AlgorithmIdentifier | 3807 |Reference | 3808 |
|---|---|---|---|
| id-X25519 (1.3.101.110) | 3813 |CurvePrivateKey | 3814 |3815 | "`X25519`" 3816 | | 3817 |3818 | [[RFC8410]] 3819 | | 3820 |
| id-X448 (1.3.101.111) | 3823 |CurvePrivateKey | 3824 |3825 | "`X448`" 3826 | | 3827 |3828 | [[RFC8410]] 3829 | | 3830 |
| id-Ed25519 (1.3.101.112) | 3833 |CurvePrivateKey | 3834 |3835 | "`Ed25519`" 3836 | | 3837 |3838 | [[RFC8410]] 3839 | | 3840 |
| id-Ed448 (1.3.101.113) | 3843 |CurvePrivateKey | 3844 |3845 | "`Ed448`" 3846 | | 3847 |3848 | [[RFC8410]] 3849 | | 3850 |