Copy array buffer data used by WebCrypto in the order expected by draft specification.

* Most data buffers to crypto.subtle.* are copied prior to algorithm normalization.

* Data buffers that are part of algorithm dictionaries are copied and read in the declaration order of the properties.

BUG=626948

Review-Url: https://codereview.chromium.org/2141843002
Cr-Commit-Position: refs/heads/master@{#406170}
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/encrypt-neutered-data-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/encrypt-neutered-data-expected.txt
new file mode 100644
index 0000000..e16b8fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/encrypt-neutered-data-expected.txt
@@ -0,0 +1,21 @@
+Tests crypto.subtle.encrypt() using a BufferSource that was neutered (prior to encrypt())
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing key...
+
+Encrypting empty plaintext (as a control group)...
+PASS: Encryption should be [c84af0b613435d5d9182801a9bd9320b] and was
+
+Creating ArrayBuffer...
+PASS plainText.byteLength is 1000
+Neutering plainText...
+PASS plainText.byteLength is 0
+
+Encrypting neutered plaintext...
+PASS: Encryption should be [c84af0b613435d5d9182801a9bd9320b] and was
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/encrypt-neutered-data.html b/third_party/WebKit/LayoutTests/crypto/subtle/encrypt-neutered-data.html
new file mode 100644
index 0000000..e350ad9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/encrypt-neutered-data.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Tests crypto.subtle.encrypt() using a BufferSource that was neutered (prior to encrypt())");
+
+jsTestIsAsync = true;
+
+data = null;
+key = null;
+
+var keyData = hexStringToUint8Array("2b7e151628aed2a6abf7158809cf4f3c");
+var iv = hexStringToUint8Array("000102030405060708090a0b0c0d0e0f");
+var kExpectedCipherTextHex = "c84af0b613435d5d9182801a9bd9320b";
+
+var extractable = true;
+var usages = ['encrypt', 'decrypt'];
+
+debug("Importing key...");
+crypto.subtle.importKey('raw', keyData, "aes-cbc", extractable, usages).then(function(result) {
+    key = result;
+
+    debug("\nEncrypting empty plaintext (as a control group)...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, new Uint8Array());
+}).then(function(result) {
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+
+    debug("\nCreating ArrayBuffer...");
+    plainText = new ArrayBuffer(1000);
+    shouldBe("plainText.byteLength", "1000");
+
+    debug("Neutering plainText...");
+    try { postMessage(plainText, "xxx", [plainText]); } catch (e) { }
+    shouldBe("plainText.byteLength", "0");
+
+    debug("\nEncrypting neutered plaintext...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, plainText);
+}).then(function(result) {
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+}).then(finishJSTest, failAndFinishJSTest);
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/modify-encrypt-data-during-normalization-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/modify-encrypt-data-during-normalization-expected.txt
new file mode 100644
index 0000000..4f7e7bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/modify-encrypt-data-during-normalization-expected.txt
@@ -0,0 +1,21 @@
+Tests crypto.subtle.encrypt() using a BufferSource that is modified during algorithm normalization
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing key...
+
+Encrypting (as a control group)...
+PASS: Encryption should be [7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012] and was
+
+Encrypting again, using an algorithm that mutates the array buffer...
+Accessed name property
+Corrupted plainText
+Accessed iv property
+Corrupted plainText
+PASS: plainText should be [0000bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710] and was
+PASS: Encryption should be [7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012] and was
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/modify-encrypt-data-during-normalization.html b/third_party/WebKit/LayoutTests/crypto/subtle/modify-encrypt-data-during-normalization.html
new file mode 100644
index 0000000..b5ecdf4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/modify-encrypt-data-during-normalization.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Tests crypto.subtle.encrypt() using a BufferSource that is modified during algorithm normalization");
+
+jsTestIsAsync = true;
+
+data = null;
+key = null;
+
+var keyData = hexStringToUint8Array("2b7e151628aed2a6abf7158809cf4f3c");
+var iv = hexStringToUint8Array("000102030405060708090a0b0c0d0e0f");
+var kPlainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
+var kExpectedCipherTextHex = "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012";
+var plainText = hexStringToUint8Array(kPlainText);
+// This is the plaintext resulting from corruptPlainText.
+var kModifiedPlainText = "0000bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
+
+function corruptPlainText()
+{
+    debug("Corrupted plainText");
+    plainText[0] = 0;
+    plainText[1] = 0;
+}
+
+var extractable = true;
+var usages = ['encrypt', 'decrypt'];
+
+debug("Importing key...");
+crypto.subtle.importKey('raw', keyData, "aes-cbc", extractable, usages).then(function(result) {
+    key = result;
+    
+    debug("\nEncrypting (as a control group)...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, plainText);
+}).then(function(result) {
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+
+    // This algorithm has custom getters that modifies plainText.
+    var algorithm = {
+        get name() {
+            debug("Accessed name property");
+            corruptPlainText();
+            return 'aes-cbc';
+        },
+
+        get iv() {
+            debug("Accessed iv property");
+            corruptPlainText();
+            return iv;
+        }
+    };
+
+    debug("\nEncrypting again, using an algorithm that mutates the array buffer...");
+    return crypto.subtle.encrypt(algorithm, key, plainText);
+}).then(function(result) {
+    bytesShouldMatchHexString("plainText", kModifiedPlainText, plainText);
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+}).then(finishJSTest, failAndFinishJSTest);
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/neuter-algorithm-data-during-encrypt-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-algorithm-data-during-encrypt-expected.txt
new file mode 100644
index 0000000..8a787f4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-algorithm-data-during-encrypt-expected.txt
@@ -0,0 +1,19 @@
+Tests bad algorithm inputs for AES-CTR
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Importing AES-CTR key...
+
+encrypt() with normal data (control group)...
+PASS: Encryption should be [1592076075] and was
+Accessed counter
+Accessed length
+Neutering counter...
+PASS counter.byteLength is 0
+PASS: Encryption should be [1592076075] and was
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/neuter-algorithm-data-during-encrypt.html b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-algorithm-data-during-encrypt.html
new file mode 100644
index 0000000..c9e687a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-algorithm-data-during-encrypt.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Tests bad algorithm inputs for AES-CTR");
+
+jsTestIsAsync = true;
+
+var keyData = hexStringToUint8Array("2b7e151628aed2a6abf7158809cf4f3c");
+var data = asciiToUint8Array("hello");
+var key = null;
+var counter = new Uint8Array(16);
+var kExpectedCipherTextHex = "1592076075";
+var kLength = 8;
+
+function corruptCounter()
+{
+    debug("Neutering counter...");
+    try { postMessage(counter, "xxx", [counter.buffer]); } catch (e) { }
+    shouldBe("counter.byteLength", "0");
+}
+
+Promise.resolve(null).then(function(result) {
+    var usages = ['encrypt', 'decrypt'];
+    var extractable = false;
+
+    debug("\nImporting AES-CTR key...");
+    return crypto.subtle.importKey('raw', keyData, "aes-ctr", extractable, usages);
+}).then(function(result) {
+    key = result;
+
+    debug("\nencrypt() with normal data (control group)...");
+    return crypto.subtle.encrypt({name: 'AES-CTR', counter: counter, length: kLength}, key, data);
+}).then(function(result) {
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+
+    var algorithm = {
+        name: 'AES-CTR',
+
+        get counter() {
+            debug("Accessed counter");
+            return counter;
+        },
+
+        get length() {
+            debug("Accessed length");
+            corruptCounter();
+            return kLength;
+        }
+    };
+
+    return crypto.subtle.encrypt(algorithm, key, data);
+}).then(function(result) {
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+
+}).then(finishJSTest, failAndFinishJSTest);
+
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/neuter-encrypt-data-during-normalization-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-encrypt-data-during-normalization-expected.txt
new file mode 100644
index 0000000..6c65e03
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-encrypt-data-during-normalization-expected.txt
@@ -0,0 +1,21 @@
+Tests crypto.subtle.encrypt() using a BufferSource that is modified during algorithm normalization
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing key...
+
+Encrypting (as a control group)...
+PASS: Encryption should be [7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012] and was
+
+Encrypting again, using an algorithm that mutates the array buffer...
+Accessed name property
+Corrupted plainText
+Neutering plainText...
+PASS plainText.byteLength is 0
+PASS: plainText should be [] and was
+PASS: Encryption should be [7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012] and was
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/neuter-encrypt-data-during-normalization.html b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-encrypt-data-during-normalization.html
new file mode 100644
index 0000000..1bf56bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/crypto/subtle/neuter-encrypt-data-during-normalization.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Tests crypto.subtle.encrypt() using a BufferSource that is modified during algorithm normalization");
+
+jsTestIsAsync = true;
+
+data = null;
+key = null;
+
+var keyData = hexStringToUint8Array("2b7e151628aed2a6abf7158809cf4f3c");
+var iv = hexStringToUint8Array("000102030405060708090a0b0c0d0e0f");
+var kPlainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
+var kExpectedCipherTextHex = "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012";
+var plainText = hexStringToUint8Array(kPlainText);
+// This is the plaintext resulting from corruptPlainText.
+var kModifiedPlainText = "";
+
+function corruptPlainText()
+{
+    debug("Corrupted plainText");
+
+    debug("Neutering plainText...");
+    try { postMessage(plainText, "xxx", [plainText.buffer]); } catch (e) { }
+    shouldBe("plainText.byteLength", "0");
+}
+
+var extractable = true;
+var usages = ['encrypt', 'decrypt'];
+
+debug("Importing key...");
+crypto.subtle.importKey('raw', keyData, "aes-cbc", extractable, usages).then(function(result) {
+    key = result;
+    
+    debug("\nEncrypting (as a control group)...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, plainText);
+}).then(function(result) {
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+
+    // This algorithm has custom getters that modifies plainText.
+    var algorithm = {
+        get name() {
+            debug("Accessed name property");
+            corruptPlainText();
+            return 'aes-cbc';
+        },
+
+        iv: iv,
+    };
+
+    debug("\nEncrypting again, using an algorithm that mutates the array buffer...");
+    return crypto.subtle.encrypt(algorithm, key, plainText);
+}).then(function(result) {
+    bytesShouldMatchHexString("plainText", kModifiedPlainText, plainText);
+    bytesShouldMatchHexString("Encryption", kExpectedCipherTextHex, result);
+}).then(finishJSTest, failAndFinishJSTest);
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp b/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp
index d09a7b0..592f4dc 100644
--- a/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp
+++ b/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp
@@ -46,6 +46,10 @@
 #include <algorithm>
 #include <memory>
 
+// TODO(eroman): Change the interface for constructing
+//               WebCryptoAlgorithmParams to allow transferring byte
+//               parameters (whereas currently it makes a copy).
+
 namespace blink {
 
 namespace {
@@ -270,11 +274,18 @@
     Vector<const char*, 10> m_messages;
 };
 
+static Vector<uint8_t> copyBytes(const DOMArrayPiece& source)
+{
+    Vector<uint8_t> result;
+    result.append(reinterpret_cast<const uint8_t*>(source.data()), source.byteLength());
+    return result;
+}
+
 // Defined by the WebCrypto spec as:
 //
 //     typedef (ArrayBuffer or ArrayBufferView) BufferSource;
 //
-bool getOptionalBufferSource(const Dictionary& raw, const char* propertyName, bool& hasProperty, BufferSource& buffer, const ErrorContext& context, AlgorithmError* error)
+bool getOptionalBufferSource(const Dictionary& raw, const char* propertyName, bool& hasProperty, Vector<uint8_t>& bytes, const ErrorContext& context, AlgorithmError* error)
 {
     hasProperty = false;
     v8::Local<v8::Value> v8Value;
@@ -283,12 +294,12 @@
     hasProperty = true;
 
     if (v8Value->IsArrayBufferView()) {
-        buffer.setArrayBufferView(V8ArrayBufferView::toImpl(v8::Local<v8::Object>::Cast(v8Value)));
+        bytes = copyBytes(V8ArrayBufferView::toImpl(v8::Local<v8::Object>::Cast(v8Value)));
         return true;
     }
 
     if (v8Value->IsArrayBuffer()) {
-        buffer.setArrayBuffer(V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8Value)));
+        bytes = copyBytes(V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8Value)));
         return true;
     }
 
@@ -299,10 +310,10 @@
     return true;
 }
 
-bool getBufferSource(const Dictionary& raw, const char* propertyName, BufferSource& buffer, const ErrorContext& context, AlgorithmError* error)
+bool getBufferSource(const Dictionary& raw, const char* propertyName, Vector<uint8_t>& bytes, const ErrorContext& context, AlgorithmError* error)
 {
     bool hasProperty;
-    bool ok = getOptionalBufferSource(raw, propertyName, hasProperty, buffer, context, error);
+    bool ok = getOptionalBufferSource(raw, propertyName, hasProperty, bytes, context, error);
     if (!hasProperty) {
         setTypeError(context.toString(propertyName, "Missing required property"), error);
         return false;
@@ -310,26 +321,28 @@
     return ok;
 }
 
-bool getUint8Array(const Dictionary& raw, const char* propertyName, DOMUint8Array*& array, const ErrorContext& context, AlgorithmError* error)
+bool getUint8Array(const Dictionary& raw, const char* propertyName, Vector<uint8_t>& bytes, const ErrorContext& context, AlgorithmError* error)
 {
+    DOMUint8Array* array = nullptr;
     if (!DictionaryHelper::get(raw, propertyName, array) || !array) {
         setTypeError(context.toString(propertyName, "Missing or not a Uint8Array"), error);
         return false;
     }
+    bytes = copyBytes(array);
     return true;
 }
 
 // Defined by the WebCrypto spec as:
 //
 //     typedef Uint8Array BigInteger;
-bool getBigInteger(const Dictionary& raw, const char* propertyName, DOMUint8Array*& array, const ErrorContext& context, AlgorithmError* error)
+bool getBigInteger(const Dictionary& raw, const char* propertyName, Vector<uint8_t>& bytes, const ErrorContext& context, AlgorithmError* error)
 {
-    if (!getUint8Array(raw, propertyName, array, context, error))
+    if (!getUint8Array(raw, propertyName, bytes, context, error))
         return false;
 
-    if (!array->byteLength()) {
+    if (bytes.isEmpty()) {
         // Empty BigIntegers represent 0 according to the spec
-        array = DOMUint8Array::create(1);
+        bytes.fill(0, 1);
     }
 
     return true;
@@ -451,13 +464,11 @@
 //    };
 bool parseAesCbcParams(const Dictionary& raw, std::unique_ptr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
 {
-    BufferSource ivBufferSource;
-    if (!getBufferSource(raw, "iv", ivBufferSource, context, error))
+    Vector<uint8_t> iv;
+    if (!getBufferSource(raw, "iv", iv, context, error))
         return false;
 
-    DOMArrayPiece iv(ivBufferSource);
-
-    params = wrapUnique(new WebCryptoAesCbcParams(iv.bytes(), iv.byteLength()));
+    params = wrapUnique(new WebCryptoAesCbcParams(iv.data(), iv.size()));
     return true;
 }
 
@@ -565,7 +576,7 @@
     if (!getUint32(raw, "modulusLength", modulusLength, context, error))
         return false;
 
-    DOMUint8Array* publicExponent = nullptr;
+    Vector<uint8_t> publicExponent;
     if (!getBigInteger(raw, "publicExponent", publicExponent, context, error))
         return false;
 
@@ -573,7 +584,7 @@
     if (!parseHash(raw, hash, context, error))
         return false;
 
-    params = wrapUnique(new WebCryptoRsaHashedKeyGenParams(hash, modulusLength, static_cast<const unsigned char*>(publicExponent->baseAddress()), publicExponent->byteLength()));
+    params = wrapUnique(new WebCryptoRsaHashedKeyGenParams(hash, modulusLength, publicExponent.data(), publicExponent.size()));
     return true;
 }
 
@@ -585,16 +596,15 @@
 //    };
 bool parseAesCtrParams(const Dictionary& raw, std::unique_ptr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
 {
-    BufferSource counterBufferSource;
-    if (!getBufferSource(raw, "counter", counterBufferSource, context, error))
+    Vector<uint8_t> counter;
+    if (!getBufferSource(raw, "counter", counter, context, error))
         return false;
 
-    DOMArrayPiece counter(counterBufferSource);
     uint8_t length;
     if (!getUint8(raw, "length", length, context, error))
         return false;
 
-    params = wrapUnique(new WebCryptoAesCtrParams(length, counter.bytes(), counter.byteLength()));
+    params = wrapUnique(new WebCryptoAesCtrParams(length, counter.data(), counter.size()));
     return true;
 }
 
@@ -607,13 +617,13 @@
 //     }
 bool parseAesGcmParams(const Dictionary& raw, std::unique_ptr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
 {
-    BufferSource ivBufferSource;
-    if (!getBufferSource(raw, "iv", ivBufferSource, context, error))
+    Vector<uint8_t> iv;
+    if (!getBufferSource(raw, "iv", iv, context, error))
         return false;
 
     bool hasAdditionalData;
-    BufferSource additionalDataBufferSource;
-    if (!getOptionalBufferSource(raw, "additionalData", hasAdditionalData, additionalDataBufferSource, context, error))
+    Vector<uint8_t> additionalData;
+    if (!getOptionalBufferSource(raw, "additionalData", hasAdditionalData, additionalData, context, error))
         return false;
 
     uint8_t tagLength = 0;
@@ -621,10 +631,7 @@
     if (!getOptionalUint8(raw, "tagLength", hasTagLength, tagLength, context, error))
         return false;
 
-    DOMArrayPiece iv(ivBufferSource);
-    DOMArrayPiece additionalData(additionalDataBufferSource, DOMArrayPiece::AllowNullPointToNullWithZeroSize);
-
-    params = wrapUnique(new WebCryptoAesGcmParams(iv.bytes(), iv.byteLength(), hasAdditionalData, additionalData.bytes(), additionalData.byteLength(), hasTagLength, tagLength));
+    params = wrapUnique(new WebCryptoAesGcmParams(iv.data(), iv.size(), hasAdditionalData, additionalData.data(), additionalData.size(), hasTagLength, tagLength));
     return true;
 }
 
@@ -636,12 +643,11 @@
 bool parseRsaOaepParams(const Dictionary& raw, std::unique_ptr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
 {
     bool hasLabel;
-    BufferSource labelBufferSource;
-    if (!getOptionalBufferSource(raw, "label", hasLabel, labelBufferSource, context, error))
+    Vector<uint8_t> label;
+    if (!getOptionalBufferSource(raw, "label", hasLabel, label, context, error))
         return false;
 
-    DOMArrayPiece label(labelBufferSource, DOMArrayPiece::AllowNullPointToNullWithZeroSize);
-    params = wrapUnique(new WebCryptoRsaOaepParams(hasLabel, label.bytes(), label.byteLength()));
+    params = wrapUnique(new WebCryptoRsaOaepParams(hasLabel, label.data(), label.size()));
     return true;
 }
 
@@ -770,12 +776,10 @@
 //     };
 bool parsePbkdf2Params(const Dictionary& raw, std::unique_ptr<WebCryptoAlgorithmParams>& params, const ErrorContext& context, AlgorithmError* error)
 {
-    BufferSource saltBufferSource;
-    if (!getBufferSource(raw, "salt", saltBufferSource, context, error))
+    Vector<uint8_t> salt;
+    if (!getBufferSource(raw, "salt", salt, context, error))
         return false;
 
-    DOMArrayPiece salt(saltBufferSource);
-
     uint32_t iterations;
     if (!getUint32(raw, "iterations", iterations, context, error))
         return false;
@@ -783,7 +787,7 @@
     WebCryptoAlgorithm hash;
     if (!parseHash(raw, hash, context, error))
         return false;
-    params = wrapUnique(new WebCryptoPbkdf2Params(hash, salt.bytes(), salt.byteLength(), iterations));
+    params = wrapUnique(new WebCryptoPbkdf2Params(hash, salt.data(), salt.size(), iterations));
     return true;
 }
 
@@ -819,17 +823,14 @@
     WebCryptoAlgorithm hash;
     if (!parseHash(raw, hash, context, error))
         return false;
-    BufferSource saltBufferSource;
-    if (!getBufferSource(raw, "salt", saltBufferSource, context, error))
+    Vector<uint8_t> salt;
+    if (!getBufferSource(raw, "salt", salt, context, error))
         return false;
-    BufferSource infoBufferSource;
-    if (!getBufferSource(raw, "info", infoBufferSource, context, error))
+    Vector<uint8_t> info;
+    if (!getBufferSource(raw, "info", info, context, error))
         return false;
 
-    DOMArrayPiece salt(saltBufferSource);
-    DOMArrayPiece info(infoBufferSource);
-
-    params = wrapUnique(new WebCryptoHkdfParams(hash, salt.bytes(), salt.byteLength(), info.bytes(), info.byteLength()));
+    params = wrapUnique(new WebCryptoHkdfParams(hash, salt.data(), salt.size(), info.data(), info.size()));
     return true;
 }
 
diff --git a/third_party/WebKit/Source/modules/crypto/SubtleCrypto.cpp b/third_party/WebKit/Source/modules/crypto/SubtleCrypto.cpp
index 33daf93..5b3f2e8 100644
--- a/third_party/WebKit/Source/modules/crypto/SubtleCrypto.cpp
+++ b/third_party/WebKit/Source/modules/crypto/SubtleCrypto.cpp
@@ -31,6 +31,9 @@
 #include "modules/crypto/SubtleCrypto.h"
 
 #include "bindings/core/v8/Dictionary.h"
+#include "core/dom/DOMArrayBuffer.h"
+#include "core/dom/DOMArrayBufferView.h"
+#include "core/dom/DOMArrayPiece.h"
 #include "core/dom/ExecutionContext.h"
 #include "modules/crypto/CryptoHistograms.h"
 #include "modules/crypto/CryptoKey.h"
@@ -41,6 +44,10 @@
 #include "public/platform/WebCrypto.h"
 #include "public/platform/WebCryptoAlgorithm.h"
 
+// TODO(eroman): Change the public blink::WebCrypto interface to allow
+//               transferring ownership of data buffers instead of just taking
+//               a raw pointer+length. This will avoid an extra copy.
+
 namespace blink {
 
 static bool parseAlgorithm(const AlgorithmIdentifier& raw, WebCryptoOperation op, WebCryptoAlgorithm& algorithm, CryptoResult* result)
@@ -88,7 +95,7 @@
 // an unpublished editor's draft for:
 //   https://www.w3.org/Bugs/Public/show_bug.cgi?id=24963
 // See http://crbug.com/373917.
-static bool copyJwkDictionaryToJson(const Dictionary& dict, CString& jsonUtf8, CryptoResult* result)
+static bool copyJwkDictionaryToJson(const Dictionary& dict, Vector<uint8_t>& jsonUtf8, CryptoResult* result)
 {
     RefPtr<JSONObject> jsonObject = JSONObject::create();
 
@@ -110,22 +117,36 @@
         copyStringProperty(propertyNames[i], dict, jsonObject.get());
 
     String json = jsonObject->toJSONString();
-    jsonUtf8 = json.utf8();
+    jsonUtf8.clear();
+    jsonUtf8.append(json.utf8().data(), json.utf8().length());
     return true;
 }
 
+static Vector<uint8_t> copyBytes(const DOMArrayPiece& source)
+{
+    Vector<uint8_t> result;
+    result.append(reinterpret_cast<const uint8_t*>(source.data()), source.byteLength());
+    return result;
+}
+
 SubtleCrypto::SubtleCrypto()
 {
 }
 
-ScriptPromise SubtleCrypto::encrypt(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const DOMArrayPiece& data)
+ScriptPromise SubtleCrypto::encrypt(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const BufferSource& rawData)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-encrypt
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
     if (!canAccessWebCrypto(scriptState, result))
         return promise;
 
+    // 14.3.1.2: Let data be the result of getting a copy of the bytes held by
+    //           the data parameter passed to the encrypt method.
+    Vector<uint8_t> data = copyBytes(rawData);
+
     WebCryptoAlgorithm algorithm;
     if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationEncrypt, algorithm, result))
         return promise;
@@ -134,18 +155,24 @@
         return promise;
 
     histogramAlgorithmAndKey(scriptState->getExecutionContext(), algorithm, key->key());
-    Platform::current()->crypto()->encrypt(algorithm, key->key(), data.bytes(), data.byteLength(), result->result());
+    Platform::current()->crypto()->encrypt(algorithm, key->key(), data.data(), data.size(), result->result());
     return promise;
 }
 
-ScriptPromise SubtleCrypto::decrypt(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const DOMArrayPiece& data)
+ScriptPromise SubtleCrypto::decrypt(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const BufferSource& rawData)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-decrypt
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
     if (!canAccessWebCrypto(scriptState, result))
         return promise;
 
+    // 14.3.2.2: Let data be the result of getting a copy of the bytes held by
+    //           the data parameter passed to the decrypt method.
+    Vector<uint8_t> data = copyBytes(rawData);
+
     WebCryptoAlgorithm algorithm;
     if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationDecrypt, algorithm, result))
         return promise;
@@ -154,18 +181,24 @@
         return promise;
 
     histogramAlgorithmAndKey(scriptState->getExecutionContext(), algorithm, key->key());
-    Platform::current()->crypto()->decrypt(algorithm, key->key(), data.bytes(), data.byteLength(), result->result());
+    Platform::current()->crypto()->decrypt(algorithm, key->key(), data.data(), data.size(), result->result());
     return promise;
 }
 
-ScriptPromise SubtleCrypto::sign(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const DOMArrayPiece& data)
+ScriptPromise SubtleCrypto::sign(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const BufferSource& rawData)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-sign
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
     if (!canAccessWebCrypto(scriptState, result))
         return promise;
 
+    // 14.3.3.2: Let data be the result of getting a copy of the bytes held by
+    //           the data parameter passed to the sign method.
+    Vector<uint8_t> data = copyBytes(rawData);
+
     WebCryptoAlgorithm algorithm;
     if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationSign, algorithm, result))
         return promise;
@@ -174,44 +207,60 @@
         return promise;
 
     histogramAlgorithmAndKey(scriptState->getExecutionContext(), algorithm, key->key());
-    Platform::current()->crypto()->sign(algorithm, key->key(), data.bytes(), data.byteLength(), result->result());
+    Platform::current()->crypto()->sign(algorithm, key->key(), data.data(), data.size(), result->result());
     return promise;
 }
 
-ScriptPromise SubtleCrypto::verifySignature(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const DOMArrayPiece& signature, const DOMArrayPiece& data)
+ScriptPromise SubtleCrypto::verifySignature(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, CryptoKey* key, const BufferSource& rawSignature, const BufferSource& rawData)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-verify
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
     if (!canAccessWebCrypto(scriptState, result))
         return promise;
 
+    // 14.3.4.2: Let signature be the result of getting a copy of the bytes
+    //           held by the signature parameter passed to the verify method.
+    Vector<uint8_t> signature = copyBytes(rawSignature);
+
     WebCryptoAlgorithm algorithm;
     if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationVerify, algorithm, result))
         return promise;
 
+    // 14.3.4.5: Let data be the result of getting a copy of the bytes held by
+    //           the data parameter passed to the verify method.
+    Vector<uint8_t> data = copyBytes(rawData);
+
     if (!key->canBeUsedForAlgorithm(algorithm, WebCryptoKeyUsageVerify, result))
         return promise;
 
     histogramAlgorithmAndKey(scriptState->getExecutionContext(), algorithm, key->key());
-    Platform::current()->crypto()->verifySignature(algorithm, key->key(), signature.bytes(), signature.byteLength(), data.bytes(), data.byteLength(), result->result());
+    Platform::current()->crypto()->verifySignature(algorithm, key->key(), signature.data(), signature.size(), data.data(), data.size(), result->result());
     return promise;
 }
 
-ScriptPromise SubtleCrypto::digest(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, const DOMArrayPiece& data)
+ScriptPromise SubtleCrypto::digest(ScriptState* scriptState, const AlgorithmIdentifier& rawAlgorithm, const BufferSource& rawData)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-digest
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
     if (!canAccessWebCrypto(scriptState, result))
         return promise;
 
+    // 14.3.5.2: Let data be the result of getting a copy of the bytes held
+    //              by the data parameter passed to the digest method.
+    Vector<uint8_t> data = copyBytes(rawData);
+
     WebCryptoAlgorithm algorithm;
     if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationDigest, algorithm, result))
         return promise;
 
     histogramAlgorithm(scriptState->getExecutionContext(), algorithm);
-    Platform::current()->crypto()->digest(algorithm, data.bytes(), data.byteLength(), result->result());
+    Platform::current()->crypto()->digest(algorithm, data.data(), data.size(), result->result());
     return promise;
 }
 
@@ -236,8 +285,10 @@
     return promise;
 }
 
-ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& rawFormat, const ArrayBufferOrArrayBufferViewOrDictionary& keyData, const AlgorithmIdentifier& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages)
+ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& rawFormat, const ArrayBufferOrArrayBufferViewOrDictionary& rawKeyData, const AlgorithmIdentifier& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-importKey
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
@@ -248,7 +299,7 @@
     if (!CryptoKey::parseFormat(rawFormat, format, result))
         return promise;
 
-    if (keyData.isDictionary()) {
+    if (rawKeyData.isDictionary()) {
         if (format != WebCryptoKeyFormatJwk) {
             result->completeWithError(WebCryptoErrorTypeData, "Key data must be a buffer for non-JWK formats");
             return promise;
@@ -266,24 +317,17 @@
     if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationImportKey, algorithm, result))
         return promise;
 
-    const unsigned char* ptr = nullptr;
-    unsigned len = 0;
-
-    CString jsonUtf8;
-    if (keyData.isArrayBuffer()) {
-        ptr = static_cast<const unsigned char*>(keyData.getAsArrayBuffer()->data());
-        len = keyData.getAsArrayBuffer()->byteLength();
-    } else if (keyData.isArrayBufferView()) {
-        ptr = static_cast<const unsigned char*>(keyData.getAsArrayBufferView()->baseAddress());
-        len = keyData.getAsArrayBufferView()->byteLength();
-    } else if (keyData.isDictionary()) {
-        if (!copyJwkDictionaryToJson(keyData.getAsDictionary(), jsonUtf8, result))
+    Vector<uint8_t> keyData;
+    if (rawKeyData.isArrayBuffer()) {
+        keyData = copyBytes(rawKeyData.getAsArrayBuffer());
+    } else if (rawKeyData.isArrayBufferView()) {
+        keyData = copyBytes(rawKeyData.getAsArrayBufferView());
+    } else if (rawKeyData.isDictionary()) {
+        if (!copyJwkDictionaryToJson(rawKeyData.getAsDictionary(), keyData, result))
             return promise;
-        ptr = reinterpret_cast<const unsigned char*>(jsonUtf8.data());
-        len = jsonUtf8.length();
     }
     histogramAlgorithm(scriptState->getExecutionContext(), algorithm);
-    Platform::current()->crypto()->importKey(format, ptr, len, algorithm, extractable, keyUsages, result->result());
+    Platform::current()->crypto()->importKey(format, keyData.data(), keyData.size(), algorithm, extractable, keyUsages, result->result());
     return promise;
 }
 
@@ -339,8 +383,10 @@
     return promise;
 }
 
-ScriptPromise SubtleCrypto::unwrapKey(ScriptState* scriptState, const String& rawFormat, const DOMArrayPiece& wrappedKey, CryptoKey* unwrappingKey, const AlgorithmIdentifier& rawUnwrapAlgorithm, const AlgorithmIdentifier& rawUnwrappedKeyAlgorithm, bool extractable, const Vector<String>& rawKeyUsages)
+ScriptPromise SubtleCrypto::unwrapKey(ScriptState* scriptState, const String& rawFormat, const BufferSource& rawWrappedKey, CryptoKey* unwrappingKey, const AlgorithmIdentifier& rawUnwrapAlgorithm, const AlgorithmIdentifier& rawUnwrappedKeyAlgorithm, bool extractable, const Vector<String>& rawKeyUsages)
 {
+    // Method described by: https://w3c.github.io/webcrypto/Overview.html#SubtleCrypto-method-unwrapKey
+
     CryptoResultImpl* result = CryptoResultImpl::create(scriptState);
     ScriptPromise promise = result->promise();
 
@@ -355,6 +401,11 @@
     if (!CryptoKey::parseUsageMask(rawKeyUsages, keyUsages, result))
         return promise;
 
+    // 14.3.12.2: Let wrappedKey be the result of getting a copy of the bytes
+    //            held by the wrappedKey parameter passed to the unwrapKey
+    //            method.
+    Vector<uint8_t> wrappedKey = copyBytes(rawWrappedKey);
+
     WebCryptoAlgorithm unwrapAlgorithm;
     if (!parseAlgorithm(rawUnwrapAlgorithm, WebCryptoOperationUnwrapKey, unwrapAlgorithm, result))
         return promise;
@@ -368,7 +419,7 @@
 
     histogramAlgorithmAndKey(scriptState->getExecutionContext(), unwrapAlgorithm, unwrappingKey->key());
     histogramAlgorithm(scriptState->getExecutionContext(), unwrappedKeyAlgorithm);
-    Platform::current()->crypto()->unwrapKey(format, wrappedKey.bytes(), wrappedKey.byteLength(), unwrappingKey->key(), unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages, result->result());
+    Platform::current()->crypto()->unwrapKey(format, wrappedKey.data(), wrappedKey.size(), unwrappingKey->key(), unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages, result->result());
     return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h b/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h
index dd9aa94..fef7a2e 100644
--- a/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h
+++ b/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h
@@ -36,7 +36,6 @@
 #include "bindings/core/v8/ScriptWrappable.h"
 #include "bindings/modules/v8/ArrayBufferOrArrayBufferViewOrDictionary.h"
 #include "bindings/modules/v8/DictionaryOrString.h"
-#include "core/dom/DOMArrayPiece.h"
 #include "platform/heap/Handle.h"
 #include "wtf/Forward.h"
 
@@ -55,19 +54,19 @@
         return new SubtleCrypto();
     }
 
-    ScriptPromise encrypt(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const DOMArrayPiece&);
-    ScriptPromise decrypt(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const DOMArrayPiece&);
-    ScriptPromise sign(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const DOMArrayPiece&);
+    ScriptPromise encrypt(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const BufferSource&);
+    ScriptPromise decrypt(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const BufferSource&);
+    ScriptPromise sign(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const BufferSource&);
     // Note that this is not named "verify" because when compiling on Mac that expands to a macro and breaks.
-    ScriptPromise verifySignature(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const DOMArrayPiece& signature, const DOMArrayPiece& data);
-    ScriptPromise digest(ScriptState*, const AlgorithmIdentifier&, const DOMArrayPiece& data);
+    ScriptPromise verifySignature(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const BufferSource& signature, const BufferSource& data);
+    ScriptPromise digest(ScriptState*, const AlgorithmIdentifier&, const BufferSource& data);
 
     ScriptPromise generateKey(ScriptState*, const AlgorithmIdentifier&, bool extractable, const Vector<String>& keyUsages);
     ScriptPromise importKey(ScriptState*, const String&, const ArrayBufferOrArrayBufferViewOrDictionary&, const AlgorithmIdentifier&, bool extractable, const Vector<String>& keyUsages);
     ScriptPromise exportKey(ScriptState*, const String&, CryptoKey*);
 
     ScriptPromise wrapKey(ScriptState*, const String&, CryptoKey*, CryptoKey*, const AlgorithmIdentifier&);
-    ScriptPromise unwrapKey(ScriptState*, const String&, const DOMArrayPiece&, CryptoKey*, const AlgorithmIdentifier&, const AlgorithmIdentifier&, bool, const Vector<String>&);
+    ScriptPromise unwrapKey(ScriptState*, const String&, const BufferSource&, CryptoKey*, const AlgorithmIdentifier&, const AlgorithmIdentifier&, bool, const Vector<String>&);
 
     ScriptPromise deriveBits(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, unsigned);
     ScriptPromise deriveKey(ScriptState*, const AlgorithmIdentifier&, CryptoKey*, const AlgorithmIdentifier&, bool extractable, const Vector<String>&);