Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<html>
<head>
<title>WebCrypto Test Suite</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="./test_WebCrypto.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<!-- Utilities for manipulating ABVs -->
<script src="util.js"></script>
<!-- A simple wrapper around IndexedDB -->
<script src="simpledb.js"></script>
<!-- Test vectors drawn from the literature -->
<script src="./test-vectors.js"></script>
<!-- General testing framework -->
<script src="./test-array.js"></script>
<script>/* <![CDATA[*/
"use strict";
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key wrap known answer, using AES-GCM",
function() {
var that = this;
var alg = {
name: "AES-GCM",
iv: tv.key_wrap_known_answer.wrapping_iv,
tagLength: 128,
};
var key, wrappingKey;
function doImport(k) {
wrappingKey = k;
return crypto.subtle.importKey("raw", tv.key_wrap_known_answer.key,
alg, true, ["encrypt", "decrypt"]);
}
function doWrap(k) {
key = k;
return crypto.subtle.wrapKey("raw", key, wrappingKey, alg);
}
crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key,
alg, false, ["wrapKey"])
.then(doImport, error(that))
.then(doWrap, error(that))
.then(
memcmp_complete(that, tv.key_wrap_known_answer.wrapped_key),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key wrap failing on non-extractable key",
function() {
var that = this;
var alg = {
name: "AES-GCM",
iv: tv.key_wrap_known_answer.wrapping_iv,
tagLength: 128,
};
var key, wrappingKey;
function doImport(k) {
wrappingKey = k;
return crypto.subtle.importKey("raw", tv.key_wrap_known_answer.key,
alg, false, ["encrypt", "decrypt"]);
}
function doWrap(k) {
key = k;
return crypto.subtle.wrapKey("raw", key, wrappingKey, alg);
}
crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key,
alg, false, ["wrapKey"])
.then(doImport, error(that))
.then(doWrap, error(that))
.then(
error(that),
complete(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key unwrap known answer, using AES-GCM",
function() {
var that = this;
var alg = {
name: "AES-GCM",
iv: tv.key_wrap_known_answer.wrapping_iv,
tagLength: 128,
};
var wrappingKey;
function doUnwrap(k) {
wrappingKey = k;
return crypto.subtle.unwrapKey(
"raw", tv.key_wrap_known_answer.wrapped_key,
wrappingKey, alg,
"AES-GCM", true, ["encrypt", "decrypt"]
);
}
function doExport(k) {
return crypto.subtle.exportKey("raw", k);
}
crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key,
alg, false, ["unwrapKey"])
.then(doUnwrap, error(that))
.then(doExport, error(that))
.then(
memcmp_complete(that, tv.key_wrap_known_answer.key),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key wrap/unwrap round-trip, using RSA-OAEP",
function() {
var that = this;
var oaep = {
name: "RSA-OAEP",
hash: "SHA-256",
};
var gcm = {
name: "AES-GCM",
iv: tv.aes_gcm_enc.iv,
additionalData: tv.aes_gcm_enc.adata,
tagLength: 128,
};
var unwrapKey;
function doWrap(keys) {
var originalKey = keys[0];
var wrapKey = keys[1];
unwrapKey = keys[2];
return crypto.subtle.wrapKey("raw", originalKey, wrapKey, oaep);
}
function doUnwrap(wrappedKey) {
return crypto.subtle.unwrapKey("raw", wrappedKey, unwrapKey, oaep,
gcm, false, ["encrypt"]);
}
function doEncrypt(aesKey) {
return crypto.subtle.encrypt(gcm, aesKey, tv.aes_gcm_enc.data);
}
// 1.Import:
// -> HMAC key
// -> OAEP wrap key (public)
// -> OAEP unwrap key (private)
// 2. Wrap the HMAC key
// 3. Unwrap it
// 4. Compute HMAC
// 5. Check HMAC value
Promise.all([
crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, gcm, true, ["encrypt"]),
crypto.subtle.importKey("spki", tv.rsaoaep.spki, oaep, true, ["wrapKey"]),
crypto.subtle.importKey("pkcs8", tv.rsaoaep.pkcs8, oaep, false, ["unwrapKey"]),
])
.then(doWrap, error(that))
.then(doUnwrap, error(that))
.then(doEncrypt, error(that))
.then(
memcmp_complete(that, tv.aes_gcm_enc.result),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"HMAC JWK wrap/unwrap round-trip, with AES-GCM",
function() {
var that = this;
var genAlg = { name: "HMAC", hash: "SHA-384", length: 512 };
var wrapAlg = { name: "AES-GCM", iv: tv.aes_gcm_enc.iv };
var wrapKey, originalKey, originalKeyJwk;
function doExport(k) {
return crypto.subtle.exportKey("jwk", k);
}
function doWrap() {
return crypto.subtle.wrapKey("jwk", originalKey, wrapKey, wrapAlg);
}
function doUnwrap(wrappedKey) {
return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg,
{ name: "HMAC", hash: "SHA-384"},
true, ["sign", "verify"]);
}
Promise.all([
crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk,
"AES-GCM", false, ["wrapKey", "unwrapKey"])
.then(function(x) { wrapKey = x; }),
crypto.subtle.generateKey(genAlg, true, ["sign", "verify"])
.then(function(x) { originalKey = x; return x; })
.then(doExport)
.then(function(x) { originalKeyJwk = x; }),
])
.then(doWrap)
.then(doUnwrap)
.then(doExport)
.then(
complete(that, function(x) {
return exists(x.k) && x.k == originalKeyJwk.k;
}),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"ECDSA private JWK wrap/unwrap round-trip, with AES-GCM",
function() {
var that = this;
var genAlg = { name: "ECDSA", namedCurve: "P-256" };
var wrapAlg = { name: "AES-GCM", iv: tv.aes_gcm_enc.iv };
var wrapKey, originalKey, originalKeyJwk;
function doExport(k) {
return crypto.subtle.exportKey("jwk", k);
}
function doWrap() {
return crypto.subtle.wrapKey("jwk", originalKey, wrapKey, wrapAlg);
}
function doUnwrap(wrappedKey) {
return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg,
genAlg, true, ["sign"]);
}
Promise.all([
crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk,
"AES-GCM", false, ["wrapKey", "unwrapKey"])
.then(function(x) { wrapKey = x; }),
crypto.subtle.generateKey(genAlg, true, ["sign", "verify"])
.then(function(x) { originalKey = x.privateKey; return x.privateKey; })
.then(doExport)
.then(function(x) { originalKeyJwk = x; }),
])
.then(doWrap)
.then(doUnwrap)
.then(doExport)
.then(
complete(that, function(x) {
return (x.kty == originalKeyJwk.kty) &&
(x.crv == originalKeyJwk.crv) &&
(x.d == originalKeyJwk.d) &&
(x.x == originalKeyJwk.x) &&
(x.y == originalKeyJwk.y);
}),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"AES-KW known answer",
function() {
var that = this;
function doWrap(keys) {
var wrapKey = keys[0];
var originalKey = keys[1];
return crypto.subtle.wrapKey("raw", originalKey, wrapKey, "AES-KW");
}
Promise.all([
crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key,
"AES-KW", false, ["wrapKey"]),
crypto.subtle.importKey("jwk", tv.aes_kw.key,
"AES-GCM", true, ["encrypt"]),
])
.then(doWrap)
.then(
memcmp_complete(that, tv.aes_kw.wrapped_key),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"AES-KW unwrap failure on tampered key data",
function() {
var that = this;
var tamperedWrappedKey = new Uint8Array(tv.aes_kw.wrapped_key);
tamperedWrappedKey[5] ^= 0xFF;
function doUnwrap(wrapKey) {
return crypto.subtle.unwrapKey("raw", tamperedWrappedKey, wrapKey,
"AES-KW", "AES-GCM",
true, ["encrypt", "decrypt"]);
}
crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key,
"AES-KW", false, ["unwrapKey"])
.then(doUnwrap)
.then(error(that), complete(that));
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"AES-KW unwrap AES-KW key data",
function() {
var that = this;
var wrappedKey = new Uint8Array(tv.aes_kw.wrapped_key);
function doUnwrap(wrapKey) {
return crypto.subtle.unwrapKey("raw", wrappedKey, wrapKey,
"AES-KW", "AES-KW",
true, ["wrapKey", "unwrapKey"]);
}
crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key,
"AES-KW", false, ["unwrapKey"])
.then(doUnwrap)
.then(
memcmp_complete(that, tv.aes_kw.key),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"AES-KW wrap/unwrap round-trip",
function() {
var that = this;
var genAlg = { name: "HMAC", hash: "SHA-384", length: 512 };
var wrapKey, originalKey, originalKeyJwk;
function doExport(k) {
return crypto.subtle.exportKey("jwk", k);
}
function doWrap() {
return crypto.subtle.wrapKey("raw", originalKey, wrapKey, "AES-KW");
}
function doUnwrap(wrappedKey) {
return crypto.subtle.unwrapKey("raw", wrappedKey, wrapKey,
"AES-KW", { name: "HMAC", hash: "SHA-384"},
true, ["sign", "verify"]);
}
Promise.all([
crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key,
"AES-KW", false, ["wrapKey", "unwrapKey"])
.then(function(x) { wrapKey = x; }),
crypto.subtle.generateKey(genAlg, true, ["sign"])
.then(function(x) { originalKey = x; return x; })
.then(doExport)
.then(function(x) { originalKeyJwk = x; }),
])
.then(doWrap)
.then(doUnwrap)
.then(doExport)
.then(
complete(that, function(x) {
return exists(x.k) && x.k == originalKeyJwk.k;
}),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"JWK unwrap attempt on bogus data should error out",
function() {
// Largely cribbed from the "JWK wrap/unwrap round-trip, with AES-GCM" test
var that = this;
var wrapAlg = { name: "AES-GCM", iv: tv.aes_gcm_enc.iv };
var wrapKey;
function doBogusWrap() {
var abv = new TextEncoder().encode("I am so not JSON");
return crypto.subtle.encrypt(wrapAlg, wrapKey, abv);
}
function doUnwrap(wrappedKey) {
return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg,
{name: "HMAC", hash: "SHA-384"},
true, ["sign", "verify"]);
}
crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk,
"AES-GCM", false, ["encrypt", "unwrapKey"])
.then(function(x) { wrapKey = x; })
.then(doBogusWrap, error(that))
.then(doUnwrap, error(that))
.then(
error(that),
complete(that)
);
}
);
/* ]]>*/</script>
</head>
<body>
<div id="content">
<div id="head">
<b>Web</b>Crypto<br>
</div>
<div id="start" onclick="start();">RUN ALL</div>
<div id="resultDiv" class="content">
Summary:
<span class="pass"><span id="passN">0</span> passed, </span>
<span class="fail"><span id="failN">0</span> failed, </span>
<span class="pending"><span id="pendingN">0</span> pending.</span>
<br/>
<br/>
<table id="results">
<tr>
<th>Test</th>
<th>Result</th>
<th>Time</th>
</tr>
</table>
</div>
<div id="foot"></div>
</div>
</body>
</html>