// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/webcrypto/algorithms/util.h" #include "base/check_op.h" #include "components/webcrypto/status.h" #include "crypto/openssl_util.h" #include "third_party/boringssl/src/include/openssl/aead.h" #include "third_party/boringssl/src/include/openssl/bn.h" #include "third_party/boringssl/src/include/openssl/digest.h" namespace webcrypto { const EVP_MD* GetDigest(const blink::WebCryptoAlgorithm& hash_algorithm) { return GetDigest(hash_algorithm.Id()); } const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) { switch (id) { case blink::kWebCryptoAlgorithmIdSha1: return EVP_sha1(); case blink::kWebCryptoAlgorithmIdSha256: return EVP_sha256(); case blink::kWebCryptoAlgorithmIdSha384: return EVP_sha384(); case blink::kWebCryptoAlgorithmIdSha512: return EVP_sha512(); default: return nullptr; } } void TruncateToBitLength(size_t length_bits, std::vector* bytes) { size_t length_bytes = NumBitsToBytes(length_bits); if (bytes->size() != length_bytes) { CHECK_LT(length_bytes, bytes->size()); bytes->resize(length_bytes); } size_t remainder_bits = length_bits % 8; // Zero any "unused bits" in the final byte. if (remainder_bits) bytes->back() &= ~((0xFF) >> remainder_bits); } Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, blink::WebCryptoKeyUsageMask actual_usages) { if (!ContainsKeyUsages(all_possible_usages, actual_usages)) return Status::ErrorCreateKeyBadUsages(); return Status::Success(); } bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, blink::WebCryptoKeyUsageMask b) { return (a & b) == b; } Status AeadEncryptDecrypt(EncryptOrDecrypt mode, base::span raw_key, base::span data, unsigned int tag_length_bytes, base::span iv, base::span additional_data, const EVP_AEAD* aead_alg, std::vector* buffer) { crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); bssl::ScopedEVP_AEAD_CTX ctx; if (!aead_alg) return Status::ErrorUnexpected(); if (!EVP_AEAD_CTX_init(ctx.get(), aead_alg, raw_key.data(), raw_key.size(), tag_length_bytes, nullptr)) { return Status::OperationError(); } size_t len; int ok; if (mode == DECRYPT) { if (data.size() < tag_length_bytes) return Status::ErrorDataTooSmall(); buffer->resize(data.size() - tag_length_bytes); ok = EVP_AEAD_CTX_open(ctx.get(), buffer->data(), &len, buffer->size(), iv.data(), iv.size(), data.data(), data.size(), additional_data.data(), additional_data.size()); } else { // No need to check for unsigned integer overflow here (seal fails if // the output buffer is too small). buffer->resize(data.size() + EVP_AEAD_max_overhead(aead_alg)); ok = EVP_AEAD_CTX_seal(ctx.get(), buffer->data(), &len, buffer->size(), iv.data(), iv.size(), data.data(), data.size(), additional_data.data(), additional_data.size()); } if (!ok) return Status::OperationError(); buffer->resize(len); return Status::Success(); } } // namespace webcrypto