Add WebCrypto AES-CBC
authorap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Nov 2013 06:59:40 +0000 (06:59 +0000)
committerap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Nov 2013 06:59:40 +0000 (06:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123647

Reviewed by Anders Carlsson.

Source/WebCore:

Tests: crypto/subtle/aes-cbc-192-encrypt-decrypt.html
       crypto/subtle/aes-cbc-256-encrypt-decrypt.html
       crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html
       crypto/subtle/aes-cbc-encrypt-decrypt.html
       crypto/subtle/aes-cbc-invalid-length.html
       crypto/subtle/aes-cbc-wrong-key-class.html

* WebCore.xcodeproj/project.pbxproj: Added new files.
* bindings/js/JSCryptoAlgorithmDictionary.cpp:
(WebCore::getProperty): Factored out a function to get a property as JSValue.
(WebCore::getHashAlgorithm): Use it.
(WebCore::createAesCbcParams): Added converter for AesCbcParams.
(WebCore::JSCryptoAlgorithmDictionary::createParametersForEncrypt): Support AES_CBC.
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDecrypt): Ditto.
(WebCore::JSCryptoAlgorithmDictionary::createParametersForImportKey): Support all
algorithms, all the new ones just have trivial dictionaries.
(WebCore::JSCryptoAlgorithmDictionary::createParametersForExportKey): Ditto.

* bindings/js/JSCryptoOperationData.cpp: Added.
(WebCore::sequenceOfCryptoOperationDataFromJSValue):
(WebCore::cryptoOperationDataFromJSValue):
* bindings/js/JSCryptoOperationData.h: Added.
Moved CryptoOperationData bindings out of JSSubtleCryptoCustom.cpp, so that we
could use them in JSCryptoAlgorithmDictionary.cpp.

* bindings/js/JSDOMPromise.h: (WebCore::PromiseWrapper::reject): Added a specialization
to reject with null result. The spec doesn't actually say how algorithms fail.

* bindings/js/JSSubtleCryptoCustom.cpp:
(WebCore::JSSubtleCrypto::encrypt): Added.
(WebCore::JSSubtleCrypto::decrypt): Ditto.
(WebCore::JSSubtleCrypto::sign): Style fix.

* crypto/CryptoAlgorithmAesCbcParams.h: Added.

* crypto/CryptoKey.h:
(WebCore::CryptoKeyClass):
* crypto/keys/CryptoKeyHMAC.h:
(WebCore::asCryptoKeyHMAC):
Added poor man's RTTI, so that we can safely upcast Keys passed fro JavaScript code.

* crypto/CryptoKeyAES.cpp: Added.
(WebCore::CryptoKeyAES::CryptoKeyAES):
(WebCore::CryptoKeyAES::~CryptoKeyAES):
(WebCore::CryptoKeyAES::buildAlgorithmDescription):
* crypto/CryptoKeyAES.h: Added.
(WebCore::asCryptoKeyAES):
AES keys are the same for all algorithms, but they still need to remember the algorithm.

* crypto/SubtleCrypto.idl: Added encrypt/decrypt.

* crypto/algorithms/CryptoAlgorithmAES_CBC.cpp: Added.
(WebCore::CryptoAlgorithmAES_CBC::CryptoAlgorithmAES_CBC):
(WebCore::CryptoAlgorithmAES_CBC::~CryptoAlgorithmAES_CBC):
(WebCore::CryptoAlgorithmAES_CBC::create):
(WebCore::CryptoAlgorithmAES_CBC::identifier):
(WebCore::CryptoAlgorithmAES_CBC::importKey):
(WebCore::CryptoAlgorithmAES_CBC::exportKey):
* crypto/algorithms/CryptoAlgorithmAES_CBC.h: Added.
* crypto/mac/CryptoAlgorithmAES_CBCMac.cpp: Added.
(WebCore::transformAES_CBC):
(WebCore::CryptoAlgorithmAES_CBC::encrypt):
(WebCore::CryptoAlgorithmAES_CBC::decrypt):
(WebCore::CryptoAlgorithmAES_CBC::generateKey):
Added.

* crypto/mac/CryptoAlgorithmHMACMac.cpp:
(WebCore::CryptoAlgorithmHMAC::sign):
(WebCore::CryptoAlgorithmHMAC::verify):
Check key class before casting it to CryptoKeyHMAC.

* crypto/mac/CryptoAlgorithmRegistryMac.cpp:
(WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms): Register AES-CBC
on Mac, so that it can be used.

Source/WTF:

* wtf/FixedArray.h: (WTF::FixedArray::data): Added a const version of the function.

* wtf/Vector.h: Added a comment to Vector constructor about how it is different
from std::vector.

LayoutTests:

Part of aes-cbc-encrypt-decrypt.html test was taken from Blink.

* crypto/subtle/aes-cbc-192-encrypt-decrypt-expected.txt: Added.
* crypto/subtle/aes-cbc-192-encrypt-decrypt.html: Added.
* crypto/subtle/aes-cbc-256-encrypt-decrypt-expected.txt: Added.
* crypto/subtle/aes-cbc-256-encrypt-decrypt.html: Added.
* crypto/subtle/aes-cbc-encrypt-decrypt-expected.txt: Added.
* crypto/subtle/aes-cbc-encrypt-decrypt-with-padding-expected.txt: Added.
* crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html: Added.
* crypto/subtle/aes-cbc-encrypt-decrypt.html: Added.
* crypto/subtle/aes-cbc-invalid-length-expected.txt: Added.
* crypto/subtle/aes-cbc-invalid-length.html: Added.
* crypto/subtle/aes-cbc-wrong-key-class-expected.txt: Added.
* crypto/subtle/aes-cbc-wrong-key-class.html: Added.

* crypto/subtle/hmac-sign-verify-expected.txt:
* crypto/subtle/hmac-sign-verify.html:
Corrected a description.

* crypto/subtle/resources/common.js: (hexToArrayBuffer): Added a helper.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@158485 268f45cc-cd09-0410-ab3c-d52691b4dbfc

37 files changed:
LayoutTests/ChangeLog
LayoutTests/crypto/subtle/aes-cbc-192-encrypt-decrypt-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-192-encrypt-decrypt.html [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-256-encrypt-decrypt-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-256-encrypt-decrypt.html [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-with-padding-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt.html [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-invalid-length-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-invalid-length.html [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-wrong-key-class-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-wrong-key-class.html [new file with mode: 0644]
LayoutTests/crypto/subtle/hmac-sign-verify-expected.txt
LayoutTests/crypto/subtle/hmac-sign-verify.html
LayoutTests/crypto/subtle/resources/common.js
Source/WTF/ChangeLog
Source/WTF/wtf/FixedArray.h
Source/WTF/wtf/Vector.h
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.cpp
Source/WebCore/bindings/js/JSCryptoOperationData.cpp [new file with mode: 0644]
Source/WebCore/bindings/js/JSCryptoOperationData.h [new file with mode: 0644]
Source/WebCore/bindings/js/JSDOMPromise.h
Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
Source/WebCore/crypto/CryptoAlgorithmAesCbcParams.h [new file with mode: 0644]
Source/WebCore/crypto/CryptoKey.h
Source/WebCore/crypto/CryptoKeyAES.cpp [new file with mode: 0644]
Source/WebCore/crypto/CryptoKeyAES.h [new file with mode: 0644]
Source/WebCore/crypto/SubtleCrypto.idl
Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.cpp [new file with mode: 0644]
Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h [new file with mode: 0644]
Source/WebCore/crypto/keys/CryptoKeyHMAC.h
Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp [new file with mode: 0644]
Source/WebCore/crypto/mac/CryptoAlgorithmHMACMac.cpp
Source/WebCore/crypto/mac/CryptoAlgorithmRegistryMac.cpp

index 77f9a47..017e201 100644 (file)
@@ -1,3 +1,31 @@
+2013-11-01  Alexey Proskuryakov  <ap@apple.com>
+
+        Add WebCrypto AES-CBC
+        https://bugs.webkit.org/show_bug.cgi?id=123647
+
+        Reviewed by Anders Carlsson.
+
+        Part of aes-cbc-encrypt-decrypt.html test was taken from Blink.
+
+        * crypto/subtle/aes-cbc-192-encrypt-decrypt-expected.txt: Added.
+        * crypto/subtle/aes-cbc-192-encrypt-decrypt.html: Added.
+        * crypto/subtle/aes-cbc-256-encrypt-decrypt-expected.txt: Added.
+        * crypto/subtle/aes-cbc-256-encrypt-decrypt.html: Added.
+        * crypto/subtle/aes-cbc-encrypt-decrypt-expected.txt: Added.
+        * crypto/subtle/aes-cbc-encrypt-decrypt-with-padding-expected.txt: Added.
+        * crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html: Added.
+        * crypto/subtle/aes-cbc-encrypt-decrypt.html: Added.
+        * crypto/subtle/aes-cbc-invalid-length-expected.txt: Added.
+        * crypto/subtle/aes-cbc-invalid-length.html: Added.
+        * crypto/subtle/aes-cbc-wrong-key-class-expected.txt: Added.
+        * crypto/subtle/aes-cbc-wrong-key-class.html: Added.
+
+        * crypto/subtle/hmac-sign-verify-expected.txt:
+        * crypto/subtle/hmac-sign-verify.html:
+        Corrected a description.
+
+        * crypto/subtle/resources/common.js: (hexToArrayBuffer): Added a helper.
+
 2013-11-01  Jaehun Lim  <ljaehun.lim@samsung.com>
 
         Update layout test results after CSS calc() simplification
diff --git a/LayoutTests/crypto/subtle/aes-cbc-192-encrypt-decrypt-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-192-encrypt-decrypt-expected.txt
new file mode 100644 (file)
index 0000000..a59751c
--- /dev/null
@@ -0,0 +1,19 @@
+Test AES-CBC encrypt and decrypt functions with a 256 bit key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a raw AES key from string literal...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'aes-cbc'
+PASS key.algorithm.length is 192
+PASS key.usages is ['encrypt', 'decrypt']
+Using the key to encrypt plaintext...
+PASS byteArrayToHexString(new Uint8Array(encryptionResult)) is '[4f 02 1d b2 43 bc 63 3d 71 78 18 3a 9f a0 71 e8 b4 d9 ad a9 ad 7d ed f4 e5 e7 38 76 3f 69 14 5a 57 1b 24 20 12 fb 7a e0 7f a9 ba ac 3d f1 02 e0 08 b0 e2 79 88 59 88 81 d9 20 a9 e6 4f 56 15 cd 61 2c cd 79 22 4b 35 09 35 d4 5d d6 a9 8f 81 76]'
+Decrypting it back...
+PASS new Uint8Array(decryptionResult) is plaintext
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-192-encrypt-decrypt.html b/LayoutTests/crypto/subtle/aes-cbc-192-encrypt-decrypt.html
new file mode 100644 (file)
index 0000000..ad6f7f9
--- /dev/null
@@ -0,0 +1,51 @@
+<!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 AES-CBC encrypt and decrypt functions with a 256 bit key.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var keyData = hexToArrayBuffer("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
+var iv = hexToArrayBuffer("000102030405060708090a0b0c0d0e0f");
+var plaintext = hexToArrayBuffer("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
+var extractable = true;
+
+debug("Importing a raw AES key from string literal...");
+crypto.subtle.importKey("raw", keyData, "aes-cbc", extractable, ["encrypt", "decrypt"]).then(function(result) {
+    key = result;
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'aes-cbc'");
+    shouldBe("key.algorithm.length", "192");
+    shouldBe("key.usages", "['encrypt', 'decrypt']");
+
+    debug("Using the key to encrypt plaintext...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext]);
+}).then(function(result) {
+    encryptionResult = result;
+    shouldBe("byteArrayToHexString(new Uint8Array(encryptionResult))", "'[4f 02 1d b2 43 bc 63 3d 71 78 18 3a 9f a0 71 e8 b4 d9 ad a9 ad 7d ed f4 e5 e7 38 76 3f 69 14 5a 57 1b 24 20 12 fb 7a e0 7f a9 ba ac 3d f1 02 e0 08 b0 e2 79 88 59 88 81 d9 20 a9 e6 4f 56 15 cd 61 2c cd 79 22 4b 35 09 35 d4 5d d6 a9 8f 81 76]'");
+
+    debug("Decrypting it back...");
+    return crypto.subtle.decrypt({name: "aes-cbc", iv: iv}, key, [result]);
+}).then(function(result) {
+    decryptionResult = result;
+    shouldBe("new Uint8Array(decryptionResult)", "plaintext");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/aes-cbc-256-encrypt-decrypt-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-256-encrypt-decrypt-expected.txt
new file mode 100644 (file)
index 0000000..06cdac3
--- /dev/null
@@ -0,0 +1,19 @@
+Test AES-CBC encrypt and decrypt functions with a 256 bit key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a raw AES key from string literal...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'aes-cbc'
+PASS key.algorithm.length is 256
+PASS key.usages is ['encrypt', 'decrypt']
+Using the key to encrypt plaintext...
+PASS byteArrayToHexString(new Uint8Array(encryptionResult)) is '[f5 8c 4c 04 d6 e5 f1 ba 77 9e ab fb 5f 7b fb d6 9c fc 4e 96 7e db 80 8d 67 9f 77 7b c6 70 2c 7d 39 f2 33 69 a9 d9 ba cf a5 30 e2 63 04 23 14 61 b2 eb 05 e2 c3 9b e9 fc da 6c 19 07 8c 6a 9d 1b 3f 46 17 96 d6 b0 d6 b2 e0 c2 a7 2b 4d 80 e6 44]'
+Decrypting it back...
+PASS new Uint8Array(decryptionResult) is plaintext
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-256-encrypt-decrypt.html b/LayoutTests/crypto/subtle/aes-cbc-256-encrypt-decrypt.html
new file mode 100644 (file)
index 0000000..eddc3d3
--- /dev/null
@@ -0,0 +1,51 @@
+<!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 AES-CBC encrypt and decrypt functions with a 256 bit key.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var keyData = hexToArrayBuffer("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
+var iv = hexToArrayBuffer("000102030405060708090a0b0c0d0e0f");
+var plaintext = hexToArrayBuffer("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
+var extractable = true;
+
+debug("Importing a raw AES key from string literal...");
+crypto.subtle.importKey("raw", keyData, "aes-cbc", extractable, ["encrypt", "decrypt"]).then(function(result) {
+    key = result;
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'aes-cbc'");
+    shouldBe("key.algorithm.length", "256");
+    shouldBe("key.usages", "['encrypt', 'decrypt']");
+
+    debug("Using the key to encrypt plaintext...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext]);
+}).then(function(result) {
+    encryptionResult = result;
+    shouldBe("byteArrayToHexString(new Uint8Array(encryptionResult))", "'[f5 8c 4c 04 d6 e5 f1 ba 77 9e ab fb 5f 7b fb d6 9c fc 4e 96 7e db 80 8d 67 9f 77 7b c6 70 2c 7d 39 f2 33 69 a9 d9 ba cf a5 30 e2 63 04 23 14 61 b2 eb 05 e2 c3 9b e9 fc da 6c 19 07 8c 6a 9d 1b 3f 46 17 96 d6 b0 d6 b2 e0 c2 a7 2b 4d 80 e6 44]'");
+
+    debug("Decrypting it back...");
+    return crypto.subtle.decrypt({name: "aes-cbc", iv: iv}, key, [result]);
+}).then(function(result) {
+    decryptionResult = result;
+    shouldBe("new Uint8Array(decryptionResult)", "plaintext");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-expected.txt
new file mode 100644 (file)
index 0000000..157ae96
--- /dev/null
@@ -0,0 +1,24 @@
+Test AES-CBC encrypt and decrypt functions.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a raw AES key from string literal...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'aes-cbc'
+PASS key.algorithm.length is 128
+PASS key.usages is ['encrypt', 'decrypt']
+Using the key to encrypt plaintext...
+PASS byteArrayToHexString(new Uint8Array(encryptionResult)) is '[76 49 ab ac 81 19 b2 46 ce e9 8e 9b 12 e9 19 7d 50 86 cb 9b 50 72 19 ee 95 db 11 3a 91 76 78 b2 73 be d6 b8 e3 c1 74 3b 71 16 e6 9e 22 22 95 16 3f f1 ca a1 68 1f ac 09 12 0e ca 30 75 86 e1 a7 8c b8 28 07 23 0e 13 21 d3 fa e0 0d 18 cc 20 12]'
+Decrypting it back...
+PASS new Uint8Array(decryptionResult) is plaintext
+Testing initialization vector bindings...
+PASS crypto.subtle.encrypt({name: 'AES-CBC', iv: null}, key, [plaintext]) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData.
+PASS crypto.subtle.encrypt({name: 'AES-CBC'}, key, [plaintext]) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData.
+PASS crypto.subtle.encrypt({name: 'AES-CBC', iv: 3}, key, [plaintext]) threw exception TypeError: Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData.
+PASS crypto.subtle.encrypt({name: 'AES-CBC', iv: new Uint8Array([0])}, key, [plaintext]) threw exception Error: AES-CBC initialization data must be 16 bytes.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-with-padding-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-with-padding-expected.txt
new file mode 100644 (file)
index 0000000..0cc4f74
--- /dev/null
@@ -0,0 +1,19 @@
+Test AES-CBC encrypt and decrypt functions on a plaintext that is not a multiple of block size in length.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a raw AES key from string literal...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'aes-cbc'
+PASS key.algorithm.length is 128
+PASS key.usages is ['encrypt', 'decrypt']
+Using the key to encrypt plaintext...
+    = [63 01 99 c5 f2 02 cc 71 67 bb 84 c6 c7 2b 34 9d]
+Decrypting it back...
+PASS new Uint8Array(decryptionResult) is plaintext
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html b/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html
new file mode 100644 (file)
index 0000000..5b9dc36
--- /dev/null
@@ -0,0 +1,49 @@
+<!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 AES-CBC encrypt and decrypt functions on a plaintext that is not a multiple of block size in length.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var keyData = hexToArrayBuffer("2b7e151628aed2a6abf7158809cf4f3c");
+var iv = hexToArrayBuffer("000102030405060708090a0b0c0d0e0f");
+var plaintext = asciiToArrayBuffer("test");
+var extractable = true;
+
+debug("Importing a raw AES key from string literal...");
+crypto.subtle.importKey("raw", keyData, "aes-cbc", extractable, ["encrypt", "decrypt"]).then(function(result) {
+    key = result;
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'aes-cbc'");
+    shouldBe("key.algorithm.length", "128");
+    shouldBe("key.usages", "['encrypt', 'decrypt']");
+
+    debug("Using the key to encrypt plaintext...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext]);
+}).then(function(result) {
+    printAcceptedResult(result);
+
+    debug("Decrypting it back...");
+    return crypto.subtle.decrypt({name: "aes-cbc", iv: iv}, key, [result]);
+}).then(function(result) {
+    decryptionResult = result;
+    shouldBe("new Uint8Array(decryptionResult)", "plaintext");
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt.html b/LayoutTests/crypto/subtle/aes-cbc-encrypt-decrypt.html
new file mode 100644 (file)
index 0000000..c387b6f
--- /dev/null
@@ -0,0 +1,57 @@
+<!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 AES-CBC encrypt and decrypt functions.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var keyData = hexToArrayBuffer("2b7e151628aed2a6abf7158809cf4f3c");
+var iv = hexToArrayBuffer("000102030405060708090a0b0c0d0e0f");
+var plaintext = hexToArrayBuffer("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
+var extractable = true;
+
+debug("Importing a raw AES key from string literal...");
+crypto.subtle.importKey("raw", keyData, "aes-cbc", extractable, ["encrypt", "decrypt"]).then(function(result) {
+    key = result;
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'aes-cbc'");
+    shouldBe("key.algorithm.length", "128");
+    shouldBe("key.usages", "['encrypt', 'decrypt']");
+
+    debug("Using the key to encrypt plaintext...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext]);
+}).then(function(result) {
+    encryptionResult = result;
+    shouldBe("byteArrayToHexString(new Uint8Array(encryptionResult))", "'[76 49 ab ac 81 19 b2 46 ce e9 8e 9b 12 e9 19 7d 50 86 cb 9b 50 72 19 ee 95 db 11 3a 91 76 78 b2 73 be d6 b8 e3 c1 74 3b 71 16 e6 9e 22 22 95 16 3f f1 ca a1 68 1f ac 09 12 0e ca 30 75 86 e1 a7 8c b8 28 07 23 0e 13 21 d3 fa e0 0d 18 cc 20 12]'");
+
+    debug("Decrypting it back...");
+    return crypto.subtle.decrypt({name: "aes-cbc", iv: iv}, key, [result]);
+}).then(function(result) {
+    decryptionResult = result;
+    shouldBe("new Uint8Array(decryptionResult)", "plaintext");
+
+    debug("Testing initialization vector bindings...");
+    shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: null}, key, [plaintext])");
+    shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC'}, key, [plaintext])");
+    shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: 3}, key, [plaintext])");
+    shouldThrow("crypto.subtle.encrypt({name: 'AES-CBC', iv: new Uint8Array([0])}, key, [plaintext])");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/aes-cbc-invalid-length-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-invalid-length-expected.txt
new file mode 100644 (file)
index 0000000..4fa7214
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 38: SyntaxError: Unexpected identifier 'finishJSTest'. Expected ')' to end a argument list.
+FAIL successfullyParsed should be true (of type boolean). Was undefined (of type undefined).
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-invalid-length.html b/LayoutTests/crypto/subtle/aes-cbc-invalid-length.html
new file mode 100644 (file)
index 0000000..0a215c2
--- /dev/null
@@ -0,0 +1,44 @@
+<!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 an unsupported AES key length.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var keyData = hexToArrayBuffer("8e73b0f7da0e6452c810f32b809079e562f8ead2522c");
+var iv = hexToArrayBuffer("000102030405060708090a0b0c0d0e0f");
+var plaintext = hexToArrayBuffer("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
+var extractable = true;
+
+debug("Importing a raw AES key from string literal...");
+crypto.subtle.importKey("raw", keyData, "aes-cbc", extractable, ["encrypt", "decrypt"]).then(function(result) {
+    key = result;
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'aes-cbc'");
+    shouldBe("key.algorithm.length", "176");
+    shouldBe("key.usages", "['encrypt', 'decrypt']");
+
+    debug("Using the key to encrypt plaintext...");
+    return crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext]);
+}).then(undefined, function(result) {
+    debug("Failed, as expected. Note that the spec doesn't appear to clearly define which step should fail."
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/aes-cbc-wrong-key-class-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-wrong-key-class-expected.txt
new file mode 100644 (file)
index 0000000..27bd653
--- /dev/null
@@ -0,0 +1,12 @@
+Test calling AES-CBC encrypt with a HMAC key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a raw HMAC key from string literal...
+Using the key to encrypt plaintext...
+PASS crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-wrong-key-class.html b/LayoutTests/crypto/subtle/aes-cbc-wrong-key-class.html
new file mode 100644 (file)
index 0000000..eeb733c
--- /dev/null
@@ -0,0 +1,36 @@
+<!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 calling AES-CBC encrypt with a HMAC key.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var iv = hexToArrayBuffer("000102030405060708090a0b0c0d0e0f");
+var plaintext = hexToArrayBuffer("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710");
+var hmacKey = asciiToArrayBuffer('a');
+var extractable = true;
+
+debug("Importing a raw HMAC key from string literal...");
+crypto.subtle.importKey("raw", hmacKey, {name: 'hmac', hash: {name: 'sha-1'}}, extractable, ["sign", "verify", "encrypt", "decrypt"]).then(function(result) {
+    key = result;
+    debug("Using the key to encrypt plaintext...");
+    shouldThrow('crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, key, [plaintext])')
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 7e3f4e9..75497a7 100644 (file)
@@ -1,4 +1,4 @@
-Test crypto.subtle.digest.
+Test HMAC sign and verify functions.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
index f56b855..705f9ca 100644 (file)
@@ -9,7 +9,7 @@
 <div id="console"></div>
 
 <script>
-description("Test crypto.subtle.digest.");
+description("Test HMAC sign and verify functions.");
 
 jsTestIsAsync = true;
 
index 4e0b5ff..384a502 100644 (file)
@@ -45,6 +45,16 @@ function asciiToArrayBuffer(str)
     return new Uint8Array(chars);
 }
 
+function hexToArrayBuffer(str)
+{
+    if (str.length % 2)
+        throw "Hex string lenght must be even";
+    var chars = [];
+    for (var i = 0; i < str.length; i += 2)
+        chars.push(parseInt(str.substr(i, 2), 16));
+    return new Uint8Array(chars);
+}
+
 function printRejectedResult(value)
 {
     debug("    rejected with value of " + value);
index f8bf196..75760c2 100644 (file)
@@ -1,3 +1,15 @@
+2013-11-01  Alexey Proskuryakov  <ap@apple.com>
+
+        Add WebCrypto AES-CBC
+        https://bugs.webkit.org/show_bug.cgi?id=123647
+
+        Reviewed by Anders Carlsson.
+
+        * wtf/FixedArray.h: (WTF::FixedArray::data): Added a const version of the function.
+
+        * wtf/Vector.h: Added a comment to Vector constructor about how it is different
+        from std::vector.
+
 2013-11-01  Joseph Pecoraro  <pecoraro@apple.com>
 
         Unreviewed extended attempt at Windows build fix after r158471.
index c50a12b..fe2c960 100644 (file)
@@ -45,6 +45,7 @@ public:
     }
 
     T* data() { return m_data; }
+    const T* data() const { return m_data; }
     size_t size() const { return Size; }
 
 private:
index 4d32585..0039597 100644 (file)
@@ -532,7 +532,8 @@ public:
     Vector()
     {
     }
-    
+
+    // Unlike in std::vector, this constructor does not initialize POD types.
     explicit Vector(size_t size)
         : Base(size, size)
     {
index 3908cc4..de4276f 100644 (file)
@@ -1,3 +1,85 @@
+2013-11-01  Alexey Proskuryakov  <ap@apple.com>
+
+        Add WebCrypto AES-CBC
+        https://bugs.webkit.org/show_bug.cgi?id=123647
+
+        Reviewed by Anders Carlsson.
+
+        Tests: crypto/subtle/aes-cbc-192-encrypt-decrypt.html
+               crypto/subtle/aes-cbc-256-encrypt-decrypt.html
+               crypto/subtle/aes-cbc-encrypt-decrypt-with-padding.html
+               crypto/subtle/aes-cbc-encrypt-decrypt.html
+               crypto/subtle/aes-cbc-invalid-length.html
+               crypto/subtle/aes-cbc-wrong-key-class.html
+
+        * WebCore.xcodeproj/project.pbxproj: Added new files.
+        * bindings/js/JSCryptoAlgorithmDictionary.cpp:
+        (WebCore::getProperty): Factored out a function to get a property as JSValue.
+        (WebCore::getHashAlgorithm): Use it.
+        (WebCore::createAesCbcParams): Added converter for AesCbcParams.
+        (WebCore::JSCryptoAlgorithmDictionary::createParametersForEncrypt): Support AES_CBC.
+        (WebCore::JSCryptoAlgorithmDictionary::createParametersForDecrypt): Ditto.
+        (WebCore::JSCryptoAlgorithmDictionary::createParametersForImportKey): Support all
+        algorithms, all the new ones just have trivial dictionaries.
+        (WebCore::JSCryptoAlgorithmDictionary::createParametersForExportKey): Ditto.
+
+        * bindings/js/JSCryptoOperationData.cpp: Added.
+        (WebCore::sequenceOfCryptoOperationDataFromJSValue):
+        (WebCore::cryptoOperationDataFromJSValue):
+        * bindings/js/JSCryptoOperationData.h: Added.
+        Moved CryptoOperationData bindings out of JSSubtleCryptoCustom.cpp, so that we
+        could use them in JSCryptoAlgorithmDictionary.cpp.
+
+        * bindings/js/JSDOMPromise.h: (WebCore::PromiseWrapper::reject): Added a specialization
+        to reject with null result. The spec doesn't actually say how algorithms fail.
+
+        * bindings/js/JSSubtleCryptoCustom.cpp:
+        (WebCore::JSSubtleCrypto::encrypt): Added.
+        (WebCore::JSSubtleCrypto::decrypt): Ditto.
+        (WebCore::JSSubtleCrypto::sign): Style fix.
+
+        * crypto/CryptoAlgorithmAesCbcParams.h: Added.
+
+        * crypto/CryptoKey.h:
+        (WebCore::CryptoKeyClass):
+        * crypto/keys/CryptoKeyHMAC.h:
+        (WebCore::asCryptoKeyHMAC):
+        Added poor man's RTTI, so that we can safely upcast Keys passed fro JavaScript code.
+
+        * crypto/CryptoKeyAES.cpp: Added.
+        (WebCore::CryptoKeyAES::CryptoKeyAES):
+        (WebCore::CryptoKeyAES::~CryptoKeyAES):
+        (WebCore::CryptoKeyAES::buildAlgorithmDescription):
+        * crypto/CryptoKeyAES.h: Added.
+        (WebCore::asCryptoKeyAES):
+        AES keys are the same for all algorithms, but they still need to remember the algorithm.
+
+        * crypto/SubtleCrypto.idl: Added encrypt/decrypt.
+
+        * crypto/algorithms/CryptoAlgorithmAES_CBC.cpp: Added.
+        (WebCore::CryptoAlgorithmAES_CBC::CryptoAlgorithmAES_CBC):
+        (WebCore::CryptoAlgorithmAES_CBC::~CryptoAlgorithmAES_CBC):
+        (WebCore::CryptoAlgorithmAES_CBC::create):
+        (WebCore::CryptoAlgorithmAES_CBC::identifier):
+        (WebCore::CryptoAlgorithmAES_CBC::importKey):
+        (WebCore::CryptoAlgorithmAES_CBC::exportKey):
+        * crypto/algorithms/CryptoAlgorithmAES_CBC.h: Added.
+        * crypto/mac/CryptoAlgorithmAES_CBCMac.cpp: Added.
+        (WebCore::transformAES_CBC):
+        (WebCore::CryptoAlgorithmAES_CBC::encrypt):
+        (WebCore::CryptoAlgorithmAES_CBC::decrypt):
+        (WebCore::CryptoAlgorithmAES_CBC::generateKey):
+        Added.
+
+        * crypto/mac/CryptoAlgorithmHMACMac.cpp:
+        (WebCore::CryptoAlgorithmHMAC::sign):
+        (WebCore::CryptoAlgorithmHMAC::verify):
+        Check key class before casting it to CryptoKeyHMAC.
+
+        * crypto/mac/CryptoAlgorithmRegistryMac.cpp:
+        (WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms): Register AES-CBC
+        on Mac, so that it can be used.
+
 2013-11-01  Andreas Kling  <akling@apple.com>
 
         SVGRenderStyle accessors should return references.
index cebc83f..51aff25 100644 (file)
                E125F8351822F18A00D84CD9 /* CryptoKeyHMAC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F8331822F18A00D84CD9 /* CryptoKeyHMAC.cpp */; };
                E125F8361822F18A00D84CD9 /* CryptoKeyHMAC.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F8341822F18A00D84CD9 /* CryptoKeyHMAC.h */; };
                E125F8381822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */; };
+               E125F83A1824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F8391824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h */; };
+               E125F83D182411E700D84CD9 /* JSCryptoOperationData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F83B182411E700D84CD9 /* JSCryptoOperationData.cpp */; };
+               E125F83E182411E700D84CD9 /* JSCryptoOperationData.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F83C182411E700D84CD9 /* JSCryptoOperationData.h */; };
+               E125F8411824253A00D84CD9 /* CryptoAlgorithmAES_CBC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F83F1824253A00D84CD9 /* CryptoAlgorithmAES_CBC.cpp */; };
+               E125F8421824253A00D84CD9 /* CryptoAlgorithmAES_CBC.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F8401824253A00D84CD9 /* CryptoAlgorithmAES_CBC.h */; };
+               E125F845182425C900D84CD9 /* CryptoAlgorithmAES_CBCMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F843182425C900D84CD9 /* CryptoAlgorithmAES_CBCMac.cpp */; };
+               E125F84D1824289D00D84CD9 /* CryptoKeyAES.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E125F84B1824289D00D84CD9 /* CryptoKeyAES.cpp */; };
+               E125F84E1824289D00D84CD9 /* CryptoKeyAES.h in Headers */ = {isa = PBXBuildFile; fileRef = E125F84C1824289D00D84CD9 /* CryptoKeyAES.h */; };
                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 */; };
                E125F8331822F18A00D84CD9 /* CryptoKeyHMAC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoKeyHMAC.cpp; path = keys/CryptoKeyHMAC.cpp; sourceTree = "<group>"; };
                E125F8341822F18A00D84CD9 /* CryptoKeyHMAC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoKeyHMAC.h; path = keys/CryptoKeyHMAC.h; sourceTree = "<group>"; };
                E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmHMACMac.cpp; path = mac/CryptoAlgorithmHMACMac.cpp; sourceTree = "<group>"; };
+               E125F8391824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmAesCbcParams.h; sourceTree = "<group>"; };
+               E125F83B182411E700D84CD9 /* JSCryptoOperationData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCryptoOperationData.cpp; sourceTree = "<group>"; };
+               E125F83C182411E700D84CD9 /* JSCryptoOperationData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCryptoOperationData.h; sourceTree = "<group>"; };
+               E125F83F1824253A00D84CD9 /* CryptoAlgorithmAES_CBC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmAES_CBC.cpp; sourceTree = "<group>"; };
+               E125F8401824253A00D84CD9 /* CryptoAlgorithmAES_CBC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmAES_CBC.h; sourceTree = "<group>"; };
+               E125F843182425C900D84CD9 /* CryptoAlgorithmAES_CBCMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmAES_CBCMac.cpp; path = mac/CryptoAlgorithmAES_CBCMac.cpp; sourceTree = "<group>"; };
+               E125F84B1824289D00D84CD9 /* CryptoKeyAES.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoKeyAES.cpp; sourceTree = "<group>"; };
+               E125F84C1824289D00D84CD9 /* CryptoKeyAES.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoKeyAES.h; 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>"; };
                                1C81BA040E97348300266E07 /* JavaScriptCallFrame.h */,
                                E157A8EE18185425009F821D /* JSCryptoAlgorithmBuilder.cpp */,
                                E157A8EF18185425009F821D /* JSCryptoAlgorithmBuilder.h */,
+                               E125F83B182411E700D84CD9 /* JSCryptoOperationData.cpp */,
+                               E125F83C182411E700D84CD9 /* JSCryptoOperationData.h */,
                                E1C657101815F9DD00256CDD /* JSCryptoAlgorithmDictionary.cpp */,
                                E1C657111815F9DD00256CDD /* JSCryptoAlgorithmDictionary.h */,
                                BCE438A1140C0DBF005E437E /* JSDictionary.cpp */,
                E172AF71180F343400FBADB9 /* mac */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F843182425C900D84CD9 /* CryptoAlgorithmAES_CBCMac.cpp */,
                                E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */,
                                E1BB84AC1822CA7400525043 /* CryptoAlgorithmRegistryMac.cpp */,
                                E125F82D1822CFFF00D84CD9 /* CryptoAlgorithmSHA1Mac.cpp */,
                E172AF7C180F3B0D00FBADB9 /* algorithms */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F83F1824253A00D84CD9 /* CryptoAlgorithmAES_CBC.cpp */,
+                               E125F8401824253A00D84CD9 /* CryptoAlgorithmAES_CBC.h */,
                                E125F82F1822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp */,
                                E125F8301822F11B00D84CD9 /* CryptoAlgorithmHMAC.h */,
                                E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */,
                E19DA29D181995CE00088BC8 /* keys */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F84B1824289D00D84CD9 /* CryptoKeyAES.cpp */,
+                               E125F84C1824289D00D84CD9 /* CryptoKeyAES.h */,
                                E125F8331822F18A00D84CD9 /* CryptoKeyHMAC.cpp */,
                                E125F8341822F18A00D84CD9 /* CryptoKeyHMAC.h */,
                        );
                E1C657141816015F00256CDD /* parameters */ = {
                        isa = PBXGroup;
                        children = (
+                               E125F8391824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h */,
                                E19DA29B18189ADD00088BC8 /* CryptoAlgorithmHmacKeyParams.h */,
                                E1C6571E1816E50300256CDD /* CryptoAlgorithmHmacParams.h */,
                        );
                                9B50B1DE17CD4C0F0087F63C /* FormNamedItem.h in Headers */,
                                1477E7770BF4134A00152872 /* PageCache.h in Headers */,
                                DAED203116F244480070EC0F /* PageConsole.h in Headers */,
+                               E125F83E182411E700D84CD9 /* JSCryptoOperationData.h in Headers */,
                                F3820893147D35F90010BC06 /* PageConsoleAgent.h in Headers */,
                                F34742DD134362F000531BC2 /* PageDebuggerAgent.h in Headers */,
                                9302B0BF0D79F82C00C7EE83 /* PageGroup.h in Headers */,
                                514C76750CE923A1007EF3CD /* ProtectionSpace.h in Headers */,
                                51A052561058874000CC9E95 /* ProtectionSpaceHash.h in Headers */,
                                1AF8E11A1256592600230FF7 /* ProxyServer.h in Headers */,
+                               E125F84E1824289D00D84CD9 /* CryptoKeyAES.h in Headers */,
                                FF945ECC161F7F3600971BC8 /* PseudoElement.h in Headers */,
                                0081FF0016B0A2D3008AAA7A /* PublicSuffix.h in Headers */,
                                10FB084B14E15C7E00A3DB98 /* PublicURLManager.h in Headers */,
                                379E371713736A6600B9E919 /* QuotedPrintable.h in Headers */,
                                5A574F29131DB96D00471B88 /* QuotesData.h in Headers */,
                                B22279720D00BF220071B782 /* RadialGradientAttributes.h in Headers */,
+                               E125F8421824253A00D84CD9 /* CryptoAlgorithmAES_CBC.h in Headers */,
                                F55B3DCC1251F12D003EF269 /* RadioInputType.h in Headers */,
                                B658FFA61522EFAA00DD5595 /* RadioNodeList.h in Headers */,
                                93F1991808245E59001E9ABC /* Range.h in Headers */,
                                14476AA815DC4BB100305DB2 /* WritingMode.h in Headers */,
                                6565820209D1508D000E61D7 /* XLinkNames.h in Headers */,
                                00B9318813BA8DBA0035A948 /* XMLDocumentParser.h in Headers */,
+                               E125F83A1824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h in Headers */,
                                00B9318C13BA8DCC0035A948 /* XMLDocumentParserScope.h in Headers */,
                                59C28046138DC2410079B7E2 /* XMLErrors.h in Headers */,
                                BC772C470C4EB2C60083285F /* XMLHttpRequest.h in Headers */,
                                07C59B6817F784BA000FBCBB /* MediaSourceStates.cpp in Sources */,
                                859A9C4A0AA5E3BD00B694B2 /* DOMHTMLBodyElement.mm in Sources */,
                                85183B430AA6926100F19FA3 /* DOMHTMLBRElement.mm in Sources */,
+                               E125F84D1824289D00D84CD9 /* CryptoKeyAES.cpp in Sources */,
                                85BA4CDE0AA6861B0088052D /* DOMHTMLButtonElement.mm in Sources */,
                                93F9B6570BA0F35E00854064 /* DOMHTMLCanvasElement.mm in Sources */,
                                85DF2F8F0AA3C88100AD64C5 /* DOMHTMLCollection.mm in Sources */,
                                511EF2C717F0FD3500E4FA16 /* JSIDBObjectStore.cpp in Sources */,
                                BC94D14E0C275C68006BC617 /* JSHistory.cpp in Sources */,
                                BCE7B1930D4E86960075A539 /* JSHistoryCustom.cpp in Sources */,
+                               E125F83D182411E700D84CD9 /* JSCryptoOperationData.cpp in Sources */,
                                BC97E412109154FA0010D361 /* JSHTMLAllCollection.cpp in Sources */,
                                BC97E42C10915B060010D361 /* JSHTMLAllCollectionCustom.cpp in Sources */,
                                1A4A2DEF0A1B852A00C807F8 /* JSHTMLAnchorElement.cpp in Sources */,
                                97BC84831236FD93000C6161 /* TextDocumentParser.cpp in Sources */,
                                B2C3DA460D006C1D00EF6F26 /* TextEncoding.cpp in Sources */,
                                C105DA620F3AA68F001DD44F /* TextEncodingDetectorICU.cpp in Sources */,
+                               E125F8411824253A00D84CD9 /* CryptoAlgorithmAES_CBC.cpp in Sources */,
                                B2C3DA480D006C1D00EF6F26 /* TextEncodingRegistry.cpp in Sources */,
                                933A142E0B7D188600A53FFD /* TextEvent.cpp in Sources */,
                                F55B3DD71251F12D003EF269 /* TextFieldInputType.cpp in Sources */,
                                FD3160AE12B026F700C1A359 /* VectorMath.cpp in Sources */,
                                BE88E0DE1715D2A200658D98 /* VideoTrack.cpp in Sources */,
                                BE88E0E11715D2A200658D98 /* VideoTrackList.cpp in Sources */,
+                               E125F845182425C900D84CD9 /* CryptoAlgorithmAES_CBCMac.cpp in Sources */,
                                CEF418CE1179678C009D112C /* ViewportArguments.cpp in Sources */,
                                3FFFF9AD159D9B060020BBD5 /* ViewportStyleResolver.cpp in Sources */,
                                93309E1F099E64920056E581 /* VisiblePosition.cpp in Sources */,
index f734985..d9a09a5 100644 (file)
 
 #if ENABLE(SUBTLE_CRYPTO)
 
+#include "CryptoAlgorithmAesCbcParams.h"
 #include "CryptoAlgorithmHmacKeyParams.h"
 #include "CryptoAlgorithmHmacParams.h"
 #include "CryptoAlgorithmRegistry.h"
 #include "ExceptionCode.h"
+#include "JSCryptoOperationData.h"
 #include "JSDOMBinding.h"
 #include "JSDictionary.h"
 
@@ -80,6 +82,17 @@ bool JSCryptoAlgorithmDictionary::getAlgorithmIdentifier(ExecState* exec, JSValu
     return true;
 }
 
+static JSValue getProperty(ExecState* exec, JSObject* object, const char* name)
+{
+    Identifier identifier(exec, name);
+    PropertySlot slot(object);
+
+    if (object->getPropertySlot(exec, identifier, slot))
+        return slot.getValue(exec, identifier);
+
+    return jsUndefined();
+}
+
 static bool getHashAlgorithm(JSDictionary& dictionary, CryptoAlgorithmIdentifier& result)
 {
     // FXIME: Teach JSDictionary how to return JSValues, and use that to get hash element value.
@@ -90,15 +103,9 @@ static bool getHashAlgorithm(JSDictionary& dictionary, CryptoAlgorithmIdentifier
     Identifier identifier(exec, "hash");
     PropertySlot slot(object);
 
-    JSValue hash = jsUndefined();
-    if (object->getPropertySlot(exec, identifier, slot)) {
-        if (exec->hadException())
-            return false;
-
-        hash = slot.getValue(exec, identifier);
-        if (exec->hadException())
-            return false;
-    }
+    JSValue hash = getProperty(exec, object, "hash");
+    if (exec->hadException())
+        return false;
 
     if (hash.isUndefinedOrNull()) {
         setDOMException(exec, NOT_SUPPORTED_ERR);
@@ -108,6 +115,35 @@ static bool getHashAlgorithm(JSDictionary& dictionary, CryptoAlgorithmIdentifier
     return JSCryptoAlgorithmDictionary::getAlgorithmIdentifier(exec, hash, result);
 }
 
+static std::unique_ptr<CryptoAlgorithmParameters> createAesCbcParams(JSC::ExecState* exec, JSC::JSValue value)
+{
+    if (!value.isObject()) {
+        throwTypeError(exec);
+        return nullptr;
+    }
+
+    JSValue iv = getProperty(exec, value.getObject(), "iv");
+    if (exec->hadException())
+        return nullptr;
+
+    std::unique_ptr<CryptoAlgorithmAesCbcParams> result = std::make_unique<CryptoAlgorithmAesCbcParams>();
+
+    CryptoOperationData ivData;
+    if (!cryptoOperationDataFromJSValue(exec, iv, ivData)) {
+        ASSERT(exec->hadException());
+        return nullptr;
+    }
+
+    if (ivData.second != 16) {
+        exec->vm().throwException(exec, createError(exec, "AES-CBC initialization data must be 16 bytes"));
+        return nullptr;
+    }
+
+    memcpy(result->iv.data(), ivData.first, ivData.second);
+
+    return std::move(result);
+}
+
 static std::unique_ptr<CryptoAlgorithmParameters> createHmacParams(JSC::ExecState* exec, JSC::JSValue value)
 {
     if (!value.isObject()) {
@@ -148,7 +184,7 @@ static std::unique_ptr<CryptoAlgorithmParameters> createHmacKeyParams(JSC::ExecS
     return std::move(result);
 }
 
-std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForEncrypt(JSC::ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSC::JSValue)
+std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForEncrypt(JSC::ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSC::JSValue value)
 {
     switch (algorithm) {
     case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
@@ -158,7 +194,10 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     case CryptoAlgorithmIdentifier::ECDSA:
     case CryptoAlgorithmIdentifier::ECDH:
     case CryptoAlgorithmIdentifier::AES_CTR:
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return nullptr;
     case CryptoAlgorithmIdentifier::AES_CBC:
+        return createAesCbcParams(exec, value);
     case CryptoAlgorithmIdentifier::AES_CMAC:
     case CryptoAlgorithmIdentifier::AES_GCM:
     case CryptoAlgorithmIdentifier::AES_CFB:
@@ -177,7 +216,7 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     }
 }
 
-std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForDecrypt(JSC::ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSC::JSValue)
+std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForDecrypt(JSC::ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSC::JSValue value)
 {
     switch (algorithm) {
     case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
@@ -187,7 +226,10 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     case CryptoAlgorithmIdentifier::ECDSA:
     case CryptoAlgorithmIdentifier::ECDH:
     case CryptoAlgorithmIdentifier::AES_CTR:
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return nullptr;
     case CryptoAlgorithmIdentifier::AES_CBC:
+        return createAesCbcParams(exec, value);
     case CryptoAlgorithmIdentifier::AES_CMAC:
     case CryptoAlgorithmIdentifier::AES_GCM:
     case CryptoAlgorithmIdentifier::AES_CFB:
@@ -403,11 +445,11 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     case CryptoAlgorithmIdentifier::AES_CMAC:
     case CryptoAlgorithmIdentifier::AES_GCM:
     case CryptoAlgorithmIdentifier::AES_CFB:
-        setDOMException(exec, NOT_SUPPORTED_ERR);
-        return nullptr;
+        return std::make_unique<CryptoAlgorithmParameters>();
     case CryptoAlgorithmIdentifier::HMAC:
         return createHmacKeyParams(exec, value);
     case CryptoAlgorithmIdentifier::DH:
+        return std::make_unique<CryptoAlgorithmParameters>();
     case CryptoAlgorithmIdentifier::SHA_1:
     case CryptoAlgorithmIdentifier::SHA_224:
     case CryptoAlgorithmIdentifier::SHA_256:
@@ -437,6 +479,7 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     case CryptoAlgorithmIdentifier::AES_CFB:
     case CryptoAlgorithmIdentifier::HMAC:
     case CryptoAlgorithmIdentifier::DH:
+        return std::make_unique<CryptoAlgorithmParameters>();
     case CryptoAlgorithmIdentifier::SHA_1:
     case CryptoAlgorithmIdentifier::SHA_224:
     case CryptoAlgorithmIdentifier::SHA_256:
diff --git a/Source/WebCore/bindings/js/JSCryptoOperationData.cpp b/Source/WebCore/bindings/js/JSCryptoOperationData.cpp
new file mode 100644 (file)
index 0000000..59bff01
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 "JSCryptoOperationData.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "JSDOMBinding.h"
+
+using namespace JSC;
+
+namespace WebCore {
+
+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;
+}
+
+bool cryptoOperationDataFromJSValue(ExecState* exec, JSValue value, CryptoOperationData& result)
+{
+    if (ArrayBuffer* buffer = toArrayBuffer(value))
+        result = std::make_pair(static_cast<char*>(buffer->data()), buffer->byteLength());
+    else if (RefPtr<ArrayBufferView> bufferView = toArrayBufferView(value))
+        result = std::make_pair(static_cast<char*>(bufferView->baseAddress()), bufferView->byteLength());
+    else {
+        throwTypeError(exec, "Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData");
+        return false;
+    }
+    return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/bindings/js/JSCryptoOperationData.h b/Source/WebCore/bindings/js/JSCryptoOperationData.h
new file mode 100644 (file)
index 0000000..a9e2333
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 JSCryptoOperationData_h
+#define JSCryptoOperationData_h
+
+#include <wtf/Vector.h>
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace JSC {
+class ExecState;
+class JSValue;
+}
+
+namespace WebCore {
+
+typedef std::pair<const char*, size_t> CryptoOperationData;
+
+bool sequenceOfCryptoOperationDataFromJSValue(JSC::ExecState*, JSC::JSValue, Vector<CryptoOperationData>&);
+bool cryptoOperationDataFromJSValue(JSC::ExecState*, JSC::JSValue, CryptoOperationData&);
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+#endif // JSCryptoOperationData_h
index 8dec5f1..2864716 100644 (file)
@@ -73,6 +73,13 @@ inline void PromiseWrapper::reject(const RejectResultType& result)
 }
 
 template<>
+inline void PromiseWrapper::reject(const std::nullptr_t&)
+{
+    JSC::ExecState* exec = m_globalObject->globalExec();
+    m_promise->resolver()->rejectIfNotResolved(exec, JSC::jsNull());
+}
+
+template<>
 inline void PromiseWrapper::fulfill<String>(const String& result)
 {
     JSC::ExecState* exec = m_globalObject->globalExec();
index 96eed48..b143ead 100644 (file)
@@ -34,6 +34,7 @@
 #include "Document.h"
 #include "ExceptionCode.h"
 #include "JSCryptoAlgorithmDictionary.h"
+#include "JSCryptoOperationData.h"
 #include "JSDOMPromise.h"
 #include <runtime/Error.h>
 
@@ -55,42 +56,6 @@ static std::unique_ptr<CryptoAlgorithm> createAlgorithmFromJSValue(ExecState* ex
     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;
-}
-
-static bool cryptoOperationDataFromJSValue(ExecState* exec, JSValue value, CryptoOperationData& result)
-{
-    if (ArrayBuffer* buffer = toArrayBuffer(value))
-        result = std::make_pair(static_cast<char*>(buffer->data()), buffer->byteLength());
-    else if (RefPtr<ArrayBufferView> bufferView = toArrayBufferView(value))
-        result = 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;
-}
-
 static bool cryptoKeyFormatFromJSValue(ExecState* exec, JSValue value, CryptoKeyFormat& result)
 {
     String keyFormatString = value.toString(exec)->value(exec);
@@ -146,6 +111,98 @@ static bool cryptoKeyUsagesFromJSValue(ExecState* exec, JSValue value, CryptoKey
     return true;
 }
 
+JSValue JSSubtleCrypto::encrypt(ExecState* exec)
+{
+    if (exec->argumentCount() < 3)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    if (!algorithm) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
+    if (!key)
+        return throwTypeError(exec);
+
+    if (!key->allows(CryptoKeyUsageEncrypt)) {
+        m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'encrypt'");
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return jsUndefined();
+    }
+
+    Vector<CryptoOperationData> data;
+    if (!sequenceOfCryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), data)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->encrypt(*parameters, *key, data, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
+JSValue JSSubtleCrypto::decrypt(ExecState* exec)
+{
+    if (exec->argumentCount() < 3)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    if (!algorithm) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
+    if (!key)
+        return throwTypeError(exec);
+
+    if (!key->allows(CryptoKeyUsageDecrypt)) {
+        m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'decrypt'");
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return jsUndefined();
+    }
+
+    Vector<CryptoOperationData> data;
+    if (!sequenceOfCryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), data)) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->decrypt(*parameters, *key, data, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
 JSValue JSSubtleCrypto::sign(ExecState* exec)
 {
     if (exec->argumentCount() < 3)
@@ -183,7 +240,7 @@ JSValue JSSubtleCrypto::sign(ExecState* exec)
     auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
 
     ExceptionCode ec = 0;
-    algorithm->sign(*parameters, *key.get(), data, std::move(promiseWrapper), ec);
+    algorithm->sign(*parameters, *key, data, std::move(promiseWrapper), ec);
     if (ec) {
         setDOMException(exec, ec);
         return jsUndefined();
diff --git a/Source/WebCore/crypto/CryptoAlgorithmAesCbcParams.h b/Source/WebCore/crypto/CryptoAlgorithmAesCbcParams.h
new file mode 100644 (file)
index 0000000..ce65468
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 CryptoAlgorithmAesCbcParams_h
+#define CryptoAlgorithmAesCbcParams_h
+
+#include "CryptoAlgorithmParameters.h"
+#include <wtf/FixedArray.h>
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoAlgorithmAesCbcParams FINAL : public CryptoAlgorithmParameters {
+public:
+    // The initialization vector. MUST be 16 bytes.
+    FixedArray<char, 16> iv;
+};
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+#endif // CryptoAlgorithmAesCbcParams_h
index 10a271d..a43accb 100644 (file)
@@ -39,11 +39,18 @@ namespace WebCore {
 
 class CryptoAlgorithmDescriptionBuilder;
 
+ENUM_CLASS(CryptoKeyClass) {
+    HMAC,
+    AES
+};
+
 class CryptoKey : public RefCounted<CryptoKey> {
 public:
     CryptoKey(CryptoAlgorithmIdentifier, CryptoKeyType, bool extractable, CryptoKeyUsage);
     virtual ~CryptoKey();
 
+    virtual CryptoKeyClass keyClass() const = 0;
+
     String type() const;
     bool extractable() const { return m_extractable; }
     virtual void buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder&) const;
diff --git a/Source/WebCore/crypto/CryptoKeyAES.cpp b/Source/WebCore/crypto/CryptoKeyAES.cpp
new file mode 100644 (file)
index 0000000..6743026
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 "CryptoKeyAES.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CryptoAlgorithmDescriptionBuilder.h"
+#include "CryptoAlgorithmRegistry.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+CryptoKeyAES::CryptoKeyAES(CryptoAlgorithmIdentifier algorithm, const Vector<char>& key, bool extractable, CryptoKeyUsage usage)
+    : CryptoKey(algorithm, CryptoKeyType::Secret, extractable, usage)
+    , m_key(key)
+{
+    ASSERT(algorithm == CryptoAlgorithmIdentifier::AES_CTR
+        || algorithm == CryptoAlgorithmIdentifier::AES_CBC
+        || algorithm == CryptoAlgorithmIdentifier::AES_CMAC
+        || algorithm == CryptoAlgorithmIdentifier::AES_GCM
+        || algorithm == CryptoAlgorithmIdentifier::AES_CFB);
+}
+
+CryptoKeyAES::~CryptoKeyAES()
+{
+}
+
+void CryptoKeyAES::buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder& builder) const
+{
+    CryptoKey::buildAlgorithmDescription(builder);
+    builder.add("length", m_key.size() * 8);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/CryptoKeyAES.h b/Source/WebCore/crypto/CryptoKeyAES.h
new file mode 100644 (file)
index 0000000..8f96430
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 CryptoKeyAES_h
+#define CryptoKeyAES_h
+
+#include "CryptoAlgorithmIdentifier.h"
+#include "CryptoKey.h"
+#include <wtf/Vector.h>
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoKeyAES FINAL : public CryptoKey {
+public:
+    static PassRefPtr<CryptoKeyAES> create(CryptoAlgorithmIdentifier algorithm, const Vector<char>& key, bool extractable, CryptoKeyUsage usage)
+    {
+        return adoptRef(new CryptoKeyAES(algorithm, key, extractable, usage));
+    }
+    virtual ~CryptoKeyAES();
+
+    virtual CryptoKeyClass keyClass() const OVERRIDE { return CryptoKeyClass::AES; }
+
+    const Vector<char>& key() const { return m_key; }
+
+    virtual void buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder&) const OVERRIDE;
+
+private:
+    CryptoKeyAES(CryptoAlgorithmIdentifier, const Vector<char>& key, bool extractable, CryptoKeyUsage);
+
+    Vector<char> m_key;
+};
+
+inline const CryptoKeyAES* asCryptoKeyAES(const CryptoKey& key)
+{
+    if (key.keyClass() != CryptoKeyClass::AES)
+        return nullptr;
+    return static_cast<const CryptoKeyAES*>(&key);
+}
+
+inline CryptoKeyAES* asCryptoKeyAES(CryptoKey& key)
+{
+    if (key.keyClass() != CryptoKeyClass::AES)
+        return nullptr;
+    return static_cast<CryptoKeyAES*>(&key);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+
+
+#endif // CryptoKeyAES_h
index d00c4df..c690395 100644 (file)
@@ -30,6 +30,8 @@
     NoInterfaceObject,
     OperationsNotDeletable
 ] interface SubtleCrypto {
+    [Custom] Promise encrypt(AlgorithmIdentifier algorithm, Key key, sequence<CryptoOperationData> data);
+    [Custom] Promise decrypt(AlgorithmIdentifier algorithm, Key key, sequence<CryptoOperationData> data);
     [Custom] Promise sign(AlgorithmIdentifier algorithm, Key key, sequence<CryptoOperationData> data);
     [Custom] Promise verify(AlgorithmIdentifier algorithm, Key key, CryptoOperationData signature, sequence<CryptoOperationData> data);
     [Custom] Promise digest(AlgorithmIdentifier algorithm, sequence<CryptoOperationData> data);
diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.cpp b/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.cpp
new file mode 100644 (file)
index 0000000..53ab65a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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 "CryptoAlgorithmAES_CBC.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CryptoAlgorithmAesCbcParams.h"
+#include "CryptoKeyAES.h"
+#include "ExceptionCode.h"
+#include "JSDOMPromise.h"
+
+namespace WebCore {
+
+const char* const CryptoAlgorithmAES_CBC::s_name = "aes-cbc";
+
+CryptoAlgorithmAES_CBC::CryptoAlgorithmAES_CBC()
+{
+}
+
+CryptoAlgorithmAES_CBC::~CryptoAlgorithmAES_CBC()
+{
+}
+
+std::unique_ptr<CryptoAlgorithm> CryptoAlgorithmAES_CBC::create()
+{
+    return std::unique_ptr<CryptoAlgorithm>(new CryptoAlgorithmAES_CBC);
+}
+
+CryptoAlgorithmIdentifier CryptoAlgorithmAES_CBC::identifier() const
+{
+    return s_identifier;
+}
+
+void CryptoAlgorithmAES_CBC::importKey(const CryptoAlgorithmParameters&, CryptoKeyFormat format, const CryptoOperationData& data, bool extractable, CryptoKeyUsage usage, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
+{
+    if (format != CryptoKeyFormat::Raw) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+    Vector<char> keyData;
+    keyData.append(data.first, data.second);
+    RefPtr<CryptoKeyAES> result = CryptoKeyAES::create(CryptoAlgorithmIdentifier::AES_CBC, keyData, extractable, usage);
+    promise->fulfill(result.release());
+}
+
+void CryptoAlgorithmAES_CBC::exportKey(const CryptoAlgorithmParameters&, CryptoKeyFormat, const CryptoKey&, std::unique_ptr<PromiseWrapper>, ExceptionCode& ec)
+{
+    // Not implemented yet.
+    ec = NOT_SUPPORTED_ERR;
+}
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h b/Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.h
new file mode 100644 (file)
index 0000000..65b9bbb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 CryptoAlgorithmAES_CBC_h
+#define CryptoAlgorithmAES_CBC_h
+
+#include "CryptoAlgorithm.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoAlgorithmAES_CBC FINAL : public CryptoAlgorithm {
+public:
+    static const char* const s_name;
+    static const CryptoAlgorithmIdentifier s_identifier = CryptoAlgorithmIdentifier::AES_CBC;
+
+    static std::unique_ptr<CryptoAlgorithm> create();
+
+    virtual CryptoAlgorithmIdentifier identifier() const OVERRIDE;
+
+    virtual void encrypt(const CryptoAlgorithmParameters&, const CryptoKey&, const Vector<CryptoOperationData>&, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void decrypt(const CryptoAlgorithmParameters&, const CryptoKey&, const Vector<CryptoOperationData>&, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void generateKey(const CryptoAlgorithmParameters&, bool extractable, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void importKey(const CryptoAlgorithmParameters&, CryptoKeyFormat, const CryptoOperationData&, bool extractable, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+    virtual void exportKey(const CryptoAlgorithmParameters&, CryptoKeyFormat, const CryptoKey&, std::unique_ptr<PromiseWrapper>, ExceptionCode&) OVERRIDE;
+
+private:
+    CryptoAlgorithmAES_CBC();
+    virtual ~CryptoAlgorithmAES_CBC();
+};
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+
+#endif // CryptoAlgorithmAES_CBC_h
index 57dd31d..96de3a5 100644 (file)
@@ -27,7 +27,6 @@
 #define CryptoKeyHMAC_h
 
 #include "CryptoKey.h"
-#include <wtf/Ref.h>
 #include <wtf/Vector.h>
 
 #if ENABLE(SUBTLE_CRYPTO)
@@ -42,6 +41,8 @@ public:
     }
     virtual ~CryptoKeyHMAC();
 
+    virtual CryptoKeyClass keyClass() const OVERRIDE { return CryptoKeyClass::HMAC; }
+
     const Vector<char>& key() const { return m_key; }
 
     virtual void buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder&) const OVERRIDE;
@@ -53,6 +54,20 @@ private:
     Vector<char> m_key;
 };
 
+inline const CryptoKeyHMAC* asCryptoKeyHMAC(const CryptoKey& key)
+{
+    if (key.keyClass() != CryptoKeyClass::HMAC)
+        return nullptr;
+    return static_cast<const CryptoKeyHMAC*>(&key);
+}
+
+inline CryptoKeyHMAC* asCryptoKeyHMAC(CryptoKey& key)
+{
+    if (key.keyClass() != CryptoKeyClass::HMAC)
+        return nullptr;
+    return static_cast<CryptoKeyHMAC*>(&key);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp b/Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp
new file mode 100644 (file)
index 0000000..97cfe55
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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 "CryptoAlgorithmAES_CBC.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CryptoAlgorithmAesCbcParams.h"
+#include "CryptoKeyAES.h"
+#include "ExceptionCode.h"
+#include "JSDOMPromise.h"
+#include <CommonCrypto/CommonCrypto.h>
+
+namespace WebCore {
+
+static void transformAES_CBC(CCOperation operation, const CryptoAlgorithmAesCbcParams& parameters, const CryptoKeyAES& key, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise)
+{
+    static_assert(sizeof(parameters.iv) == kCCBlockSizeAES128, "Initialization vector size must be the same as algorithm block size");
+
+    size_t keyLengthInBytes = key.key().size();
+    if (keyLengthInBytes != 16 && keyLengthInBytes != 24 && keyLengthInBytes != 32) {
+        promise->reject(nullptr);
+        return;
+    }
+
+    CCCryptorRef cryptor;
+#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    CCAlgorithm aesAlgorithm = kCCAlgorithmAES;
+#else
+    CCAlgorithm aesAlgorithm = kCCAlgorithmAES128;
+#endif
+    CCCryptorStatus status = CCCryptorCreate(operation, aesAlgorithm, kCCOptionPKCS7Padding, key.key().data(), keyLengthInBytes, parameters.iv.data(), &cryptor);
+    if (status) {
+        promise->reject(nullptr);
+        return;
+    }
+
+    size_t inputSize = 0;
+    for (size_t i = 0, size = data.size(); i < size; ++i)
+        inputSize += data[i].second;
+
+    Vector<unsigned char> result(CCCryptorGetOutputLength(cryptor, inputSize, true));
+
+    unsigned char* p = result.data();
+    size_t resultChunkSize;
+    for (size_t i = 0, size = data.size(); i < size; ++i) {
+        status = CCCryptorUpdate(cryptor, data[i].first, data[i].second, p, result.end() - p, &resultChunkSize);
+        if (status) {
+            promise->reject(nullptr);
+            return;
+        }
+        p += resultChunkSize;
+    }
+    status = CCCryptorFinal(cryptor, p, result.end() - p, &resultChunkSize);
+    p += resultChunkSize;
+    if (status) {
+        promise->reject(nullptr);
+        return;
+    }
+
+    ASSERT(p <= result.end());
+    result.shrink(p - result.begin());
+
+    CCCryptorRelease(cryptor);
+
+    promise->fulfill(result);
+}
+
+void CryptoAlgorithmAES_CBC::encrypt(const CryptoAlgorithmParameters& parameters, const CryptoKey& key, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
+{
+    const CryptoAlgorithmAesCbcParams& aesCBCParameters = static_cast<const CryptoAlgorithmAesCbcParams&>(parameters);
+    const CryptoKeyAES* aesKey = asCryptoKeyAES(key);
+
+    if (!aesKey) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    transformAES_CBC(kCCEncrypt, aesCBCParameters, *aesKey, data, std::move(promise));
+}
+
+void CryptoAlgorithmAES_CBC::decrypt(const CryptoAlgorithmParameters& parameters, const CryptoKey& key, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
+{
+    const CryptoAlgorithmAesCbcParams& aesCBCParameters = static_cast<const CryptoAlgorithmAesCbcParams&>(parameters);
+    const CryptoKeyAES* aesKey = asCryptoKeyAES(key);
+
+    if (!aesKey) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    transformAES_CBC(kCCDecrypt, aesCBCParameters, *aesKey, data, std::move(promise));
+}
+
+void CryptoAlgorithmAES_CBC::generateKey(const CryptoAlgorithmParameters&, bool /*extractable*/, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode& ec)
+{
+    // Not yet implemented.
+    ec = NOT_SUPPORTED_ERR;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
index a8146eb..33b5227 100644 (file)
@@ -95,7 +95,7 @@ static Vector<unsigned char> calculateSignature(CCHmacAlgorithm algorithm, const
 void CryptoAlgorithmHMAC::sign(const CryptoAlgorithmParameters& parameters, const CryptoKey& key, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
 {
     const CryptoAlgorithmHmacParams& hmacParameters = static_cast<const CryptoAlgorithmHmacParams&>(parameters);
-    const CryptoKeyHMAC& hmacKey = static_cast<const CryptoKeyHMAC&>(key);
+    const CryptoKeyHMAC* hmacKey = asCryptoKeyHMAC(key);
 
     CCHmacAlgorithm algorithm;
     if (!getCommonCryptoAlgorithm(hmacParameters.hash, algorithm)) {
@@ -103,7 +103,12 @@ void CryptoAlgorithmHMAC::sign(const CryptoAlgorithmParameters& parameters, cons
         return;
     }
 
-    Vector<unsigned char> signature = calculateSignature(algorithm, hmacKey.key(), data);
+    if (!hmacKey) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    Vector<unsigned char> signature = calculateSignature(algorithm, hmacKey->key(), data);
 
     promise->fulfill(signature);
 }
@@ -111,7 +116,7 @@ void CryptoAlgorithmHMAC::sign(const CryptoAlgorithmParameters& parameters, cons
 void CryptoAlgorithmHMAC::verify(const CryptoAlgorithmParameters& parameters, const CryptoKey& key, const CryptoOperationData& expectedSignature, const Vector<CryptoOperationData>& data, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
 {
     const CryptoAlgorithmHmacParams& hmacParameters = static_cast<const CryptoAlgorithmHmacParams&>(parameters);
-    const CryptoKeyHMAC& hmacKey = static_cast<const CryptoKeyHMAC&>(key);
+    const CryptoKeyHMAC* hmacKey = asCryptoKeyHMAC(key);
 
     CCHmacAlgorithm algorithm;
     if (!getCommonCryptoAlgorithm(hmacParameters.hash, algorithm)) {
@@ -119,7 +124,12 @@ void CryptoAlgorithmHMAC::verify(const CryptoAlgorithmParameters& parameters, co
         return;
     }
 
-    Vector<unsigned char> signature = calculateSignature(algorithm, hmacKey.key(), data);
+    if (!hmacKey) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    Vector<unsigned char> signature = calculateSignature(algorithm, hmacKey->key(), data);
 
     bool result = signature.size() == expectedSignature.second && !memcmp(signature.data(), expectedSignature.first, signature.size());
 
index c5cbdfc..56ac304 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(SUBTLE_CRYPTO)
 
+#include "CryptoAlgorithmAES_CBC.h"
 #include "CryptoAlgorithmHMAC.h"
 #include "CryptoAlgorithmSHA1.h"
 
@@ -35,6 +36,7 @@ namespace WebCore {
 
 void CryptoAlgorithmRegistry::platformRegisterAlgorithms()
 {
+    registerAlgorithm(CryptoAlgorithmAES_CBC::s_name, CryptoAlgorithmAES_CBC::s_identifier, CryptoAlgorithmAES_CBC::create);
     registerAlgorithm(CryptoAlgorithmHMAC::s_name, CryptoAlgorithmHMAC::s_identifier, CryptoAlgorithmHMAC::create);
     registerAlgorithm(CryptoAlgorithmSHA1::s_name, CryptoAlgorithmSHA1::s_identifier, CryptoAlgorithmSHA1::create);
 }