[webcrypto] Add JWK import for HMAC and AES-CBC key.
BUG=245025
TEST=content_unittests --gtest_filter="WebCryptoImpl*"
Review URL: https://codereview.chromium.org/25906002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238574 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/renderer/webcrypto/webcrypto_impl.cc b/content/renderer/webcrypto/webcrypto_impl.cc
index 4c4f3bf..c70a423 100644
--- a/content/renderer/webcrypto/webcrypto_impl.cc
+++ b/content/renderer/webcrypto/webcrypto_impl.cc
@@ -4,10 +4,18 @@
#include "content/renderer/webcrypto/webcrypto_impl.h"
+#include <algorithm>
+#include <functional>
+#include <map>
+#include "base/json/json_reader.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "content/renderer/webcrypto/webcrypto_util.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKey.h"
namespace content {
@@ -22,30 +30,130 @@
algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
}
+// Binds a specific key length value to a compatible factory function.
+typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)(
+ unsigned short);
+template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length>
+blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() {
+ return func(key_length);
+}
+
+// Binds a WebCryptoAlgorithmId value to a compatible factory function.
+typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)(
+ blink::WebCryptoAlgorithmId);
+template <AlgFactoryFuncWithWebCryptoAlgIdArg func,
+ blink::WebCryptoAlgorithmId algorithm_id>
+blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() {
+ return func(algorithm_id);
+}
+
+// Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto
+// factory function.
+typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)();
+typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap;
+
+class JwkAlgorithmFactoryMap {
+ public:
+ JwkAlgorithmFactoryMap() {
+ map_["HS256"] =
+ &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
+ 256>;
+ map_["HS384"] =
+ &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
+ 384>;
+ map_["HS512"] =
+ &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
+ 512>;
+ map_["RS256"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
+ blink::WebCryptoAlgorithmIdSha256>;
+ map_["RS384"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
+ blink::WebCryptoAlgorithmIdSha384>;
+ map_["RS512"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
+ blink::WebCryptoAlgorithmIdSha512>;
+ map_["RSA1_5"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>;
+ map_["RSA-OAEP"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
+ blink::WebCryptoAlgorithmIdSha1>;
+ // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
+ map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull;
+ // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
+ map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull;
+ map_["A128GCM"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
+ blink::WebCryptoAlgorithmIdAesGcm>;
+ map_["A256GCM"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
+ blink::WebCryptoAlgorithmIdAesGcm>;
+ map_["A128CBC"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
+ blink::WebCryptoAlgorithmIdAesCbc>;
+ map_["A192CBC"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
+ blink::WebCryptoAlgorithmIdAesCbc>;
+ map_["A256CBC"] =
+ &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
+ blink::WebCryptoAlgorithmIdAesCbc>;
+ }
+
+ blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id)
+ const {
+ const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id);
+ if (pos == map_.end())
+ return blink::WebCryptoAlgorithm::createNull();
+ return pos->second();
+ }
+
+ private:
+ JwkAlgFactoryMap map_;
+};
+
+base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory =
+ LAZY_INSTANCE_INITIALIZER;
+
+bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
+ const blink::WebCryptoAlgorithm& alg2) {
+ DCHECK(!alg1.isNull());
+ DCHECK(!alg2.isNull());
+ if (alg1.id() != alg2.id())
+ return false;
+ switch (alg1.id()) {
+ case blink::WebCryptoAlgorithmIdHmac:
+ case blink::WebCryptoAlgorithmIdRsaOaep:
+ case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
+ if (WebCryptoAlgorithmsConsistent(
+ webcrypto::GetInnerHashAlgorithm(alg1),
+ webcrypto::GetInnerHashAlgorithm(alg2))) {
+ return true;
+ }
+ break;
+ case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
+ case blink::WebCryptoAlgorithmIdSha1:
+ case blink::WebCryptoAlgorithmIdSha224:
+ case blink::WebCryptoAlgorithmIdSha256:
+ case blink::WebCryptoAlgorithmIdSha384:
+ case blink::WebCryptoAlgorithmIdSha512:
+ case blink::WebCryptoAlgorithmIdAesCbc:
+ case blink::WebCryptoAlgorithmIdAesGcm:
+ case blink::WebCryptoAlgorithmIdAesCtr:
+ return true;
+ default:
+ NOTREACHED(); // Not a supported algorithm.
+ break;
+ }
+ return false;
+}
+
} // namespace
WebCryptoImpl::WebCryptoImpl() {
Init();
}
-// static
-// TODO(eroman): This works by re-allocating a new buffer. It would be better if
-// the WebArrayBuffer could just be truncated instead.
-void WebCryptoImpl::ShrinkBuffer(
- blink::WebArrayBuffer* buffer,
- unsigned new_size) {
- DCHECK_LE(new_size, buffer->byteLength());
-
- if (new_size == buffer->byteLength())
- return;
-
- blink::WebArrayBuffer new_buffer =
- blink::WebArrayBuffer::create(new_size, 1);
- DCHECK(!new_buffer.isNull());
- memcpy(new_buffer.data(), buffer->data(), new_size);
- *buffer = new_buffer;
-}
-
void WebCryptoImpl::encrypt(
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
@@ -140,15 +248,27 @@
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoResult result) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
- if (!ImportKeyInternal(format,
- key_data,
- key_data_size,
- algorithm_or_null,
- extractable,
- usage_mask,
- &key)) {
- result.completeWithError();
- return;
+ if (format == blink::WebCryptoKeyFormatJwk) {
+ if (!ImportKeyJwk(key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ &key)) {
+ result.completeWithError();
+ return;
+ }
+ } else {
+ if (!ImportKeyInternal(format,
+ key_data,
+ key_data_size,
+ algorithm_or_null,
+ extractable,
+ usage_mask,
+ &key)) {
+ result.completeWithError();
+ return;
+ }
}
DCHECK(key.handle());
DCHECK(!key.algorithm().isNull());
@@ -206,4 +326,269 @@
}
}
+bool WebCryptoImpl::ImportKeyJwk(
+ const unsigned char* key_data,
+ unsigned key_data_size,
+ const blink::WebCryptoAlgorithm& algorithm_or_null,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key) {
+
+ // The goal of this method is to extract key material and meta data from the
+ // incoming JWK, combine them with the input parameters, and ultimately import
+ // a Web Crypto Key.
+ //
+ // JSON Web Key Format (JWK)
+ // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
+ // TODO(padolph): Not all possible values are handled by this code right now
+ //
+ // A JWK is a simple JSON dictionary with the following entries
+ // - "kty" (Key Type) Parameter, REQUIRED
+ // - <kty-specific parameters, see below>, REQUIRED
+ // - "use" (Key Use) Parameter, OPTIONAL
+ // - "alg" (Algorithm) Parameter, OPTIONAL
+ // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
+ // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
+ // (all other entries are ignored)
+ //
+ // OPTIONAL here means that this code does not require the entry to be present
+ // in the incoming JWK, because the method input parameters contain similar
+ // information. If the optional JWK entry is present, it will be validated
+ // against the corresponding input parameter for consistency and combined with
+ // it according to rules defined below. A special case is that the method
+ // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
+ // value (if present) is used as a fallback.
+ //
+ // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
+ // values are parsed out and combined with the method input parameters to
+ // build a Web Crypto Key:
+ // Web Crypto Key type <-- (deduced)
+ // Web Crypto Key extractable <-- JWK extractable + input extractable
+ // Web Crypto Key algorithm <-- JWK alg + input algorithm
+ // Web Crypto Key keyUsage <-- JWK use + input usage_mask
+ // Web Crypto Key keying material <-- kty-specific parameters
+ //
+ // Values for each JWK entry are case-sensitive and defined in
+ // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
+ // Note that not all values specified by JOSE are handled by this code. Only
+ // handled values are listed.
+ // - kty (Key Type)
+ // +-------+--------------------------------------------------------------+
+ // | "RSA" | RSA [RFC3447] |
+ // | "oct" | Octet sequence (used to represent symmetric keys) |
+ // +-------+--------------------------------------------------------------+
+ // - use (Key Use)
+ // +-------+--------------------------------------------------------------+
+ // | "enc" | encrypt and decrypt operations |
+ // | "sig" | sign and verify (MAC) operations |
+ // | "wrap"| key wrap and unwrap [not yet part of JOSE] |
+ // +-------+--------------------------------------------------------------+
+ // - extractable (Key Exportability)
+ // +-------+--------------------------------------------------------------+
+ // | true | Key may be exported from the trusted environment |
+ // | false | Key cannot exit the trusted environment |
+ // +-------+--------------------------------------------------------------+
+ // - alg (Algorithm)
+ // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
+ // +--------------+-------------------------------------------------------+
+ // | Digital Signature or MAC Algorithm |
+ // +--------------+-------------------------------------------------------+
+ // | "HS256" | HMAC using SHA-256 hash algorithm |
+ // | "HS384" | HMAC using SHA-384 hash algorithm |
+ // | "HS512" | HMAC using SHA-512 hash algorithm |
+ // | "RS256" | RSASSA using SHA-256 hash algorithm |
+ // | "RS384" | RSASSA using SHA-384 hash algorithm |
+ // | "RS512" | RSASSA using SHA-512 hash algorithm |
+ // +--------------+-------------------------------------------------------|
+ // | Key Management Algorithm |
+ // +--------------+-------------------------------------------------------+
+ // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] |
+ // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
+ // | | (OAEP) [RFC3447], with the default parameters |
+ // | | specified by RFC3447 in Section A.2.1 |
+ // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
+ // | | [RFC3394] using 128 bit keys |
+ // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
+ // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
+ // | | 128 bit keys |
+ // | "A256GCM" | AES GCM using 256 bit keys |
+ // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
+ // | | padding [NIST.800-38A] [not yet part of JOSE, see |
+ // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 |
+ // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] |
+ // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] |
+ // +--------------+-------------------------------------------------------+
+ //
+ // kty-specific parameters
+ // The value of kty determines the type and content of the keying material
+ // carried in the JWK to be imported. Currently only two possibilities are
+ // supported: a raw key or an RSA public key. RSA private keys are not
+ // supported because typical applications seldom need to import a private key,
+ // and the large number of JWK parameters required to describe one.
+ // - kty == "oct" (symmetric or other raw key)
+ // +-------+--------------------------------------------------------------+
+ // | "k" | Contains the value of the symmetric (or other single-valued) |
+ // | | key. It is represented as the base64url encoding of the |
+ // | | octet sequence containing the key value. |
+ // +-------+--------------------------------------------------------------+
+ // - kty == "RSA" (RSA public key)
+ // +-------+--------------------------------------------------------------+
+ // | "n" | Contains the modulus value for the RSA public key. It is |
+ // | | represented as the base64url encoding of the value's |
+ // | | unsigned big endian representation as an octet sequence. |
+ // +-------+--------------------------------------------------------------+
+ // | "e" | Contains the exponent value for the RSA public key. It is |
+ // | | represented as the base64url encoding of the value's |
+ // | | unsigned big endian representation as an octet sequence. |
+ // +-------+--------------------------------------------------------------+
+ //
+ // Consistency and conflict resolution
+ // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters
+ // may be different than the corresponding values inside the JWK. The Web
+ // Crypto spec says that if a JWK value is present but is inconsistent with
+ // the input value, it is an error and the operation must fail. If no
+ // inconsistency is found, the input and JWK values are combined as follows:
+ //
+ // algorithm
+ // If an algorithm is provided by both the input parameter and the JWK,
+ // consistency between the two is based only on algorithm ID's (including an
+ // inner hash algorithm if present). In this case if the consistency
+ // check is passed, the input algorithm is used. If only one of either the
+ // input algorithm and JWK alg is provided, it is used as the final
+ // algorithm.
+ //
+ // extractable
+ // If the JWK extractable is true but the input parameter is false, make the
+ // Web Crypto Key non-extractable. Conversely, if the JWK extractable is
+ // false but the input parameter is true, it is an inconsistency. If both
+ // are true or both are false, use that value.
+ //
+ // usage_mask
+ // The input usage_mask must be a strict subset of the interpreted JWK use
+ // value, else it is judged inconsistent. In all cases the input usage_mask
+ // is used as the final usage_mask.
+ //
+
+ if (!key_data_size)
+ return false;
+ DCHECK(key);
+
+ // Parse the incoming JWK JSON.
+ base::StringPiece json_string(reinterpret_cast<const char*>(key_data),
+ key_data_size);
+ scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
+ // Note, bare pointer dict_value is ok since it points into scoped value.
+ base::DictionaryValue* dict_value = NULL;
+ if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
+ return false;
+
+ // JWK "kty". Exit early if this required JWK parameter is missing.
+ std::string jwk_kty_value;
+ if (!dict_value->GetString("kty", &jwk_kty_value))
+ return false;
+
+ // JWK "extractable" (optional) --> extractable parameter
+ {
+ bool jwk_extractable_value;
+ if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) {
+ if (!jwk_extractable_value && extractable)
+ return false;
+ extractable = extractable && jwk_extractable_value;
+ }
+ }
+
+ // JWK "alg" (optional) --> algorithm parameter
+ // Note: input algorithm is also optional, so we have six cases to handle.
+ // 1. JWK alg present but unrecognized: error
+ // 2. JWK alg valid AND input algorithm isNull: use JWK value
+ // 3. JWK alg valid AND input algorithm specified, but JWK value
+ // inconsistent with input: error
+ // 4. JWK alg valid AND input algorithm specified, both consistent: use
+ // input value (because it has potentially more details)
+ // 5. JWK alg missing AND input algorithm isNull: error
+ // 6. JWK alg missing AND input algorithm specified: use input value
+ blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
+ std::string jwk_alg_value;
+ if (dict_value->GetString("alg", &jwk_alg_value)) {
+ // JWK alg present
+ const blink::WebCryptoAlgorithm jwk_algorithm =
+ jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value);
+ if (jwk_algorithm.isNull()) {
+ // JWK alg unrecognized
+ return false; // case 1
+ }
+ // JWK alg valid
+ if (algorithm_or_null.isNull()) {
+ // input algorithm not specified
+ algorithm = jwk_algorithm; // case 2
+ } else {
+ // input algorithm specified
+ if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
+ return false; // case 3
+ algorithm = algorithm_or_null; // case 4
+ }
+ } else {
+ // JWK alg missing
+ if (algorithm_or_null.isNull())
+ return false; // case 5
+ algorithm = algorithm_or_null; // case 6
+ }
+ DCHECK(!algorithm.isNull());
+
+ // JWK "use" (optional) --> usage_mask parameter
+ std::string jwk_use_value;
+ if (dict_value->GetString("use", &jwk_use_value)) {
+ blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
+ if (jwk_use_value == "enc") {
+ jwk_usage_mask =
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
+ } else if (jwk_use_value == "sig") {
+ jwk_usage_mask =
+ blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
+ } else if (jwk_use_value == "wrap") {
+ jwk_usage_mask =
+ blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
+ } else {
+ return false;
+ }
+ if ((jwk_usage_mask & usage_mask) != usage_mask) {
+ // A usage_mask must be a subset of jwk_usage_mask.
+ return false;
+ }
+ }
+
+ // JWK keying material --> ImportKeyInternal()
+ if (jwk_kty_value == "oct") {
+ std::string jwk_k_value_url64;
+ if (!dict_value->GetString("k", &jwk_k_value_url64))
+ return false;
+ std::string jwk_k_value;
+ if (!webcrypto::Base64DecodeUrlSafe(jwk_k_value_url64, &jwk_k_value) ||
+ !jwk_k_value.size()) {
+ return false;
+ }
+
+ // TODO(padolph): Some JWK alg ID's embed information about the key length
+ // in the alg ID string. For example "A128" implies the JWK carries 128 bits
+ // of key material, and "HS512" implies the JWK carries _at least_ 512 bits
+ // of key material. For such keys validate the actual key length against the
+ // value in the ID.
+
+ return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
+ reinterpret_cast<const uint8*>(jwk_k_value.data()),
+ jwk_k_value.size(),
+ algorithm,
+ extractable,
+ usage_mask,
+ key);
+ } else if (jwk_kty_value == "RSA") {
+ // TODO(padolph): JWK import RSA public key
+ return false;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace content
diff --git a/content/renderer/webcrypto/webcrypto_impl.h b/content/renderer/webcrypto/webcrypto_impl.h
index b194c9f..b39bf42 100644
--- a/content/renderer/webcrypto/webcrypto_impl.h
+++ b/content/renderer/webcrypto/webcrypto_impl.h
@@ -66,7 +66,6 @@
unsigned data_size,
blink::WebCryptoResult result);
- static void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned new_size);
protected:
friend class WebCryptoImplTest;
@@ -128,6 +127,14 @@
unsigned data_size,
bool* signature_match);
+ bool ImportKeyJwk(
+ const unsigned char* key_data,
+ unsigned key_data_size,
+ const blink::WebCryptoAlgorithm& algorithm_or_null,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key);
+
private:
DISALLOW_COPY_AND_ASSIGN(WebCryptoImpl);
};
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc
index bf6fcda..42dfc33 100644
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc
@@ -11,6 +11,7 @@
#include <vector>
#include "base/logging.h"
+#include "content/renderer/webcrypto/webcrypto_util.h"
#include "crypto/nss_util.h"
#include "crypto/scoped_nss_types.h"
#include "crypto/secure_util.h"
@@ -170,7 +171,7 @@
return false;
}
- WebCryptoImpl::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
+ webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
return true;
}
@@ -584,7 +585,7 @@
return false;
}
DCHECK_LE(output_length_bytes, max_output_length_bytes);
- WebCryptoImpl::ShrinkBuffer(buffer, output_length_bytes);
+ webcrypto::ShrinkBuffer(buffer, output_length_bytes);
return true;
}
diff --git a/content/renderer/webcrypto/webcrypto_impl_openssl.cc b/content/renderer/webcrypto/webcrypto_impl_openssl.cc
index 3543f5a..85e52fa 100644
--- a/content/renderer/webcrypto/webcrypto_impl_openssl.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_openssl.cc
@@ -13,6 +13,7 @@
#include <openssl/rand.h>
#include "base/logging.h"
+#include "content/renderer/webcrypto/webcrypto_util.h"
#include "crypto/openssl_util.h"
#include "crypto/secure_util.h"
#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
@@ -151,7 +152,7 @@
static_cast<unsigned>(final_output_chunk_len);
DCHECK_LE(final_output_len, output_max_len);
- WebCryptoImpl::ShrinkBuffer(buffer, final_output_len);
+ webcrypto::ShrinkBuffer(buffer, final_output_len);
return true;
}
@@ -330,7 +331,8 @@
return false;
}
- // TODO(padolph): Need to split handling for symmetric
+ // TODO(padolph): Need to split handling for symmetric (raw format) and
+ // asymmetric (spki or pkcs8 format) keys.
// Currently only supporting symmetric.
// Symmetric keys are always type secret
diff --git a/content/renderer/webcrypto/webcrypto_impl_unittest.cc b/content/renderer/webcrypto/webcrypto_impl_unittest.cc
index f9ff0d6..c59de0e 100644
--- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc
@@ -9,17 +9,21 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/renderer_webkitplatformsupport_impl.h"
+#include "content/renderer/webcrypto/webcrypto_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKey.h"
+namespace content {
+
namespace {
std::vector<uint8> HexStringToBytes(const std::string& hex) {
@@ -32,55 +36,28 @@
const blink::WebArrayBuffer& array_buffer) {
EXPECT_STRCASEEQ(
expected_hex.c_str(),
- base::HexEncode(
- array_buffer.data(), array_buffer.byteLength()).c_str());
+ base::HexEncode(array_buffer.data(), array_buffer.byteLength()).c_str());
}
-blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
+std::vector<uint8> MakeJsonVector(const std::string& json_string) {
+ return std::vector<uint8>(json_string.begin(), json_string.end());
}
-blink::WebCryptoAlgorithm CreateHmacAlgorithm(
- blink::WebCryptoAlgorithmId hashId) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
- new blink::WebCryptoHmacParams(CreateAlgorithm(hashId)));
+std::vector<uint8> MakeJsonVector(const base::DictionaryValue& dict) {
+ std::string json;
+ base::JSONWriter::Write(&dict, &json);
+ return MakeJsonVector(json);
}
-blink::WebCryptoAlgorithm CreateHmacKeyAlgorithm(
- blink::WebCryptoAlgorithmId hashId,
- unsigned hash_length) {
- // hash_length < 0 means unspecified
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdHmac,
- new blink::WebCryptoHmacKeyParams(CreateAlgorithm(hashId),
- (hash_length != 0),
- hash_length));
+// Helper for ImportJwkBadJwk; restores JWK JSON dictionary to a good state
+void RestoreDictionaryForImportBadJwkTest(base::DictionaryValue* dict) {
+ dict->Clear();
+ dict->SetString("kty", "oct");
+ dict->SetString("alg", "A128CBC");
+ dict->SetString("use", "enc");
+ dict->SetBoolean("extractable", false);
+ dict->SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
}
-
-// Returns a pointer to the start of |data|, or NULL if it is empty. This is a
-// convenience function for getting the pointer, and should not be used beyond
-// the expected lifetime of |data|.
-const uint8* Start(const std::vector<uint8>& data) {
- if (data.empty())
- return NULL;
- return &data[0];
-}
-
-blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
- const std::vector<uint8>& iv) {
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesCbc,
- new blink::WebCryptoAesCbcParams(Start(iv), iv.size()));
-}
-
-blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
- unsigned short key_length_bits) { // NOLINT
- return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesCbc,
- new blink::WebCryptoAesKeyGenParams(key_length_bits));
-}
-
#if !defined(USE_OPENSSL)
blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm(
@@ -93,15 +70,15 @@
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
algorithm_id,
new blink::WebCryptoRsaKeyGenParams(
- modulus_length, Start(public_exponent), public_exponent.size()));
+ modulus_length,
+ webcrypto::Uint8VectorStart(public_exponent),
+ public_exponent.size()));
}
#endif // #if !defined(USE_OPENSSL)
} // namespace
-namespace content {
-
class WebCryptoImplTest : public testing::Test {
protected:
blink::WebCryptoKey ImportSecretKeyFromRawHexString(
@@ -113,7 +90,7 @@
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
bool extractable = true;
EXPECT_TRUE(crypto_.ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
- Start(key_raw),
+ webcrypto::Uint8VectorStart(key_raw),
key_raw.size(),
algorithm,
extractable,
@@ -133,7 +110,8 @@
const blink::WebCryptoAlgorithm& algorithm,
const std::vector<uint8>& data,
blink::WebArrayBuffer* buffer) {
- return crypto_.DigestInternal(algorithm, Start(data), data.size(), buffer);
+ return crypto_.DigestInternal(
+ algorithm, webcrypto::Uint8VectorStart(data), data.size(), buffer);
}
bool GenerateKeyInternal(
@@ -162,7 +140,7 @@
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
return crypto_.ImportKeyInternal(format,
- Start(key_data),
+ webcrypto::Uint8VectorStart(key_data),
key_data.size(),
algorithm,
extractable,
@@ -183,7 +161,7 @@
const std::vector<uint8>& data,
blink::WebArrayBuffer* buffer) {
return crypto_.SignInternal(
- algorithm, key, Start(data), data.size(), buffer);
+ algorithm, key, webcrypto::Uint8VectorStart(data), data.size(), buffer);
}
bool VerifySignatureInternal(
@@ -197,7 +175,7 @@
key,
signature,
signature_size,
- Start(data),
+ webcrypto::Uint8VectorStart(data),
data.size(),
signature_match);
}
@@ -217,7 +195,7 @@
const std::vector<uint8>& data,
blink::WebArrayBuffer* buffer) {
return crypto_.EncryptInternal(
- algorithm, key, Start(data), data.size(), buffer);
+ algorithm, key, webcrypto::Uint8VectorStart(data), data.size(), buffer);
}
bool DecryptInternal(
@@ -235,7 +213,21 @@
const std::vector<uint8>& data,
blink::WebArrayBuffer* buffer) {
return crypto_.DecryptInternal(
- algorithm, key, Start(data), data.size(), buffer);
+ algorithm, key, webcrypto::Uint8VectorStart(data), data.size(), buffer);
+ }
+
+ bool ImportKeyJwk(
+ const std::vector<uint8>& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usage_mask,
+ blink::WebCryptoKey* key) {
+ return crypto_.ImportKeyJwk(webcrypto::Uint8VectorStart(key_data),
+ key_data.size(),
+ algorithm,
+ extractable,
+ usage_mask,
+ key);
}
private:
@@ -314,7 +306,8 @@
SCOPED_TRACE(test_index);
const TestCase& test = kTests[test_index];
- blink::WebCryptoAlgorithm algorithm = CreateAlgorithm(test.algorithm);
+ blink::WebCryptoAlgorithm algorithm =
+ webcrypto::CreateAlgorithm(test.algorithm);
std::vector<uint8> input = HexStringToBytes(test.hex_input);
blink::WebArrayBuffer output;
@@ -416,7 +409,8 @@
SCOPED_TRACE(test_index);
const TestCase& test = kTests[test_index];
- blink::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm);
+ blink::WebCryptoAlgorithm algorithm =
+ webcrypto::CreateHmacAlgorithmByHashId(test.algorithm);
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString(
test.key, algorithm, blink::WebCryptoKeyUsageSign);
@@ -462,10 +456,12 @@
}
}
+#if !defined(USE_OPENSSL)
+
TEST_F(WebCryptoImplTest, AesCbcFailures) {
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString(
"2b7e151628aed2a6abf7158809cf4f3c",
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
blink::WebArrayBuffer output;
@@ -474,20 +470,20 @@
{
std::vector<uint8> input(32);
std::vector<uint8> iv;
- EXPECT_FALSE(
- EncryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output));
- EXPECT_FALSE(
- DecryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output));
+ EXPECT_FALSE(EncryptInternal(
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output));
+ EXPECT_FALSE(DecryptInternal(
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output));
}
// Use an invalid |iv| (more than 16 bytes)
{
std::vector<uint8> input(32);
std::vector<uint8> iv(17);
- EXPECT_FALSE(
- EncryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output));
- EXPECT_FALSE(
- DecryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output));
+ EXPECT_FALSE(EncryptInternal(
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output));
+ EXPECT_FALSE(DecryptInternal(
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output));
}
// Give an input that is too large (would cause integer overflow when
@@ -502,9 +498,9 @@
unsigned input_len = INT_MAX - 3;
EXPECT_FALSE(EncryptInternal(
- CreateAesCbcAlgorithm(iv), key, input, input_len, &output));
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, input_len, &output));
EXPECT_FALSE(DecryptInternal(
- CreateAesCbcAlgorithm(iv), key, input, input_len, &output));
+ webcrypto::CreateAesCbcAlgorithm(iv), key, input, input_len, &output));
}
// Fail importing the key (too few bytes specified)
@@ -515,7 +511,7 @@
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
key_raw,
- CreateAesCbcAlgorithm(iv),
+ webcrypto::CreateAesCbcAlgorithm(iv),
true,
blink::WebCryptoKeyUsageEncrypt,
&key));
@@ -610,7 +606,7 @@
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString(
test.key,
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
std::vector<uint8> plain_text = HexStringToBytes(test.plain_text);
@@ -619,7 +615,7 @@
blink::WebArrayBuffer output;
// Test encryption.
- EXPECT_TRUE(EncryptInternal(CreateAesCbcAlgorithm(iv),
+ EXPECT_TRUE(EncryptInternal(webcrypto::CreateAesCbcAlgorithm(iv),
key,
plain_text,
&output));
@@ -627,7 +623,7 @@
// Test decryption.
std::vector<uint8> cipher_text = HexStringToBytes(test.cipher_text);
- EXPECT_TRUE(DecryptInternal(CreateAesCbcAlgorithm(iv),
+ EXPECT_TRUE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv),
key,
cipher_text,
&output));
@@ -638,7 +634,7 @@
// Decrypt with a padding error by stripping the last block. This also ends
// up testing decryption over empty cipher text.
if (cipher_text.size() >= kAesCbcBlockSize) {
- EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv),
+ EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv),
key,
&cipher_text[0],
cipher_text.size() - kAesCbcBlockSize,
@@ -648,7 +644,7 @@
// Decrypt cipher text which is not a multiple of block size by stripping
// a few bytes off the cipher text.
if (cipher_text.size() > 3) {
- EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv),
+ EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv),
key,
&cipher_text[0],
cipher_text.size() - 3,
@@ -661,21 +657,26 @@
TEST_F(WebCryptoImplTest, GenerateKeyAes) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
- ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key));
+ ASSERT_TRUE(
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(128), &key));
EXPECT_TRUE(key.handle());
EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
}
TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
- EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key));
- EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key));
+ EXPECT_FALSE(
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key));
+ EXPECT_FALSE(
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key));
+ EXPECT_FALSE(
+ GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(129), &key));
}
TEST_F(WebCryptoImplTest, GenerateKeyHmac) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
- blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 128);
+ blink::WebCryptoAlgorithm algorithm = webcrypto::CreateHmacKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdSha1, 128);
ASSERT_TRUE(GenerateKeyInternal(algorithm, &key));
EXPECT_FALSE(key.isNull());
EXPECT_TRUE(key.handle());
@@ -685,7 +686,7 @@
TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
blink::WebCryptoAlgorithm algorithm =
- CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
+ webcrypto::CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
ASSERT_TRUE(GenerateKeyInternal(algorithm, &key));
EXPECT_TRUE(key.handle());
EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
@@ -704,6 +705,250 @@
&key));
}
+#endif //#if !defined(USE_OPENSSL)
+
+TEST_F(WebCryptoImplTest, ImportJwkBadJwk) {
+
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
+ blink::WebCryptoAlgorithm algorithm =
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
+ blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt;
+
+ // Baseline pass: each test below breaks a single item, so we start with a
+ // passing case to make sure each failure is caused by the isolated break.
+ // Each breaking subtest below resets the dictionary to this passing case when
+ // complete.
+ base::DictionaryValue dict;
+ RestoreDictionaryForImportBadJwkTest(&dict);
+ std::vector<uint8> json_vec = MakeJsonVector(dict);
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+
+ // Fail on empty JSON.
+ EXPECT_FALSE(
+ ImportKeyJwk(MakeJsonVector(""), algorithm, false, usage_mask, &key));
+
+ // Fail on invalid JSON.
+ const std::vector<uint8> bad_json_vec = MakeJsonVector(
+ "{"
+ "\"kty\" : \"oct\","
+ "\"alg\" : \"HS256\","
+ "\"use\" : "
+ );
+ EXPECT_FALSE(ImportKeyJwk(bad_json_vec, algorithm, false, usage_mask, &key));
+
+ // Fail on JWK alg present but unrecognized.
+ dict.SetString("alg", "A127CBC");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on both JWK and input algorithm missing.
+ dict.Remove("alg", NULL);
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec,
+ blink::WebCryptoAlgorithm::createNull(),
+ false,
+ usage_mask,
+ &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on invalid kty.
+ dict.SetString("kty", "foo");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on missing kty.
+ dict.Remove("kty", NULL);
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on invalid use.
+ dict.SetString("use", "foo");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on missing k when kty = "oct".
+ dict.Remove("k", NULL);
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on bad b64 encoding for k.
+ dict.SetString("k", "Qk3f0DsytU8lfza2au #$% Htaw2xpop9GYyTuH0p5GghxTI=");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on empty k.
+ dict.SetString("k", "");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // Fail on k actual length (120 bits) inconsistent with the embedded JWK alg
+ // value (128) for an AES key.
+ dict.SetString("k", "AVj42h0Y5aqGtE3yluKL");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ RestoreDictionaryForImportBadJwkTest(&dict);
+
+ // TODO(padolph) RSA public key bad data:
+ // Missing n or e when kty = "RSA"
+ // Bad encoding for n or e
+ // Size check on n??
+ // Value check on e??
+}
+
+TEST_F(WebCryptoImplTest, ImportJwkInputConsistency) {
+ // The Web Crypto spec says that if a JWK value is present, but is
+ // inconsistent with the input value, the operation must fail.
+
+ // Consistency rules when JWK value is not present: Inputs should be used.
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
+ bool extractable = false;
+ blink::WebCryptoAlgorithm algorithm =
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageVerify;
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+ std::vector<uint8> json_vec = MakeJsonVector(dict);
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key));
+ EXPECT_TRUE(key.handle());
+ EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ EXPECT_EQ(extractable, key.extractable());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
+ key.algorithm().hmacParams()->hash().id());
+ EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
+ key = blink::WebCryptoKey::createNull();
+
+ // Consistency rules when JWK value exists: Fail if inconsistency is found.
+
+ // Pass: All input values are consistent with the JWK values.
+ dict.Clear();
+ dict.SetString("kty", "oct");
+ dict.SetString("alg", "HS256");
+ dict.SetString("use", "sig");
+ dict.SetBoolean("extractable", false);
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+ json_vec = MakeJsonVector(dict);
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key));
+
+ // Extractable cases:
+ // 1. input=T, JWK=F ==> fail (inconsistent)
+ // 4. input=F, JWK=F ==> pass, result extractable is F
+ // 2. input=T, JWK=T ==> pass, result extractable is T
+ // 3. input=F, JWK=T ==> pass, result extractable is F
+ EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, true, usage_mask, &key));
+ EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key));
+ EXPECT_FALSE(key.extractable());
+ dict.SetBoolean("extractable", true);
+ EXPECT_TRUE(
+ ImportKeyJwk(MakeJsonVector(dict), algorithm, true, usage_mask, &key));
+ EXPECT_TRUE(key.extractable());
+ EXPECT_TRUE(
+ ImportKeyJwk(MakeJsonVector(dict), algorithm, false, usage_mask, &key));
+ EXPECT_FALSE(key.extractable());
+ dict.SetBoolean("extractable", true); // restore previous value
+
+ // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value
+ // (HMAC SHA256).
+ EXPECT_FALSE(ImportKeyJwk(
+ json_vec,
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ extractable,
+ usage_mask,
+ &key));
+
+ // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value
+ // (HMAC SHA256).
+ EXPECT_FALSE(ImportKeyJwk(
+ json_vec,
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha1),
+ extractable,
+ usage_mask,
+ &key));
+
+ // Pass: JWK alg valid but input algorithm isNull: use JWK algorithm value.
+ EXPECT_TRUE(ImportKeyJwk(json_vec,
+ blink::WebCryptoAlgorithm::createNull(),
+ extractable,
+ usage_mask,
+ &key));
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
+
+ // Pass: JWK alg missing but input algorithm specified: use input value
+ dict.Remove("alg", NULL);
+ EXPECT_TRUE(ImportKeyJwk(
+ MakeJsonVector(dict),
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256),
+ extractable,
+ usage_mask,
+ &key));
+ EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
+ dict.SetString("alg", "HS256");
+
+ // Fail: Input usage_mask (encrypt) is not a subset of the JWK value
+ // (sign|verify)
+ EXPECT_FALSE(ImportKeyJwk(
+ json_vec, algorithm, extractable, blink::WebCryptoKeyUsageEncrypt, &key));
+
+ // Fail: Input usage_mask (encrypt|sign|verify) is not a subset of the JWK
+ // value (sign|verify)
+ usage_mask = blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageSign |
+ blink::WebCryptoKeyUsageVerify;
+ EXPECT_FALSE(
+ ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key));
+ usage_mask = blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
+}
+
+TEST_F(WebCryptoImplTest, ImportJwkHappy) {
+
+ // This test verifies the happy path of JWK import, including the application
+ // of the imported key material.
+
+ blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
+ bool extractable = false;
+ blink::WebCryptoAlgorithm algorithm =
+ webcrypto::CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256);
+ blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageSign;
+
+ // Import a symmetric key JWK and HMAC-SHA256 sign()
+ // Uses the first SHA256 test vector from the HMAC sample set above.
+
+ base::DictionaryValue dict;
+ dict.SetString("kty", "oct");
+ dict.SetString("alg", "HS256");
+ dict.SetString("use", "sig");
+ dict.SetBoolean("extractable", false);
+ dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
+ std::vector<uint8> json_vec = MakeJsonVector(dict);
+
+ ASSERT_TRUE(ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key));
+
+ const std::vector<uint8> message_raw = HexStringToBytes(
+ "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a"
+ "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92"
+ "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f"
+ "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e");
+
+ blink::WebArrayBuffer output;
+
+ ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output));
+
+ const std::string mac_raw =
+ "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b";
+
+ ExpectArrayBufferMatchesHex(mac_raw, output);
+
+ // TODO(padolph)
+ // Import an RSA public key JWK and use it
+}
+
#if !defined(USE_OPENSSL)
TEST_F(WebCryptoImplTest, ImportExportSpki) {
@@ -727,7 +972,7 @@
ASSERT_TRUE(ImportKeyInternal(
blink::WebCryptoKeyFormatSpki,
HexStringToBytes(hex_rsa_spki_der),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5),
true,
blink::WebCryptoKeyUsageEncrypt,
&key));
@@ -760,7 +1005,7 @@
EXPECT_FALSE(ImportKeyInternal(
blink::WebCryptoKeyFormatSpki,
HexStringToBytes("618333c4cb"),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5),
true,
blink::WebCryptoKeyUsageEncrypt,
&key));
@@ -769,7 +1014,7 @@
EXPECT_FALSE(ImportKeyInternal(
blink::WebCryptoKeyFormatSpki,
HexStringToBytes(hex_rsa_spki_der),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
true,
blink::WebCryptoKeyUsageEncrypt,
&key));
@@ -784,15 +1029,13 @@
ASSERT_TRUE(ImportKeyInternal(
blink::WebCryptoKeyFormatSpki,
HexStringToBytes(hex_rsa_spki_der),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5),
false,
blink::WebCryptoKeyUsageEncrypt,
&key));
EXPECT_TRUE(key.handle());
EXPECT_FALSE(key.extractable());
EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output));
-
- // TODO(padolph): Use the imported key for a Known Answer Test (KAT).
}
TEST_F(WebCryptoImplTest, ImportPkcs8) {
@@ -825,7 +1068,7 @@
ASSERT_TRUE(ImportKeyInternal(
blink::WebCryptoKeyFormatPkcs8,
HexStringToBytes(hex_rsa_pkcs8_der),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
true,
blink::WebCryptoKeyUsageSign,
&key));
@@ -858,7 +1101,7 @@
EXPECT_FALSE(ImportKeyInternal(
blink::WebCryptoKeyFormatPkcs8,
HexStringToBytes("618333c4cb"),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
true,
blink::WebCryptoKeyUsageSign,
&key));
@@ -867,12 +1110,10 @@
EXPECT_FALSE(ImportKeyInternal(
blink::WebCryptoKeyFormatPkcs8,
HexStringToBytes(hex_rsa_pkcs8_der),
- CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
true,
blink::WebCryptoKeyUsageSign,
&key));
-
- // TODO(padolph): Use the imported key for a Known Answer Test (KAT).
}
TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) {
@@ -881,11 +1122,11 @@
// Successful WebCryptoAlgorithmIdRsaEsPkcs1v1_5 key generation.
const unsigned modulus_length = 256;
const std::vector<uint8> public_exponent = HexStringToBytes("010001");
- blink::WebCryptoAlgorithm algorithm =
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
- modulus_length,
- public_exponent);
- bool extractable = true;
+ blink::WebCryptoAlgorithm algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
+ modulus_length,
+ public_exponent);
+ bool extractable = false;
const blink::WebCryptoKeyUsageMask usage_mask = 0;
blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
@@ -901,34 +1142,34 @@
EXPECT_EQ(usage_mask, private_key.usages());
// Fail with bad modulus.
- algorithm = CreateRsaKeyGenAlgorithm(
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, 0, public_exponent);
EXPECT_FALSE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
// Fail with bad exponent: larger than unsigned long.
- unsigned exponent_length = sizeof(unsigned long) + 1; // NOLINT
+ unsigned exponent_length = sizeof(unsigned long) + 1; // NOLINT
const std::vector<uint8> long_exponent(exponent_length, 0x01);
- algorithm = CreateRsaKeyGenAlgorithm(
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, modulus_length, long_exponent);
EXPECT_FALSE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
// Fail with bad exponent: empty.
const std::vector<uint8> empty_exponent;
- algorithm =
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
- modulus_length,
- empty_exponent);
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
+ modulus_length,
+ empty_exponent);
EXPECT_FALSE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
// Fail with bad exponent: all zeros.
std::vector<uint8> exponent_with_leading_zeros(15, 0x00);
- algorithm =
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
- modulus_length,
- exponent_with_leading_zeros);
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
+ modulus_length,
+ exponent_with_leading_zeros);
EXPECT_FALSE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
@@ -936,10 +1177,10 @@
exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
public_exponent.begin(),
public_exponent.end());
- algorithm =
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
- modulus_length,
- exponent_with_leading_zeros);
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5,
+ modulus_length,
+ exponent_with_leading_zeros);
EXPECT_TRUE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
EXPECT_FALSE(public_key.isNull());
@@ -952,7 +1193,7 @@
EXPECT_EQ(usage_mask, private_key.usages());
// Successful WebCryptoAlgorithmIdRsaOaep key generation.
- algorithm = CreateRsaKeyGenAlgorithm(
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
blink::WebCryptoAlgorithmIdRsaOaep, modulus_length, public_exponent);
EXPECT_TRUE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
@@ -966,10 +1207,10 @@
EXPECT_EQ(usage_mask, private_key.usages());
// Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation.
- algorithm =
- CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
- modulus_length,
- public_exponent);
+ algorithm = webcrypto::CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ modulus_length,
+ public_exponent);
EXPECT_TRUE(GenerateKeyPairInternal(
algorithm, extractable, usage_mask, &public_key, &private_key));
EXPECT_FALSE(public_key.isNull());
@@ -1018,7 +1259,8 @@
// Verify encrypt / decrypt round trip on a few messages. Note that RSA
// encryption does not support empty input.
- algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5);
+ algorithm =
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5);
const char* const kTestDataHex[] = {
"ff",
"0102030405060708090a0b0c0d0e0f",
@@ -1112,7 +1354,7 @@
// Import the public key.
const blink::WebCryptoAlgorithm algorithm =
- CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5);
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5);
blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
ASSERT_TRUE(ImportKeyInternal(
blink::WebCryptoKeyFormatSpki,
@@ -1189,7 +1431,8 @@
EXPECT_FALSE(private_key.isNull());
// Fail encrypt with a private key.
- algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5);
+ algorithm =
+ webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5);
blink::WebArrayBuffer encrypted_data;
const std::string message_hex_str("0102030405060708090a0b0c0d0e0f");
const std::vector<uint8> message_hex(HexStringToBytes(message_hex_str));
diff --git a/content/renderer/webcrypto/webcrypto_util.cc b/content/renderer/webcrypto/webcrypto_util.cc
new file mode 100644
index 0000000..34690e0
--- /dev/null
+++ b/content/renderer/webcrypto/webcrypto_util.cc
@@ -0,0 +1,192 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/webcrypto/webcrypto_util.h"
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+
+namespace content {
+
+namespace webcrypto {
+
+namespace {
+
+blink::WebCryptoAlgorithm CreateAesKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId aes_alg_id,
+ unsigned short length) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ aes_alg_id, new blink::WebCryptoAesKeyGenParams(length));
+}
+
+bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id) {
+ return alg_id == blink::WebCryptoAlgorithmIdSha1 ||
+ alg_id == blink::WebCryptoAlgorithmIdSha224 ||
+ alg_id == blink::WebCryptoAlgorithmIdSha256 ||
+ alg_id == blink::WebCryptoAlgorithmIdSha384 ||
+ alg_id == blink::WebCryptoAlgorithmIdSha512;
+}
+
+} // namespace
+
+const uint8* Uint8VectorStart(const std::vector<uint8>& data) {
+ if (data.empty())
+ return NULL;
+ return &data[0];
+}
+
+void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned new_size) {
+ DCHECK_LE(new_size, buffer->byteLength());
+
+ if (new_size == buffer->byteLength())
+ return;
+
+ blink::WebArrayBuffer new_buffer = blink::WebArrayBuffer::create(new_size, 1);
+ DCHECK(!new_buffer.isNull());
+ memcpy(new_buffer.data(), buffer->data(), new_size);
+ *buffer = new_buffer;
+}
+
+bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
+ std::string base64EncodedText(input);
+ std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+');
+ std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/');
+ base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '=');
+ return base::Base64Decode(base64EncodedText, output);
+}
+
+blink::WebCryptoAlgorithm GetInnerHashAlgorithm(
+ const blink::WebCryptoAlgorithm& algorithm) {
+ if (algorithm.hmacParams())
+ return algorithm.hmacParams()->hash();
+ if (algorithm.hmacKeyParams())
+ return algorithm.hmacKeyParams()->hash();
+ if (algorithm.rsaSsaParams())
+ return algorithm.rsaSsaParams()->hash();
+ if (algorithm.rsaOaepParams())
+ return algorithm.rsaOaepParams()->hash();
+ return blink::WebCryptoAlgorithm::createNull();
+}
+
+blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
+}
+
+blink::WebCryptoAlgorithm CreateHmacAlgorithmByHashOutputLen(
+ unsigned short hash_output_length_bits) {
+ blink::WebCryptoAlgorithmId hash_id;
+ switch (hash_output_length_bits) {
+ case 160:
+ hash_id = blink::WebCryptoAlgorithmIdSha1;
+ break;
+ case 224:
+ hash_id = blink::WebCryptoAlgorithmIdSha224;
+ break;
+ case 256:
+ hash_id = blink::WebCryptoAlgorithmIdSha256;
+ break;
+ case 384:
+ hash_id = blink::WebCryptoAlgorithmIdSha384;
+ break;
+ case 512:
+ hash_id = blink::WebCryptoAlgorithmIdSha512;
+ break;
+ default:
+ NOTREACHED();
+ return blink::WebCryptoAlgorithm::createNull();
+ }
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacParams(CreateAlgorithm(hash_id)));
+}
+
+blink::WebCryptoAlgorithm CreateHmacAlgorithmByHashId(
+ blink::WebCryptoAlgorithmId hash_id) {
+ DCHECK(IsHashAlgorithm(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacParams(CreateAlgorithm(hash_id)));
+}
+
+blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id,
+ unsigned key_length_bytes) {
+ DCHECK(IsHashAlgorithm(hash_id));
+ // key_length_bytes == 0 means unspecified
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdHmac,
+ new blink::WebCryptoHmacKeyParams(
+ CreateAlgorithm(hash_id), (key_length_bytes != 0), key_length_bytes));
+}
+
+blink::WebCryptoAlgorithm CreateRsaSsaAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id) {
+ DCHECK(IsHashAlgorithm(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
+ new blink::WebCryptoRsaSsaParams(CreateAlgorithm(hash_id)));
+}
+
+blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id) {
+ DCHECK(IsHashAlgorithm(hash_id));
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdRsaOaep,
+ new blink::WebCryptoRsaOaepParams(
+ CreateAlgorithm(hash_id), false, NULL, 0));
+}
+
+blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId algorithm_id,
+ unsigned modulus_length,
+ const std::vector<uint8>& public_exponent) {
+ DCHECK(algorithm_id == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
+ algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
+ algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep);
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ algorithm_id,
+ new blink::WebCryptoRsaKeyGenParams(
+ modulus_length,
+ webcrypto::Uint8VectorStart(public_exponent),
+ public_exponent.size()));
+}
+
+blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(const std::vector<uint8>& iv) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdAesCbc,
+ new blink::WebCryptoAesCbcParams(Uint8VectorStart(iv), iv.size()));
+}
+
+blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
+ const std::vector<uint8>& iv,
+ const std::vector<uint8>& additional_data,
+ uint8 tag_length_bytes) {
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
+ blink::WebCryptoAlgorithmIdAesCbc,
+ new blink::WebCryptoAesGcmParams(Uint8VectorStart(iv),
+ iv.size(),
+ additional_data.size() != 0,
+ Uint8VectorStart(additional_data),
+ additional_data.size(),
+ tag_length_bytes != 0,
+ tag_length_bytes));
+}
+
+blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
+ unsigned short key_length_bits) {
+ return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesCbc,
+ key_length_bits);
+}
+
+blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
+ unsigned short key_length_bits) {
+ return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesGcm,
+ key_length_bits);
+}
+
+} // namespace webcrypto
+
+} // namespace content
diff --git a/content/renderer/webcrypto/webcrypto_util.h b/content/renderer/webcrypto/webcrypto_util.h
new file mode 100644
index 0000000..1c95e631
--- /dev/null
+++ b/content/renderer/webcrypto/webcrypto_util.h
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_WEBCRYPTO_WEBCRYPTO_UTIL_H_
+#define CONTENT_RENDERER_WEBCRYPTO_WEBCRYPTO_UTIL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebArrayBuffer.h"
+#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
+
+namespace content {
+
+namespace webcrypto {
+
+// Returns a pointer to the start of |data|, or NULL if it is empty. This is a
+// convenience function for getting the pointer, and should not be used beyond
+// the expected lifetime of |data|.
+CONTENT_EXPORT const uint8* Uint8VectorStart(const std::vector<uint8>& data);
+
+// Shrinks a WebArrayBuffer to a new size.
+// TODO(eroman): This works by re-allocating a new buffer. It would be better if
+// the WebArrayBuffer could just be truncated instead.
+void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned new_size);
+
+// This function decodes unpadded 'base64url' encoded data, as described in
+// RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5. To do this, first
+// change the incoming data to 'base64' encoding by applying the appropriate
+// transformation including adding padding if required, and then call a base64
+// decoder.
+// In Web Crypto, this type of encoding is only used inside JWK.
+bool Base64DecodeUrlSafe(const std::string& input, std::string* output);
+
+// Returns the "hash" param for an algorithm if it exists, otherwise returns
+// a null algorithm.
+blink::WebCryptoAlgorithm GetInnerHashAlgorithm(
+ const blink::WebCryptoAlgorithm& algorithm);
+
+// Creates a WebCryptoAlgorithm without any parameters.
+CONTENT_EXPORT blink::WebCryptoAlgorithm CreateAlgorithm(
+ blink::WebCryptoAlgorithmId id);
+
+// Creates an HMAC algorithm whose inner hash algorithm is determined by the
+// specified hash output length. It is an error to call this method with an
+// unsupported hash output length.
+blink::WebCryptoAlgorithm CreateHmacAlgorithmByHashOutputLen(
+ unsigned short hash_output_length_bits);
+
+// Creates an HMAC algorithm whose inner hash algorithm is determined by the
+// specified algorithm ID. It is an error to call this method with a hash
+// algorithm that is not SHA*.
+CONTENT_EXPORT blink::WebCryptoAlgorithm CreateHmacAlgorithmByHashId(
+ blink::WebCryptoAlgorithmId hash_id);
+
+// Creates an HMAC algorithm whose parameters struct is compatible with key
+// generation. It is an error to call this with a hash_id that is not a SHA*.
+// The key_length_bytes parameter is optional, with zero meaning unspecified.
+CONTENT_EXPORT blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id,
+ unsigned key_length_bytes);
+
+// Creates an RSASSA-PKCS1-v1_5 algorithm. It is an error to call this with a
+// hash_id that is not a SHA*.
+blink::WebCryptoAlgorithm CreateRsaSsaAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id);
+
+// Creates an RSA-OAEP algorithm. It is an error to call this with a hash_id
+// that is not a SHA*.
+blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
+ blink::WebCryptoAlgorithmId hash_id);
+
+// Creates an RSA algorithm with ID algorithm_id, whose parameters struct is
+// compatible with key generation.
+CONTENT_EXPORT blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm(
+ blink::WebCryptoAlgorithmId algorithm_id,
+ unsigned modulus_length,
+ const std::vector<uint8>& public_exponent);
+
+// Creates an AES-CBC algorithm.
+CONTENT_EXPORT blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
+ const std::vector<uint8>& iv);
+
+// Creates and AES-GCM algorithm.
+blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
+ const std::vector<uint8>& iv,
+ const std::vector<uint8>& additional_data,
+ uint8 tag_length_bytes);
+
+// Creates an AES-CBC algorithm whose parameters struct is compatible with key
+// generation.
+CONTENT_EXPORT blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
+ unsigned short key_length_bits);
+
+// Creates an AES-GCM algorithm whose parameters struct is compatible with key
+// generation.
+blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
+ unsigned short key_length_bits);
+
+} // namespace webcrypto
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_WEBCRYPTO_WEBCRYPTO_UTIL_H_