Secure contextThis feature is available only in secure contexts (HTTPS), in some or all supporting browsers.
The unwrapKey()
method of the SubtleCrypto
interface "unwraps" a key. This means that it takes as its input a key that has been exported and then encrypted (also called "wrapped"). It decrypts the key and then imports it, returning a CryptoKey
object that can be used in the Web Crypto API.
As with SubtleCrypto.importKey()
, you specify the key's import format and other attributes of the key to import details such as whether it is extractable, and which operations it can be used for.
But because unwrapKey()
also decrypts the key to be imported, you also need to pass in the key that must be used to decrypt it. This is sometimes called the "unwrapping key".
The inverse of unwrapKey()
is SubtleCrypto.wrapKey()
: while unwrapKey
is composed of decrypt + import, wrapKey
is composed of encrypt + export.
Syntax
const result = crypto.subtle.unwrapKey( format, wrappedKey, unwrappingKey, unwrapAlgo, unwrappedKeyAlgo, extractable, keyUsages );
Parameters
format
is a string describing the data format of the key to unwrap. It can be one of the following:raw
: Raw format.pkcs8
: PKCS #8 format.spki
: SubjectPublicKeyInfo format.jwk
: JSON Web Key format.
wrappedKey
is anArrayBuffer
containing the wrapped key in the given format.unwrappingKey
is theCryptoKey
to use to decrypt the wrapped key. The key must have theunwrapKey
usage set.unwrapAlgo
is an object specifying the algorithm to be used to encrypt the exported key, and any extra parameters as required:- To use RSA-OAEP, pass an
RsaOaepParams
object. - To use AES-CTR, pass an
AesCtrParams
object. - To use AES-CBC, pass an
AesCbcParams
object. - To use AES-GCM, pass an
AesGcmParams
object. - To use AES-KW, pass the string
"AES-KW"
or an object of the form{ "name": "AES-KW }
.
- To use RSA-OAEP, pass an
unwrappedKeyAlgo
' is a dictionary object defining the type of key to unwrap and providing extra algorithm-specific parameters as required.- For RSASSA-PKCS1-v1_5, RSA-PSS, or RSA-OAEP: Pass an
RsaHashedImportParams
object. - For ECDSA or ECDH: Pass an
EcKeyImportParams
object. - For HMAC: Pass an
HmacImportParams
object. - For AES-CTR, AES-CBC, AES-GCM, or AES-KW: Pass the string identifying the algorithm or an object of the form
{ "name": ALGORITHM }
, whereALGORITHM
is the name of the algorithm.
- For RSASSA-PKCS1-v1_5, RSA-PSS, or RSA-OAEP: Pass an
extractable
is aBoolean
indicating whether it will be possible to export the key usingSubtleCrypto.exportKey()
orSubtleCrypto.wrapKey()
.keyUsages
is anArray
indicating what can be done with the key. Possible values of the array are:encrypt
: The key may be used toencrypt
messages.decrypt
: The key may be used todecrypt
messages.sign
: The key may be used tosign
messages.verify
: The key may be used toverify
signatures.deriveKey
: The key may be used inderiving a new key
.deriveBits
: The key may be used inderiving bits
.wrapKey
: The key may be used towrap a key
.unwrapKey
: The key may be used tounwrap a key
Return value
Exceptions
The promise is rejected when one of the following exceptions is encountered:
InvalidAccessError
- Raised when the unwrapping key is not a key for the requested unwrap algorithm or if the
CryptoKey.usages
value of that key doesn't containunwrap
. NotSupported
- Raised when trying to use an algorithm that is either unknown or isn't suitable for encryption or wrapping.
SyntaxError
- Raised when
keyUsages
is empty but the unwrapped key is of typesecret
orprivate
. TypeError
- Raised when trying to use an invalid format.
Supported algorithms
The unwrapKey()
method supports the same algorithms as the wrapKey()
method.
Examples
Note: You can [[../../../../../../../mdn.github.io/dom-examples/web-crypto/unwrap-key/index|try the working examples]] on Github.
Unwrapping a "raw" key
In this example we unwrap an AES-GCM symmetric key. The key was exported in "raw" format and encrypted using the AES-KW algorithm, with a key derived from a password.
To unwrap, we ask the user for the password and use PBKDF2 and some salt to derive the AES-KW unwrapping key. The salt needs to be the same as the salt that was used to derive the original AES-KW key wrapping key.
Once we have the unwrapping key we pass it into unwrapKey()
with the wrapped key and other parameters. See the complete code on GitHub.
/*
Salt that is to be used in derivation of the key-wrapping key,
alongside the password the user supplies.
This must match the salt value that was originally used to derive
the key.
*/
const saltBytes = [89,113,135,234,168,204,21,36,55,93,1,132,242,242,192,156];
/*
The wrapped key itself.
*/
const wrappedKeyBytes = [171,223,14,36,201,233,233,120,164,68,217,192,226,80,
224,39,199,235,239,60,212,169,100,23,61,54,244,197,160,80,109,230,207,
225,57,197,175,71,80,209];
/*
Convert an array of byte values to an ArrayBuffer.
*/
function bytesToArrayBuffer(bytes) {
const bytesAsArrayBuffer = new ArrayBuffer(bytes.length);
const bytesUint8 = new Uint8Array(bytesAsArrayBuffer);
bytesUint8.set(bytes);
return bytesAsArrayBuffer;
}
/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
let password = window.prompt("Enter your password");
let enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{name: "PBKDF2"},
false,
["deriveBits", "deriveKey"]
);
}
/*
Derive an AES-KW key using PBKDF2.
*/
async function getUnwrappingKey() {
// 1. get the key material (user-supplied password)
const keyMaterial = await getKeyMaterial();
// 2 initialize the salt parameter.
// The salt must match the salt originally used to derive the key.
// In this example it's supplied as a constant "saltBytes".
const saltBuffer = bytesToArrayBuffer(saltBytes);
// 3 derive the key from key material and salt
return window.crypto.subtle.deriveKey(
{
"name": "PBKDF2",
salt: saltBuffer,
"iterations": 100000,
"hash": "SHA-256"
},
keyMaterial,
{ "name": "AES-KW", "length": 256},
true,
[ "wrapKey", "unwrapKey" ]
);
}
/*
Unwrap an AES secret key from an ArrayBuffer containing the raw bytes.
Takes an array containing the bytes, and returns a Promise
that will resolve to a CryptoKey representing the secret key.
*/
async function unwrapSecretKey(wrappedKey) {
// 1. get the unwrapping key
const unwrappingKey = await getUnwrappingKey();
// 2. initialize the wrapped key
const wrappedKeyBuffer = bytesToArrayBuffer(wrappedKey);
// 3. unwrap the key
return window.crypto.subtle.unwrapKey(
"raw", // import format
wrappedKeyBuffer, // ArrayBuffer representing key to unwrap
unwrappingKey, // CryptoKey representing key encryption key
"AES-KW", // algorithm identifier for key encryption key
"AES-GCM", // algorithm identifier for key to unwrap
true, // extractability of key to unwrap
["encrypt", "decrypt"] // key usages for key to unwrap
);
}
Unwrapping a "pkcs8" key
In this example we unwrap an RSA-PSS private signing key. The key was exported in "pkcs8" format and encrypted using the AES-GCM algorithm, with a key derived from a password.
To unwrap, we ask the user for the password and use PBKDF2 and some salt to derive the AES-GCM unwrapping key. The salt needs to be the same as the salt that was used to derive the original AES-GCM key wrapping key.
Once we have the unwrapping key we pass it into unwrapKey()
with the wrapped key and other parameters. Note that when using AES-GCM we have to pass the iv value into unwrapKey()
, and this must be the same as the iv that was used in the corresponding wrapKey()
operation. See the complete code on GitHub.
/*
Salt that is to be used in derivation of the key-wrapping key,
alongside the password the user supplies.
This must match the salt value that was originally used to derive
the key.
*/
const saltBytes = [180,253,62,216,47,35,90,55,218,233,103,10,172,143,161,177];
/*
IV that is to be used in decrypting the key to unwrap.
This must the the same IV that was originally used to encrypt
the key.
*/
const ivBytes = [212,187,26,247,172,51,37,151,27,177,249,142];
/*
The wrapped key itself.
*/
const wrappedKeyBytes = [6,155,182,208,7,141,44,18,3,151,58,126,68,100,252,
225,241,11,25,201,153,171,102,174,150,29,62,195,110,138,106,109,14,6,108,
148,104,221,22,93,102,221,146,25,65,112,4,140,79,194,164,163,156,250,108,
11,14,220,78,194,161,17,14,57,121,70,13,28,220,210,78,32,46,217,36,165,220,
170,244,152,214,150,83,2,138,128,11,251,227,213,72,100,158,10,162,40,195,
60,248,77,37,156,34,10,213,171,67,147,73,231,31,63,80,176,103,206,187,164,
214,250,49,223,185,5,48,241,17,1,253,59,185,181,209,255,42,223,175,90,159,
174,169,205,156,120,195,1,135,165,226,46,119,27,97,183,23,197,227,85,138,
235,79,158,167,59,62,194,34,210,214,240,215,101,233,63,138,53,87,253,189,
27,66,150,76,242,76,102,174,179,163,184,205,11,161,224,19,110,34,175,192,
101,117,169,86,66,56,241,128,13,156,165,125,139,110,138,50,108,129,251,137,
26,186,110,117,113,207,179,59,213,18,175,14,203,192,2,97,131,125,167,227,
182,87,72,123,54,156,60,195,88,224,96,46,126,245,251,247,147,110,147,173,
82,106,93,210,55,71,127,133,41,37,181,17,106,16,158,220,136,43,75,133,96,
240,151,116,40,44,254,2,32,74,226,193,172,48,211,71,109,163,143,30,92,28,
30,183,25,16,176,207,77,93,139,242,114,91,218,126,123,234,18,9,245,53,46,
172,215,62,92,249,191,17,27,0,58,151,33,23,169,93,177,253,152,147,198,196,
226,42,202,166,99,250,127,40,221,196,121,195,198,235,30,159,159,95,182,107,
175,137,177,49,72,63,131,162,198,186,22,255,230,237,195,56,147,177,101,52,
227,125,32,180,242,47,92,212,6,148,218,107,125,137,123,15,51,107,159,228,
238,212,60,54,184,48,110,248,252,208,46,23,149,78,169,201,68,242,193,251,
156,227,42,90,109,102,172,61,207,124,96,98,79,37,218,16,212,139,162,0,183,
235,171,75,18,84,160,120,173,156,187,99,24,58,88,213,148,24,193,111,75,169,
10,158,207,148,84,249,156,248,19,221,2,175,1,8,74,221,212,244,123,34,223,
175,54,166,101,51,175,141,80,87,9,146,72,223,46,251,199,192,2,22,125,16,15,
99,26,159,165,133,172,169,26,236,44,86,182,162,81,143,249,15,207,12,232,15,
205,199,78,133,199,19,232,183,33,183,72,117,72,27,43,254,13,17,252,1,143,
137,154,10,4,77,85,24,85,143,200,81,76,171,43,124,42,191,150,70,10,90,178,
198,40,233,233,225,146,231,209,254,2,90,216,5,97,105,204,82,88,81,99,92,
159,116,192,223,148,252,12,24,197,211,187,212,98,252,201,154,184,65,54,47,
13,106,151,168,208,112,212,74,204,36,233,98,104,58,103,1,194,13,26,109,101,
60,42,3,215,20,25,99,176,63,28,112,102,121,190,96,198,228,196,78,38,82,37,
248,42,150,115,6,10,22,101,42,237,175,69,232,212,231,40,193,70,211,245,106,
231,175,150,88,105,170,139,238,196,64,218,250,47,165,22,36,196,161,30,79,
175,14,133,88,129,182,56,140,147,168,134,91,68,172,110,195,134,156,68,78,
249,215,68,250,11,23,70,59,156,99,75,249,159,84,16,206,93,16,130,34,66,210,
82,252,53,251,84,59,226,212,154,15,20,163,58,228,109,53,214,151,237,10,169,
107,180,123,174,159,182,8,240,115,115,220,131,128,79,80,61,133,58,24,98,
193,225,56,36,159,254,199,49,44,160,28,81,140,163,24,143,114,31,237,235,
250,83,72,215,44,232,182,45,39,182,193,248,65,174,186,52,219,30,198,48,1,
134,151,81,114,38,124,7,213,205,138,28,22,216,76,46,224,241,88,156,7,62,
23,104,34,54,25,156,93,212,133,182,61,93,255,195,68,244,234,53,132,151,140,
72,146,127,113,227,34,243,218,222,47,218,113,18,173,203,158,133,90,156,214,
77,20,113,1,231,164,52,55,69,132,24,68,131,212,7,153,34,179,113,156,81,
127,83,57,29,195,90,64,211,115,202,188,5,42,188,142,203,109,231,53,206,72,
220,90,23,12,1,178,122,60,221,68,6,14,154,108,203,171,142,159,249,13,55,52,
110,214,33,147,164,181,50,79,164,200,83,251,40,105,223,50,0,115,240,146,23,
122,80,204,169,38,198,154,31,29,23,236,39,35,131,147,242,163,138,158,236,
117,7,108,33,132,98,50,111,46,146,251,82,34,85,5,130,237,67,40,170,235,124,
92,66,71,239,12,97,136,251,1,206,13,51,232,92,46,35,95,5,123,24,183,99,243,
124,75,155,89,66,54,72,17,255,99,137,199,232,204,9,248,78,35,218,136,117,
239,102,240,187,40,89,244,140,109,229,120,116,54,207,171,11,248,190,199,81,
53,109,8,188,51,93,165,34,255,165,191,198,130,220,41,192,166,194,69,104,
124,158,122,236,176,24,60,87,240,42,158,143,37,143,208,155,249,230,21,4,
230,56,194,62,235,132,14,50,180,216,134,28,25,159,64,199,161,236,60,233,
160,172,68,169,2,5,252,190,20,54,115,248,63,93,107,156,8,96,85,32,189,118,
66,114,126,64,203,97,235,13,18,102,192,51,59,5,122,171,96,129,40,32,154,4,
191,234,75,184,112,201,244,110,50,216,44,88,139,175,58,112,7,52,25,64,112,
40,148,187,39,234,96,151,16,158,114,113,109,164,47,108,94,148,35,232,221,
33,110,126,170,25,234,45,165,180,210,193,120,247,155,127];
/*
The unwrapped signing key.
*/
let signingKey;
const signButton = document.querySelector(".pkcs8 .sign-button");
/*
Convert an array of byte values to an ArrayBuffer.
*/
function bytesToArrayBuffer(bytes) {
const bytesAsArrayBuffer = new ArrayBuffer(bytes.length);
const bytesUint8 = new Uint8Array(bytesAsArrayBuffer);
bytesUint8.set(bytes);
return bytesAsArrayBuffer;
}
/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
let password = window.prompt("Enter your password");
let enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{name: "PBKDF2"},
false,
["deriveBits", "deriveKey"]
);
}
/*
Derive an AES-GCM key using PBKDF2.
*/
async function getUnwrappingKey() {
// 1. get the key material (user-supplied password)
const keyMaterial = await getKeyMaterial();
// 2 initialize the salt parameter.
// The salt must match the salt originally used to derive the key.
// In this example it's supplied as a constant "saltBytes".
const saltBuffer = bytesToArrayBuffer(saltBytes);
// 3 derive the key from key material and salt
return window.crypto.subtle.deriveKey(
{
"name": "PBKDF2",
salt: saltBuffer,
"iterations": 100000,
"hash": "SHA-256"
},
keyMaterial,
{ "name": "AES-GCM", "length": 256},
true,
[ "wrapKey", "unwrapKey" ]
);
}
/*
Unwrap an RSA-PSS private signing key from an ArrayBuffer containing
the raw bytes.
Takes an array containing the bytes, and returns a Promise
that will resolve to a CryptoKey representing the private key.
*/
async function unwrapPrivateKey(wrappedKey) {
// 1. get the unwrapping key
const unwrappingKey = await getUnwrappingKey();
// 2. initialize the wrapped key
const wrappedKeyBuffer = bytesToArrayBuffer(wrappedKey);
// 3. initialize the iv
const ivBuffer = bytesToArrayBuffer(ivBytes);
// 4. unwrap the key
return window.crypto.subtle.unwrapKey(
"pkcs8", // import format
wrappedKeyBuffer, // ArrayBuffer representing key to unwrap
unwrappingKey, // CryptoKey representing key encryption key
{ // algorithm params for key encryption key
name: "AES-GCM",
iv: ivBuffer
},
{ // algorithm params for key to unwrap
name: "RSA-PSS",
hash: "SHA-256"
},
true, // extractability of key to unwrap
["sign"] // key usages for key to unwrap
);
}
Specifications
Specification | Status | Comment |
Web Cryptography APIThe definition of 'SubtleCrypto.unwrapKey()' in that specification. | Recommendation | Initial definition. |
Browser compatibility
The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.
Update compatibility data on GitHub
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
unwrapKey
|
Chrome
Full support 37 |
Edge Partial support 12 Partial support 12 Notes' Not supported: AES-CTR. |
Firefox Full support 34 Full support 34 No support 32 — 34 Disabled' From version 32 until version 34 (exclusive): this feature is behind the |
IE Partial support 11 Partial support 11 Notes' Returns |
Opera
Full support 24 |
Safari
Full support 7 |
WebView Android
? |
Chrome Android
Full support 37 |
Firefox Android Full support 34 Full support 34 No support 32 — 34 Disabled' From version 32 until version 34 (exclusive): this feature is behind the |
Opera Android
Full support 24 |
Safari iOS
Full support 7 |
Samsung Internet Android
Full support 6.0 |
Legend
- Full support
- Full support
- Partial support
- Partial support
- Compatibility unknown
- Compatibility unknown
- See implementation notes.'
- See implementation notes.
- User must explicitly enable this feature.'
- User must explicitly enable this feature.
See also
SubtleCrypto.importKey()
- PKCS #8 format.
- SubjectPublicKeyInfo format.
- JSON Web Key format.
- AES-KW specification.
SubtleCrypto.unwrapKey() by Mozilla Contributors is licensed under CC-BY-SA 2.5.