Send feedback to public-webcrypto@w3.org (archives), or file a bug (see existing bugs).
Copyright © 2013 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
This specification describes a JavaScript API for performing basic cryptographic operations in web applications, such as hashing, signature generation and verification, and encryption and decryption. Additionally, it describes an API for applications to generate and/or manage the keying material necessary to perform these operations. Uses for this API range from user or service authentication, document or code signing, and the confidentiality and integrity of communications.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document is the 8 January 2013 Working Draft of the Web Cryptography API specification. Please send comments about this document to public-webcrypto-comments@w3.org (archived).
This document is produced by the Web Cryptography WG of the W3C.
Implementors should be aware that this specification is not stable. Implementors who are not taking part in the discussions are likely to find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation stage should join the mailing lists that follow and take part in the discussions.
The Web Cryptography Working Group invites discussion and feedback on this draft document by web developers, companies, standardization bodies or forums interested in deployment of secure services with web applications. Specifically, Web Cryptography Working Group is looking for feedback on:
Previous discussion of this specification has taken place on three other mailing lists: whatwg@whatwg.org (archive) , public-websecurity@w3.org (archive), and public-identity@w3.org (archive). Ongoing discussion will be on the public-webcrypto@w3.org mailing list.
Web content and browser developers are encouraged to review this draft. Please send comments to public-webcrypto-comments@w3.org, the W3C's public email list for issues related to Web Cryptography. Archives of the public list and archives of the member's-only list are available.
Changes made to this document can be found in the W3C public Mercurial server.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This section is non-normative.
The Web Cryptography API defines a low-level interface to interacting with cryptographic key material that is managed or exposed by user agents. The API itself is agnostic of the underlying implementation of key storage, but provides a common set of interfaces that allow rich web applications to perform operations such as signature generation and verification, hashing and verification, encryption and decryption, without requiring access to the raw keying material.
Cryptographic transformations are exposed via the CryptoOperation interface, which defines a common set of methods and events for dealing with initialization, processing data, and completing the operation to yield the final output. In addition to operations such as signature generation and verification, hashing and verification, and encryption and decryption, the API provides interfaces for key generation, key derivation, key import and export, and key discovery.
This section is non-normative
A web application may wish to extend or replace existing username/password based authentication schemes with authentication methods based on proving that the user has access to some secret keying material. Rather than using transport-layer authentication, such as TLS client certificates, the web application may wish to provide a rich user experience by providing authentication within the application itself.
Using the Web Cryptography API, such an application could locate suitable client keys, which may have been previously generated via the user agent or pre-provisioned out-of-band by the web application. It could then perform cryptographic operations such as decrypting an authentication challenge followed by signing an authentication response.
Further, the authentication data could be further enhanced by binding the authentication to the TLS session that the client is authenticating over, by deriving a key based on properties of the underlying transport.
If a user did not already have a key associated with their account, the web application could direct the user agent to either generate a new key or to re-use an existing key of the user's choosing.
When exchanging documents that may contain sensitive or personal information, a web application may wish to ensure that only certain users can view the documents, even after they have been securely received, such as over TLS. One way that a web application can do so is by encrypting the documents with a secret key, and then wrapping that key with the public keys associated with authorized users.
When a user agent navigates to such a web application, the application may send the encrypted form of the document. The user agent is then instructed to unwrap the encryption key, using the user's private key, and from there, decrypt and display the document.
When storing data with remote service providers, users may wish to protect the confidentiality of their documents and data prior to uploading them. The Web Cryptography API allows an application to have a user select a private or secret key, to either derive encryption keys from the selected key or to directly encrypt documents using this key, and then to upload the transformed/encrypted data to the service provider using existing APIs.
This use case is similar to the Protected Document Exchange use case because Cloud Storage can be considered as a user exchanging protected data with himself in the future.
A web application may wish to accept electronic signatures on documents, in lieu of requiring physical signatures. An authorized signature may use a key that was pre-provisioned out-of-band by the web application, or it may be using a key that the client generated specifically for the web application.
The web application must be able to locate any appropriate keys for signatures, then direct the user to perform a signing operation over some data, as proof that they accept the document.
When caching data locally, an application may wish to ensure that this data cannot be modified in an offline attack. In such a case, the server may sign the data that it intends the client to cache, with a private key held by the server. The web application that subsequently uses this cached data may contain a public key that enables it to validate that the cache contents have not been modified by anyone else.
In addition to a number of web applications already offering chat based services, the rise of WebSockets and RTCWEB allows a great degree of flexibility in inter-user-agent messaging. While TLS/DTLS may be used to protect messages to web applications, users may wish to directly secure messages using schemes such as off-the-record (OTR) messaging.
The Web Cryptography API enables OTR, by allowing key agreement to be performed so that the two parties can negotiate shared encryption keys and message authentication code (MAC) keys, to allow encryption and decryption of messages, and to prevent tampering of messages through the MACs.
A web application wishes to make use of the structures and format of messages defined by the IETF Javascript Object Signing and Encryption (JOSE) Working Group. The web application wishes to manipulate public keys encoded in the JSON key format (JWK), messages that have been integrity protected using digital signatures or MACs (JWS), or that have been encrypted (JWE).
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, RECOMMENDED, MAY, OPTIONAL, in this specification are to be interpreted as described in Key words for use in RFCs to Indicate Requirement Levels [RFC2119].
The following conformance classes are defined by this specification:
A user agent is considered to be a conforming user agent if it satisfies all of the MUST-, REQUIRED- and SHALL-level criteria in this specification that apply to implementations. This specification uses both the terms "conforming user agent" and "user agent" to refer to this product class.
User agents MAY implement algorithms in this specification in any way desired, so long as the end result is indistinguishable from the result that would be obtained from the specification's algorithms.
User agents that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [WEBIDL] as this specification uses that specification and terminology.
This section is non-normative.
The specification attempts to focus on the common functionality and features between various platform-specific or standardized cryptographic APIs, and avoid features and functionality that are specific to one or two implementations. As such this API allows key generation, management, and exchange with a level of abstraction that avoids developers needing to care about the implementation of the underlying key storage. The API is focused specifically around Key objects, as an abstraction for the underlying raw cryptographic keying material. The intent behind this is to allow an API that is generic enough to allow conforming user agents to expose keys that are stored and managed directly by the user agent, that may be stored or managed using isolated storage APIs such as per-user key stores provided by some operating systems, or within key storage devices such as secure elements, while allowing rich web applications to manipulate the keys and without requiring the web application be aware of the nature of the underlying key storage.
Because the underlying cryptographic implementations will vary between conforming user agents, and may be subject to local policy, including but not limited to concerns such as government or industry regulation, security best practices, intellectual property concerns, and constrained operational environments, this specification does not dictate a mandatory set of algorithms that MUST be implemented. Instead, it defines a common set of bindings that can be used in an algorithm-independent manner, a common framework for discovering if a user agent or key handle supports the underlying algorithm, and a set of conformance requirements for the behaviours of individual algorithms, if implemented.
Although the API does not expose the notion of cryptographic providers or modules, each key is internally bound to a cryptographic provider or module, so web applications can rest assured that the right cryptographic provider or module will be used to perform cryptographic operations involving that key.
This API, while allowing applications to generate, retrieve, and manipulate keying material, does not specifically address the provisioning of keys in particular types of key storage, such as secure elements or smart cards. This is due to such provisioning operations often being burdened with vendor-specific details that make defining a vendor-agnostic interface an unsuitably unbounded task. Additionally, this API does not deal with or address the discovery of cryptographic modules, as such concepts are dependent upon the underlying user agent and are not concepts that are portable between common operating systems, cryptographic libraries, and implementations.
This section is non-normative.
User agents should take care before exposing keys that were not explicitly generated via the API in this specification or exposing keys that were generated in the context of other origins. Two applications with access to the same key handle may be able to spoof messages to each other, as both valid and hostile messages will appear to be valid for the given key. Because of this, user agents are recommended to obtain express permission from the user before re-using keys, unless there is a prearranged trust relationship.
User agents should be aware of the security considerations of each algorithm implemented and exposed to applications. For a number of algorithms, their cryptographic strength is relative to the amount of work necessary to compute the result, whether this be through the generation of significantly large prime numbers or through the repeatedly iterating through the same algorithm to reduce its susceptibility to brute force. Implementations should therefore take measures to ensure against misuse. Such measures may include requiring express user permission to compute some expensive operations, rate limiting the number of times the application may call certain APIs/algorithms, and defining implementation-specific upper limits for inputs such as key sizes or iteration counts, as appropriate for the device on which the implementation executes.
In some cases, the same underlying cryptographic key material may be re-usable for multiple algorithms. One such example is an RSA key, which may be used for both signing and encryption, or with RSA-PKCS1v1.5 and RSA-PSS. In some cases, the re-use of this key material may undermine the security properties of the key and allow applications to recover the raw material.
While this API provides important functionality for the development of secure applications, it does not try to address all of the issues that may arise from the web security model. As such, application developers must take care to ensure against common attacks such as script injection by making use of appropriate security functionality such as Content Security Policy and the use of TLS.
This API includes a variety of cryptographic operations, some of which may have known security issues when used inappropriately. Application developers should take care to review the appropriate cryptographic literature before making use of certain algorithms, and should avoid attempting to develop new cryptographic protocols whenever possible.
While the API in this specification provides a means to protect keys from future access by web applications, it makes no statements as to how the actual keying material will be stored by an implementation. As such, although a key may be inaccessible to web content, it should not be presumed that it is inaccessible to end-users. For example, a conforming user agent may choose to implement key storage by storing key material in plain text on device storage. Although the user agent prevents access to the raw keying material to web applications, any user with access to device storage may be able to recover the key.
In some situations, allowing low-level access to key handles, such as to permit the signing or encryption of arbitrary text, may allow an attacker to construct an oracle that can be used to recover key material. Application developers are thus encouraged to be careful about permitting the signing of arbitrary messages, and should consider the use of existing cryptographic messaging protocols as appropriate.
This section is non-normative.
This specification relies on underlying specifications.
A conforming user agent MUST support at
least the subset of the functionality defined in DOM4 that this specification relies
upon; in particular, it MUST support EventTarget
.
[DOM4]
A conforming user agent MUST support at least the subset of the functionality defined in HTML that this specification relies upon; in particular, it MUST support event loops and event handler IDL attributes. [HTML]
A conforming user agent MUST be a conforming implementation of the IDL fragments in this specification, as described in the Web IDL specification. [WebIDL]
A conforming user agent MUST support the Typed Arrays specification [TypedArrays].
The terms and algorithms document, event handler IDL attributes, event handler event type, origin, same origin, URL, event loops, task, task source, queue a task, fire a simple event, and structured clone, are defined by the HTML specification [HTML].
When this specification says to terminate the algorithm, the user agent must terminate the algorithm after finishing the step it is on. The algorithm referred to is the set of specification-defined processing steps, rather than the underlying cryptographic algorithm that may be in the midst of processing.
[NoInterfaceObject]
interface RandomSource {
ArrayBufferView getRandomValues(ArrayBufferView array);
};
The RandomSource interface represents an interface to a cryptographically strong pseudo-random number generator seeded with truly random values.
Implementation note: Implementations should generate cryptographically random values using well-established cryptographic pseudo-random number generators seeded with high-quality entropy, such as from an operating-system entropy source (e.g., "/dev/urandom"). This specification provides no lower-bound on the information theoretic entropy present in cryptographically random values, but implementations should make a best effort to provide as much entropy as practicable.
Implementation note: This interface defines a synchronous method for obtaining cryptographically random values. While some devices and implementations may support truly random cryptographic number generators or provide interfaces that block when there is insufficient entropy, implementations are encouraged not to use these sources when implementing getRandomValues, both for performance and to avoid depleting the system of entropy. Instead, these sources should be used to seed a cryptographic pseudo-random number generator that can then return suitable values efficiently.
The getRandomValues
method generates cryptographically random values. It must act as follows:
If array is not of an integer type (i.e., Int8Array, Uint8Array,
Int16Array, Uint16Array, Int32Array, or Uint32Array), throw a
TypeMismatchError
and
terminate the algorithm.
If the byteLength
of array is greater than 65536, throw a
QuotaExceededError
and
terminate the algorithm.
Overwrite all elements of array with cryptographically random values of the appropriate type.
Return array.
Do not generate keys using the getRandomValues
method. Use the
generateKey
method instead.
getRandomValues
function has been implemented in several WebKit-based browsers,
including Google Chrome and Apple Safari. If the specification of
this function changes, steps will need to be taken to resolve the
inconsistency - including possibly renaming the function.
The Algorithm object is a dictionary object [WebIDL] which is used to specify an algorithm and any additional parameters required to fully specify the desired operation.
// TBD: ISSUE-28
typedef (Algorithm or DOMString) AlgorithmIdentifier;
dictionary AlgorithmParameters {
};
dictionary Algorithm {
DOMString name;
AlgorithmParameters params;
};
name
params
The Key object represents an opaque reference to keying material that is managed by the user agent.
This specification provides a uniform interface for many different kinds of keying material managed by the user agent. This may include keys that have been generated by the user agent, derived from other keys by the user agent, imported to the user agent through user actions or using this API, pre-provisioned within software or hardware to which the user agent has access or made available to the user agent in other ways. The term key refers broadly to any keying material including actual keys for cryptographic operations and secret values obtained within key derivation or exchange operations.
The Key object is not required to directly interface with the underlying key storage mechanism, and may instead simply be a reference for the user agent to understand how to obtain the keying material when needed, eg. when performing a CryptoOperation.
type
"secret"
, while keys used as
part of asymmetric algorithms composed of public/private keypairs will be either
"public"
or "private"
.
extractable
algorithm
Algorithm
used to generate the key.
keyUsage
Array
of KeyUsages
that
indicate what CryptoOperations may be used with this
key.
When a user agent is required to obtain a structured clone of a Key object, it must run the following steps.
Key
object, it is important that the underlying cryptographic key material
not be exposed to a JavaScript implementation. Such a situation may arise if an implementation
fails to implement the structured clone algorithm correctly, such as by allowing a Key
object
to be serialized as part of a structured clone implementation, but then deserializing it as
a DOMString
, rather than as a Key
object.
interface CryptoOperation : EventTarget {
void process(ArrayBufferView buffer);
void finish();
void abort();
readonly attribute Key? key;
readonly attribute Algorithm algorithm;
readonly attribute any result;
[TreatNonCallableasNull] attribute Function? onabort;
[TreatNonCallableAsNull] attribute Function? onerror;
[TreatNonCallableAsNull] attribute Function? onprogress;
[TreatNonCallableAsNull] attribute Function? oncomplete;
};
Every CryptoOperation
object must have a list
of pending data. Each item in the list represents data that should be transformed by the
cryptographic operation. The list functions as a queue that observes first-in, first-out ordering. That is,
the order in which items are added shall reflect the order in which items are removed.
When a CryptoOperation is said to process data, the user agent must execute the following steps:
If there are no items in the list of pending data, the algorithm is complete.
Let bytes be an empty sequence of bytes.
For each item in the list of pending data:
Let item be the oldest remaining item in the list of pending data.
Remove item from the list of pending data.
Convert item to a sequence of byteLength
bytes from the underlying
ArrayBuffer
, starting at the byteOffset
of the ArrayBufferView
,
and append those bytes to bytes
Perform the underlying cryptographic algorithm, using bytes as the input data.
If the cryptographic operation fails, proceed to the error steps below:
Update the internal state to "error"
.
Queue a task to
fire a simple event named
onerror
at the
CryptoOperation
.
Let output be the result of the underlying cryptographic algorithm.
Let bytes be an empty sequence of bytes.
Let item be the oldest remaining item in the list of pending data.
Remove item from the list of pending data.
Convert item to a sequence of byteLength
bytes from the underlying
ArrayBuffer
, starting at the byteOffset
of the ArrayBufferView
,
and append those bytes to bytes
A conforming user agent MAY repeat the preceeding steps as many times as desired, for as long as items remain in the list of pending data, provided that the output of the underlying cryptographic algorithm is indistinguishable from when only a single item is processed at a time.
Perform the underlying cryptographic algorithm, using bytes as the input data.
If the cryptographic operation fails, proceed to the error steps below:
Clear the list of pending data.
Update the internal state to "error"
.
Queue a task to
fire a simple event named
onerror
at the
CryptoOperation
.
Let output be the result of the underlying cryptographic algorithm.
Update result
with the algorithm-specific
result using output.
ISSUE-18:
The wording here is presently ambiguous. It is modeled after the File API [FileAPI],
which has result
accumulating the output as it becomes available. Because of this behaviour,
the entire cryptographic output is stored in result
at the end of the operation.
In order to reduce the need to keep the entire cryptographic output in result
, it has also been
requested to have an interface to support streaming/progressive output, in which only as much cryptographic
output as desired/requested is made available. How such functionality would be implemented, if at all,
remains to be determined.
Queue a task to
fire a simple event named
onprogress
at the CryptoOperation
.
If the underlying cryptographic implementation supports multi-part cryptographic operations for the current algorithm, repeat these steps for each item remaining in the list of pending data.
The above algorithm is meant to describe a possible way of supporting multi-part input (sometimes called "streaming" or "progressive" input, but not to be confused with the Streams API [StreamsAPI]). The downside to the above algorithm is that it does not describe a good interface for supporting algorithms that may support multiple multi-part inputs.
An example of such an algorithm would be AES-GCM, which has two sources of input - the encrypted-and-authenticated
data ("ciphertext") and the authenticated data ("additional authenticated data"). A truly multi-part implementation
would allow both the plaintext/ciphertext and the authenticated data to be supplied independently, and in parts,
until finish()
was called.
However, at present, several major cryptographic APIs (CDSA, CNG, PKCS#11) do not support such uses, and so for now, the details for handling multiple multi-part inputs have been omitted.
abort
ing an in-progress operation.
The following are the event handler IDL attributes
(and their corresponding event handler event
types) that user agents must support on the
CryptoOperation
as DOM attributes:
event handler IDL attributes | event handler event type |
---|---|
onabort | abort |
onerror | error |
onprogress | progress |
oncomplete | complete |
key
On getting, the key
attribute returns the
Key
used to initialize the CryptoOperation
.
If the CryptoOperation
represents a keyless-operation, such as digesting,
then key
MUST return null
.
algorithm
algorithm
attribute returns the
normalized algorithm of the algorithm used
to initialize the CryptoOperation
.
result
result
attribute returns the
algorithm-specific result for the current
CryptoOperation
.
On getting, if an error in performing the operation has occurred, then the
result
attribute MUST return
null
.
process(ArrayBufferView data)
When the process(ArrayBufferView data)
method is called, the user agent must run
the following steps:
If the internal state is in the "error"
state, throw an
InvalidStateError
exception and abort these steps.
Let data be the data to be processed.
Add data to the list of pending data.
If the underlying cryptographic implementation for the specified algorithm supports multi-part cryptographic operations, asynchrously process data, allowing the task that invoked this algorithm to continue.
Warning: The text here is currently ambiguous in terms of defining how the event loop
processes events; in particular, it leaves under-specified how the
abort()
method should be handled when data is being processed.
finish()
method
When finish()
method is called, the user agent must run the steps below.
If the internal state is in the "error"
state, throw an
InvalidStateError
exception and abort these steps.
Set the internal state to "complete"
.
If the underlying cryptographic implementation for the specified algorithm does not support multi-part cryptographic operations, asynchronously process data, allowing the task that invoked this algorithm to continue.
Once all items in the list of pending data have
been processed, queue a task
to fire a simple event called
oncomplete
at the
CryptoOperation
.
abort()
method
When abort()
method is called, the user agent must run the steps below.
If the internal state is in the "error"
state, throw an
InvalidStateError
exception and abort these steps.
Abort processing data.
CryptoOperation
, then remove those
tasks.
onabort
at the
CryptoOperation
.
The above algorithm is underspecified, both for user agents that do not implement abortable processing and because the process data algorithm does not define how to abort midstream.
interface KeyOperation : EventTarget {
readonly attribute any result;
[TreatNonCallableAsNull] attribute Function? onerror;
[TreatNonCallableAsNull] attribute Function? oncomplete;
};
enum KeyFormat {
// An unformatted sequence of bytes. Intended for secret keys.
"raw",
// The DER encoding of the PrivateKeyInfo structure from RFC 5208.
"pkcs8",
// The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280.
"spki",
// The key is represented as JSON according to the JSON Web Key format.
"jwk",
};
interface Crypto {
CryptoOperation encrypt(AlgorithmIdentifier algorithm,
Key key,
optional ArrayBufferView? buffer = null);
CryptoOperation decrypt(AlgorithmIdentifier algorithm,
Key key,
optional ArrayBufferView? buffer = null);
CryptoOperation sign(AlgorithmIdentifier algorithm,
Key key,
optional ArrayBufferView? buffer = null);
CryptoOperation verify(AlgorithmIdentifier algorithm,
Key key,
ArrayBufferView signature,
optional ArrayBufferView? buffer = null);
CryptoOperation digest(AlgorithmIdentifier algorithm,
optional ArrayBufferView? buffer = null);
// TBD: ISSUE-36
KeyOperation generateKey(AlgorithmIdentifier algorithm,
bool extractable = false,
KeyUsage[] keyUsages = []);
KeyOperation deriveKey(AlgorithmIdentifier algorithm,
Key baseKey,
AlgorithmIdentifier? derivedKeyType,
bool extractable = false,
KeyUsage[] keyUsages = []);
// TBD: ISSUE-35
KeyOperation importKey(KeyFormat format,
ArrayBufferView keyData,
AlgorithmIdentifier? algorithm,
bool extractable = false,
KeyUsage[] keyUsages = []);
KeyOperation exportKey(KeyFormat format, Key key);
};
Crypto implements RandomSource;
partial interface Window {
readonly attribute Crypto crypto;
};
The encrypt
method returns a new CryptoOperation
object that will encrypt data using the specified
AlgorithmIdentifier
with
the supplied Key
. It must act
as follows:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the encrypt
operation, throw a NotSupportedError
and
terminate the algorithm.
Create a new CryptoOperation
object
S with the following characteristics:
If buffer is specified:
Queue a task to invoke the process()
method on the new object, with buffer as the buffer
argument.
Queue a task to invoke the finish()
method on the new object.
Supporting single-part operations is intended to address two use cases:
Developers that "just" want to perform a simple operation. The single-method invocation best matches existing JavaScript cryptographic libraries, particularly the synchronous aspect.
User agents that can optimize implementation when there is only a single operation being performed.
Having the single-part operation return a CryptoOperation
may change,
as may make it easier for developers if a Promise type object (whether through
TC39 or through DOM) is returned, since the only possible results are "success" and "error".
Return the new object.
The decrypt
method returns a new CryptoOperation
object that will decrypt data using the specified
AlgorithmIdentifier
with
the supplied Key
. It must act
as follows:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the decrypt
operation, throw a NotSupportedError
and
terminate the algorithm.
Create a new CryptoOperation
object
S with the following characteristics:
If buffer is specified:
Queue a task to invoke the process()
method on the new object, with buffer as the buffer
argument.
Queue a task to invoke the finish()
method on the new object.
Supporting single-part operations is intended to address two use cases:
Developers that "just" want to perform a simple operation. The single-method invocation best matches existing JavaScript cryptographic libraries, particularly the synchronous aspect.
User agents that can optimize implementation when there is only a single operation being performed.
Having the single-part operation return a CryptoOperation
may change,
as may make it easier for developers if a Promise type object (whether through
TC39 or through DOM) is returned, since the only possible results are "success" and "error".
Return the new object.
The sign
method
returns a new CryptoOperation
object that will sign data using the specified
AlgorithmIdentifier
with
the supplied Key
. It must act as follows:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the sign
operation, throw a NotSupportedError
and
terminate the algorithm.
Create a new CryptoOperation
object
S with the following characteristics:
If buffer is specified:
Queue a task to invoke the process()
method on the new object, with buffer as the buffer
argument.
Queue a task to invoke the finish()
method on the new object.
Supporting single-part operations is intended to address two use cases:
Developers that "just" want to perform a simple operation. The single-method invocation best matches existing JavaScript cryptographic libraries, particularly the synchronous aspect.
User agents that can optimize implementation when there is only a single operation being performed.
Having the single-part operation return a CryptoOperation
may change,
as may make it easier for developers if a Promise type object (whether through
TC39 or through DOM) is returned, since the only possible results are "success" and "error".
Return the new object.
The verify
method
returns a new CryptoOperation
object that will verify data using the specified
AlgorithmIdentifier
with
the supplied Key
. It must act as follows:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the verify
operation, throw a NotSupportedError
and
terminate the algorithm.
Create a new CryptoOperation
object
S with the following characteristics:
If buffer is specified:
Queue a task to invoke the process()
method on the new object, with buffer as the buffer
argument.
Queue a task to invoke the finish()
method on the new object.
Supporting single-part operations is intended to address two use cases:
Developers that "just" want to perform a simple operation. The single-method invocation best matches existing JavaScript cryptographic libraries, particularly the synchronous aspect.
User agents that can optimize implementation when there is only a single operation being performed.
Having the single-part operation return a CryptoOperation
may change,
as may make it easier for developers if a Promise type object (whether through
TC39 or through DOM) is returned, since the only possible results are "success" and "error".
Return the new object.
The digest
method returns
a new CryptoOperation
object that will digest data using the specified
AlgorithmIdentifier
.
It must act as follows:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the digest
operation, throw a NotSupportedError
and
terminate the algorithm.
Create a new CryptoOperation
object
S with the following characteristics:
If buffer is specified:
Queue a task to invoke the process()
method on the new object, with buffer as the buffer
argument.
Queue a task to invoke the finish()
method on the new object.
Supporting single-part operations is intended to address two use cases:
Developers that "just" want to perform a simple operation. The single-method invocation best matches existing JavaScript cryptographic libraries, particularly the synchronous aspect.
User agents that can optimize implementation when there is only a single operation being performed.
Having the single-part operation return a CryptoOperation
may change,
as may make it easier for developers if a Promise type object (whether through
TC39 or through DOM) is returned, since the only possible results are "success" and "error".
Return the new object.
When invoked, generateKey
MUST perform the following steps:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the generate
operation, throw a NotSupportedError
and
terminate the algorithm.
Let keyOp be a newly created object implementing the
KeyOperation
interface.
Return keyOp to the task that invoked this generateKey
, while
continuing the remaining steps of this algorithm.
Queue up an operation to run the following steps:
Invoke the algorithm-specific key generation method.
If an error occured, queue a task to
fire a simple event
called onerror
at
KeyOp and terminate the algorithm.
Otherwise, if the algorithm-specific key generation method completed successfully, let result be the result of that operation.
Set keyOp.result
=
result
Queue a task to
fire a simple event called
oncomplete
at
KeyOp
The handling for extractable and keyUsages are currently underspecified. The intent is that any derived secret/private keys will reflect whatever the caller specified. However, the exact wording of how to specify that remains TBD.
Consider, for example, generation of an RSA key pair. The intent may be that the public key has the "verify" usage, and the private key has the "sign" usage, but there is no way in the API to specify that. The same concern applies for "encrypt" and "decrypt".
An alternative would be to allow the caller to write to the attributes on individual
Key
objects themselves, after generation, and then
have some operation to finalize the object itself, but this as well remains TBD.
When invoked, deriveKey
MUST perform the following steps:
Let normalizedAlgorithm be the result of processing
algorithm
according to the
algorithm normalizing rules.
If normalizedAlgorithm does not describe a
registered algorithm that supports the derive
operation, throw a NotSupportedError
and
terminate the algorithm.
Let keyOp be a newly created object implementing the
KeyOperation
interface.
Return keyOp to the task that invoked this generateKey
, while
continuing the remaining steps of this algorithm.
Queue up an operation to run the following steps:
If baseKey.keyUsage
does not
contain the "derive"
KeyUsage
,
queue a task to
fire a simple event
called onerror
at
KeyOp and terminate the algorithm.
Invoke the algorithm-specific key generation method.
If an error occured, queue a task to
fire a simple event
called onerror
at
KeyOp and terminate the algorithm.
Otherwise, if the algorithm-specific key derivation method completed successfully, let result be the result of that operation.
Set keyOp.result
=
result
Queue a task to
fire a simple event called
oncomplete
at
KeyOp
The handling for extractable and keyUsages are currently underspecified. The intent is that any derived secret/private keys will reflect whatever the caller specified. However, the exact wording of how to specify that remains TBD.
Consider, for example, when derivation results in multiple key handles. The intent
may be that one Key
object is used for encrypt
ing, while
another is used for decrypt
ing. However, the current way of specifying
KeyUsage
does not provide a means for callers to do so.
An alternative would be to allow the caller to write to the attributes on individual
Key
objects themselves, after generation, and then
have some operation to finalize the object itself, but this as well remains TBD.
interface WorkerCrypto {
};
WorkerCrypto implements RandomSource;
partial interface WorkerGlobalScope {
readonly attribute WorkerCrypto crypto;
};
The WorkerCrypto interface provides cryptographic functionality for background scripts, as specified by Web Workers [ Web Workers].
typedef Uint8Array BigInteger;
The BigInteger typedef is a Uint8Array
that holds a multiple-precision unsigned integer. Each Uint8
element in the array represents a base-256 digit of the integer.
The digits are in big-endian order: the first Uint8 element in the array
is the most significant digit. A leading zero Uint8 element
is not needed if the most significant bit of the integer is set.
The KeyPair interface represents an asymmetric key pair that is comprised of both public and private keys.
This section is non-normative.
The Working Group is actively discussing means of discovering Key
objects that are not not directly created by the application via
generateKey
, or allowing
web applications to dicate how and where the cryptographic keying material associated with
Key
objects is stored. Examples of such Key
objects or interfaces that
may be exposed include:
There is currently no consensus within the Web Cryptography Working Group about how and where such interfaces should be specified, nor is there consensus with regards to various proposals intended to address specific use cases.
Such features bring a variety of concerns, most notably unique concerns regarding
privacy, security, and user interaction, that may be best addressed through separate
specifications that expand on sources for generating or storing Key
objects.
This section is non-normative
As the API is meant to be extensible in order to keep up with future developments within cryptography and to provide flexibility, there are no strictly required algorithms. Thus users of this API should check to see what algorithms are currently recommended and supported by implementations.
However, in order to promote interoperability for developers, there are a number of recommended algorithms. The recommended algorithms are:
To see the results of test-cases between implementations, please see the [@@Upcoming] Web Cryptography Test Cases Working Group.
Each algorithm that is to be exposed via the Web Cryptography API SHOULD be registered via the Web Cryptography working group, and MUST include all of the following details. Algorithms that are not registered via these means, but are exposed via this API, MUST be processed as if the sections had been defined.
Each registered algorithm MUST have a canonical name for which applications can refer to the algorithm. The canonical name MUST contain only ASCII characters and MUST NOT equal any other canonical name or algorithm alias when every character in both names are converted to lower case.
Each registered algorithm MUST define the operations that it supports.
Each registered algorithm MUST define the expected
contents of the params
member of
the Algorithm object for every
supported operation.
Each registered algorithm MUST define the normalization
rules for the contents of the params
member of the Algorithm object for every
supported operation.
Each registered algorithm MUST define the contents
of the result
attribute of the
CryptoOperation object for every
supported operation.
Each registered algorithm MAY define one or more aliases that may define a fully normalized Algorithm object.
Each algorithm alias MUST follow the same naming rules as the recognized algorithm name.
The "RSAES-PKCS1-v1_5"
algorithm identifier is used to perform encryption
and decryption ordering to the RSAES-PKCS1-v1_5 algorithm specified in
[RFC3447].
The recognized algorithm name for
this algorithm is "RSAES-PKCS1-v1_5"
.
Operation | Parameters | Result |
---|---|---|
encrypt | None | ArrayBufferView? |
decrypt | None | ArrayBufferView? |
generateKey | RsaKeyGenParams | KeyPair? |
dictionary RsaKeyGenParams : AlgorithmParameters {
// The length, in bits, of the RSA modulus
unsigned long modulusLength;
// The RSA public exponent
BigInteger publicExponent;
};
Note: The following processing algorithms have not been updated to match the processing algorithm described in the CryptoOperation processing model.
CryptoOperation
shall behave as follows:
CryptoOperation
:
key
does not describe an
RSA public key, raise an error and
terminate the algorithm.
process
:
ArrayBufferView
to be processed.
byteLength
bytes from
the underlying ArrayBuffer
, starting at the byteOffset
of the ArrayBufferView
, and append those bytes to M.
finish
:
Key
.
ArrayBuffer
with enough bytes to hold
C.length
bytes, with the contents of the underlying buffer
initialized to the contents of C.
CryptoOperation
shall behave as follows:
CryptoOperation
:
key
does not describe an
RSA private key, raise an error and
terminate the algorithm.
process
:
ArrayBufferView
to be processed.
byteLength
bytes from
the underlying ArrayBuffer
, starting at the byteOffset
of the ArrayBufferView
, and append those bytes to C.
finish
:
Key
.
ArrayBuffer
with enough bytes to hold
M.length
bytes, with the contents of the underlying buffer
initialized to the contents of M.
The "RSASSA-PKCS1-v1_5"
algorithm identifier is used to perform
signing and verification using the RSASSA-PKCS1-v1_5 algorithm specified in
[RFC3447].
The recognized algorithm name for
this algorithm is "RSASSA-PKCS1-v1_5"
.
Operation | Parameters | Result |
---|---|---|
sign | RsaSsaParams | ArrayBufferView? |
verify | RsaSsaParams | boolean? |
generateKey | RsaKeyGenParams | KeyPair? |
dictionary RsaSsaParams : AlgorithmParameters {
// The hash algorithm to use
AlgorithmIdentifier hash;
};
The "RSA-PSS"
algorithm identifier is used to perform signing
and verification using the RSASSA-PSS algorithm specified in
[RFC3447].
The recognized algorithm name for
this algorithm is "RSA-PSS"
.
Operation | Parameters | Result |
---|---|---|
sign | RsaPssParams | ArrayBufferView? |
verify | RsaPssParams | boolean? |
generateKey | RsaKeyGenParams | KeyPair? |
dictionary RsaPssParams : AlgorithmParameters {
// The hash function to apply to the message
AlgorithmIdentifier hash;
// The mask generation function
AlgorithmIdentifier mgf;
// The desired length of the random salt
unsigned long saltLength;
};
The "RSA-OAEP"
algorithm identifier is used to perform encryption
and decryption ordering to the RSAES-OAEP algorithm specified in
[RFC3447].
The recognized algorithm name for
this algorithm is "RSA-OAEP"
.
Operation | Parameters | Result |
---|---|---|
encrypt | RsaOaepParams | ArrayBufferView? |
decrypt | RsaOaepParams | ArrayBufferView? |
generateKey | RsaKeyGenParams | KeyPair? |
dictionary RsaOaepParams : AlgorithmParameters {
// The hash function to apply to the message
AlgorithmIdentifier hash;
// The mask generation function
AlgorithmIdentifier mgf;
// The optional label/application data to associate with the message
ArrayBufferView? label;
};
The "ECDSA"
algorithm identifier is used to perform signing
and verification using the ECDSA algorithm specified in
[X9.62].
The recognized algorithm name for
this algorithm is "ECDSA"
.
Operation | Parameters | Result |
---|---|---|
sign | EcdsaParams | ArrayBufferView? |
verify | EcdsaParams | boolean? |
generateKey | EcKeyGenParams | KeyPair? |
dictionary EcdsaParams : AlgorithmParameters {
// The hash algorithm to use
AlgorithmIdentifier hash;
};
enum NamedCurve {
// NIST recommended curve P-256, also known as secp256r1.
"P-256",
// NIST recommended curve P-384, also known as secp384r1.
"P-384",
// NIST recommended curve P-521, also known as secp521r1.
"P-521"
};
dictionary EcKeyGenParams : AlgorithmParameters {
// A named curve
NamedCurve namedCurve;
};
The NamedCurve enumeration type represents named elliptic curves, which are a convenient way to specify the domain parameters of well-known elliptic curves.
Note: The following processing algorithms have not been updated to match the processing algorithm described in the CryptoOperation processing model.
CryptoOperation
shall behave as follows:
init
:
key
does not describe an
ECDSA private key, raise an error and terminate the algorithm.
process
:
ArrayBufferView
to be processed.
byteLength
bytes from
the underlying ArrayBuffer
, starting at the byteOffset
of the ArrayBufferView
, and append those bytes to M.
finish
:
Key
,
and with the hash function obtained from the EcdsaParams dictionary.
ArrayBuffer
holding
the concatenation of r and s, each as a ceil(ceil(log2(n))/8)
byte sequence, where n (a prime number) is the order of the base point generator.
CryptoOperation
shall behave as follows:
init
:
key
does not describe an
ECDSA public key, raise an error and terminate the algorithm.
process
:
ArrayBufferView
to be processed.
byteLength
bytes from
the underlying ArrayBuffer
, starting at the byteOffset
of the ArrayBufferView
, and append those bytes to M'.
finish
:
Key
, and with the hash
function obtained from the EcdsaParams dictionary.
boolean
that indicates whether the
purported signature is valid (true
) or not (false
).
This describes using Elliptic Curve Diffie-Hellman (ECDH) for key generation and key agreement, as specified by X9.63.
The recognized algorithm name for
this algorithm is "ECDH"
.
Operation | Parameters | Result |
---|---|---|
generateKey | EcKeyGenParams | KeyPair? |
deriveKey | EcdhKeyDeriveParams | Key? |
typedef Uint8Array ECPoint;
dictionary EcdhKeyDeriveParams : AlgorithmParameters {
// The peer's EC public key.
ECPoint public;
};
The ECPoint typedef is a Uint8Array
holding an
elliptic curve point. An elliptic curve point is converted to an array of Uint8 elements
using the procedure specified in X9.62 Annex A.5.7.
Perform the standard ECDH primitive specified in X9.63 Section 5.4.1. The output of ECDH key agreement is the x-coordinate of the shared secret value P.
Note: X9.63 Section 5.4.2 and NIST SP 800-56A Section 5.7.1.2 specify a modified ECDH primitive that multiplies the shared secret value by the cofactor of the curve. The cofactor of the NIST recommended curves P-256, P-384, and P-521 is 1, so the standard and modified ECDH primitives are equivalent for those curves.
The recognized algorithm name for
this algorithm is "AES-CTR"
.
Operation | Parameters | Result |
---|---|---|
encrypt | AesCtrParams | ArrayBufferView? |
decrypt | AesCtrParams | ArrayBufferView? |
generateKey | AesKeyGenParams | Key? |
dictionary AesCtrParams : AlgorithmParameters {
// The initial value of the counter block. 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.
ArrayBuffer counter;
// The length, in bits, of the rightmost part of the counter block
// that is incremented.
[EnforceRange] octet length;
};
dictionary AesKeyGenParams : AlgorithmParameters {
// The length, in bits, of the key.
[EnforceRange] unsigned short length;
};
The recognized algorithm name for
this algorithm is "AES-CBC"
.
Operation | Parameters | Result |
---|---|---|
encrypt | AesCbcParams | ArrayBufferView? |
decrypt | AesCbcParams | ArrayBufferView? |
generateKey | AesKeyGenParams | Key? |
dictionary AesCbcParams : AlgorithmParameters {
// The initialization vector. MUST be 16 bytes.
ArrayBufferView iv;
};
The recognized algorithm name for
this algorithm is "AES-GCM"
.
Operation | Parameters | Result |
---|---|---|
encrypt | AesGcmParams | ArrayBufferView? |
decrypt | AesGcmParams | ArrayBufferView? |
generateKey | AesKeyGenParams | Key? |
dictionary AesGcmParams : AlgorithmParameters {
// The initialization vector to use. May be up to 2^56 bytes long.
ArrayBufferView? iv;
// The additional authentication data to include.
ArrayBufferView? additionalData;
// The desired length of the authentication tag. May be 0 - 128.
[EnforceRange] octet? tagLength = 0;
};
The recognized algorithm name for
this algorithm is "HMAC"
.
Operation | Parameters | Result |
---|---|---|
sign | HmacParams | ArrayBufferView? |
verify | HmacParams | boolean? |
generateKey | HmacParams | Key? |
dictionary HmacParams : AlgorithmParameters {
// The inner hash function to use.
AlgorithmIdentifier hash;
};
This describes using Diffie-Hellman for key generation and key agreement, as specified by PKCS #3.
The recognized algorithm name for
this algorithm is "DH"
.
Operation | Parameters | Result |
---|---|---|
generateKey | DhKeyGenParams | KeyPair? |
deriveKey | DhKeyDeriveParams | Key? |
dictionary DhKeyGenParams : AlgorithmParameters {
// The prime p.
BigInteger prime;
// The base g.
BigInteger generator;
};
dictionary DhKeyDeriveParams : AlgorithmParameters {
// The peer's public value.
BigInteger public;
};
This describes the SHA-1 and SHA-2 families, as specified by [FIPS 180-4].
The following algorithms are added as recognized algorithm names:
"SHA-1"
"SHA-224"
"SHA-256"
"SHA-384"
"SHA-512"
Operation | Parameters | Result |
---|---|---|
digest | None | ArrayBufferView? |
The "CONCAT"
algorithm identifier is used to perform key derivation
using the key derivation algorithm defined in Section 5.8.1 of NIST SP 800-56A
[SP800-56A].
The recognized algorithm name for
this algorithm is "CONCAT"
.
Operation | Parameters | Result |
---|---|---|
deriveKey | ConcatParams | Key? |
dictionary ConcatParams : AlgorithmParameters {
// The digest method to use to derive the keying material.
AlgorithmIdentifier hash;
// A bit string corresponding to the AlgorithmId field of the OtherInfo parameter.
// The AlgorithmId indicates how the derived keying material will be parsed and for which
// algorithm(s) the derived secret keying material will be used.
ArrayBufferView algorithmId;
// A bit string that corresponds to the PartyUInfo field of the OtherInfo parameter.
ArrayBufferView partyUInfo;
// A bit string that corresponds to the PartyVInfo field of the OtherInfo parameter.
ArrayBufferView partyVInfo;
// An optional bit string that corresponds to the SuppPubInfo field of the OtherInfo parameter.
ArrayBufferView? publicInfo;
// An optional bit string that corresponds to the SuppPrivInfo field of the OtherInfo parameter.
ArrayBufferView? privateInfo;
};
The recognized algorithm name for
this algorithm is "PBKDF2"
.
Operation | Parameters | Result |
---|---|---|
deriveKey | Pbkdf2Params | Key? |
dictionary Pbkdf2Params : AlgorithmParameters {
ArrayBufferView salt;
[Clamp] unsigned long iterations;
AlgorithmIdentifier prf;
ArrayBufferView? password;
};
In the above snippet, password
is an optional field. The intent is
that conforming user agents MAY support applications
that wish to use PBKDF2 by providing password entry via an un-spoofable (by the
web application) UI.
The AlgorithmIdentifier
typedef
permits algorithms to be specified as either a dictionary
or a DOMString.
In order to ensure consistency, conforming user agents must normalize all AlgorithmIdentifier
inputs into a single, canonical form. When normalization is indicated, it must act as
follows:
AlgorithmIdentifier
to be
normalized.
SyntaxError
and return from this algorithm.
InvalidAlgorithmError
exception and return from this algorithm.
name
member of the
Algorithm
dictionary.
SyntaxError
and return from this algorithm.
InvalidAlgorithmError
exception
and return from this algorithm.
params
member
of the Algorithm
dictionary.
Algorithm
object, with its
name
set to name and its
params
set to params.
// Algorithm Object
var algorithmKeyGen = {
name: "RSASSA-PKCS1-v1_5",
// RsaKeyGenParams
params: {
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537
}
};
var algorithmSign = {
name: "RSASSA-PKCS1-v1_5",
// RsaSsaParams
params: {
hash: {
name: "SHA-256",
}
}
};
var keyGen = window.crypto.generateKey(algorithmKeyGen,
false, // extractable
["sign"]);
keyGen.oncomplete = function(event) {
// Because we are not supplying data to .sign(), a multi-part
// CryptoOperation will be returned, which requires us to call .process()
// and .finish().
var signer = window.crypt.sign(algorithmSign, event.target.result.privateKey);
signer.oncomplete = function(event) {
console.log("The signature is: " + event.target.result);
}
signer.onerror = function(event) {
console.error("Unable to sign");
}
var dataPart1 = convertPlainTextToArrayBufferView("hello,");
var dataPart2 = convertPlainTextToArrayBufferView(" world!");
// TODO: create example utility function that converts text -> ArrayBufferView
signer.process(dataPart1);
signer.process(dataPart2);
signer.finish();
};
keyGen.onerror = function(event) {
console.error("Unable to generate a key.");
};
var clearDataArrayBufferView = convertPlainTextToArrayBufferView("Plain Text Data");
// TODO: create example utility function that converts text -> ArrayBufferView
var aesAlgorithmKeyGen = {
name: "AES-CBC",
// AesKeyGenParams
params: {
length: 128
}
};
var aesAlgorithmEncrypt = {
name: "AES-CBC",
// AesCbcParams
params: {
iv: window.crypto.getRandomValues(new Uint8Array(16))
}
};
// Create a keygenerator to produce a one-time-use AES key to encrypt some data
var cryptoKeyGen = window.crypto.generateKey(aesAlgorithmKeyGen,
false, // extractable
["encrypt"]);
cryptoKeyGen.oncomplete = function(event) {
// A new, random AES key has been generated.
var aesKey = event.target.result;
// Unlike the signing example, which showed multi-part encryption, here we
// will perform the entire AES operation in a single call.
var aesOp = window.crypto.encrypt(aesAlgorithmEncrypt, aesKey, clearDataArrayBufferView);
aesOp.oncomplete = function(event) {
// The clearData has been encrypted.
var ciphertext = event.target.result; // ArrayBufferView
};
aesOp.onerror = function(event) {
console.error("Unable to AES encrypt.");
};
};
The editors would like to thank Adam Barth, Alex Russell, Ali Asad, Arun Ranganathan, Brian Smith, Brian Warner, Channy Yun, Kai Engert, Mark Watson, Vijay Bharadwaj, Virginie Galindo, and Wan-Teh Chang for their technical feedback and assistance.
Thanks to the W3C Web Cryptography WG, and to participants on the public-webcrypto@w3.org mailing list.
The W3C would like to thank the Northrop Grumman Cybersecurity Research Consortium for supporting W3C/MIT.
The getRandomValues
method
in the Crypto
interface was originally proposed by Adam Barth to the
WHATWG.