From fff0b51a67c8b8353b509c8b23e5811ba1caba04 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Sun, 5 Nov 2023 14:33:37 +0100 Subject: [PATCH 1/5] Add X25519 and Ed25519 --- spec/Overview.html | 2167 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 2008 insertions(+), 159 deletions(-) diff --git a/spec/Overview.html b/spec/Overview.html index 357ab22..f5d4d59 100644 --- a/spec/Overview.html +++ b/spec/Overview.html @@ -3348,6 +3348,36 @@

Algorithm Overview

+ + Ed25519 + + + ✔ + ✔ + + ✔ + + + ✔ + ✔ + + + + + X25519 + + + + + + ✔ + ✔ + ✔ + ✔ + ✔ + + + AES-CTR ✔ @@ -9975,45 +10005,45 @@

Operations

-
-

AES-CTR

-
+
+

Ed25519

+

Description

- The "`AES-CTR`" algorithm identifier is used to perform - encryption and decryption using AES in Counter mode, - as described in [[NIST-SP800-38A]]. + The "`Ed25519`" algorithm identifier is used to perform signing + and verification using the Ed25519 algorithm specified in + [[RFC8032]].

-
+

Registration

- The [= recognized algorithm name =] for - this algorithm is "`AES-CTR`". + The recognized algorithm name + for this algorithm is "`Ed25519`".

- - - + + + - - + + - - - + + + - - + + @@ -10025,140 +10055,81 @@

Registration

- - - - -
OperationParametersResultOperationParametersResult
encrypt{{AesCtrParams}}signNone {{ArrayBuffer}}
decrypt{{AesCtrParams}}{{ArrayBuffer}}verifyNoneboolean
generateKey{{AesKeyGenParams}}{{CryptoKey}}None{{CryptoKeyPair}}
importKey None object
get key length{{AesDerivedKeyParams}}Integer
-
-

AesCtrParams dictionary

-
-dictionary AesCtrParams : Algorithm {
-  required BufferSource counter;
-  required [EnforceRange] octet length;
-};
-          
-

The counter member contains the initial value of the counter block. {{AesCtrParams/counter}} MUST be 16 bytes (the AES block size). The counter bits are the rightmost length - bits of the counter block. The rest of the counter block is for - the nonce. The counter bits are incremented using the standard - incrementing function specified in NIST SP 800-38A Appendix B.1: - the counter bits are interpreted as a big-endian integer and - incremented by one.

-

The length member contains the length, in bits, of the rightmost part of the counter block that is incremented.

-
-
-

AesKeyAlgorithm dictionary

-
-dictionary AesKeyAlgorithm : KeyAlgorithm {
-  required unsigned short length;
-};
-          
-

The length member represents the length, in bits, of the key.

-
-
-

AesKeyGenParams dictionary

-
-dictionary AesKeyGenParams : Algorithm {
-  required [EnforceRange] unsigned short length;
-};
-          
-

The length member represents the length, in bits, of the key.

-
-
-

AesDerivedKeyParams dictionary

-
-dictionary AesDerivedKeyParams : Algorithm {
-  required [EnforceRange] unsigned short length;
-};
-          
-

The length member represents the length, in bits, of the key.

-
- -
+

Operations

-
Encrypt
+
Sign
+ When signing, the following algorithm should be used:
  1. - If the {{AesCtrParams/counter}} member of - |normalizedAlgorithm| does not have length 16 - bytes, - then [= exception/throw =] an - {{OperationError}}. -

    -
  2. -
  3. -

    - If the {{AesCtrParams/length}} member of - |normalizedAlgorithm| is zero or is greater - than 128, - then [= exception/throw =] an - {{OperationError}}. + If the [[\type]] internal slot of + |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}.

  4. - Let |ciphertext| be the result of performing the CTR Encryption - operation described in Section 6.5 of [[NIST-SP800-38A]] using AES as the block cipher, the contents of the {{AesCtrParams/counter}} member of - |normalizedAlgorithm| as the initial value of the counter block, the - {{AesCtrParams/length}} member of - |normalizedAlgorithm| as the input parameter |m| to the - standard counter block incrementing function defined in Appendix B.1 of - [[NIST-SP800-38A]] and the contents of - |plaintext| as the input plaintext. + Perform the Ed25519 signing process, as specified in [[RFC8032]], + Section 5.1.6, with |message| as |M|, + using the Ed25519 private key associated with |key|.

  5. - Return the result of [= ArrayBuffer/create | creating =] - an {{ArrayBuffer}} containing |ciphertext|. + Return a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing the + bytes of the signature resulting from performing + the Ed25519 signing process.

-
Decrypt
+
Verify
+ When verifying, the following algorithm should be used:
  1. - If the {{AesCtrParams/counter}} member of - |normalizedAlgorithm| does not have length 16 - bytes, - then [= exception/throw =] an - {{OperationError}}. + If the [[\type]] internal slot of + |key| is not {{KeyType/"public"}}, then [= exception/throw =] an {{InvalidAccessError}}.

  2. - If the {{AesCtrParams/length}} member of - |normalizedAlgorithm| is zero or is greater - than 128, - then [= exception/throw =] an - {{OperationError}}. + If the key data of |key| represents an invalid point or a small-order element + on the Elliptic Curve of Ed25519, return `false`.

  3. - Let |plaintext| be the result of performing the CTR Decryption - operation described in Section 6.5 of [[NIST-SP800-38A]] using AES as the block cipher, the contents of the {{AesCtrParams/counter}} member of - |normalizedAlgorithm| as the initial value of the counter block, the - {{AesCtrParams/length}} member of - |normalizedAlgorithm| as the input parameter |m| to the - standard counter block incrementing function defined in Appendix B.1 of - [[NIST-SP800-38A]] and the contents of - |ciphertext| as the input ciphertext. + If the point R, encoded in the first half of |signature|, + represents an invalid point or a small-order element + on the Elliptic Curve of Ed25519, return `false`.

  4. - Return the result of [= ArrayBuffer/create | creating =] - an {{ArrayBuffer}} containing |plaintext|. + Perform the Ed25519 verification steps, as specified in [[RFC8032]], + Section 5.1.7, using the cofactorless (unbatched) equation, + `[S]B = R + [k]A'`, on the |signature|, with |message| as |M|, + using the Ed25519 public key associated with |key|. +

    +
  5. +
  6. +

    + Let |result| be a boolean with the value `true` if the signature is valid + and the value `false` otherwise. +

    +
  7. +
  8. +

    + Return |result|.

@@ -10168,111 +10139,1877 @@

Operations

  1. - If |usages| contains any entry which is not - one of "`encrypt`", "`decrypt`", - "`wrapKey`" or "`unwrapKey`", + If |usages| contains a value which is not + one of "`sign`" or "`verify`", then [= exception/throw =] a {{SyntaxError}}.

  2. - If the {{AesKeyGenParams/length}} member of - |normalizedAlgorithm| is not equal to one of - 128, 192 or 256, - then [= exception/throw =] an - {{OperationError}}. + Generate an Ed25519 key pair, as defined in [[RFC8032]], section 5.1.5.

  3. -
  4. - Generate an AES key of length - equal to the {{AesKeyGenParams/length}} member of - |normalizedAlgorithm|. + Let |algorithm| be a new {{KeyAlgorithm}} object.

  5. - If the key generation step fails, - then [= exception/throw =] an - {{OperationError}}. + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`Ed25519`".

  6. - Let |key| be a new - {{CryptoKey}} object representing the - generated AES key. + Let |publicKey| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + representing the public key of the generated key pair.

  7. - Let |algorithm| be a new - {{AesKeyAlgorithm}}. + Set the [[\type]] internal slot of + |publicKey| to "`public`"

  8. - Set the {{KeyAlgorithm/name}} attribute of - |algorithm| to "`AES-CTR`". + Set the [[\algorithm]] internal + slot of |publicKey| to |algorithm|.

  9. - Set the {{AesKeyAlgorithm/length}} attribute of - |algorithm| to equal the - {{AesKeyGenParams/length}} member of - |normalizedAlgorithm|. + Set the [[\extractable]] internal + slot of |publicKey| to true.

  10. - Set the {{CryptoKey/[[algorithm]]}} internal - slot of |key| to |algorithm|. + Set the [[\usages]] internal slot of + |publicKey| to be the usage intersection + of |usages| and `[ "verify" ]`.

  11. - Set the {{CryptoKey/[[extractable]]}} internal - slot of |key| to be |extractable|. + Let |privateKey| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + representing the private key of the generated key pair.

  12. - Set the {{CryptoKey/[[usages]]}} internal slot of - |key| to be |usages|. + Set the [[\type]] internal slot of + |privateKey| to {{KeyType/"private"}}

  13. - Return |key|. + Set the [[\algorithm]] internal + slot of |privateKey| to |algorithm|. +

    +
  14. +
  15. +

    + Set the [[\extractable]] internal + slot of |privateKey| to |extractable|. +

    +
  16. +
  17. +

    + Set the [[\usages]] internal slot of + |privateKey| to be the usage intersection + of |usages| and `[ "sign" ]`. +

    +
  18. +
  19. +

    + Let |result| be a new {{CryptoKeyPair}} + dictionary. +

    +
  20. +
  21. +

    + Set the {{CryptoKeyPair/publicKey}} attribute + of |result| to be |publicKey|. +

    +
  22. +
  23. +

    + Set the {{CryptoKeyPair/privateKey}} attribute + of |result| to be |privateKey|. +

    +
  24. +
  25. +

    + Return the result of converting |result| to an ECMAScript Object, as + defined by [[WebIDL]].

+
Import Key
  1. -

    - If |usages| contains an entry which is not - one of "`encrypt`", "`decrypt`", - "`wrapKey`" or "`unwrapKey`", - then [= exception/throw =] a - {{SyntaxError}}. -

    +

    Let |keyData| be the key data to be imported.

  2. -
    If |format| is {{KeyFormat/"raw"}}:
    +
    If |format| is {{KeyFormat/"spki"}}:
    1. - Let |data| be the [= octet string =] contained in |keyData|. -

      -
    2. + If |usages| contains a value which is not + "`verify`" + then [= exception/throw =] a + {{SyntaxError}}. +

      + +
    3. +

      + Let |spki| be the result of running the + parse a subjectPublicKeyInfo + algorithm over |keyData|. +

      +
    4. +
    5. +

      + If an error occurred while parsing, + then [= exception/throw =] a + {{DataError}}. +

      +
    6. +
    7. +

      + If the `algorithm` object identifier field of the + `algorithm` AlgorithmIdentifier field of |spki| is + not equal to the `id-Ed25519` + object identifier defined in [[RFC8410]], + then [= exception/throw =] a + {{DataError}}. +

      +
    8. +
    9. +

      + If the `parameters` field of the `algorithm` + AlgorithmIdentifier field of |spki| is present, + then [= exception/throw =] a + {{DataError}}. +

      +
    10. +
    11. +

      + Let |publicKey| be the Ed25519 public key identified by + the `subjectPublicKey` field of |spki|. +

      +
    12. +
    13. +

      + Let |key| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + that represents |publicKey|. +

      +
    14. +
    15. +

      + Set the [[\type]] internal slot + of |key| to "`public`" +

      +
    16. +
    17. +

      + Let |algorithm| be a new {{KeyAlgorithm}}. +

      +
    18. +
    19. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`Ed25519`". +

      +
    20. +
    21. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    22. +
    +
    +
    If |format| is {{KeyFormat/"pkcs8"}}:
    +
    +
      +
    1. +

      + If |usages| contains a value which is not + "`sign`" + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    2. +
    3. +

      + Let |privateKeyInfo| be the result of running the + parse a privateKeyInfo + algorithm over |keyData|. +

      +
    4. +
    5. +

      + If an error occurs while parsing, + then [= exception/throw =] a + {{DataError}}. +

      +
    6. +
    7. +

      + If the `algorithm` object identifier field of the + `privateKeyAlgorithm` PrivateKeyAlgorithm field of + |privateKeyInfo| is not equal to the + `id-Ed25519` object identifier defined in [[RFC8410]], + then [= exception/throw =] a + {{DataError}}. +

      +
    8. +
    9. +

      + If the `parameters` field of the + `privateKeyAlgorithm` PrivateKeyAlgorithmIdentifier field + of |privateKeyInfo| is present, + then [= exception/throw =] a + {{DataError}}. +

      +
    10. +
    11. +

      + Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure + algorithm, with |data| as the `privateKey` field + of |privateKeyInfo|, |structure| as the ASN.1 + `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. +

      +
    12. +
    13. +

      + If an error occurred while parsing, + then [= exception/throw =] a + {{DataError}}. +

      +
    14. +
    15. +

      + Let |key| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + that represents the Ed25519 private key identified by |curvePrivateKey|. +

      +
    16. +
    17. +

      + Set the [[\type]] internal slot + of |key| to {{KeyType/"private"}} +

      +
    18. +
    19. +

      + Let |algorithm| be a new {{KeyAlgorithm}}. +

      +
    20. +
    21. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`Ed25519`". +

      +
    22. +
    23. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    24. +
    +
    +
    If |format| is {{KeyFormat/"jwk"}}:
    +
    +
      +
    1. +
      +
      If |keyData| is a {{JsonWebKey}} dictionary:
      +

      Let |jwk| equal |keyData|.

      +
      Otherwise:
      +

      [= exception/Throw =] a {{DataError}}.

      +
      +
    2. +
    3. +

      + If the {{JsonWebKey/d}} field is present and |usages| contains + a value which is not + "`sign`", or, + if the {{JsonWebKey/d}} field is not present and |usages| contains + a value which is not + "`verify`" + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    4. +
    5. +

      + If the {{JsonWebKey/kty}} field of |jwk| is not + "`OKP`", + then [= exception/throw =] a + {{DataError}}. +

      +
    6. +
    7. +

      + If the {{JsonWebKey/crv}} field of |jwk| is not + "`Ed25519`", + then [= exception/throw =] a + {{DataError}}. +

      +
    8. +
    9. +

      + If |usages| is non-empty and the {{JsonWebKey/use}} field of |jwk| is present and is + not "`sig`", + then [= exception/throw =] a + {{DataError}}. +

      +
    10. +
    11. +

      + If the {{JsonWebKey/key_ops}} field of |jwk| is present, and + is invalid according to the requirements of JSON Web + Key [[JWK]], or it does not contain all of the specified |usages| + values, + then [= exception/throw =] a + {{DataError}}. +

      +
    12. +
    13. +

      + If the {{JsonWebKey/ext}} field of |jwk| is present and + has the value false and |extractable| is true, + then [= exception/throw =] a + {{DataError}}. +

      +
    14. +
    15. +
      +
      If the {{JsonWebKey/d}} field is present:
      +
      +
        +
      1. +

        + If |jwk| does not meet the requirements of Section 2 + of [[RFC8037]], then [= exception/throw =] a {{DataError}}. +

        +
      2. +
      3. +

        + Let |key| be a new {{CryptoKey}} object that represents the + Ed25519 private key identified by interpreting + |jwk| according to Section 2 of [[RFC8037]]. +

        +
      4. +
      5. +

        + Set the [[\type]] + internal slot of |Key| to {{KeyType/"private"}}. +

        +
      6. +
      +
      +
      Otherwise:
      +
      +
        +
      1. +

        + If |jwk| does not meet the requirements of Section 2 + of [[RFC8037]], then [= exception/throw =] a {{DataError}}. +

        +
      2. +
      3. +

        + Let |key| be a new {{CryptoKey}} object that represents the + Ed25519 public key identified by interpreting + |jwk| according to Section 2 of [[RFC8037]]. +

        +
      4. +
      5. +

        + Set the [[\type]] + internal slot of |Key| to {{KeyType/"public"}}. +

        +
      6. +
      +
      +
      +
    16. +
    17. +

      + Let |algorithm| be a new instance of a {{KeyAlgorithm}} object. +

      +
    18. +
    19. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`Ed25519`". +

      +
    20. +
    21. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    22. +
    +
    +
    If |format| is {{KeyFormat/"raw"}}:
    +
    +
      +
    1. +

      + If |usages| contains a value which is not + "`verify`" + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    2. +
    3. +

      + Let |algorithm| be a new {{KeyAlgorithm}} object. +

      +
    4. +
    5. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`Ed25519`". +

      +
    6. +
    7. +

      + Let |key| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + representing the key data provided in |keyData|. +

      +
    8. +
    9. +

      + Set the [[\type]] internal slot + of |key| to "`public`" +

      +
    10. +
    11. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    12. +
    +
    +
    Otherwise:
    +
    +

    + [= exception/throw =] a + {{NotSupportedError}}. +

    +
    +
    +
  3. +
  4. +

    + Return |key| +

    +
  5. +
+
+ +
Export Key
+
+
    +
  1. +

    + Let |key| be the {{CryptoKey}} to be + exported. +

    +
  2. +
  3. +

    + If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| + cannot be accessed, then [= exception/throw =] an {{OperationError}}. +

    +
  4. +
  5. +
    +
    If |format| is {{KeyFormat/"spki"}}:
    +
    +
      +
    1. +

      + If the [[\type]] internal slot + of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. +

      +
    2. +
    3. +

      + Let |data| be an instance of the `subjectPublicKeyInfo` + ASN.1 structure defined in [[RFC5280]] + with the following properties: +

      +
        +
      • +

        + Set the |algorithm| field to an + `AlgorithmIdentifier` ASN.1 type with the following + properties: +

        +
          +
        • +

          + Set the |algorithm| object identifier to the + `id-Ed25519` OID defined in [[RFC8410]]. +

          +
        • +
        +
      • +
      • +

        + Set the |subjectPublicKey| field to |keyData|. +

        +
      • +
      +
    4. +
    5. +

      + Let |result| be a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing + |data|. +

      +
    6. +
    +
    +
    If |format| is {{KeyFormat/"pkcs8"}}:
    +
    +
      +
    1. +

      + If the [[\type]] internal slot + of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. +

      +
    2. +
    3. +

      + Let |data| be an instance of the `privateKeyInfo` + ASN.1 structure defined in [[RFC5208]] + with the following properties: +

      +
        +
      • +

        + Set the |version| field to `0`. +

        +
      • +
      • +

        + Set the |privateKeyAlgorithm| field to a + `PrivateKeyAlgorithmIdentifier` ASN.1 type with the + following properties: +

        +
          +
        • +

          + Set the |algorithm| object identifier to the + `id-Ed25519` OID defined in [[RFC8410]]. +

          +
        • +
        +
      • +
      • +

        + Set the |privateKey| field to the result of DER-encoding + a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the + Ed25519 private key represented by the [[\handle]] internal slot of + |key| +

        +
      • +
      +
    4. +
    5. +

      + Let |result| be a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing + |data|. +

      +
    6. +
    +
    +
    If |format| is {{KeyFormat/"jwk"}}:
    +
    +
      +
    1. +

      + Let |jwk| be a new {{JsonWebKey}} + dictionary. +

      +
    2. +
    3. +

      + Set the `kty` attribute of |jwk| to + "`OKP`". +

      +
    4. +
    5. +

      + Set the `crv` attribute of |jwk| to + "`Ed25519`". +

      +
    6. +
    7. +

      + Set the {{JsonWebKey/x}} attribute of |jwk| according to the + definition in Section 2 of [[RFC8037]]. +

      +
    8. +
    9. +
      +
      + If the [[\type]] internal slot + of |key| is {{KeyType/"private"}} +
      +
      + Set the {{JsonWebKey/d}} attribute of |jwk| according to the + definition in Section 2 of [[RFC8037]]. +
      +
      +
    10. +
    11. +

      + Set the `key_ops` attribute of |jwk| to the {{CryptoKey/usages}} attribute of |key|. +

      +
    12. +
    13. +

      + Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot + of |key|. +

      +
    14. +
    15. +

      + Let |result| be the result of converting |jwk| + to an ECMAScript Object, as defined by [[WebIDL]]. +

      +
    16. +
    +
    +
    + If |format| is {{KeyFormat/"raw"}}: +
    +
    +
      +
    1. +

      + If the [[\type]] internal slot + of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. +

      +
    2. +
    3. +

      + Let |data| be an octet string representing the Ed25519 + public key represented by the [[\handle]] internal slot of + |key|. +

      +
    4. +
    5. +

      + Let |result| be a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing + |data|. +

      +
    6. +
    +
    +
    Otherwise:
    +
    +

    + [= exception/throw =] a + {{NotSupportedError}}. +

    +
    +
    +
  6. +
  7. +

    + Return |result|. +

    +
  8. +
+
+
+
+
+ +
+

X25519

+
+

Description

+

+ The "`X25519`" algorithm identifier is used to perform + key agreement using the X25519 algorithm specified in + [[RFC7748]]. +

+
+
+

Registration

+

+ The recognized algorithm name + for this algorithm is "`X25519`". +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationParametersResult
deriveBits{{EcdhKeyDeriveParams}}octet string
generateKeyNone{{CryptoKeyPair}}
importKeyNone{{CryptoKey}}
exportKeyNoneobject
+
+ +
+

Operations

+
+
Derive Bits
+
+
    +
  1. +

    + If the [[\type]] internal slot of + |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. +

    +
  2. +
  3. +

    + Let |publicKey| be the + {{EcdhKeyDeriveParams/public}} member of + |normalizedAlgorithm|. +

    +
  4. +
  5. +

    + If the [[\type]] internal slot of + |publicKey| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. +

    +
  6. +
  7. +

    + If the {{KeyAlgorithm/name}} attribute of + the [[\algorithm]] internal slot of + |publicKey| is not equal to the {{KeyAlgorithm/name}} property of the [[\algorithm]] internal slot of + |key|, then [= exception/throw =] an {{InvalidAccessError}}. +

    +
  8. +
  9. +

    + Let |secret| be the result of performing the X25519 function specified in + [[RFC7748]] Section 5 with |key| as the X25519 private key |k| + and the X25519 public key represented by the [[\handle]] + internal slot of |publicKey| as the X25519 public key |u|. +

    +
  10. +
  11. +

    + If |secret| is the all-zero value, + then [= exception/throw =] a {{OperationError}}. + This check must be performed in constant-time, as per [[RFC7748]] Section 6.1. +

    +
  12. +
  13. +
    +
    If |length| is null:
    +
    Return |secret|
    +
    Otherwise:
    +
    +
    +
    + If the length of |secret| in bits is less than + |length|: +
    +
    + [= exception/throw =] an + {{OperationError}}. +
    +
    Otherwise:
    +
    + Return an octet string containing the first |length| bits of |secret|. +
    +
    +
    +
    +
  14. +
+
+
Generate Key
+
+
    +
  1. +

    + If |usages| contains an entry which is not + "`deriveKey`" or "`deriveBits`" + then [= exception/throw =] a + {{SyntaxError}}. +

    +
  2. +
  3. +

    + Generate an X25519 key pair, with the private key being 32 random bytes, + and the public key being `X25519(a, 9)`, + as defined in [[RFC7748]], section 6.1. +

    +
  4. +
  5. +

    + Let |algorithm| be a new {{KeyAlgorithm}} object. +

    +
  6. +
  7. +

    + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`X25519`". +

    +
  8. +
  9. +

    + Let |publicKey| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + representing the public key of the generated key pair. +

    +
  10. +
  11. +

    + Set the [[\type]] internal slot of + |publicKey| to "`public`" +

    +
  12. +
  13. +

    + Set the [[\algorithm]] internal + slot of |publicKey| to |algorithm|. +

    +
  14. +
  15. +

    + Set the [[\extractable]] internal + slot of |publicKey| to true. +

    +
  16. +
  17. +

    + Set the [[\usages]] internal slot of + |publicKey| to be the empty list. +

    +
  18. +
  19. +

    + Let |privateKey| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + representing the private key of the generated key pair. +

    +
  20. +
  21. +

    + Set the [[\type]] internal slot of + |privateKey| to {{KeyType/"private"}} +

    +
  22. +
  23. +

    + Set the [[\algorithm]] internal + slot of |privateKey| to |algorithm|. +

    +
  24. +
  25. +

    + Set the [[\extractable]] internal + slot of |privateKey| to |extractable|. +

    +
  26. +
  27. +

    + Set the [[\usages]] internal slot of + |privateKey| to be the + usage intersection of + |usages| and `[ "deriveKey", "deriveBits" ]`. +

    +
  28. +
  29. +

    + Let |result| be a new {{CryptoKeyPair}} + dictionary. +

    +
  30. +
  31. +

    + Set the {{CryptoKeyPair/publicKey}} attribute + of |result| to be |publicKey|. +

    +
  32. +
  33. +

    + Set the {{CryptoKeyPair/privateKey}} attribute + of |result| to be |privateKey|. +

    +
  34. +
  35. +

    + Return the result of converting |result| to an ECMAScript Object, as + defined by [[WebIDL]]. +

    +
  36. +
+
+ +
Import Key
+
+
    +
  1. +

    Let |keyData| be the key data to be imported.

    +
  2. +
  3. +
    +
    If |format| is {{KeyFormat/"spki"}}:
    +
    +
      +
    1. +

      + If |usages| is not empty + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    2. +
    3. +

      + Let |spki| be the result of running the + parse a subjectPublicKeyInfo + algorithm over |keyData|. +

      +
    4. +
    5. +

      + If an error occurred while parsing, + then [= exception/throw =] a + {{DataError}}. +

      +
    6. +
    7. +

      + If the `algorithm` object identifier field of the + `algorithm` AlgorithmIdentifier field of |spki| is + not equal to the `id-X25519` + object identifier defined in [[RFC8410]], + then [= exception/throw =] a + {{DataError}}. +

      +
    8. +
    9. +

      + If the `parameters` field of the `algorithm` + AlgorithmIdentifier field of |spki| is present, + then [= exception/throw =] a + {{DataError}}. +

      +
    10. +
    11. +

      + Let |publicKey| be the X25519 public key identified by + the `subjectPublicKey` field of |spki|. +

      +
    12. +
    13. +

      + Let |key| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + that represents |publicKey|. +

      +
    14. +
    15. +

      + Set the [[\type]] internal slot + of |key| to "`public`" +

      +
    16. +
    17. +

      + Let |algorithm| be a new {{KeyAlgorithm}}. +

      +
    18. +
    19. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`X25519`". +

      +
    20. +
    21. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    22. +
    +
    +
    If |format| is {{KeyFormat/"pkcs8"}}:
    +
    +
      +
    1. +

      + If |usages| contains an entry which is not + "`deriveKey`" or "`deriveBits`" + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    2. +
    3. +

      + Let |privateKeyInfo| be the result of running the + parse a privateKeyInfo + algorithm over |keyData|. +

      +
    4. +
    5. +

      + If an error occurs while parsing, + then [= exception/throw =] a + {{DataError}}. +

      +
    6. +
    7. +

      + If the `algorithm` object identifier field of the + `privateKeyAlgorithm` PrivateKeyAlgorithm field of + |privateKeyInfo| is not equal to the + `id-X25519` object identifier defined in [[RFC8410]], + then [= exception/throw =] a + {{DataError}}. +

      +
    8. +
    9. +

      + If the `parameters` field of the + `privateKeyAlgorithm` PrivateKeyAlgorithmIdentifier field + of |privateKeyInfo| is present, + then [= exception/throw =] a + {{DataError}}. +

      +
    10. +
    11. +

      + Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure + algorithm, with |data| as the `privateKey` field + of |privateKeyInfo|, |structure| as the ASN.1 + `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. +

      +
    12. +
    13. +

      + If an error occurred while parsing, + then [= exception/throw =] a + {{DataError}}. +

      +
    14. +
    15. +

      + Let |key| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + that represents the X25519 private key identified by |curvePrivateKey|. +

      +
    16. +
    17. +

      + Set the [[\type]] internal slot + of |key| to {{KeyType/"private"}} +

      +
    18. +
    19. +

      + Let |algorithm| be a new {{KeyAlgorithm}}. +

      +
    20. +
    21. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`X25519`". +

      +
    22. +
    23. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    24. +
    +
    +
    If |format| is {{KeyFormat/"jwk"}}:
    +
    +
      +
    1. +
      +
      If |keyData| is a {{JsonWebKey}} dictionary:
      +

      Let |jwk| equal |keyData|.

      +
      Otherwise:
      +

      [= exception/Throw =] a {{DataError}}.

      +
      +
    2. +
    3. +

      + If the {{JsonWebKey/d}} field is present and if |usages| + contains an entry which is not + "`deriveKey`" or "`deriveBits`" + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    4. +
    5. +

      + If the {{JsonWebKey/d}} field is not present and if |usages| is not + empty + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    6. +
    7. +

      + If the {{JsonWebKey/kty}} field of |jwk| is not + "`OKP`", + then [= exception/throw =] a + {{DataError}}. +

      +
    8. +
    9. +

      + If the {{JsonWebKey/crv}} field of |jwk| is not + "`X25519`", + then [= exception/throw =] a + {{DataError}}. +

      +
    10. +
    11. +

      + If |usages| is non-empty and the {{JsonWebKey/use}} field of |jwk| is present + and is not equal to "`enc`" then [= exception/throw =] a + {{DataError}}. +

      +
    12. +
    13. +

      + If the {{JsonWebKey/key_ops}} field of |jwk| is present, and + is invalid according to the requirements of JSON Web + Key [[JWK]], or it does not contain all of the specified |usages| + values, + then [= exception/throw =] a + {{DataError}}. +

      +
    14. +
    15. +

      + If the {{JsonWebKey/ext}} field of |jwk| is present and + has the value false and |extractable| is true, + then [= exception/throw =] a + {{DataError}}. +

      +
    16. +
    17. +
      +
      If the {{JsonWebKey/d}} field is present:
      +
      +
        +
      1. +

        + If |jwk| does not meet the requirements of Section 2 + of [[RFC8037]], then [= exception/throw =] a {{DataError}}. +

        +
      2. +
      3. +

        + Let |key| be a new {{CryptoKey}} object that represents the + X25519 private key identified by interpreting + |jwk| according to Section 2 of [[RFC8037]]. +

        +
      4. +
      5. +

        + Set the [[\type]] + internal slot of |Key| to {{KeyType/"private"}}. +

        +
      6. +
      +
      +
      Otherwise:
      +
      +
        +
      1. +

        + If |jwk| does not meet the requirements of Section 2 + of [[RFC8037]], then [= exception/throw =] a {{DataError}}. +

        +
      2. +
      3. +

        + Let |key| be a new {{CryptoKey}} object that represents the + X25519 public key identified by interpreting + |jwk| according to Section 2 of [[RFC8037]]. +

        +
      4. +
      5. +

        + Set the [[\type]] + internal slot of |Key| to {{KeyType/"public"}}. +

        +
      6. +
      +
      +
      +
    18. +
    19. +

      + Let |algorithm| be a new instance of a {{KeyAlgorithm}} object. +

      +
    20. +
    21. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`X25519`". +

      +
    22. +
    23. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    24. +
    +
    +
    If |format| is {{KeyFormat/"raw"}}:
    +
    +
      +
    1. +

      + If |usages| is not empty + then [= exception/throw =] a + {{SyntaxError}}. +

      +
    2. +
    3. +

      + Let |algorithm| be a new {{KeyAlgorithm}} object. +

      +
    4. +
    5. +

      + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`X25519`". +

      +
    6. +
    7. +

      + Let |key| be a new {{CryptoKey}} associated with the + [= relevant global object =] + of `this` [[HTML]], and + representing the key data provided in |keyData|. +

      +
    8. +
    9. +

      + Set the [[\type]] internal slot + of |key| to "`public`" +

      +
    10. +
    11. +

      + Set the [[\algorithm]] + internal slot of |key| to |algorithm|. +

      +
    12. +
    +
    +
    Otherwise:
    +
    +

    + [= exception/throw =] a + {{NotSupportedError}}. +

    +
    +
    +
  4. +
  5. +

    + Return |key| +

    +
  6. +
+
+ +
Export Key
+
+
    +
  1. +

    + Let |key| be the {{CryptoKey}} to be + exported. +

    +
  2. +
  3. +

    + If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| + cannot be accessed, then [= exception/throw =] an {{OperationError}}. +

    +
  4. +
  5. +
    +
    If |format| is {{KeyFormat/"spki"}}:
    +
    +
      +
    1. +

      + If the [[\type]] internal slot + of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. +

      +
    2. +
    3. +

      + Let |data| be an instance of the `subjectPublicKeyInfo` + ASN.1 structure defined in [[RFC5280]] + with the following properties: +

      +
        +
      • +

        + Set the |algorithm| field to an + `AlgorithmIdentifier` ASN.1 type with the following + properties: +

        +
          +
        • +

          + Set the |algorithm| object identifier to the + `id-X25519` OID defined in [[RFC8410]]. +

          +
        • +
        +
      • +
      • +

        + Set the |subjectPublicKey| field to |keyData|. +

        +
      • +
      +
    4. +
    5. +

      + Let |result| be a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing + |data|. +

      +
    6. +
    +
    +
    If |format| is {{KeyFormat/"pkcs8"}}:
    +
    +
      +
    1. +

      + If the [[\type]] internal slot + of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}. +

      +
    2. +
    3. +

      + Let |data| be an instance of the `privateKeyInfo` + ASN.1 structure defined in [[RFC5208]] + with the following properties: +

      +
        +
      • +

        + Set the |version| field to `0`. +

        +
      • +
      • +

        + Set the |privateKeyAlgorithm| field to a + `PrivateKeyAlgorithmIdentifier` ASN.1 type with the + following properties: +

        +
          +
        • +

          + Set the |algorithm| object identifier to the + `id-X25519` OID defined in [[RFC8410]]. +

          +
        • +
        +
      • +
      • +

        + Set the |privateKey| field to the result of DER-encoding + a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the + X25519 private key represented by the [[\handle]] internal slot of + |key| +

        +
      • +
      +
    4. +
    5. +

      + Let |result| be a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing + |data|. +

      +
    6. +
    +
    +
    If |format| is {{KeyFormat/"jwk"}}:
    +
    +
      +
    1. +

      + Let |jwk| be a new {{JsonWebKey}} + dictionary. +

      +
    2. +
    3. +

      + Set the `kty` attribute of |jwk| to + "`OKP`". +

      +
    4. +
    5. +

      + Set the `crv` attribute of |jwk| to + "`X25519`". +

      +
    6. +
    7. +

      + Set the {{JsonWebKey/x}} attribute of |jwk| according to the + definition in Section 2 of [[RFC8037]]. +

      +
    8. +
    9. +
      +
      + If the [[\type]] internal slot + of |key| is {{KeyType/"private"}} +
      +
      + Set the {{JsonWebKey/d}} attribute of |jwk| according to the + definition in Section 2 of [[RFC8037]]. +
      +
      +
    10. +
    11. +

      + Set the `key_ops` attribute of |jwk| to the {{CryptoKey/usages}} attribute of |key|. +

      +
    12. +
    13. +

      + Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot + of |key|. +

      +
    14. +
    15. +

      + Let |result| be the result of converting |jwk| + to an ECMAScript Object, as defined by [[WebIDL]]. +

      +
    16. +
    +
    +
    + If |format| is {{KeyFormat/"raw"}}: +
    +
    +
      +
    1. +

      + If the [[\type]] internal slot + of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}. +

      +
    2. +
    3. +

      + Let |data| be an octet string representing the X25519 + public key represented by the [[\handle]] internal slot of + |key|. +

      +
    4. +
    5. +

      + Let |result| be a new {{ArrayBuffer}} associated with the + [= relevant global object =] + of `this` [[HTML]], and containing + |data|. +

      +
    6. +
    +
    +
    Otherwise:
    +
    +

    + [= exception/throw =] a + {{NotSupportedError}}. +

    +
    +
    +
  6. +
  7. +

    + Return |result|. +

    +
  8. +
+
+
+
+
+ +
+

AES-CTR

+
+

Description

+

+ The "`AES-CTR`" algorithm identifier is used to perform + encryption and decryption using AES in Counter mode, + as described in [[NIST-SP800-38A]]. +

+
+
+

Registration

+

+ The [= recognized algorithm name =] for + this algorithm is "`AES-CTR`". +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationParametersResult
encrypt{{AesCtrParams}}{{ArrayBuffer}}
decrypt{{AesCtrParams}}{{ArrayBuffer}}
generateKey{{AesKeyGenParams}}{{CryptoKey}}
importKeyNone{{CryptoKey}}
exportKeyNoneobject
get key length{{AesDerivedKeyParams}}Integer
+
+ +
+

AesCtrParams dictionary

+
+dictionary AesCtrParams : Algorithm {
+  required BufferSource counter;
+  required [EnforceRange] octet length;
+};
+          
+

The counter member contains the initial value of the counter block. {{AesCtrParams/counter}} MUST be 16 bytes (the AES block size). The counter bits are the rightmost length + bits of the counter block. The rest of the counter block is for + the nonce. The counter bits are incremented using the standard + incrementing function specified in NIST SP 800-38A Appendix B.1: + the counter bits are interpreted as a big-endian integer and + incremented by one.

+

The length member contains the length, in bits, of the rightmost part of the counter block that is incremented.

+
+
+

AesKeyAlgorithm dictionary

+
+dictionary AesKeyAlgorithm : KeyAlgorithm {
+  required unsigned short length;
+};
+          
+

The length member represents the length, in bits, of the key.

+
+
+

AesKeyGenParams dictionary

+
+dictionary AesKeyGenParams : Algorithm {
+  required [EnforceRange] unsigned short length;
+};
+          
+

The length member represents the length, in bits, of the key.

+
+
+

AesDerivedKeyParams dictionary

+
+dictionary AesDerivedKeyParams : Algorithm {
+  required [EnforceRange] unsigned short length;
+};
+          
+

The length member represents the length, in bits, of the key.

+
+ +
+

Operations

+
+
Encrypt
+
+
    +
  1. +

    + If the {{AesCtrParams/counter}} member of + |normalizedAlgorithm| does not have length 16 + bytes, + then [= exception/throw =] an + {{OperationError}}. +

    +
  2. +
  3. +

    + If the {{AesCtrParams/length}} member of + |normalizedAlgorithm| is zero or is greater + than 128, + then [= exception/throw =] an + {{OperationError}}. +

    +
  4. +
  5. +

    + Let |ciphertext| be the result of performing the CTR Encryption + operation described in Section 6.5 of [[NIST-SP800-38A]] using AES as the block cipher, the contents of the {{AesCtrParams/counter}} member of + |normalizedAlgorithm| as the initial value of the counter block, the + {{AesCtrParams/length}} member of + |normalizedAlgorithm| as the input parameter |m| to the + standard counter block incrementing function defined in Appendix B.1 of + [[NIST-SP800-38A]] and the contents of + |plaintext| as the input plaintext. +

    +
  6. +
  7. +

    + Return the result of [= ArrayBuffer/create | creating =] + an {{ArrayBuffer}} containing |ciphertext|. +

    +
  8. +
+
+
Decrypt
+
+
    +
  1. +

    + If the {{AesCtrParams/counter}} member of + |normalizedAlgorithm| does not have length 16 + bytes, + then [= exception/throw =] an + {{OperationError}}. +

    +
  2. +
  3. +

    + If the {{AesCtrParams/length}} member of + |normalizedAlgorithm| is zero or is greater + than 128, + then [= exception/throw =] an + {{OperationError}}. +

    +
  4. +
  5. +

    + Let |plaintext| be the result of performing the CTR Decryption + operation described in Section 6.5 of [[NIST-SP800-38A]] using AES as the block cipher, the contents of the {{AesCtrParams/counter}} member of + |normalizedAlgorithm| as the initial value of the counter block, the + {{AesCtrParams/length}} member of + |normalizedAlgorithm| as the input parameter |m| to the + standard counter block incrementing function defined in Appendix B.1 of + [[NIST-SP800-38A]] and the contents of + |ciphertext| as the input ciphertext. +

    +
  6. +
  7. +

    + Return the result of [= ArrayBuffer/create | creating =] + an {{ArrayBuffer}} containing |plaintext|. +

    +
  8. +
+
+
Generate Key
+
+
    +
  1. +

    + If |usages| contains any entry which is not + one of "`encrypt`", "`decrypt`", + "`wrapKey`" or "`unwrapKey`", + then [= exception/throw =] a + {{SyntaxError}}. +

    +
  2. +
  3. +

    + If the {{AesKeyGenParams/length}} member of + |normalizedAlgorithm| is not equal to one of + 128, 192 or 256, + then [= exception/throw =] an + {{OperationError}}. +

    +
  4. + +
  5. +

    + Generate an AES key of length + equal to the {{AesKeyGenParams/length}} member of + |normalizedAlgorithm|. +

    +
  6. +
  7. +

    + If the key generation step fails, + then [= exception/throw =] an + {{OperationError}}. +

    +
  8. +
  9. +

    + Let |key| be a new + {{CryptoKey}} object representing the + generated AES key. +

    +
  10. +
  11. +

    + Let |algorithm| be a new + {{AesKeyAlgorithm}}. +

    +
  12. +
  13. +

    + Set the {{KeyAlgorithm/name}} attribute of + |algorithm| to "`AES-CTR`". +

    +
  14. +
  15. +

    + Set the {{AesKeyAlgorithm/length}} attribute of + |algorithm| to equal the + {{AesKeyGenParams/length}} member of + |normalizedAlgorithm|. +

    +
  16. +
  17. +

    + Set the {{CryptoKey/[[algorithm]]}} internal + slot of |key| to |algorithm|. +

    +
  18. +
  19. +

    + Set the {{CryptoKey/[[extractable]]}} internal + slot of |key| to be |extractable|. +

    +
  20. +
  21. +

    + Set the {{CryptoKey/[[usages]]}} internal slot of + |key| to be |usages|. +

    +
  22. +
  23. +

    + Return |key|. +

    +
  24. +
+
+
Import Key
+
+
    +
  1. +

    + If |usages| contains an entry which is not + one of "`encrypt`", "`decrypt`", + "`wrapKey`" or "`unwrapKey`", + then [= exception/throw =] a + {{SyntaxError}}. +

    +
  2. +
  3. +
    +
    If |format| is {{KeyFormat/"raw"}}:
    +
    +
      +
    1. +

      + Let |data| be the [= octet string =] contained in |keyData|. +

      +
    2. If the length in bits of |data| is not 128, 192 or 256 @@ -13408,6 +15145,52 @@

      Operations

      JavaScript Example Code

      +
      +

      Usage Example

      +

      + This example generates two X25519 key pairs, one for Alice and one for Bob, performs + a key agreement between them, derives a 256-bit AES-GCM key from the result using + HKDF with SHA-256, and encrypts and decrypts some data with it. +

      +
      +            // Generate a key pair for Alice.
      +            const alice_x25519_key = await crypto.subtle.generateKey('X25519', false /* extractable */, ['deriveKey']);
      +            const alice_private_key = alice_x25519_key.privateKey;
      +
      +            // Normally, the public key would be sent by Bob to Alice in advance over some authenticated channel.
      +            // In this example, we'll generate another key pair and use its public key instead.
      +            const bob_x25519_key = await crypto.subtle.generateKey('X25519', false /* extractable */, ['deriveKey']);
      +            const bob_public_key = bob_x25519_key.publicKey;
      +
      +            // Perform the key agreement.
      +            const alice_x25519_params = { name: 'X25519', public: bob_public_key };
      +            const alice_shared_key = await crypto.subtle.deriveKey(alice_x25519_params, alice_private_key, 'HKDF', false /* extractable */, ['deriveKey']);
      +
      +            // Derive a symmetric key from the result.
      +            const salt = crypto.getRandomValues(new Uint8Array(32));
      +            const info = new TextEncoder().encode('X25519 key agreement for an AES-GCM-256 key');
      +            const hkdf_params = { name: 'HKDF', hash: 'SHA-256', salt, info };
      +            const gcm_params = { name: 'AES-GCM', length: 256 };
      +            const alice_symmetric_key = await crypto.subtle.deriveKey(hkdf_params, alice_shared_key, gcm_params, false /* extractable */, ['encrypt', 'decrypt']);
      +
      +            // Encrypt some data with the symmetric key, and send it to Bob. The IV must be passed along as well.
      +            const iv = crypto.getRandomValues(new Uint8Array(12));
      +            const message = new TextEncoder().encode('Hi Bob!');
      +            const encrypted = await crypto.subtle.encrypt({ ...gcm_params, iv }, alice_symmetric_key, message);
      +
      +            // On Bob's side, Alice's public key and Bob's private key are used, instead.
      +            // To get the same result, Alice and Bob must agree on using the same salt and info.
      +            const alice_public_key = alice_x25519_key.publicKey;
      +            const bob_private_key = bob_x25519_key.privateKey;
      +            const bob_x25519_params = { name: 'X25519', public: alice_public_key };
      +            const bob_shared_key = await crypto.subtle.deriveKey(bob_x25519_params, bob_private_key, 'HKDF', false /* extractable */, ['deriveKey']);
      +            const bob_symmetric_key = await crypto.subtle.deriveKey(hkdf_params, bob_shared_key, gcm_params, false /* extractable */, ['encrypt', 'decrypt']);
      +
      +            // On Bob's side, the data can be decrypted.
      +            const decrypted = await crypto.subtle.decrypt({ ...gcm_params, iv }, bob_symmetric_key, encrypted);
      +            const decrypted_message = new TextDecoder().decode(decrypted);
      +          
      +

      Generate a signing key pair, sign some data

      @@ -13844,6 +15627,32 @@

      Algorithm mappings

      +{ kty: "OKP",
      +  crv: "Ed25519" }
      +
      + + +
      +{ name: "Ed25519" }
      +
      + + + + +
      +{ kty: "OKP",
      +  crv: "X25519" }
      +
      + + +
      +{ name: "X25519" }
      +
      + + + + +
       { kty: "oct",
         alg: "A128CTR" }
       
      @@ -14148,6 +15957,26 @@

      Mapping between Algorithm and SubjectPublicKeyInfo

      "`ECDH`" or "`ECDSA`" [[RFC5480]] + + id-Ed25519 (1.3.101.112) + BIT STRING + + "`Ed25519`" + + + [[RFC8410]] + + + + id-X25519 (1.3.101.110) + BIT STRING + + "`X25519`" + + + [[RFC8410]] + +
      @@ -14196,6 +16025,26 @@

      Mapping between Algorithm and PKCS#8 PrivateKeyInfo

      [[RFC5480]] + + id-Ed25519 (1.3.101.112) + CurvePrivateKey + + "`Ed25519`" + + + [[RFC8410]] + + + + id-X25519 (1.3.101.110) + CurvePrivateKey + + "`X25519`" + + + [[RFC8410]] + +
      From f120a972ce03e2ceace9fd4a98c9b74edd7b7d0a Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Sun, 5 Nov 2023 16:08:31 +0100 Subject: [PATCH 2/5] Update examples Also, fix section hierarchy. --- spec/Overview.html | 93 +++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/spec/Overview.html b/spec/Overview.html index f5d4d59..302c137 100644 --- a/spec/Overview.html +++ b/spec/Overview.html @@ -15146,7 +15146,7 @@

      Operations

      JavaScript Example Code

      -

      Usage Example

      +

      Generate two key pairs, derive a shared key, encrypt some data

      This example generates two X25519 key pairs, one for Alice and one for Bob, performs a key agreement between them, derives a 256-bit AES-GCM key from the result using @@ -15194,71 +15194,38 @@

      Usage Example

      Generate a signing key pair, sign some data

      -
      -var encoder = new TextEncoder('utf-8');
      -
      -// Algorithm Object
      -var algorithmKeyGen = {
      -  name: "RSASSA-PKCS1-v1_5",
      -  // RsaHashedKeyGenParams
      -  modulusLength: 2048,
      -  publicExponent: new Uint8Array([0x01, 0x00, 0x01]),  // Equivalent to 65537
      -  hash: {
      -    name: "SHA-256"
      -  }
      -};
      -
      -var algorithmSign = {
      -  name: "RSASSA-PKCS1-v1_5"
      -};
      -
      -window.crypto.subtle.generateKey(algorithmKeyGen, false, ["sign"]).then(
      -  function(key) {
      -    var dataPart1 = encoder.encode("hello,");
      -    var dataPart2 = encoder.encode(" world!");
      -
      -    return window.crypto.subtle.sign(algorithmSign, key.privateKey, [dataPart1, dataPart2]);
      -  },
      -  console.error.bind(console, "Unable to generate a key")
      -).then(
      -  console.log.bind(console, "The signature is: "),
      -  console.error.bind(console, "Unable to sign")
      -);
      -        
      +
      +            const data = new TextEncoder().encode('Hello, world!');
      +            const key = await crypto.subtle.generateKey('Ed25519', false, ['sign']);
      +            const signature = await crypto.subtle.sign('Ed25519', key.privateKey, data);
      +          
      -

      Symmetric Encryption

      -
      -var encoder = new TextEncoder('utf-8');
      -var clearDataArrayBufferView = encoder.encode("Plain Text Data");
      -
      -var aesAlgorithmKeyGen = {
      -  name: "AES-CBC",
      -  // AesKeyGenParams
      -  length: 128
      -};
      -
      -var aesAlgorithmEncrypt = {
      -  name: "AES-CBC",
      -  // AesCbcParams
      -  iv: window.crypto.getRandomValues(new Uint8Array(16))
      -};
      -
      -// Create a key generator to produce a one-time-use AES key to encrypt some data
      -window.crypto.subtle.generateKey(aesAlgorithmKeyGen, false, ["encrypt"]).then(
      -  function(aesKey) {
      -    return window.crypto.subtle.encrypt(aesAlgorithmEncrypt, aesKey, clearDataArrayBufferView);
      -  }
      -).then(console.log.bind(console, "The ciphertext is: "),
      -       console.error.bind(console, "Unable to encrypt"));
      -
      +

      Generate a symmetric key, encrypt some data

      +
      +            const data = new TextEncoder().encode('Hello, world!');
      +            const aesAlgorithmKeyGen = {
      +              name: 'AES-GCM',
      +              // AesKeyGenParams
      +              length: 256
      +            };
      +            const aesAlgorithmEncrypt = {
      +              name: 'AES-GCM',
      +              // AesGcmParams
      +              iv: crypto.getRandomValues(new Uint8Array(16))
      +            };
      +            const key = await crypto.subtle.generateKey(aesAlgorithmKeyGen, false, ['encrypt']);
      +            const encrypted = await crypto.subtle.encrypt(aesAlgorithmEncrypt, key, data);
      +          
      +
      +
      +

      Generate unique name for download

      +
      +            const filename = `${crypto.randomUUID()}.txt`;
      +          
      +
      -
      -

      Generate unique name for download

      -
      -const filename = `${crypto.randomUUID()}.txt`;
      -
      -
      +

      IANA Considerations

      From 624818930d181dcf71cc0f69aa99cced4a7a472f Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Mon, 19 Feb 2024 18:30:55 +0100 Subject: [PATCH 3/5] Update references --- spec/Overview.html | 162 +++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/spec/Overview.html b/spec/Overview.html index 302c137..f724f3e 100644 --- a/spec/Overview.html +++ b/spec/Overview.html @@ -10018,15 +10018,15 @@

      Description

      Registration

      - The recognized algorithm name - for this algorithm is "`Ed25519`". + The [= recognized algorithm name =] for + this algorithm is "`Ed25519`".

      - - - + + + @@ -10068,7 +10068,7 @@

      Operations

      1. - If the [[\type]] internal slot of + If the {{CryptoKey/[[type]]}} internal slot of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}.

      2. @@ -10096,7 +10096,7 @@

        Operations

        1. - If the [[\type]] internal slot of + If the {{CryptoKey/[[type]]}} internal slot of |key| is not {{KeyType/"public"}}, then [= exception/throw =] an {{InvalidAccessError}}.

        2. @@ -10171,26 +10171,26 @@

          Operations

        3. - Set the [[\type]] internal slot of + Set the {{CryptoKey/[[type]]}} internal slot of |publicKey| to "`public`"

        4. - Set the [[\algorithm]] internal + Set the {{CryptoKey/[[algorithm]]}} internal slot of |publicKey| to |algorithm|.

        5. - Set the [[\extractable]] internal + Set the {{CryptoKey/[[extractable]]}} internal slot of |publicKey| to true.

        6. - Set the [[\usages]] internal slot of - |publicKey| to be the usage intersection + Set the {{CryptoKey/[[usages]]}} internal slot of + |publicKey| to be the [= usage intersection =] of |usages| and `[ "verify" ]`.

        7. @@ -10204,26 +10204,26 @@

          Operations

        8. - Set the [[\type]] internal slot of + Set the {{CryptoKey/[[type]]}} internal slot of |privateKey| to {{KeyType/"private"}}

        9. - Set the [[\algorithm]] internal + Set the {{CryptoKey/[[algorithm]]}} internal slot of |privateKey| to |algorithm|.

        10. - Set the [[\extractable]] internal + Set the {{CryptoKey/[[extractable]]}} internal slot of |privateKey| to |extractable|.

        11. - Set the [[\usages]] internal slot of - |privateKey| to be the usage intersection + Set the {{CryptoKey/[[usages]]}} internal slot of + |privateKey| to be the [= usage intersection =] of |usages| and `[ "sign" ]`.

        12. @@ -10276,7 +10276,7 @@

          Operations

        13. Let |spki| be the result of running the - parse a subjectPublicKeyInfo + [= parse a subjectPublicKeyInfo =] algorithm over |keyData|.

        14. @@ -10321,7 +10321,7 @@

          Operations

        15. - Set the [[\type]] internal slot + Set the {{CryptoKey/[[type]]}} internal slot of |key| to "`public`"

        16. @@ -10338,7 +10338,7 @@

          Operations

        17. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

        18. @@ -10358,7 +10358,7 @@

          Operations

        19. Let |privateKeyInfo| be the result of running the - parse a privateKeyInfo + [= parse a privateKeyInfo =] algorithm over |keyData|.

        20. @@ -10390,7 +10390,8 @@

          Operations

        21. - Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure + Let |curvePrivateKey| be the result of performing the + [= parse an ASN.1 structure =] algorithm, with |data| as the `privateKey` field of |privateKeyInfo|, |structure| as the ASN.1 `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. @@ -10413,7 +10414,7 @@

          Operations

        22. - Set the [[\type]] internal slot + Set the {{CryptoKey/[[type]]}} internal slot of |key| to {{KeyType/"private"}}

        23. @@ -10430,7 +10431,7 @@

          Operations

        24. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

        25. @@ -10521,7 +10522,7 @@

          Operations

        26. - Set the [[\type]] + Set the {{CryptoKey/[[type]]}} internal slot of |Key| to {{KeyType/"private"}}.

        27. @@ -10545,7 +10546,7 @@

          Operations

        28. - Set the [[\type]] + Set the {{CryptoKey/[[type]]}} internal slot of |Key| to {{KeyType/"public"}}.

        29. @@ -10566,7 +10567,7 @@

          Operations

        30. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

        31. @@ -10604,13 +10605,13 @@

          Operations

        32. - Set the [[\type]] internal slot + Set the {{CryptoKey/[[type]]}} internal slot of |key| to "`public`"

        33. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

        34. @@ -10644,7 +10645,7 @@

          Operations

        35. - If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| + If the underlying cryptographic key material represented by the {{CryptoKey/[[handle]]}} internal slot of |key| cannot be accessed, then [= exception/throw =] an {{OperationError}}.

        36. @@ -10655,7 +10656,7 @@

          Operations

          1. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}.

          2. @@ -10703,7 +10704,7 @@

            Operations

            1. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}.

            2. @@ -10738,7 +10739,7 @@

              Operations

              Set the |privateKey| field to the result of DER-encoding a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the - Ed25519 private key represented by the [[\handle]] internal slot of + Ed25519 private key represented by the {{CryptoKey/[[handle]]}} internal slot of |key|

              @@ -10784,7 +10785,7 @@

              Operations

            3. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is {{KeyType/"private"}}
              @@ -10800,7 +10801,7 @@

              Operations

            4. - Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot + Set the `ext` attribute of |jwk| to the {{CryptoKey/[[extractable]]}} internal slot of |key|.

            5. @@ -10819,14 +10820,14 @@

              Operations

              1. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}.

              2. - Let |data| be an octet string representing the Ed25519 - public key represented by the [[\handle]] internal slot of + Let |data| be an [= octet string =] representing the Ed25519 + public key represented by the {{CryptoKey/[[handle]]}} internal slot of |key|.

              3. @@ -10873,22 +10874,22 @@

                Description

                Registration

                - The recognized algorithm name - for this algorithm is "`X25519`". + The [= recognized algorithm name =] for + this algorithm is "`X25519`".

      OperationParametersResultOperationParametersResult
      - - - + + + - + @@ -10917,7 +10918,7 @@

      Operations

      1. - If the [[\type]] internal slot of + If the {{CryptoKey/[[type]]}} internal slot of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}.

      2. @@ -10930,15 +10931,15 @@

        Operations

      3. - If the [[\type]] internal slot of + If the {{CryptoKey/[[type]]}} internal slot of |publicKey| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}.

      4. If the {{KeyAlgorithm/name}} attribute of - the [[\algorithm]] internal slot of - |publicKey| is not equal to the {{KeyAlgorithm/name}} property of the [[\algorithm]] internal slot of + the {{CryptoKey/[[algorithm]]}} internal slot of + |publicKey| is not equal to the {{KeyAlgorithm/name}} property of the {{CryptoKey/[[algorithm]]}} internal slot of |key|, then [= exception/throw =] an {{InvalidAccessError}}.

      5. @@ -10946,7 +10947,7 @@

        Operations

        Let |secret| be the result of performing the X25519 function specified in [[RFC7748]] Section 5 with |key| as the X25519 private key |k| - and the X25519 public key represented by the [[\handle]] + and the X25519 public key represented by the {{CryptoKey/[[handle]]}} internal slot of |publicKey| as the X25519 public key |u|.

        @@ -10974,7 +10975,7 @@

        Operations

        Otherwise:
        - Return an octet string containing the first |length| bits of |secret|. + Return an [= octet string containing =] the first |length| bits of |secret|.
        @@ -11021,25 +11022,25 @@

        Operations

      6. - Set the [[\type]] internal slot of + Set the {{CryptoKey/[[type]]}} internal slot of |publicKey| to "`public`"

      7. - Set the [[\algorithm]] internal + Set the {{CryptoKey/[[algorithm]]}} internal slot of |publicKey| to |algorithm|.

      8. - Set the [[\extractable]] internal + Set the {{CryptoKey/[[extractable]]}} internal slot of |publicKey| to true.

      9. - Set the [[\usages]] internal slot of + Set the {{CryptoKey/[[usages]]}} internal slot of |publicKey| to be the empty list.

      10. @@ -11053,27 +11054,27 @@

        Operations

      11. - Set the [[\type]] internal slot of + Set the {{CryptoKey/[[type]]}} internal slot of |privateKey| to {{KeyType/"private"}}

      12. - Set the [[\algorithm]] internal + Set the {{CryptoKey/[[algorithm]]}} internal slot of |privateKey| to |algorithm|.

      13. - Set the [[\extractable]] internal + Set the {{CryptoKey/[[extractable]]}} internal slot of |privateKey| to |extractable|.

      14. - Set the [[\usages]] internal slot of + Set the {{CryptoKey/[[usages]]}} internal slot of |privateKey| to be the - usage intersection of + [= usage intersection =] of |usages| and `[ "deriveKey", "deriveBits" ]`.

      15. @@ -11125,7 +11126,7 @@

        Operations

      16. Let |spki| be the result of running the - parse a subjectPublicKeyInfo + [= parse a subjectPublicKeyInfo =] algorithm over |keyData|.

      17. @@ -11170,7 +11171,7 @@

        Operations

      18. - Set the [[\type]] internal slot + Set the {{CryptoKey/[[type]]}} internal slot of |key| to "`public`"

      19. @@ -11187,7 +11188,7 @@

        Operations

      20. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

      21. @@ -11207,7 +11208,7 @@

        Operations

      22. Let |privateKeyInfo| be the result of running the - parse a privateKeyInfo + [= parse a privateKeyInfo =] algorithm over |keyData|.

      23. @@ -11239,7 +11240,8 @@

        Operations

      24. - Let |curvePrivateKey| be the result of performing the parse an ASN.1 structure + Let |curvePrivateKey| be the result of performing the + [= parse an ASN.1 structure =] algorithm, with |data| as the `privateKey` field of |privateKeyInfo|, |structure| as the ASN.1 `CurvePrivateKey` structure specified in Section 7 of [[RFC8410]], and |exactData| set to true. @@ -11262,7 +11264,7 @@

        Operations

      25. - Set the [[\type]] internal slot + Set the {{CryptoKey/[[type]]}} internal slot of |key| to {{KeyType/"private"}}

      26. @@ -11279,7 +11281,7 @@

        Operations

      27. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

      28. @@ -11374,7 +11376,7 @@

        Operations

      29. - Set the [[\type]] + Set the {{CryptoKey/[[type]]}} internal slot of |Key| to {{KeyType/"private"}}.

      30. @@ -11398,7 +11400,7 @@

        Operations

      31. - Set the [[\type]] + Set the {{CryptoKey/[[type]]}} internal slot of |Key| to {{KeyType/"public"}}.

      32. @@ -11419,7 +11421,7 @@

        Operations

      33. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

      34. @@ -11456,13 +11458,13 @@

        Operations

      35. - Set the [[\type]] internal slot + Set the {{CryptoKey/[[type]]}} internal slot of |key| to "`public`"

      36. - Set the [[\algorithm]] + Set the {{CryptoKey/[[algorithm]]}} internal slot of |key| to |algorithm|.

      37. @@ -11496,7 +11498,7 @@

        Operations

      38. - If the underlying cryptographic key material represented by the [[\handle]] internal slot of |key| + If the underlying cryptographic key material represented by the {{CryptoKey/[[handle]]}} internal slot of |key| cannot be accessed, then [= exception/throw =] an {{OperationError}}.

      39. @@ -11507,7 +11509,7 @@

        Operations

        1. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}.

        2. @@ -11555,7 +11557,7 @@

          Operations

          1. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is not {{KeyType/"private"}}, then [= exception/throw =] an {{InvalidAccessError}}.

          2. @@ -11590,7 +11592,7 @@

            Operations

            Set the |privateKey| field to the result of DER-encoding a `CurvePrivateKey` ASN.1 type, as defined in Section 7 of [[RFC8410]], that represents the - X25519 private key represented by the [[\handle]] internal slot of + X25519 private key represented by the {{CryptoKey/[[handle]]}} internal slot of |key|

            @@ -11636,7 +11638,7 @@

            Operations

          3. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is {{KeyType/"private"}}
            @@ -11652,7 +11654,7 @@

            Operations

          4. - Set the `ext` attribute of |jwk| to the [[\extractable]] internal slot + Set the `ext` attribute of |jwk| to the {{CryptoKey/[[extractable]]}} internal slot of |key|.

          5. @@ -11671,14 +11673,14 @@

            Operations

            1. - If the [[\type]] internal slot + If the {{CryptoKey/[[type]]}} internal slot of |key| is not "`public`", then [= exception/throw =] an {{InvalidAccessError}}.

            2. - Let |data| be an octet string representing the X25519 - public key represented by the [[\handle]] internal slot of + Let |data| be an [= octet string =] representing the X25519 + public key represented by the {{CryptoKey/[[handle]]}} internal slot of |key|.

            3. From f6d2b016bca60f9a562f1db29e6fac313d42439d Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Tue, 15 Oct 2024 18:00:03 +0200 Subject: [PATCH 4/5] Document open issues around Ed25519 Reference the open issues in WICG/webcrypto-secure-curves around randomized signatures and small-order points in the spec text. --- spec/Overview.html | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/Overview.html b/spec/Overview.html index f724f3e..104f816 100644 --- a/spec/Overview.html +++ b/spec/Overview.html @@ -10078,6 +10078,16 @@

              Operations

              Section 5.1.6, with |message| as |M|, using the Ed25519 private key associated with |key|.

              +
              +

              + Some implementations may (wish to) generate randomized signatures + as per draft-irtf-cfrg-det-sigs-with-noise + instead of deterministic signatures as per [[RFC8032]]. +

              +

              + See WICG/webcrypto-secure-curves issue 28. +

              +
            4. @@ -10105,6 +10115,14 @@

              Operations

              If the key data of |key| represents an invalid point or a small-order element on the Elliptic Curve of Ed25519, return `false`.

              +
              +

              + Not all implementations perform this check. +

              +

              + See WICG/webcrypto-secure-curves issue 27. +

              +
            5. @@ -10112,6 +10130,14 @@

              Operations

              represents an invalid point or a small-order element on the Elliptic Curve of Ed25519, return `false`.

              +
              +

              + Not all implementations perform this check. +

              +

              + See WICG/webcrypto-secure-curves issue 27. +

              +
            6. From 9cd8b2e7ef0d380c3cf9b3d4c47d534aa9574db2 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Mon, 21 Oct 2024 18:59:22 +0200 Subject: [PATCH 5/5] Make JWK format validation language more specific --- spec/Overview.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/Overview.html b/spec/Overview.html index 104f816..8e3c5de 100644 --- a/spec/Overview.html +++ b/spec/Overview.html @@ -10535,7 +10535,8 @@

              Operations

              1. - If |jwk| does not meet the requirements of Section 2 + If |jwk| does not meet the requirements of + the JWK private key format described in Section 2 of [[RFC8037]], then [= exception/throw =] a {{DataError}}.

              2. @@ -10559,7 +10560,8 @@

                Operations

                1. - If |jwk| does not meet the requirements of Section 2 + If |jwk| does not meet the requirements of + the JWK public key format described in Section 2 of [[RFC8037]], then [= exception/throw =] a {{DataError}}.

                2. @@ -11389,7 +11391,8 @@

                  Operations

                  1. - If |jwk| does not meet the requirements of Section 2 + If |jwk| does not meet the requirements of + the JWK private key format described in Section 2 of [[RFC8037]], then [= exception/throw =] a {{DataError}}.

                  2. @@ -11413,7 +11416,8 @@

                    Operations

                    1. - If |jwk| does not meet the requirements of Section 2 + If |jwk| does not meet the requirements of + the JWK public key format described in Section 2 of [[RFC8037]], then [= exception/throw =] a {{DataError}}.

      OperationParametersResultOperationParametersResult
      deriveBits {{EcdhKeyDeriveParams}}octet string[= octet string =]
      generateKey