Implement generateKey for HMAC and AES-CBC
authorap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 3 Nov 2013 06:58:53 +0000 (06:58 +0000)
committerap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 3 Nov 2013 06:58:53 +0000 (06:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123669

Reviewed by Dan Bernstein.

Source/WebCore:

Tests: crypto/subtle/aes-cbc-generate-key.html
       crypto/subtle/hmac-generate-key.html

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

* bindings/js/JSCryptoAlgorithmDictionary.cpp:
(WebCore::createAesKeyGenParams): Added bindings for AesKeyGenParams.
(WebCore::JSCryptoAlgorithmDictionary::createParametersForGenerateKey): Handle
algorithms that generate AES and HMAC keys.

* bindings/js/JSSubtleCryptoCustom.cpp: (WebCore::JSSubtleCrypto::generateKey): Added.

* crypto/CryptoAlgorithmAesKeyGenParams.h: Added.

* crypto/CryptoKey.cpp: (WebCore::CryptoKey::randomData):
* crypto/CryptoKey.h:
* crypto/CryptoKeyMac.cpp: Added
Expose a function that produces random data for symmetric crypto keys. Cross-platform
implementation uses ARC4 code from WTF, while Mac uses a system function that
provides a FIPS validated random number generator.

* crypto/CryptoKeyAES.cpp: (WebCore::CryptoKeyAES::generate):
* crypto/CryptoKeyAES.h:
Added a function that creates AES keys.

* crypto/SubtleCrypto.idl: Added generateKey.

* crypto/algorithms/CryptoAlgorithmAES_CBC.cpp:
(WebCore::CryptoAlgorithmAES_CBC::generateKey): Added.

* crypto/algorithms/CryptoAlgorithmHMAC.cpp:
(WebCore::CryptoAlgorithmHMAC::generateKey): Added.

* crypto/keys/CryptoKeyHMAC.cpp: (WebCore::CryptoKeyHMAC::generate):
* crypto/keys/CryptoKeyHMAC.h:
Added a function that creates HMAC keys.

* crypto/mac/CryptoAlgorithmAES_CBCMac.cpp: Removed generateKey stub, the implementation
ended up in cross-platform file.

* crypto/mac/CryptoAlgorithmHMACMac.cpp: Ditto.

LayoutTests:

* crypto/subtle/aes-cbc-generate-key-expected.txt: Added.
* crypto/subtle/aes-cbc-generate-key.html: Added.
* crypto/subtle/hmac-generate-key-expected.txt: Added.
* crypto/subtle/hmac-generate-key.html: Added.

* crypto/subtle/sha-1-expected.txt: Now that crypto.webkitSubtle.generateKey exists,
a different exception is raised.

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/crypto/subtle/aes-cbc-generate-key-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/aes-cbc-generate-key.html [new file with mode: 0644]
LayoutTests/crypto/subtle/hmac-generate-key-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/hmac-generate-key.html [new file with mode: 0644]
LayoutTests/crypto/subtle/sha-1-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.cpp
Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
Source/WebCore/crypto/CryptoAlgorithmAesKeyGenParams.h [new file with mode: 0644]
Source/WebCore/crypto/CryptoKey.cpp
Source/WebCore/crypto/CryptoKey.h
Source/WebCore/crypto/CryptoKeyAES.cpp
Source/WebCore/crypto/CryptoKeyAES.h
Source/WebCore/crypto/CryptoKeyMac.cpp [new file with mode: 0644]
Source/WebCore/crypto/SubtleCrypto.idl
Source/WebCore/crypto/algorithms/CryptoAlgorithmAES_CBC.cpp
Source/WebCore/crypto/algorithms/CryptoAlgorithmHMAC.cpp
Source/WebCore/crypto/keys/CryptoKeyHMAC.cpp
Source/WebCore/crypto/keys/CryptoKeyHMAC.h
Source/WebCore/crypto/mac/CryptoAlgorithmAES_CBCMac.cpp
Source/WebCore/crypto/mac/CryptoAlgorithmHMACMac.cpp

index d2f2656..2f562c7 100644 (file)
@@ -1,3 +1,18 @@
+2013-11-02  Alexey Proskuryakov  <ap@apple.com>
+
+        Implement generateKey for HMAC and AES-CBC
+        https://bugs.webkit.org/show_bug.cgi?id=123669
+
+        Reviewed by Dan Bernstein.
+
+        * crypto/subtle/aes-cbc-generate-key-expected.txt: Added.
+        * crypto/subtle/aes-cbc-generate-key.html: Added.
+        * crypto/subtle/hmac-generate-key-expected.txt: Added.
+        * crypto/subtle/hmac-generate-key.html: Added.
+
+        * crypto/subtle/sha-1-expected.txt: Now that crypto.webkitSubtle.generateKey exists,
+        a different exception is raised.
+
 2013-11-02  Andreas Kling  <akling@apple.com>
 
         Optimize baselines: css3
diff --git a/LayoutTests/crypto/subtle/aes-cbc-generate-key-expected.txt b/LayoutTests/crypto/subtle/aes-cbc-generate-key-expected.txt
new file mode 100644 (file)
index 0000000..e83389c
--- /dev/null
@@ -0,0 +1,19 @@
+Test generating an AES key using AES-CBC algorithm.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS crypto.subtle.generateKey("aes-cbc", extractable, ["encrypt", "decrypt"]) threw exception TypeError: Type error.
+PASS crypto.subtle.generateKey({name: "aes-cbc"}, extractable, ["encrypt", "decrypt"]) threw exception TypeError: Type error.
+PASS crypto.subtle.generateKey({name: "aes-cbc", length: undefined}, extractable, ["encrypt", "decrypt"]) threw exception TypeError: Type error.
+PASS crypto.subtle.generateKey({name: "aes-cbc", length: {}}, extractable, ["encrypt", "decrypt"]) threw exception TypeError: Type error.
+Generating a key...
+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']
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/aes-cbc-generate-key.html b/LayoutTests/crypto/subtle/aes-cbc-generate-key.html
new file mode 100644 (file)
index 0000000..b35d7ad
--- /dev/null
@@ -0,0 +1,42 @@
+<!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 generating an AES key using AES-CBC algorithm.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var extractable = true;
+
+shouldThrow('crypto.subtle.generateKey("aes-cbc", extractable, ["encrypt", "decrypt"])');
+shouldThrow('crypto.subtle.generateKey({name: "aes-cbc"}, extractable, ["encrypt", "decrypt"])');
+shouldThrow('crypto.subtle.generateKey({name: "aes-cbc", length: undefined}, extractable, ["encrypt", "decrypt"])');
+shouldThrow('crypto.subtle.generateKey({name: "aes-cbc", length: {}}, extractable, ["encrypt", "decrypt"])');
+
+debug("Generating a key...");
+crypto.subtle.generateKey({name: "aes-cbc", length: 128}, 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']");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/hmac-generate-key-expected.txt b/LayoutTests/crypto/subtle/hmac-generate-key-expected.txt
new file mode 100644 (file)
index 0000000..cf2a8b3
--- /dev/null
@@ -0,0 +1,27 @@
+Test generating a HMAC key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS crypto.subtle.generateKey("hmac", extractable, ["sign", "verify"]) threw exception TypeError: Type error.
+PASS crypto.subtle.generateKey({name: "hmac"}, extractable, ["sign", "verify"]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.generateKey({name: "hmac", length: undefined}, extractable, ["sign", "verify"]) threw exception Error: NotSupportedError: DOM Exception 9.
+PASS crypto.subtle.generateKey({name: "hmac", length: {}}, extractable, ["sign", "verify"]) threw exception Error: NotSupportedError: DOM Exception 9.
+
+Generating a key with default length...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'hmac'
+PASS key.algorithm.length is 64
+PASS key.usages is ["sign", "verify"]
+
+Generating a key with custom length...
+PASS key.type is 'secret'
+PASS key.extractable is true
+PASS key.algorithm.name is 'hmac'
+PASS key.algorithm.length is 5
+PASS key.usages is ["sign"]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/hmac-generate-key.html b/LayoutTests/crypto/subtle/hmac-generate-key.html
new file mode 100644 (file)
index 0000000..0bf261e
--- /dev/null
@@ -0,0 +1,52 @@
+<!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 generating a HMAC key.");
+
+jsTestIsAsync = true;
+
+if (!window.subtle)
+    window.crypto.subtle = window.crypto.webkitSubtle;
+
+var extractable = true;
+
+shouldThrow('crypto.subtle.generateKey("hmac", extractable, ["sign", "verify"])');
+shouldThrow('crypto.subtle.generateKey({name: "hmac"}, extractable, ["sign", "verify"])');
+shouldThrow('crypto.subtle.generateKey({name: "hmac", length: undefined}, extractable, ["sign", "verify"])');
+shouldThrow('crypto.subtle.generateKey({name: "hmac", length: {}}, extractable, ["sign", "verify"])');
+
+debug("\nGenerating a key with default length...");
+crypto.subtle.generateKey({name: "hmac", hash: "sha-1"}, extractable, ["sign", "verify"]).then(function(result) {
+    key = result;
+
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'hmac'");
+    shouldBe("key.algorithm.length", "64");
+    shouldBe("key.usages", '["sign", "verify"]');
+
+    debug("\nGenerating a key with custom length...");
+    return crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: 5}, extractable, ["sign"]);
+}).then(function(result) {
+    key = result;
+
+    shouldBe("key.type", "'secret'");
+    shouldBe("key.extractable", "true");
+    shouldBe("key.algorithm.name", "'hmac'");
+    shouldBe("key.algorithm.length", "5");
+    shouldBe("key.usages", '["sign"]');
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 98c74ef..297110f 100644 (file)
@@ -11,7 +11,7 @@ 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 crypto.subtle.generateKey('sha-1') threw exception Error: NotSupportedError: DOM Exception 9.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 14d6383..bfc90f3 100644 (file)
@@ -1,3 +1,52 @@
+2013-11-02  Alexey Proskuryakov  <ap@apple.com>
+
+        Implement generateKey for HMAC and AES-CBC
+        https://bugs.webkit.org/show_bug.cgi?id=123669
+
+        Reviewed by Dan Bernstein.
+
+        Tests: crypto/subtle/aes-cbc-generate-key.html
+               crypto/subtle/hmac-generate-key.html
+
+        * WebCore.xcodeproj/project.pbxproj: Added new files.
+
+        * bindings/js/JSCryptoAlgorithmDictionary.cpp:
+        (WebCore::createAesKeyGenParams): Added bindings for AesKeyGenParams.
+        (WebCore::JSCryptoAlgorithmDictionary::createParametersForGenerateKey): Handle
+        algorithms that generate AES and HMAC keys.
+
+        * bindings/js/JSSubtleCryptoCustom.cpp: (WebCore::JSSubtleCrypto::generateKey): Added.
+
+        * crypto/CryptoAlgorithmAesKeyGenParams.h: Added.
+
+        * crypto/CryptoKey.cpp: (WebCore::CryptoKey::randomData):
+        * crypto/CryptoKey.h:
+        * crypto/CryptoKeyMac.cpp: Added
+        Expose a function that produces random data for symmetric crypto keys. Cross-platform
+        implementation uses ARC4 code from WTF, while Mac uses a system function that
+        provides a FIPS validated random number generator.
+
+        * crypto/CryptoKeyAES.cpp: (WebCore::CryptoKeyAES::generate):
+        * crypto/CryptoKeyAES.h:
+        Added a function that creates AES keys.
+
+        * crypto/SubtleCrypto.idl: Added generateKey.
+
+        * crypto/algorithms/CryptoAlgorithmAES_CBC.cpp:
+        (WebCore::CryptoAlgorithmAES_CBC::generateKey): Added.
+
+        * crypto/algorithms/CryptoAlgorithmHMAC.cpp:
+        (WebCore::CryptoAlgorithmHMAC::generateKey): Added.
+
+        * crypto/keys/CryptoKeyHMAC.cpp: (WebCore::CryptoKeyHMAC::generate):
+        * crypto/keys/CryptoKeyHMAC.h:
+        Added a function that creates HMAC keys.
+
+        * crypto/mac/CryptoAlgorithmAES_CBCMac.cpp: Removed generateKey stub, the implementation
+        ended up in cross-platform file.
+
+        * crypto/mac/CryptoAlgorithmHMACMac.cpp: Ditto.
+
 2013-11-02  Christophe Dumez  <ch.dumez@samsung.com>
 
         EnforceRange doesn't enforce range of a short
index 2811985..046c4be 100644 (file)
                E187056316E54A0D00585E97 /* MainThreadTask.h in Headers */ = {isa = PBXBuildFile; fileRef = E187056216E54A0D00585E97 /* MainThreadTask.h */; };
                E18772F1126E2629003DD586 /* Language.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18772F0126E2629003DD586 /* Language.cpp */; };
                E19727161820549E00592D51 /* CryptoKeyType.h in Headers */ = {isa = PBXBuildFile; fileRef = E19727151820549E00592D51 /* CryptoKeyType.h */; };
+               E19AC3F71824E5D100349426 /* CryptoAlgorithmAesKeyGenParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E19AC3F61824E5D100349426 /* CryptoAlgorithmAesKeyGenParams.h */; };
+               E19AC3F9182566F700349426 /* CryptoKeyMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E19AC3F8182566F700349426 /* CryptoKeyMac.cpp */; };
                E19AC3E21824DC6900349426 /* CryptoAlgorithmSHA224Mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E19AC3DE1824DC6900349426 /* CryptoAlgorithmSHA224Mac.cpp */; };
                E19AC3E31824DC6900349426 /* CryptoAlgorithmSHA256Mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E19AC3DF1824DC6900349426 /* CryptoAlgorithmSHA256Mac.cpp */; };
                E19AC3E41824DC6900349426 /* CryptoAlgorithmSHA384Mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E19AC3E01824DC6900349426 /* CryptoAlgorithmSHA384Mac.cpp */; };
                E187056216E54A0D00585E97 /* MainThreadTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainThreadTask.h; sourceTree = "<group>"; };
                E18772F0126E2629003DD586 /* Language.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Language.cpp; sourceTree = "<group>"; };
                E19727151820549E00592D51 /* CryptoKeyType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoKeyType.h; sourceTree = "<group>"; };
+               E19AC3F61824E5D100349426 /* CryptoAlgorithmAesKeyGenParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmAesKeyGenParams.h; sourceTree = "<group>"; };
+               E19AC3F8182566F700349426 /* CryptoKeyMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoKeyMac.cpp; sourceTree = "<group>"; };
                E19AC3DE1824DC6900349426 /* CryptoAlgorithmSHA224Mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmSHA224Mac.cpp; path = mac/CryptoAlgorithmSHA224Mac.cpp; sourceTree = "<group>"; };
                E19AC3DF1824DC6900349426 /* CryptoAlgorithmSHA256Mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmSHA256Mac.cpp; path = mac/CryptoAlgorithmSHA256Mac.cpp; sourceTree = "<group>"; };
                E19AC3E01824DC6900349426 /* CryptoAlgorithmSHA384Mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmSHA384Mac.cpp; path = mac/CryptoAlgorithmSHA384Mac.cpp; sourceTree = "<group>"; };
                                E19AC3DF1824DC6900349426 /* CryptoAlgorithmSHA256Mac.cpp */,
                                E19AC3E01824DC6900349426 /* CryptoAlgorithmSHA384Mac.cpp */,
                                E19AC3E11824DC6900349426 /* CryptoAlgorithmSHA512Mac.cpp */,
+                               E19AC3F8182566F700349426 /* CryptoKeyMac.cpp */,
                        );
                        name = mac;
                        sourceTree = "<group>";
                        isa = PBXGroup;
                        children = (
                                E125F8391824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h */,
+                               E19AC3F61824E5D100349426 /* CryptoAlgorithmAesKeyGenParams.h */,
                                E19DA29B18189ADD00088BC8 /* CryptoAlgorithmHmacKeyParams.h */,
                                E1C6571E1816E50300256CDD /* CryptoAlgorithmHmacParams.h */,
                        );
                                D359D8BF129CA55C0006E5D2 /* JSHTMLDetailsElement.h in Headers */,
                                76808B50159DADFA002B5233 /* JSHTMLDialogElement.h in Headers */,
                                1A85B1E70A1B240500D8C87C /* JSHTMLDirectoryElement.h in Headers */,
+                               E19AC3F71824E5D100349426 /* CryptoAlgorithmAesKeyGenParams.h in Headers */,
                                1A85B2B70A1B2AC700D8C87C /* JSHTMLDivElement.h in Headers */,
                                1A85B1E90A1B240500D8C87C /* JSHTMLDListElement.h in Headers */,
                                1A494E350A12358B00FDAFC1 /* JSHTMLDocument.h in Headers */,
                                C6F0900E14327B6100685849 /* MutationObserver.cpp in Sources */,
                                E19AC3E51824DC6900349426 /* CryptoAlgorithmSHA512Mac.cpp in Sources */,
                                D6E528A3149A926D00EFE1F3 /* MutationObserverInterestGroup.cpp in Sources */,
+                               E19AC3F9182566F700349426 /* CryptoKeyMac.cpp in Sources */,
                                D6E276AF14637455001D280A /* MutationObserverRegistration.cpp in Sources */,
                                C6F08FBC1430FE8F00685849 /* MutationRecord.cpp in Sources */,
                                52B6C9C515E3F4DF00690B05 /* NamedFlowCollection.cpp in Sources */,
index d9a09a5..509f5cb 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(SUBTLE_CRYPTO)
 
 #include "CryptoAlgorithmAesCbcParams.h"
+#include "CryptoAlgorithmAesKeyGenParams.h"
 #include "CryptoAlgorithmHmacKeyParams.h"
 #include "CryptoAlgorithmHmacParams.h"
 #include "CryptoAlgorithmRegistry.h"
@@ -126,7 +127,7 @@ static std::unique_ptr<CryptoAlgorithmParameters> createAesCbcParams(JSC::ExecSt
     if (exec->hadException())
         return nullptr;
 
-    std::unique_ptr<CryptoAlgorithmAesCbcParams> result = std::make_unique<CryptoAlgorithmAesCbcParams>();
+    auto result = std::make_unique<CryptoAlgorithmAesCbcParams>();
 
     CryptoOperationData ivData;
     if (!cryptoOperationDataFromJSValue(exec, iv, ivData)) {
@@ -144,6 +145,24 @@ static std::unique_ptr<CryptoAlgorithmParameters> createAesCbcParams(JSC::ExecSt
     return std::move(result);
 }
 
+static std::unique_ptr<CryptoAlgorithmParameters> createAesKeyGenParams(JSC::ExecState* exec, JSC::JSValue value)
+{
+    if (!value.isObject()) {
+        throwTypeError(exec);
+        return nullptr;
+    }
+
+    auto result = std::make_unique<CryptoAlgorithmAesKeyGenParams>();
+
+    JSValue lengthValue = getProperty(exec, value.getObject(), "length");
+    if (exec->hadException())
+        return nullptr;
+
+    result->length = toUInt16(exec, lengthValue, EnforceRange);
+
+    return std::move(result);
+}
+
 static std::unique_ptr<CryptoAlgorithmParameters> createHmacParams(JSC::ExecState* exec, JSC::JSValue value)
 {
     if (!value.isObject()) {
@@ -152,7 +171,7 @@ static std::unique_ptr<CryptoAlgorithmParameters> createHmacParams(JSC::ExecStat
     }
 
     JSDictionary jsDictionary(exec, value.getObject());
-    std::unique_ptr<CryptoAlgorithmHmacParams> result = std::make_unique<CryptoAlgorithmHmacParams>();
+    auto result = std::make_unique<CryptoAlgorithmHmacParams>();
 
     if (!getHashAlgorithm(jsDictionary, result->hash)) {
         ASSERT(exec->hadException());
@@ -170,7 +189,7 @@ static std::unique_ptr<CryptoAlgorithmParameters> createHmacKeyParams(JSC::ExecS
     }
 
     JSDictionary jsDictionary(exec, value.getObject());
-    std::unique_ptr<CryptoAlgorithmHmacKeyParams> result = std::make_unique<CryptoAlgorithmHmacKeyParams>();
+    auto result = std::make_unique<CryptoAlgorithmHmacKeyParams>();
 
     if (!getHashAlgorithm(jsDictionary, result->hash)) {
         ASSERT(exec->hadException());
@@ -344,7 +363,7 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     }
 }
 
-std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForGenerateKey(JSC::ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSC::JSValue)
+std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForGenerateKey(JSC::ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSC::JSValue value)
 {
     switch (algorithm) {
     case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
@@ -353,12 +372,16 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
     case CryptoAlgorithmIdentifier::RSA_OAEP:
     case CryptoAlgorithmIdentifier::ECDSA:
     case CryptoAlgorithmIdentifier::ECDH:
+        setDOMException(exec, NOT_SUPPORTED_ERR);
+        return nullptr;
     case CryptoAlgorithmIdentifier::AES_CTR:
     case CryptoAlgorithmIdentifier::AES_CBC:
     case CryptoAlgorithmIdentifier::AES_CMAC:
     case CryptoAlgorithmIdentifier::AES_GCM:
     case CryptoAlgorithmIdentifier::AES_CFB:
+        return createAesKeyGenParams(exec, value);
     case CryptoAlgorithmIdentifier::HMAC:
+        return createHmacKeyParams(exec, value);
     case CryptoAlgorithmIdentifier::DH:
     case CryptoAlgorithmIdentifier::SHA_1:
     case CryptoAlgorithmIdentifier::SHA_224:
index b143ead..982fcba 100644 (file)
@@ -337,6 +337,51 @@ JSValue JSSubtleCrypto::digest(ExecState* exec)
     return promise;
 }
 
+JSValue JSSubtleCrypto::generateKey(JSC::ExecState* exec)
+{
+    if (exec->argumentCount() < 1)
+        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
+    if (!algorithm) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(exec, algorithm->identifier(), exec->uncheckedArgument(0));
+    if (!parameters) {
+        ASSERT(exec->hadException());
+        return jsUndefined();
+    }
+
+    bool extractable = false;
+    if (exec->argumentCount() >= 2) {
+        extractable = exec->uncheckedArgument(1).toBoolean(exec);
+        if (exec->hadException())
+            return jsUndefined();
+    }
+
+    CryptoKeyUsage keyUsages = 0;
+    if (exec->argumentCount() >= 3) {
+        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(2), keyUsages)) {
+            ASSERT(exec->hadException());
+            return jsUndefined();
+        }
+    }
+
+    JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+    auto promiseWrapper = PromiseWrapper::create(globalObject(), promise);
+
+    ExceptionCode ec = 0;
+    algorithm->generateKey(*parameters, extractable, keyUsages, std::move(promiseWrapper), ec);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return promise;
+}
+
 JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
 {
     if (exec->argumentCount() < 3)
diff --git a/Source/WebCore/crypto/CryptoAlgorithmAesKeyGenParams.h b/Source/WebCore/crypto/CryptoAlgorithmAesKeyGenParams.h
new file mode 100644 (file)
index 0000000..bcd35e9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 CryptoAlgorithmAesKeyGenParams_h
+#define CryptoAlgorithmAesKeyGenParams_h
+
+#include "CryptoAlgorithmParameters.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoAlgorithmAesKeyGenParams FINAL : public CryptoAlgorithmParameters {
+public:
+    // The length, in bits, of the key.
+    unsigned length;
+};
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
+#endif // CryptoAlgorithmAesKeyGenParams_h
index b7bee88..0cc26ba 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "CryptoAlgorithmDescriptionBuilder.h"
 #include "CryptoAlgorithmRegistry.h"
+#include <wtf/CryptographicallyRandomNumber.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -87,6 +88,14 @@ Vector<String> CryptoKey::usages() const
     return result;
 }
 
+#if !PLATFORM(MAC)
+Vector<char> CryptoKey::randomData(size_t size)
+{
+    Vector<char> result(size);
+    cryptographicallyRandomValues(result.data(), result.size());
+    return result;
+}
+#endif
 } // namespace WebCore
 
 #endif // ENABLE(SUBTLE_CRYPTO)
index a43accb..f698bb3 100644 (file)
@@ -58,6 +58,8 @@ public:
 
     bool allows(CryptoKeyUsage usage) const { return usage == (m_usages & usage); }
 
+    static Vector<char> randomData(size_t);
+
 private:
     CryptoAlgorithmIdentifier m_algorithm;
     CryptoKeyType m_type;
index 6743026..af67171 100644 (file)
@@ -49,6 +49,13 @@ CryptoKeyAES::~CryptoKeyAES()
 {
 }
 
+PassRefPtr<CryptoKeyAES> CryptoKeyAES::generate(CryptoAlgorithmIdentifier algorithm, size_t lengthBits, bool extractable, CryptoKeyUsage usages)
+{
+    if (lengthBits % 8)
+        return nullptr;
+    return adoptRef(new CryptoKeyAES(algorithm, randomData(lengthBits / 8), extractable, usages));
+}
+
 void CryptoKeyAES::buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder& builder) const
 {
     CryptoKey::buildAlgorithmDescription(builder);
index 8f96430..f77747f 100644 (file)
@@ -42,6 +42,8 @@ public:
     }
     virtual ~CryptoKeyAES();
 
+    static PassRefPtr<CryptoKeyAES> generate(CryptoAlgorithmIdentifier, size_t lengthBits, bool extractable, CryptoKeyUsage);
+
     virtual CryptoKeyClass keyClass() const OVERRIDE { return CryptoKeyClass::AES; }
 
     const Vector<char>& key() const { return m_key; }
diff --git a/Source/WebCore/crypto/CryptoKeyMac.cpp b/Source/WebCore/crypto/CryptoKeyMac.cpp
new file mode 100644 (file)
index 0000000..70c34bc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 "CryptoKey.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#ifdef __has_include
+#if __has_include(<CommonCrypto/CommonRandomSPI.h>)
+#include <CommonCrypto/CommonRandomSPI.h>
+#endif
+#endif
+
+typedef struct __CCRandom *CCRandomRef;
+extern const CCRandomRef kCCRandomDefault;
+extern "C" int CCRandomCopyBytes(CCRandomRef rnd, void *bytes, size_t count);
+
+namespace WebCore {
+
+Vector<char> CryptoKey::randomData(size_t size)
+{
+    Vector<char> result(size);
+    CCRandomCopyBytes(kCCRandomDefault, result.data(), result.size());
+    return result;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
index c690395..1321986 100644 (file)
@@ -35,5 +35,6 @@
     [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);
+    [Custom] Promise generateKey(AlgorithmIdentifier algorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
     [Custom] Promise importKey(KeyFormat format, CryptoOperationData keyData, AlgorithmIdentifier? algorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
 };
index 53ab65a..026958a 100644 (file)
@@ -28,7 +28,7 @@
 
 #if ENABLE(SUBTLE_CRYPTO)
 
-#include "CryptoAlgorithmAesCbcParams.h"
+#include "CryptoAlgorithmAesKeyGenParams.h"
 #include "CryptoKeyAES.h"
 #include "ExceptionCode.h"
 #include "JSDOMPromise.h"
@@ -55,6 +55,19 @@ CryptoAlgorithmIdentifier CryptoAlgorithmAES_CBC::identifier() const
     return s_identifier;
 }
 
+void CryptoAlgorithmAES_CBC::generateKey(const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsage usages, std::unique_ptr<PromiseWrapper> promise, ExceptionCode&)
+{
+    const CryptoAlgorithmAesKeyGenParams& aesParameters = static_cast<const CryptoAlgorithmAesKeyGenParams&>(parameters);
+
+    RefPtr<CryptoKeyAES> result = CryptoKeyAES::generate(CryptoAlgorithmIdentifier::AES_CBC, aesParameters.length, extractable, usages);
+    if (!result) {
+        promise->reject(nullptr);
+        return;
+    }
+
+    promise->fulfill(result.release());
+}
+
 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) {
index e8d4bdc..63d467e 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(SUBTLE_CRYPTO)
 
+#include "CryptoAlgorithmHmacKeyParams.h"
 #include "CryptoAlgorithmHmacParams.h"
 #include "CryptoKeyHMAC.h"
 #include "ExceptionCode.h"
@@ -55,6 +56,19 @@ CryptoAlgorithmIdentifier CryptoAlgorithmHMAC::identifier() const
     return s_identifier;
 }
 
+void CryptoAlgorithmHMAC::generateKey(const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsage usages, std::unique_ptr<PromiseWrapper> promise, ExceptionCode&)
+{
+    const CryptoAlgorithmHmacKeyParams& hmacParameters = static_cast<const CryptoAlgorithmHmacKeyParams&>(parameters);
+
+    RefPtr<CryptoKeyHMAC> result = CryptoKeyHMAC::generate(hmacParameters.hasLength ? hmacParameters.length : 0, hmacParameters.hash, extractable, usages);
+    if (!result) {
+        promise->reject(nullptr);
+        return;
+    }
+
+    promise->fulfill(result.release());
+}
+
 void CryptoAlgorithmHMAC::importKey(const CryptoAlgorithmParameters& parameters, CryptoKeyFormat format, const CryptoOperationData& data, bool extractable, CryptoKeyUsage usage, std::unique_ptr<PromiseWrapper> promise, ExceptionCode& ec)
 {
     if (format != CryptoKeyFormat::Raw) {
index f60dcf9..a013fc1 100644 (file)
@@ -45,6 +45,27 @@ CryptoKeyHMAC::~CryptoKeyHMAC()
 {
 }
 
+PassRefPtr<CryptoKeyHMAC> CryptoKeyHMAC::generate(size_t lengthBytes, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsage usages)
+{
+    if (!lengthBytes) {
+        switch (hash) {
+        case CryptoAlgorithmIdentifier::SHA_1:
+        case CryptoAlgorithmIdentifier::SHA_224:
+        case CryptoAlgorithmIdentifier::SHA_256:
+            lengthBytes = 64;
+            break;
+        case CryptoAlgorithmIdentifier::SHA_384:
+        case CryptoAlgorithmIdentifier::SHA_512:
+            lengthBytes = 128;
+            break;
+        default:
+            return nullptr;
+        }
+    }
+
+    return adoptRef(new CryptoKeyHMAC(randomData(lengthBytes), hash, extractable, usages));
+}
+
 void CryptoKeyHMAC::buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder& builder) const
 {
     CryptoKey::buildAlgorithmDescription(builder);
index 96de3a5..682e54c 100644 (file)
@@ -41,6 +41,9 @@ public:
     }
     virtual ~CryptoKeyHMAC();
 
+    // If lengthBytes is 0, a recommended length is used, which is the size of the associated hash function's block size.
+    static PassRefPtr<CryptoKeyHMAC> generate(size_t lengthBytes, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsage);
+
     virtual CryptoKeyClass keyClass() const OVERRIDE { return CryptoKeyClass::HMAC; }
 
     const Vector<char>& key() const { return m_key; }
index 97cfe55..dc48ad4 100644 (file)
@@ -115,12 +115,6 @@ void CryptoAlgorithmAES_CBC::decrypt(const CryptoAlgorithmParameters& parameters
     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 33b5227..a09f90b 100644 (file)
@@ -136,13 +136,6 @@ void CryptoAlgorithmHMAC::verify(const CryptoAlgorithmParameters& parameters, co
     promise->fulfill(result);
 }
 
-void CryptoAlgorithmHMAC::generateKey(const CryptoAlgorithmParameters&, bool /*extractable*/, CryptoKeyUsage, std::unique_ptr<PromiseWrapper>, ExceptionCode& ec)
-{
-    // Not yet implemented.
-    ec = NOT_SUPPORTED_ERR;
-}
-
-
 }
 
 #endif // ENABLE(SUBTLE_CRYPTO)