// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /////////////////////////////////////////////////////////////////////////////// #ifndef TINK_UTIL_SECRET_DATA_H_ #define TINK_UTIL_SECRET_DATA_H_ #include #include #include #include #include "absl/strings/string_view.h" #include "tink/util/secret_data_internal.h" namespace crypto { namespace tink { namespace util { namespace internal { template struct SanitizingDeleter { void operator()(T* ptr) { ptr->~T(); // Invoke destructor. Must do this before sanitize. SanitizingAllocator().deallocate(ptr, 1); } }; } // namespace internal // Stores secret (sensitive) data and makes sure it's marked as such and // destroyed in a safe way. // This should be the first choice when handling key/key derived values. // // Example: // class MyCryptoPrimitive { // public: // MyCryptoPrimitive(absl::string_view key_value) : // key_(SecretDataFromStringView(key_value)) {} // [...] // private: // const util::SecretData key_; // } using SecretData = std::vector>; // Stores secret (sensitive) object and makes sure it's marked as such and // destroyed in a safe way. // SecretUniquePtr MUST be constructed using MakeSecretUniquePtr function. // Generally SecretUniquePtr should be used iff SecretData is unsuitable. // // Example: // class MyCryptoPrimitive { // public: // MyEncryptionPrimitive(absl::string_view key_value) { // AES_set_encrypt_key(key_value.data(), key_value.size() * 8, key_.get()); // } // [...] // private: // util::SecretUniquePtr key_ = util::MakeSecretUniquePtr(); // } // // NOTE: SecretUniquePtr will only protect the data which is stored in the // memory which a T object takes on the stack. In particular, std::string and // std::vector SHOULD NOT be used as arguments of T: they allocate memory // on the heap, and hence the data stored in them will NOT be protected. template class SecretUniquePtr { private: using Value = std::unique_ptr>; public: using pointer = typename Value::pointer; using element_type = typename Value::element_type; using deleter_type = typename Value::deleter_type; SecretUniquePtr() = default; pointer get() const { return value_.get(); } deleter_type& get_deleter() { return value_.get_deleter(); } const deleter_type& get_deleter() const { return value_.get_deleter(); } void swap(SecretUniquePtr& other) { value_.swap(other.value_); } void reset() { value_.reset(); } typename std::add_lvalue_reference::type operator*() const { return value_.operator*(); } pointer operator->() const { return value_.operator->(); } explicit operator bool() const { return value_.operator bool(); } private: template friend SecretUniquePtr MakeSecretUniquePtr(Args&&... args); explicit SecretUniquePtr(Value&& value) : value_(std::move(value)) {} Value value_; }; template SecretUniquePtr MakeSecretUniquePtr(Args&&... args) { T* ptr = internal::SanitizingAllocator().allocate(1); new (ptr) T(std::forward(args)...); // Invoke constructor "placement new" return SecretUniquePtr({ptr, internal::SanitizingDeleter()}); } // Convenience conversion functions inline absl::string_view SecretDataAsStringView(const SecretData& secret) { return {reinterpret_cast(secret.data()), secret.size()}; } inline SecretData SecretDataFromStringView(absl::string_view secret) { return {secret.begin(), secret.end()}; } // The same as SecretUniquePtr, but with value semantics. // // NOTE: SecretValue will only protect the data which is stored in the // memory which a T object takes on the stack. In particular, std::string and // std::vector SHOULD NOT be used as arguments of T: they allocate memory // on the heap, and hence the data stored in them will NOT be protected. template class SecretValue { public: explicit SecretValue(T t = T()) : ptr_(MakeSecretUniquePtr(std::move(t))) {} SecretValue(const SecretValue& other) { ptr_ = MakeSecretUniquePtr(*other.ptr_); } SecretValue& operator=(const SecretValue& other) { *ptr_ = *other.ptr_; return *this; } T& value() { return *ptr_; } const T& value() const { return *ptr_; } private: SecretUniquePtr ptr_; }; inline void SafeZeroMemory(void* ptr, std::size_t size) { internal::SafeZeroMemory(ptr, size); } inline void SafeZeroString(std::string* str) { SafeZeroMemory(&(*str)[0], str->size()); } } // namespace util } // namespace tink } // namespace crypto #endif // TINK_UTIL_SECRET_DATA_H_