Index: Source/modules/crypto/NormalizeAlgorithm.cpp |
diff --git a/Source/modules/crypto/NormalizeAlgorithm.cpp b/Source/modules/crypto/NormalizeAlgorithm.cpp |
index b1231128b4367a61eaf285c92ebfe0ca2ef1d1cb..c18f469a0d784bb9a9b3d0ff6f30eec8c1e51b4b 100644 |
--- a/Source/modules/crypto/NormalizeAlgorithm.cpp |
+++ b/Source/modules/crypto/NormalizeAlgorithm.cpp |
@@ -38,65 +38,62 @@ |
#include "public/platform/WebString.h" |
#include "wtf/ArrayBuffer.h" |
#include "wtf/ArrayBufferView.h" |
-#include "wtf/HashMap.h" |
#include "wtf/MathExtras.h" |
#include "wtf/Uint8Array.h" |
#include "wtf/Vector.h" |
#include "wtf/text/StringBuilder.h" |
-#include "wtf/text/StringHash.h" |
+#include <algorithm> |
namespace WebCore { |
namespace { |
struct AlgorithmNameMapping { |
+ // Must be an upper case ASCII string. |
const char* const algorithmName; |
+ // Must be strlen(algorithmName). |
+ unsigned char algorithmNameLength; |
blink::WebCryptoAlgorithmId algorithmId; |
-}; |
- |
-// Indicates that the algorithm doesn't support the specified operation. |
-const int UnsupportedOp = -1; |
-// Either UnsupportedOp, or a value from blink::WebCryptoAlgorithmParamsType |
-typedef int AlgorithmParamsForOperation; |
+#if ASSERT_ENABLED |
+ bool operator<(const AlgorithmNameMapping&) const; |
+#endif |
+}; |
struct OperationParamsMapping { |
blink::WebCryptoAlgorithmId algorithmId; |
AlgorithmOperation operation; |
- AlgorithmParamsForOperation params; |
+ blink::WebCryptoAlgorithmParamsType params; |
+ |
+ bool operator<(const OperationParamsMapping&) const; |
}; |
+// Must be sorted by length, and then by reverse string. |
+// Also all names must be upper case ASCII. |
const AlgorithmNameMapping algorithmNameMappings[] = { |
- {"AES-CBC", blink::WebCryptoAlgorithmIdAesCbc}, |
- {"AES-CTR", blink::WebCryptoAlgorithmIdAesCtr}, |
- {"AES-GCM", blink::WebCryptoAlgorithmIdAesGcm}, |
- {"HMAC", blink::WebCryptoAlgorithmIdHmac}, |
- {"RSASSA-PKCS1-v1_5", blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5}, |
- {"RSAES-PKCS1-v1_5", blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5}, |
- {"SHA-1", blink::WebCryptoAlgorithmIdSha1}, |
- {"SHA-256", blink::WebCryptoAlgorithmIdSha256}, |
- {"SHA-384", blink::WebCryptoAlgorithmIdSha384}, |
- {"SHA-512", blink::WebCryptoAlgorithmIdSha512}, |
- {"AES-KW", blink::WebCryptoAlgorithmIdAesKw}, |
+ {"HMAC", 4, blink::WebCryptoAlgorithmIdHmac}, |
+ {"SHA-1", 5, blink::WebCryptoAlgorithmIdSha1}, |
+ {"AES-KW", 6, blink::WebCryptoAlgorithmIdAesKw}, |
+ {"SHA-512", 7, blink::WebCryptoAlgorithmIdSha512}, |
+ {"SHA-384", 7, blink::WebCryptoAlgorithmIdSha384}, |
+ {"SHA-256", 7, blink::WebCryptoAlgorithmIdSha256}, |
+ {"AES-CBC", 7, blink::WebCryptoAlgorithmIdAesCbc}, |
+ {"AES-GCM", 7, blink::WebCryptoAlgorithmIdAesGcm}, |
+ {"AES-CTR", 7, blink::WebCryptoAlgorithmIdAesCtr}, |
+ {"RSAES-PKCS1-V1_5", 16, blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5}, |
+ {"RSASSA-PKCS1-V1_5", 17, blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5}, |
}; |
// What operations each algorithm supports, and what parameters it expects. |
+// Must be sorted by algorithm id and then operation. |
const OperationParamsMapping operationParamsMappings[] = { |
// AES-CBC |
- {blink::WebCryptoAlgorithmIdAesCbc, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesCbcParams}, |
{blink::WebCryptoAlgorithmIdAesCbc, Encrypt, blink::WebCryptoAlgorithmParamsTypeAesCbcParams}, |
+ {blink::WebCryptoAlgorithmIdAesCbc, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesCbcParams}, |
{blink::WebCryptoAlgorithmIdAesCbc, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
{blink::WebCryptoAlgorithmIdAesCbc, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
- {blink::WebCryptoAlgorithmIdAesCbc, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesCbcParams}, |
{blink::WebCryptoAlgorithmIdAesCbc, WrapKey, blink::WebCryptoAlgorithmParamsTypeAesCbcParams}, |
- |
- // AES-CTR |
- {blink::WebCryptoAlgorithmIdAesCtr, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
- {blink::WebCryptoAlgorithmIdAesCtr, Encrypt, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
- {blink::WebCryptoAlgorithmIdAesCtr, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
- {blink::WebCryptoAlgorithmIdAesCtr, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
- {blink::WebCryptoAlgorithmIdAesCtr, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
- {blink::WebCryptoAlgorithmIdAesCtr, WrapKey, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
+ {blink::WebCryptoAlgorithmIdAesCbc, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesCbcParams}, |
// HMAC |
{blink::WebCryptoAlgorithmIdHmac, Sign, blink::WebCryptoAlgorithmParamsTypeNone}, |
@@ -124,89 +121,162 @@ const OperationParamsMapping operationParamsMappings[] = { |
{blink::WebCryptoAlgorithmIdSha384, Digest, blink::WebCryptoAlgorithmParamsTypeNone}, |
{blink::WebCryptoAlgorithmIdSha512, Digest, blink::WebCryptoAlgorithmParamsTypeNone}, |
- // AES-KW |
- {blink::WebCryptoAlgorithmIdAesKw, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
- {blink::WebCryptoAlgorithmIdAesKw, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
- {blink::WebCryptoAlgorithmIdAesKw, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
- {blink::WebCryptoAlgorithmIdAesKw, WrapKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
- |
// AES-GCM |
- {blink::WebCryptoAlgorithmIdAesGcm, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
- {blink::WebCryptoAlgorithmIdAesGcm, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
{blink::WebCryptoAlgorithmIdAesGcm, Encrypt, blink::WebCryptoAlgorithmParamsTypeAesGcmParams}, |
{blink::WebCryptoAlgorithmIdAesGcm, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesGcmParams}, |
- {blink::WebCryptoAlgorithmIdAesGcm, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesGcmParams}, |
+ {blink::WebCryptoAlgorithmIdAesGcm, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
+ {blink::WebCryptoAlgorithmIdAesGcm, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
{blink::WebCryptoAlgorithmIdAesGcm, WrapKey, blink::WebCryptoAlgorithmParamsTypeAesGcmParams}, |
-}; |
+ {blink::WebCryptoAlgorithmIdAesGcm, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesGcmParams}, |
-// This structure describes an algorithm and its supported operations. |
-struct AlgorithmInfo { |
- AlgorithmInfo() |
- : algorithmName(0) |
- { |
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(paramsForOperation); ++i) |
- paramsForOperation[i] = UnsupportedOp; |
- } |
+ // AES-CTR |
+ {blink::WebCryptoAlgorithmIdAesCtr, Encrypt, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
+ {blink::WebCryptoAlgorithmIdAesCtr, Decrypt, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
+ {blink::WebCryptoAlgorithmIdAesCtr, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
+ {blink::WebCryptoAlgorithmIdAesCtr, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
+ {blink::WebCryptoAlgorithmIdAesCtr, WrapKey, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
+ {blink::WebCryptoAlgorithmIdAesCtr, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeAesCtrParams}, |
- blink::WebCryptoAlgorithmId algorithmId; |
- const char* algorithmName; |
- AlgorithmParamsForOperation paramsForOperation[LastAlgorithmOperation + 1]; |
+ // AES-KW |
+ {blink::WebCryptoAlgorithmIdAesKw, GenerateKey, blink::WebCryptoAlgorithmParamsTypeAesKeyGenParams}, |
+ {blink::WebCryptoAlgorithmIdAesKw, ImportKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
+ {blink::WebCryptoAlgorithmIdAesKw, WrapKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
+ {blink::WebCryptoAlgorithmIdAesKw, UnwrapKey, blink::WebCryptoAlgorithmParamsTypeNone}, |
}; |
-// AlgorithmRegistry enumerates each of the different algorithms and its |
-// parameters. This describes the same information as the static tables above, |
-// but in a more convenient runtime form. |
-class AlgorithmRegistry { |
-public: |
- static AlgorithmRegistry& instance(); |
+#if ASSERT_ENABLED |
- const AlgorithmInfo* lookupAlgorithmByName(const String&) const; |
- const AlgorithmInfo* lookupAlgorithmById(blink::WebCryptoAlgorithmId) const; |
+// Essentially std::is_sorted() (however that function is new to C++11). |
+template <typename Iterator> |
+bool isSorted(Iterator begin, Iterator end) |
+{ |
+ if (begin == end) |
+ return true; |
-private: |
- AlgorithmRegistry(); |
+ Iterator prev = begin; |
+ Iterator cur = begin + 1; |
- // Algorithm name to ID. |
- typedef HashMap<String, blink::WebCryptoAlgorithmId, CaseFoldingHash> AlgorithmNameToIdMap; |
- AlgorithmNameToIdMap m_algorithmNameToId; |
+ while (cur != end) { |
+ if (*cur < *prev) |
+ return false; |
+ cur++; |
+ prev++; |
+ } |
- // Algorithm ID to information. |
- AlgorithmInfo m_algorithms[blink::WebCryptoAlgorithmIdLast + 1]; |
-}; |
+ return true; |
+} |
-AlgorithmRegistry& AlgorithmRegistry::instance() |
+bool AlgorithmNameMapping::operator<(const AlgorithmNameMapping& o) const |
{ |
- DEFINE_STATIC_LOCAL(AlgorithmRegistry, registry, ()); |
- return registry; |
+ if (algorithmNameLength < o.algorithmNameLength) |
+ return true; |
+ if (algorithmNameLength > o.algorithmNameLength) |
+ return false; |
+ |
+ for (size_t i = 0; i < algorithmNameLength; ++i) { |
+ size_t reverseIndex = algorithmNameLength - i - 1; |
+ char c1 = algorithmName[reverseIndex]; |
+ char c2 = o.algorithmName[reverseIndex]; |
+ |
+ if (c1 < c2) |
+ return true; |
+ if (c1 > c2) |
+ return false; |
+ } |
+ |
+ return false; |
} |
-const AlgorithmInfo* AlgorithmRegistry::lookupAlgorithmByName(const String& algorithmName) const |
+bool verifyAlgorithmNameMappings(const AlgorithmNameMapping* begin, const AlgorithmNameMapping* end) |
{ |
- AlgorithmNameToIdMap::const_iterator it = m_algorithmNameToId.find(algorithmName); |
- if (it == m_algorithmNameToId.end()) |
- return 0; |
- return lookupAlgorithmById(it->value); |
+ for (const AlgorithmNameMapping* it = begin; it != end; ++it) { |
+ if (it->algorithmNameLength != strlen(it->algorithmName)) |
+ return false; |
+ String str(it->algorithmName, it->algorithmNameLength); |
+ if (!str.containsOnlyASCII()) |
+ return false; |
+ if (str.upper() != str) |
+ return false; |
+ } |
+ |
+ return isSorted(begin, end); |
} |
+#endif |
-const AlgorithmInfo* AlgorithmRegistry::lookupAlgorithmById(blink::WebCryptoAlgorithmId algorithmId) const |
+bool OperationParamsMapping::operator<(const OperationParamsMapping& o) const |
{ |
- ASSERT(algorithmId >= 0 && algorithmId < WTF_ARRAY_LENGTH(m_algorithms)); |
- return &m_algorithms[algorithmId]; |
+ if (algorithmId < o.algorithmId) |
+ return true; |
+ if (algorithmId > o.algorithmId) |
+ return false; |
+ return operation < o.operation; |
} |
-AlgorithmRegistry::AlgorithmRegistry() |
+template <typename CharType> |
+bool algorithmNameComparator(const AlgorithmNameMapping& a, StringImpl* b) |
{ |
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(algorithmNameMappings); ++i) { |
- const AlgorithmNameMapping& mapping = algorithmNameMappings[i]; |
- m_algorithmNameToId.add(mapping.algorithmName, mapping.algorithmId); |
- m_algorithms[mapping.algorithmId].algorithmName = mapping.algorithmName; |
- m_algorithms[mapping.algorithmId].algorithmId = mapping.algorithmId; |
+ if (a.algorithmNameLength < b->length()) |
+ return true; |
+ if (a.algorithmNameLength > b->length()) |
+ return false; |
+ |
+ // Because the algorithm names contain many common prefixes, it is better |
+ // to compare starting at the end of the string. |
+ for (size_t i = 0; i < a.algorithmNameLength; ++i) { |
+ size_t reverseIndex = a.algorithmNameLength - i - 1; |
+ CharType c1 = a.algorithmName[reverseIndex]; |
+ CharType c2 = b->getCharacters<CharType>()[reverseIndex]; |
+ if (!isASCII(c2)) |
+ return false; |
+ c2 = toASCIIUpper(c2); |
+ |
+ if (c1 < c2) |
+ return true; |
+ if (c1 > c2) |
+ return false; |
} |
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(operationParamsMappings); ++i) { |
- const OperationParamsMapping& mapping = operationParamsMappings[i]; |
- m_algorithms[mapping.algorithmId].paramsForOperation[mapping.operation] = mapping.params; |
- } |
+ return false; |
+} |
+ |
+bool lookupAlgorithmIdByName(const String& algorithmName, blink::WebCryptoAlgorithmId& id) |
+{ |
+ const AlgorithmNameMapping* begin = algorithmNameMappings; |
+ const AlgorithmNameMapping* end = algorithmNameMappings + WTF_ARRAY_LENGTH(algorithmNameMappings); |
+ |
+ ASSERT(verifyAlgorithmNameMappings(begin, end)); |
+ |
+ const AlgorithmNameMapping* it; |
+ if (algorithmName.impl()->is8Bit()) |
+ it = std::lower_bound(begin, end, algorithmName.impl(), &algorithmNameComparator<LChar>); |
+ else |
+ it = std::lower_bound(begin, end, algorithmName.impl(), &algorithmNameComparator<UChar>); |
+ |
+ if (it == end) |
+ return false; |
+ |
+ if (it->algorithmNameLength != algorithmName.length() || !equalIgnoringCase(algorithmName, it->algorithmName)) |
+ return false; |
+ |
+ id = it->algorithmId; |
+ return true; |
+} |
+ |
+bool lookupAlgorithmParamsType(blink::WebCryptoAlgorithmId id, AlgorithmOperation op, blink::WebCryptoAlgorithmParamsType& paramsType) |
+{ |
+ const OperationParamsMapping* begin = operationParamsMappings; |
+ const OperationParamsMapping* end = operationParamsMappings + WTF_ARRAY_LENGTH(operationParamsMappings); |
+ |
+ ASSERT(isSorted(begin, end)); |
+ |
+ OperationParamsMapping search = { id, op }; |
+ const OperationParamsMapping* it = std::lower_bound(begin, end, search); |
+ if (it == end) |
+ return false; |
+ if (it->algorithmId != id || it->operation != op) |
+ return false; |
+ paramsType = it->params; |
+ return true; |
} |
// ErrorContext holds a stack of string literals which describe what was |
@@ -667,25 +737,25 @@ bool parseAlgorithm(const Dictionary& raw, AlgorithmOperation op, blink::WebCryp |
return false; |
} |
- const AlgorithmInfo* info = AlgorithmRegistry::instance().lookupAlgorithmByName(algorithmName); |
- if (!info) { |
+ blink::WebCryptoAlgorithmId algorithmId; |
+ if (!lookupAlgorithmIdByName(algorithmName, algorithmId)) { |
errorDetails = context.toString("Unrecognized algorithm name"); |
return false; |
} |
- context.add(info->algorithmName); |
+ context.add(algorithmIdToName(algorithmId)); |
- if (info->paramsForOperation[op] == UnsupportedOp) { |
+ blink::WebCryptoAlgorithmParamsType paramsType; |
+ if (!lookupAlgorithmParamsType(algorithmId, op, paramsType)) { |
errorDetails = context.toString("Unsupported operation"); |
return false; |
} |
- blink::WebCryptoAlgorithmParamsType paramsType = static_cast<blink::WebCryptoAlgorithmParamsType>(info->paramsForOperation[op]); |
OwnPtr<blink::WebCryptoAlgorithmParams> params; |
if (!parseAlgorithmParams(raw, paramsType, params, context, errorDetails)) |
return false; |
- algorithm = blink::WebCryptoAlgorithm(info->algorithmId, params.release()); |
+ algorithm = blink::WebCryptoAlgorithm(algorithmId, params.release()); |
return true; |
} |
@@ -703,7 +773,33 @@ bool parseAlgorithm(const Dictionary& raw, AlgorithmOperation op, blink::WebCryp |
const char* algorithmIdToName(blink::WebCryptoAlgorithmId id) |
{ |
- return AlgorithmRegistry::instance().lookupAlgorithmById(id)->algorithmName; |
+ switch (id) { |
+ case blink::WebCryptoAlgorithmIdAesCbc: |
+ return "AES-CBC"; |
+ case blink::WebCryptoAlgorithmIdAesCtr: |
+ return "AES-CTR"; |
+ case blink::WebCryptoAlgorithmIdAesGcm: |
+ return "AES-GCM"; |
+ case blink::WebCryptoAlgorithmIdHmac: |
+ return "HMAC"; |
+ case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: |
+ return "RSASSA-PKCS1-v1_5"; |
+ case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
+ return "RSAES-PKCS1-v1_5"; |
+ case blink::WebCryptoAlgorithmIdSha1: |
+ return "SHA-1"; |
+ case blink::WebCryptoAlgorithmIdSha256: |
+ return "SHA-256"; |
+ case blink::WebCryptoAlgorithmIdSha384: |
+ return "SHA-384"; |
+ case blink::WebCryptoAlgorithmIdSha512: |
+ return "SHA-512"; |
+ case blink::WebCryptoAlgorithmIdAesKw: |
+ return "AES-KW"; |
+ case blink::WebCryptoAlgorithmIdRsaOaep: |
+ return "RSA-OAEP"; |
+ } |
+ return 0; |
} |
} // namespace WebCore |