Commit c07a2c0d authored by ap@apple.com's avatar ap@apple.com

Implement generateKey for HMAC and AES-CBC

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: http://svn.webkit.org/repository/webkit/trunk@158526 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f8a43c11
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
......
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
<!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>
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
<!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>
......@@ -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
......
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
......
......@@ -5581,6 +5581,8 @@
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 */; };
......@@ -12610,6 +12612,8 @@
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>"; };
......@@ -20170,6 +20174,7 @@
E19AC3DF1824DC6900349426 /* CryptoAlgorithmSHA256Mac.cpp */,
E19AC3E01824DC6900349426 /* CryptoAlgorithmSHA384Mac.cpp */,
E19AC3E11824DC6900349426 /* CryptoAlgorithmSHA512Mac.cpp */,
E19AC3F8182566F700349426 /* CryptoKeyMac.cpp */,
);
name = mac;
sourceTree = "<group>";
......@@ -20210,6 +20215,7 @@
isa = PBXGroup;
children = (
E125F8391824104800D84CD9 /* CryptoAlgorithmAesCbcParams.h */,
E19AC3F61824E5D100349426 /* CryptoAlgorithmAesKeyGenParams.h */,
E19DA29B18189ADD00088BC8 /* CryptoAlgorithmHmacKeyParams.h */,
E1C6571E1816E50300256CDD /* CryptoAlgorithmHmacParams.h */,
);
......@@ -23183,6 +23189,7 @@
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 */,
......@@ -27001,6 +27008,7 @@
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 */,
......@@ -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:
......
......@@ -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)
......
/*
* 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
......@@ -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)
......@@ -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;
......
......@@ -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);
......
......@@ -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; }
......
/*
* 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)
......@@ -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);
};
......@@ -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) {
......
......@@ -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) {
......
......@@ -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));
}