[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_