| // Copyright 2020 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIBBRILLO_BRILLO_SECURE_STRING_H_ |
| #define LIBBRILLO_BRILLO_SECURE_STRING_H_ |
| |
| #include <cstddef> |
| #include <memory> |
| #include <type_traits> |
| |
| #include <base/check.h> |
| #include <brillo/asan.h> |
| #include <brillo/brillo_export.h> |
| |
| namespace brillo { |
| |
| // An implementation of the proposed "secure_clear" standard: |
| // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1315r5.html. |
| // |
| // This function is guaranteed to fill in the whole buffer |
| // and is not subject to compiler optimization as allowed by Sub-clause 5.1.2.3 |
| // of C Standard [ISO/IEC 9899:2011] which states: |
| // In the abstract machine, all expressions are evaluated as specified by the |
| // semantics. An actual implementation need not evaluate part of an expression |
| // if it can deduce that its value is not used and that no needed side effects |
| // are produced (including any caused by calling a function or accessing |
| // a volatile object). |
| // While memset() can be optimized out in certain situations (since most |
| // compilers implement this function as intrinsic and know of its side effects), |
| // this function will not be optimized out. |
| // |
| // SecureClearBytes is used to write beyond the size() in several functions. |
| // Since this is intentional, disable address sanitizer from analyzing it. |
| BRILLO_EXPORT BRILLO_DISABLE_ASAN void SecureClearBytes(void* v, size_t n); |
| |
| // Variant of SecureClearBytes that works with contiguous containers (vector, |
| // array, etc.), strings, and c-style arrays. |
| template <typename C> |
| BRILLO_EXPORT void SecureClearContainer(C& v) { // NOLINT(runtime/references) |
| using T = std::remove_reference_t<decltype(*std::data(v))>; |
| static_assert(std::is_trivially_destructible_v<T>, |
| "Element type of the container must be trivially destructible"); |
| SecureClearBytes(std::data(v), std::size(v) * sizeof(T)); |
| } |
| |
| // Variant of SecureClearBytes that works with generic (trivially destructible) |
| // objects, including scalar objects such as "int", "int*", etc. |
| template <typename T> |
| BRILLO_EXPORT void SecureClearObject(T& v) { // NOLINT(runtime/references) |
| static_assert(!std::is_pointer_v<T>, |
| "Pass the object to be cleared, not a pointer"); |
| static_assert(!std::is_array_v<T>, "Use SecureClearContainer for arrays"); |
| static_assert(std::is_trivially_destructible_v<T>, |
| "Object must be trivially destructible"); |
| SecureClearBytes(std::addressof(v), sizeof(v)); |
| } |
| |
| // Compare [n] bytes starting at [s1] with [s2] and return 0 if they match, |
| // 1 if they don't. Time taken to perform the comparison is only dependent on |
| // [n] and not on the relationship of the match between [s1] and [s2]. |
| // When n == 0, returns 0 (same as memcmp). |
| BRILLO_EXPORT int SecureMemcmp(const void* s1, const void* s2, size_t n); |
| |
| } // namespace brillo |
| |
| #endif // LIBBRILLO_BRILLO_SECURE_STRING_H_ |