[WebCrypto] Add SHA-1
https://bugs.webkit.org/show_bug.cgi?id=123582

Reviewed by Anders Carlsson.

Source/WebCore: 

Tests: security/crypto-subtle-arguments.html
       security/crypto-subtle-sha1.html

* WebCore.xcodeproj/project.pbxproj: Added new files.

* bindings/js/JSSubtleCryptoCustom.cpp:
(WebCore::createAlgorithmFromJSValue):
(WebCore::sequenceOfCryptoOperationDataFromJSValue):
(WebCore::JSSubtleCrypto::digest):
* crypto/SubtleCrypto.idl:
Added bindings for crypto.digest.

* crypto/algorithms: Added.
* crypto/algorithms/CryptoAlgorithmSHA1.cpp: Added.
* crypto/algorithms/CryptoAlgorithmSHA1.h: Added.
* crypto/mac/CryptoAlgorithmRegistryMac.cpp:
(WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms): Register SHA-1.

* crypto/mac/CryptoAlgorithmSHA1Mac.cpp: Added.
(WebCore::CryptoAlgorithmSHA1::digest): Performs the work synchronously, because
otherwise we'd have to copy the data first, which is crazy for something as simple
as hashing. We can change to a dispatch queue later if we find that it's actually
better to copy and do the work asynchronously.

LayoutTests: 

* security/resources/common.js: Added from Blink.
(importTestKeys):
(asciiToArrayBuffer):
(printRejectedResult):
(printAcceptedResult):
(failAndFinishJSTest):

* security/crypto-subtle-arguments-expected.txt: Added.
* security/crypto-subtle-arguments.html: Added.
Added tests for how bindings treat crazy arguments. Heavily based on a test from Blink.

* security/crypto-subtle-sha1-expected.txt: Added.
* security/crypto-subtle-sha1.html: Added.
Test that SHA-1 works.

* TestExpectations: Skip these tests everywhere for now.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@158387 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 0342553..1c58316 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,27 @@
+2013-10-31  Alexey Proskuryakov  <ap@apple.com>
+
+        [WebCrypto] Add SHA-1
+        https://bugs.webkit.org/show_bug.cgi?id=123582
+
+        Reviewed by Anders Carlsson.
+
+        * security/resources/common.js: Added from Blink.
+        (importTestKeys):
+        (asciiToArrayBuffer):
+        (printRejectedResult):
+        (printAcceptedResult):
+        (failAndFinishJSTest):
+
+        * security/crypto-subtle-arguments-expected.txt: Added.
+        * security/crypto-subtle-arguments.html: Added.
+        Added tests for how bindings treat crazy arguments. Heavily based on a test from Blink.
+
+        * security/crypto-subtle-sha1-expected.txt: Added.
+        * security/crypto-subtle-sha1.html: Added.
+        Test that SHA-1 works.
+
+        * TestExpectations: Skip these tests everywhere for now.
+
 2013-10-31  Filip Pizlo  <fpizlo@apple.com>
 
         Remove CachedTranscendentalFunction because caching math functions is an ugly idea
diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations
index 193f036..c55fa67 100644
--- a/LayoutTests/TestExpectations
+++ b/LayoutTests/TestExpectations
@@ -75,6 +75,8 @@
 webkit.org/b/122679 security/crypto-subtle-gc.html [ Skip ]
 webkit.org/b/122679 security/crypto-subtle-gc-2.html [ Skip ]
 webkit.org/b/122679 security/crypto-subtle-gc-3.html [ Skip ]
+webkit.org/b/122679 security/crypto-subtle-sha1.html [ Skip ]
+webkit.org/b/122679 security/crypto-subtle-arguments.html [ Skip ]
 
 webkit.org/b/123555 [ Debug ] media/media-fragments/TC0054.html [ Crash ]
 webkit.org/b/123555 [ Debug ] media/media-fragments/TC0061.html [ Crash ]
diff --git a/LayoutTests/security/crypto-subtle-arguments-expected.txt b/LayoutTests/security/crypto-subtle-arguments-expected.txt
new file mode 100644
index 0000000..6163e1b
--- /dev/null
+++ b/LayoutTests/security/crypto-subtle-arguments-expected.txt
@@ -0,0 +1,40 @@
+Test crypto.subtle argument conversion
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+SHA1 of new Uint8Array([]))
+    = [da 39 a3 ee 5e 6b 4b 0d 32 55 bf ef 95 60 18 90 af d8 07 09]
+
+Passing algorithm name as a string object...
+PASS ...succeeded
+
+Passing algorithm name as a string object in a dictionary...
+PASS ...succeeded
+
+Passing algorithm name as an object with toString
+PASS ...succeeded
+
+Passing invalid data to digest()
+PASS crypto.subtle.digest({name: 'sha-1'}) threw exception TypeError: Not enough arguments.
+PASS crypto.subtle.digest({name: 'sha-1'}, null) threw exception TypeError: Type error.
+PASS crypto.subtle.digest({name: 'sha-1'}, 10) threw exception TypeError: Type error.
+PASS crypto.subtle.digest({name: 'sha-1'}, [10]) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be part of CryptoOperationData sequence.
+PASS crypto.subtle.digest({name: 'sha-1'}, new Uint8Array([0])) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be part of CryptoOperationData sequence.
+
+Passing invalid algorithmIdentifiers to digest()
+PASS crypto.subtle.digest({ toString:function() { return 'sha-1' } }, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest({name: ''}, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest({name: null}, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest({name: undefined}, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest({name: 'sha'}, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest({name: 1}, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest('', [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest(null, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest(undefined, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest(1, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.digest({}, [data]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/security/crypto-subtle-arguments.html b/LayoutTests/security/crypto-subtle-arguments.html
new file mode 100644
index 0000000..bcfa36d
--- /dev/null
+++ b/LayoutTests/security/crypto-subtle-arguments.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Test crypto.subtle argument conversion");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+Promise.fulfill(null).then(function() {
+    // This looks like invalid input, but it actually isn't - Uint8Array is a sequence too,
+    // so it's just an empty sequence, same as passing [].
+    debug("SHA1 of new Uint8Array([]))");
+    return crypto.subtle.digest('sha-1', new Uint8Array([]));
+}).then(function(result) {
+    printAcceptedResult(result);
+    debug("\nPassing algorithm name as a string object...");
+    return crypto.subtle.digest(new String('sha-1'), []);
+}).then(function(result) {
+    testPassed("...succeeded");
+    debug("\nPassing algorithm name as a string object in a dictionary...");
+    return crypto.subtle.digest({name: new String('sha-1')}, []);
+}).then(function(result) {
+    testPassed("...succeeded");
+    debug("\nPassing algorithm name as an object with toString");
+    return crypto.subtle.digest({name: { toString:function() { return 'sha-1' } } }, []);
+}).then(function(result) {
+    testPassed("...succeeded");
+
+    debug("\nPassing invalid data to digest()");
+    shouldThrow("crypto.subtle.digest({name: 'sha-1'})");
+    shouldThrow("crypto.subtle.digest({name: 'sha-1'}, null)");
+    shouldThrow("crypto.subtle.digest({name: 'sha-1'}, 10)");
+    shouldThrow("crypto.subtle.digest({name: 'sha-1'}, [10])");
+    shouldThrow("crypto.subtle.digest({name: 'sha-1'}, new Uint8Array([0]))");
+
+    debug("\nPassing invalid algorithmIdentifiers to digest()");
+    data = new Uint8Array([0]);
+    shouldThrow("crypto.subtle.digest({ toString:function() { return 'sha-1' } }, [data])"); // Algorithm normalization doesn't attempt to call toString.
+    shouldThrow("crypto.subtle.digest({name: ''}, [data])");
+    shouldThrow("crypto.subtle.digest({name: null}, [data])");
+    shouldThrow("crypto.subtle.digest({name: undefined}, [data])");
+    shouldThrow("crypto.subtle.digest({name: 'sha'}, [data])");
+    shouldThrow("crypto.subtle.digest({name: 1}, [data])");
+    shouldThrow("crypto.subtle.digest('', [data])");
+    shouldThrow("crypto.subtle.digest(null, [data])");
+    shouldThrow("crypto.subtle.digest(undefined, [data])");
+    shouldThrow("crypto.subtle.digest(1, [data])");
+    shouldThrow("crypto.subtle.digest({}, [data])");
+}).then(finishJSTest);
+
+</script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/security/crypto-subtle-sha1-expected.txt b/LayoutTests/security/crypto-subtle-sha1-expected.txt
new file mode 100644
index 0000000..98c74ef
--- /dev/null
+++ b/LayoutTests/security/crypto-subtle-sha1-expected.txt
@@ -0,0 +1,18 @@
+Test crypto.subtle.digest.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+SHA1 of []
+    = [da 39 a3 ee 5e 6b 4b 0d 32 55 bf ef 95 60 18 90 af d8 07 09]
+SHA1 of [0x0]
+    = [5b a9 3c 9d b0 cf f9 3f 52 b5 21 d7 42 0e 43 f6 ed a2 78 4f]
+SHA1 of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+    = [2c 7e 7c 38 4f 78 29 69 42 82 b1 e3 a6 21 6d ef 80 82 d0 55]
+SHA1 of [new Uint8Array([0, 1, 2, 3, 4]), new Uint8Array(5, 6, 7, 8, 9, 10])]
+    = [2c 7e 7c 38 4f 78 29 69 42 82 b1 e3 a6 21 6d ef 80 82 d0 55]
+PASS crypto.subtle.generateKey('sha-1') threw exception TypeError: undefined is not a function (evaluating 'crypto.subtle.generateKey('sha-1')').
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/security/crypto-subtle-sha1.html b/LayoutTests/security/crypto-subtle-sha1.html
new file mode 100644
index 0000000..277ee74
--- /dev/null
+++ b/LayoutTests/security/crypto-subtle-sha1.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/common.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Test crypto.subtle.digest.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+Promise.fulfill(null).then(function() {
+    debug("SHA1 of []");
+    return crypto.subtle.digest('sha-1', [new Uint8Array([])]);
+}).then(function(result) {
+    printAcceptedResult(result);
+
+    debug("SHA1 of [0x0]")
+    return crypto.subtle.digest({name: 'sha-1'}, [new Uint8Array([0])]);
+}).then(function(result) {
+    printAcceptedResult(result);
+
+    debug("SHA1 of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]");
+    var data = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    return crypto.subtle.digest({name: 'sha-1'}, [data]);
+}).then(function(result) {
+    printAcceptedResult(result);
+
+    debug("SHA1 of [new Uint8Array([0, 1, 2, 3, 4]), new Uint8Array(5, 6, 7, 8, 9, 10])]");
+    return crypto.subtle.digest({name: 'sha-1'}, [new Uint8Array([0, 1, 2, 3, 4]), new Uint8Array([5, 6, 7, 8, 9, 10])]);
+}).then(function(result) {
+    printAcceptedResult(result);
+    // All SHA-1 can do is digest.
+    shouldThrow("crypto.subtle.generateKey('sha-1')");
+    finishJSTest();
+});
+</script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/security/resources/common.js b/LayoutTests/security/resources/common.js
new file mode 100644
index 0000000..4e0b5ff
--- /dev/null
+++ b/LayoutTests/security/resources/common.js
@@ -0,0 +1,63 @@
+function importTestKeys()
+{
+    var keyFormat = "spki";
+    var data = new Uint8Array([]);
+    var extractable = false;
+    var keyUsages = ['encrypt', 'decrypt', 'sign', 'verify'];
+
+    var hmacPromise = crypto.subtle.importKey(keyFormat, data, {name: 'hmac', hash: {name: 'sha-1'}}, extractable, keyUsages);
+    var rsaSsaPromise = crypto.subtle.importKey(keyFormat, data, {name: 'RSASSA-PKCS1-v1_5', hash: {name: 'sha-1'}}, extractable, keyUsages);
+    var aesCbcPromise = crypto.subtle.importKey(keyFormat, data, {name: 'AES-CBC'}, extractable, keyUsages);
+    var aesCbcJustDecrypt = crypto.subtle.importKey(keyFormat, data, {name: 'AES-CBC'}, extractable, ['decrypt']);
+
+    return Promise.every(hmacPromise, rsaSsaPromise, aesCbcPromise, aesCbcJustDecrypt).then(function(results) {
+        return {
+            hmacSha1: results[0],
+            rsaSsaSha1: results[1],
+            aesCbc: results[2],
+            aesCbcJustDecrypt: results[3],
+        };
+    });
+}
+
+// Builds a hex string representation of any array-like input (array or
+// ArrayBufferView). The output looks like this:
+//    [ab 03 4c 99]
+function byteArrayToHexString(bytes)
+{
+    var hexBytes = [];
+
+    for (var i = 0; i < bytes.length; ++i) {
+        var byteString = bytes[i].toString(16);
+        if (byteString.length < 2)
+            byteString = "0" + byteString;
+        hexBytes.push(byteString);
+    }
+
+    return "[" + hexBytes.join(" ") + "]";
+}
+
+function asciiToArrayBuffer(str)
+{
+    var chars = [];
+    for (var i = 0; i < str.length; ++i)
+        chars.push(str.charCodeAt(i));
+    return new Uint8Array(chars);
+}
+
+function printRejectedResult(value)
+{
+    debug("    rejected with value of " + value);
+}
+
+function printAcceptedResult(result)
+{
+    debug("    = " + byteArrayToHexString(new Uint8Array(result)));
+}
+
+function failAndFinishJSTest(error)
+{
+    if (error)
+       debug(error);
+    finishJSTest();
+}
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index c4f98cd..d910e9c 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,34 @@
+2013-10-31  Alexey Proskuryakov  <ap@apple.com>
+
+        [WebCrypto] Add SHA-1
+        https://bugs.webkit.org/show_bug.cgi?id=123582
+
+        Reviewed by Anders Carlsson.
+
+        Tests: security/crypto-subtle-arguments.html
+               security/crypto-subtle-sha1.html
+
+        * WebCore.xcodeproj/project.pbxproj: Added new files.
+
+        * bindings/js/JSSubtleCryptoCustom.cpp:
+        (WebCore::createAlgorithmFromJSValue):
+        (WebCore::sequenceOfCryptoOperationDataFromJSValue):
+        (WebCore::JSSubtleCrypto::digest):
+        * crypto/SubtleCrypto.idl:
+        Added bindings for crypto.digest.
+
+        * crypto/algorithms: Added.
+        * crypto/algorithms/CryptoAlgorithmSHA1.cpp: Added.
+        * crypto/algorithms/CryptoAlgorithmSHA1.h: Added.
+        * crypto/mac/CryptoAlgorithmRegistryMac.cpp:
+        (WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms): Register SHA-1.
+
+        * crypto/mac/CryptoAlgorithmSHA1Mac.cpp: Added.
+        (WebCore::CryptoAlgorithmSHA1::digest): Performs the work synchronously, because
+        otherwise we'd have to copy the data first, which is crazy for something as simple
+        as hashing. We can change to a dispatch queue later if we find that it's actually
+        better to copy and do the work asynchronously.
+
 2013-10-31  Sudarsana Nagineni  <sudarsana.nagineni@intel.com>
 
         REGRESSION(r158348): Breaks Debug build
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index 297c24e..bf16110 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -5502,6 +5502,9 @@
 		E11C9D9B0EB3681200E409DB /* ScriptExecutionContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E11C9D9A0EB3681200E409DB /* ScriptExecutionContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E11C9DB00EB3699500E409DB /* ScriptExecutionContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E11C9DAF0EB3699500E409DB /* ScriptExecutionContext.cpp */; };
 		E124748410AA161D00B79493 /* AuthenticationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E124748310AA161D00B79493 /* AuthenticationClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E125F82B1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */; };
+		E125F82C1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F82A1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h */; };
+		E125F82E1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */; };
 		E12719C70EEEC16800F61213 /* NavigatorBase.h in Headers */ = {isa = PBXBuildFile; fileRef = E12719C60EEEC16800F61213 /* NavigatorBase.h */; };
 		E12719CA0EEEC21300F61213 /* NavigatorBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E12719C90EEEC21300F61213 /* NavigatorBase.cpp */; };
 		E1271A0B0EEEC77A00F61213 /* WorkerNavigator.h in Headers */ = {isa = PBXBuildFile; fileRef = E1271A0A0EEEC77A00F61213 /* WorkerNavigator.h */; };
@@ -12506,6 +12509,9 @@
 		E11C9D9A0EB3681200E409DB /* ScriptExecutionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptExecutionContext.h; sourceTree = "<group>"; };
 		E11C9DAF0EB3699500E409DB /* ScriptExecutionContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptExecutionContext.cpp; sourceTree = "<group>"; };
 		E124748310AA161D00B79493 /* AuthenticationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthenticationClient.h; sourceTree = "<group>"; };
+		E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmSHA1.cpp; sourceTree = "<group>"; };
+		E125F82A1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmSHA1.h; sourceTree = "<group>"; };
+		E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmSHA1Mac.cpp; path = mac/CryptoAlgorithmSHA1Mac.cpp; sourceTree = "<group>"; };
 		E12719C60EEEC16800F61213 /* NavigatorBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigatorBase.h; sourceTree = "<group>"; };
 		E12719C90EEEC21300F61213 /* NavigatorBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigatorBase.cpp; sourceTree = "<group>"; };
 		E1271A0A0EEEC77A00F61213 /* WorkerNavigator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerNavigator.h; sourceTree = "<group>"; };
@@ -20132,6 +20138,7 @@
 			isa = PBXGroup;
 			children = (
 				E1BB84AC1822CA7400525043 /* CryptoAlgorithmRegistryMac.cpp */,
+				E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */,
 			);
 			name = mac;
 			sourceTree = "<group>";
@@ -20139,6 +20146,8 @@
 		E172AF7C180F3B0D00FBADB9 /* algorithms */ = {
 			isa = PBXGroup;
 			children = (
+				E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */,
+				E125F82A1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h */,
 			);
 			path = algorithms;
 			sourceTree = "<group>";
@@ -23604,6 +23613,7 @@
 				E44613AD0CD6331000FADA75 /* MediaError.h in Headers */,
 				4E1959220A39DABA00220FE5 /* MediaFeatureNames.h in Headers */,
 				07A6D1EC1491137700051D0C /* MediaFragmentURIParser.h in Headers */,
+				E125F82C1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.h in Headers */,
 				A8EA800E0A19516E00A8EF5F /* MediaList.h in Headers */,
 				E44613E40CD681A200FADA75 /* MediaPlayer.h in Headers */,
 				076F0D0E12B8192700C26AA4 /* MediaPlayerPrivateAVFoundation.h in Headers */,
@@ -25666,6 +25676,7 @@
 				85DF2F9C0AA3CAE500AD64C5 /* DOMHTMLOptionsCollection.mm in Sources */,
 				85183B470AA6926100F19FA3 /* DOMHTMLParagraphElement.mm in Sources */,
 				85ECBEF80AA7626900544F0B /* DOMHTMLParamElement.mm in Sources */,
+				E125F82B1822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp in Sources */,
 				85183B490AA6926100F19FA3 /* DOMHTMLPreElement.mm in Sources */,
 				A4226E961163D73A008B8397 /* DOMHTMLProgressElement.mm in Sources */,
 				85183B4B0AA6926100F19FA3 /* DOMHTMLQuoteElement.mm in Sources */,
@@ -26057,6 +26068,7 @@
 				D66817FA166FE6D700FA07B4 /* HTMLTemplateElement.cpp in Sources */,
 				A81369D7097374F600D74463 /* HTMLTextAreaElement.cpp in Sources */,
 				9BC6C21C13CCC97B008E0337 /* HTMLTextFormControlElement.cpp in Sources */,
+				E125F82E1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp in Sources */,
 				A871DC290A15205700B12A68 /* HTMLTitleElement.cpp in Sources */,
 				977B3877122883E900B81FF8 /* HTMLTokenizer.cpp in Sources */,
 				0707568B142262D600414161 /* HTMLTrackElement.cpp in Sources */,
diff --git a/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp b/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
index 3971d5e..f3bf533 100644
--- a/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
+++ b/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
@@ -28,10 +28,92 @@
 
 #if ENABLE(SUBTLE_CRYPTO)
 
+#include "CryptoAlgorithm.h"
+#include "CryptoAlgorithmParameters.h"
+#include "CryptoAlgorithmRegistry.h"
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "JSCryptoAlgorithmDictionary.h"
+#include "JSDOMPromise.h"
+#include <runtime/Error.h>
+
+using namespace JSC;
+
 namespace WebCore {
 
+static std::unique_ptr<CryptoAlgorithm> createAlgorithmFromJSValue(ExecState* exec, JSValue value)
+{
+    CryptoAlgorithmIdentifier algorithmIdentifier;
+    if (!JSCryptoAlgorithmDictionary::getAlgorithmIdentifier(exec, value, algorithmIdentifier)) {
+        ASSERT(exec->hadException());
+        return nullptr;
+    }
 
-
+    std::unique_ptr<CryptoAlgorithm> result(CryptoAlgorithmRegistry::shared().create(algorithmIdentifier));
+    if (!result)
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+    return result;
 }
 
+static bool sequenceOfCryptoOperationDataFromJSValue(ExecState* exec, JSValue value, Vector<CryptoOperationData>& result)
+{
+    unsigned sequenceLength;
+    JSObject* sequence = toJSSequence(exec, value, sequenceLength);
+    if (!sequence) {
+        ASSERT(exec->hadException());
+        return false;
+    }
+
+    for (unsigned i = 0; i < sequenceLength; ++i) {
+        JSValue item = sequence->get(exec, i);
+        if (ArrayBuffer* buffer = toArrayBuffer(item))
+            result.append(std::make_pair(static_cast<char*>(buffer->data()), buffer->byteLength()));
+        else if (RefPtr<ArrayBufferView> bufferView = toArrayBufferView(item))
+            result.append(std::make_pair(static_cast<char*>(bufferView->baseAddress()), bufferView->byteLength()));
+        else {
+            throwTypeError(exec, "Only ArrayBuffer and ArrayBufferView objects can be part of CryptoOperationData sequence");
+            return false;
+        }
+    }
+    return true;
+}
+
+JSValue JSSubtleCrypto::digest(ExecState* exec)
+{
+    if (exec->argumentCount() < 2)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    std::unique_ptr<CryptoAlgorithm> algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    if (!algorithm) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    std::unique_ptr<CryptoAlgorithmParameters> parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    Vector<CryptoOperationData> data;
+    if (!sequenceOfCryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    std::unique_ptr<PromiseWrapper> promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->digest(*parameters, data, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
+} // namespace WebCore
+
 #endif
diff --git a/Source/WebCore/crypto/SubtleCrypto.idl b/Source/WebCore/crypto/SubtleCrypto.idl
index 5c46942..67c6a32 100644
--- a/Source/WebCore/crypto/SubtleCrypto.idl
+++ b/Source/WebCore/crypto/SubtleCrypto.idl
@@ -30,4 +30,5 @@
     NoInterfaceObject,
     OperationsNotDeletable
 ] interface SubtleCrypto {
+    [Custom] Promise digest(AlgorithmIdentifier algorithm, sequence<CryptoOperationData> data);
 };
diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmSHA1.cpp b/Source/WebCore/crypto/algorithms/CryptoAlgorithmSHA1.cpp
new file mode 100644
index 0000000..3eaae6d
--- /dev/null
+++ b/Source/WebCore/crypto/algorithms/CryptoAlgorithmSHA1.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CryptoAlgorithmSHA1.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+const char* const CryptoAlgorithmSHA1::s_name = "sha-1";
+
+CryptoAlgorithmSHA1::CryptoAlgorithmSHA1()
+{
+}
+
+CryptoAlgorithmSHA1::~CryptoAlgorithmSHA1()
+{
+}
+
+std::unique_ptr<CryptoAlgorithm> CryptoAlgorithmSHA1::create()
+{
+    return std::make_unique<CryptoAlgorithmSHA1>();
+}
+
+CryptoAlgorithmIdentifier CryptoAlgorithmSHA1::identifier() const
+{
+    return s_identifier;
+}
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmSHA1.h b/Source/WebCore/crypto/algorithms/CryptoAlgorithmSHA1.h
new file mode 100644
index 0000000..545547a
--- /dev/null
+++ b/Source/WebCore/crypto/algorithms/CryptoAlgorithmSHA1.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CryptoAlgorithmSHA1_h
+#define CryptoAlgorithmSHA1_h
+
+#include "CryptoAlgorithm.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoAlgorithmSHA1 FINAL : public CryptoAlgorithm {
+public:
+    static const char* const s_name;
+    static const CryptoAlgorithmIdentifier s_identifier = CryptoAlgorithmIdentifier::SHA_1;
+
+    static std::unique_ptr<CryptoAlgorithm> create();
+
+    virtual CryptoAlgorithmIdentifier identifier() const OVERRIDE;
+
+    virtual void digest(const CryptoAlgorithmParameters&, const Vector<CryptoOperationData>&, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+
+private:
+    CryptoAlgorithmSHA1();
+    virtual ~CryptoAlgorithmSHA1();
+};
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+#endif // CryptoAlgorithmSHA1_h
diff --git a/Source/WebCore/crypto/mac/CryptoAlgorithmRegistryMac.cpp b/Source/WebCore/crypto/mac/CryptoAlgorithmRegistryMac.cpp
index 4c4ea08..a80c65c 100644
--- a/Source/WebCore/crypto/mac/CryptoAlgorithmRegistryMac.cpp
+++ b/Source/WebCore/crypto/mac/CryptoAlgorithmRegistryMac.cpp
@@ -29,14 +29,14 @@
 #if ENABLE(SUBTLE_CRYPTO)
 
 //#include "CryptoAlgorithmHMAC.h"
-//#include "CryptoAlgorithmSHA1.h"
+#include "CryptoAlgorithmSHA1.h"
 
 namespace WebCore {
 
 void CryptoAlgorithmRegistry::platformRegisterAlgorithms()
 {
-//    registerAlgorithm(CryptoAlgorithmHMAC::m_name, CryptoAlgorithmHMAC::m_identifier, CryptoAlgorithmHMAC::create);
-//    registerAlgorithm(CryptoAlgorithmSHA1::m_name, CryptoAlgorithmSHA1::m_identifier, CryptoAlgorithmSHA1::create);
+//    registerAlgorithm(CryptoAlgorithmHMAC::s_name, CryptoAlgorithmHMAC::s_identifier, CryptoAlgorithmHMAC::create);
+    registerAlgorithm(CryptoAlgorithmSHA1::s_name, CryptoAlgorithmSHA1::s_identifier, CryptoAlgorithmSHA1::create);
 }
 
 }
diff --git a/Source/WebCore/crypto/mac/CryptoAlgorithmSHA1Mac.cpp b/Source/WebCore/crypto/mac/CryptoAlgorithmSHA1Mac.cpp
new file mode 100644
index 0000000..481bb99
--- /dev/null
+++ b/Source/WebCore/crypto/mac/CryptoAlgorithmSHA1Mac.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CryptoAlgorithmSHA1.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "JSDOMPromise.h"
+#include <CommonCrypto/CommonCrypto.h>
+
+namespace WebCore {
+
+void CryptoAlgorithmSHA1::digest(const CryptoAlgorithmParameters&, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode&)
+{
+    Vector<unsigned char> result(CC_SHA1_DIGEST_LENGTH);
+
+    CC_SHA1_CTX context;
+    CC_SHA1_Init(&context);
+
+    for (size_t i = 0, size = data.size(); i < size; ++i)
+        CC_SHA1_Update(&context, data[i].first, data[i].second);
+
+    CC_SHA1_Final(result.data(), &context);
+
+    promise->fulfill(result);
+}
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)