hmac.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <memory>
  7. #include "base/check_op.h"
  8. #include "base/numerics/safe_math.h"
  9. #include "components/webcrypto/algorithm_implementation.h"
  10. #include "components/webcrypto/algorithms/secret_key_util.h"
  11. #include "components/webcrypto/algorithms/util.h"
  12. #include "components/webcrypto/blink_key_handle.h"
  13. #include "components/webcrypto/jwk.h"
  14. #include "components/webcrypto/status.h"
  15. #include "crypto/openssl_util.h"
  16. #include "crypto/secure_util.h"
  17. #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
  18. #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
  19. #include "third_party/boringssl/src/include/openssl/hmac.h"
  20. namespace webcrypto {
  21. namespace {
  22. Status GetDigestBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm,
  23. unsigned int* block_size_bits) {
  24. const EVP_MD* md = GetDigest(algorithm);
  25. if (!md)
  26. return Status::ErrorUnsupported();
  27. *block_size_bits = static_cast<unsigned int>(8 * EVP_MD_block_size(md));
  28. return Status::Success();
  29. }
  30. // Gets the requested key length in bits for an HMAC import operation.
  31. Status GetHmacImportKeyLengthBits(
  32. const blink::WebCryptoHmacImportParams* params,
  33. unsigned int key_data_byte_length,
  34. unsigned int* keylen_bits) {
  35. if (key_data_byte_length == 0)
  36. return Status::ErrorHmacImportEmptyKey();
  37. // Make sure that the key data's length can be represented in bits without
  38. // overflow.
  39. base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length);
  40. checked_keylen_bits *= 8;
  41. if (!checked_keylen_bits.IsValid())
  42. return Status::ErrorDataTooLarge();
  43. unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie();
  44. // Determine how many bits of the input to use.
  45. *keylen_bits = data_keylen_bits;
  46. if (params->HasLengthBits()) {
  47. // The requested bit length must be:
  48. // * No longer than the input data length
  49. // * At most 7 bits shorter.
  50. if (NumBitsToBytes(params->OptionalLengthBits()) != key_data_byte_length)
  51. return Status::ErrorHmacImportBadLength();
  52. *keylen_bits = params->OptionalLengthBits();
  53. }
  54. return Status::Success();
  55. }
  56. const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
  57. switch (hash) {
  58. case blink::kWebCryptoAlgorithmIdSha1:
  59. return "HS1";
  60. case blink::kWebCryptoAlgorithmIdSha256:
  61. return "HS256";
  62. case blink::kWebCryptoAlgorithmIdSha384:
  63. return "HS384";
  64. case blink::kWebCryptoAlgorithmIdSha512:
  65. return "HS512";
  66. default:
  67. return nullptr;
  68. }
  69. }
  70. const blink::WebCryptoKeyUsageMask kAllKeyUsages =
  71. blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify;
  72. Status SignHmac(const std::vector<uint8_t>& raw_key,
  73. const blink::WebCryptoAlgorithm& hash,
  74. base::span<const uint8_t> data,
  75. std::vector<uint8_t>* buffer) {
  76. crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
  77. const EVP_MD* digest_algorithm = GetDigest(hash);
  78. if (!digest_algorithm)
  79. return Status::ErrorUnsupported();
  80. size_t hmac_expected_length = EVP_MD_size(digest_algorithm);
  81. buffer->resize(hmac_expected_length);
  82. unsigned int hmac_actual_length;
  83. if (!HMAC(digest_algorithm, raw_key.data(), raw_key.size(), data.data(),
  84. data.size(), buffer->data(), &hmac_actual_length)) {
  85. return Status::OperationError();
  86. }
  87. // HMAC() promises to use at most EVP_MD_CTX_size(). If this was not the
  88. // case then memory corruption may have just occurred.
  89. CHECK_EQ(hmac_expected_length, hmac_actual_length);
  90. return Status::Success();
  91. }
  92. class HmacImplementation : public AlgorithmImplementation {
  93. public:
  94. HmacImplementation() {}
  95. Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
  96. bool extractable,
  97. blink::WebCryptoKeyUsageMask usages,
  98. GenerateKeyResult* result) const override {
  99. Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
  100. if (status.IsError())
  101. return status;
  102. const blink::WebCryptoHmacKeyGenParams* params =
  103. algorithm.HmacKeyGenParams();
  104. unsigned int keylen_bits = 0;
  105. if (params->HasLengthBits()) {
  106. keylen_bits = params->OptionalLengthBits();
  107. // Zero-length HMAC keys are disallowed by the spec.
  108. if (keylen_bits == 0)
  109. return Status::ErrorGenerateHmacKeyLengthZero();
  110. } else {
  111. status = GetDigestBlockSizeBits(params->GetHash(), &keylen_bits);
  112. if (status.IsError())
  113. return status;
  114. }
  115. return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::CreateHmac(
  116. params->GetHash().Id(), keylen_bits),
  117. extractable, usages, keylen_bits, result);
  118. }
  119. Status ImportKey(blink::WebCryptoKeyFormat format,
  120. base::span<const uint8_t> key_data,
  121. const blink::WebCryptoAlgorithm& algorithm,
  122. bool extractable,
  123. blink::WebCryptoKeyUsageMask usages,
  124. blink::WebCryptoKey* key) const override {
  125. switch (format) {
  126. case blink::kWebCryptoKeyFormatRaw:
  127. return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
  128. case blink::kWebCryptoKeyFormatJwk:
  129. return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
  130. default:
  131. return Status::ErrorUnsupportedImportKeyFormat();
  132. }
  133. }
  134. Status ExportKey(blink::WebCryptoKeyFormat format,
  135. const blink::WebCryptoKey& key,
  136. std::vector<uint8_t>* buffer) const override {
  137. switch (format) {
  138. case blink::kWebCryptoKeyFormatRaw:
  139. return ExportKeyRaw(key, buffer);
  140. case blink::kWebCryptoKeyFormatJwk:
  141. return ExportKeyJwk(key, buffer);
  142. default:
  143. return Status::ErrorUnsupportedExportKeyFormat();
  144. }
  145. }
  146. Status ImportKeyRaw(base::span<const uint8_t> key_data,
  147. const blink::WebCryptoAlgorithm& algorithm,
  148. bool extractable,
  149. blink::WebCryptoKeyUsageMask usages,
  150. blink::WebCryptoKey* key) const {
  151. Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
  152. if (status.IsError())
  153. return status;
  154. const blink::WebCryptoHmacImportParams* params =
  155. algorithm.HmacImportParams();
  156. unsigned int keylen_bits = 0;
  157. status = GetHmacImportKeyLengthBits(params, key_data.size(), &keylen_bits);
  158. if (status.IsError())
  159. return status;
  160. const blink::WebCryptoKeyAlgorithm key_algorithm =
  161. blink::WebCryptoKeyAlgorithm::CreateHmac(params->GetHash().Id(),
  162. keylen_bits);
  163. // If no bit truncation was requested, then done!
  164. if ((keylen_bits % 8) == 0) {
  165. return CreateWebCryptoSecretKey(key_data, key_algorithm, extractable,
  166. usages, key);
  167. }
  168. // Otherwise zero out the unused bits in the key data before importing.
  169. std::vector<uint8_t> modified_key_data(key_data.data(),
  170. key_data.data() + key_data.size());
  171. TruncateToBitLength(keylen_bits, &modified_key_data);
  172. return CreateWebCryptoSecretKey(modified_key_data, key_algorithm,
  173. extractable, usages, key);
  174. }
  175. Status ImportKeyJwk(base::span<const uint8_t> key_data,
  176. const blink::WebCryptoAlgorithm& algorithm,
  177. bool extractable,
  178. blink::WebCryptoKeyUsageMask usages,
  179. blink::WebCryptoKey* key) const {
  180. Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
  181. if (status.IsError())
  182. return status;
  183. const char* algorithm_name =
  184. GetJwkHmacAlgorithmName(algorithm.HmacImportParams()->GetHash().Id());
  185. if (!algorithm_name)
  186. return Status::ErrorUnexpected();
  187. std::vector<uint8_t> raw_data;
  188. JwkReader jwk;
  189. status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
  190. &raw_data, &jwk);
  191. if (status.IsError())
  192. return status;
  193. status = jwk.VerifyAlg(algorithm_name);
  194. if (status.IsError())
  195. return status;
  196. return ImportKeyRaw(raw_data, algorithm, extractable, usages, key);
  197. }
  198. Status ExportKeyRaw(const blink::WebCryptoKey& key,
  199. std::vector<uint8_t>* buffer) const {
  200. *buffer = GetSymmetricKeyData(key);
  201. return Status::Success();
  202. }
  203. Status ExportKeyJwk(const blink::WebCryptoKey& key,
  204. std::vector<uint8_t>* buffer) const {
  205. const std::vector<uint8_t>& raw_data = GetSymmetricKeyData(key);
  206. const char* algorithm_name =
  207. GetJwkHmacAlgorithmName(key.Algorithm().HmacParams()->GetHash().Id());
  208. if (!algorithm_name)
  209. return Status::ErrorUnexpected();
  210. WriteSecretKeyJwk(raw_data, algorithm_name, key.Extractable(), key.Usages(),
  211. buffer);
  212. return Status::Success();
  213. }
  214. Status Sign(const blink::WebCryptoAlgorithm& algorithm,
  215. const blink::WebCryptoKey& key,
  216. base::span<const uint8_t> data,
  217. std::vector<uint8_t>* buffer) const override {
  218. const blink::WebCryptoAlgorithm& hash =
  219. key.Algorithm().HmacParams()->GetHash();
  220. return SignHmac(GetSymmetricKeyData(key), hash, data, buffer);
  221. }
  222. Status Verify(const blink::WebCryptoAlgorithm& algorithm,
  223. const blink::WebCryptoKey& key,
  224. base::span<const uint8_t> signature,
  225. base::span<const uint8_t> data,
  226. bool* signature_match) const override {
  227. std::vector<uint8_t> result;
  228. Status status = Sign(algorithm, key, data, &result);
  229. if (status.IsError())
  230. return status;
  231. // Do not allow verification of truncated MACs.
  232. *signature_match = result.size() == signature.size() &&
  233. crypto::SecureMemEqual(result.data(), signature.data(),
  234. signature.size());
  235. return Status::Success();
  236. }
  237. Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
  238. blink::WebCryptoKeyType type,
  239. bool extractable,
  240. blink::WebCryptoKeyUsageMask usages,
  241. base::span<const uint8_t> key_data,
  242. blink::WebCryptoKey* key) const override {
  243. if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeHmac ||
  244. type != blink::kWebCryptoKeyTypeSecret)
  245. return Status::ErrorUnexpected();
  246. return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages,
  247. key);
  248. }
  249. Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
  250. bool* has_length_bits,
  251. unsigned int* length_bits) const override {
  252. const blink::WebCryptoHmacImportParams* params =
  253. key_length_algorithm.HmacImportParams();
  254. *has_length_bits = true;
  255. if (params->HasLengthBits()) {
  256. *length_bits = params->OptionalLengthBits();
  257. if (*length_bits == 0)
  258. return Status::ErrorGetHmacKeyLengthZero();
  259. return Status::Success();
  260. }
  261. return GetDigestBlockSizeBits(params->GetHash(), length_bits);
  262. }
  263. };
  264. } // namespace
  265. std::unique_ptr<AlgorithmImplementation> CreateHmacImplementation() {
  266. return std::make_unique<HmacImplementation>();
  267. }
  268. } // namespace webcrypto