1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #ifndef TINK_UTIL_SECRET_DATA_H_
18 #define TINK_UTIL_SECRET_DATA_H_
19
20 #include <memory>
21 #include <string>
22 #include <type_traits>
23 #include <vector>
24
25 #include "absl/strings/string_view.h"
26 #include "tink/util/secret_data_internal.h"
27
28 namespace crypto {
29 namespace tink {
30 namespace util {
31 namespace internal {
32
33 template <typename T>
34 struct SanitizingDeleter {
operatorSanitizingDeleter35 void operator()(T* ptr) {
36 ptr->~T(); // Invoke destructor. Must do this before sanitize.
37 SanitizingAllocator<T>().deallocate(ptr, 1);
38 }
39 };
40
41 } // namespace internal
42
43 // Stores secret (sensitive) data and makes sure it's marked as such and
44 // destroyed in a safe way.
45 // This should be the first choice when handling key/key derived values.
46 //
47 // Example:
48 // class MyCryptoPrimitive {
49 // public:
50 // MyCryptoPrimitive(absl::string_view key_value) :
51 // key_(SecretDataFromStringView(key_value)) {}
52 // [...]
53 // private:
54 // const util::SecretData key_;
55 // }
56 using SecretData = std::vector<uint8_t, internal::SanitizingAllocator<uint8_t>>;
57
58 // Stores secret (sensitive) object and makes sure it's marked as such and
59 // destroyed in a safe way.
60 // SecretUniquePtr MUST be constructed using MakeSecretUniquePtr function.
61 // Generally SecretUniquePtr should be used iff SecretData is unsuitable.
62 //
63 // Example:
64 // class MyCryptoPrimitive {
65 // public:
66 // MyEncryptionPrimitive(absl::string_view key_value) {
67 // AES_set_encrypt_key(key_value.data(), key_value.size() * 8, key_.get());
68 // }
69 // [...]
70 // private:
71 // util::SecretUniquePtr<AES_KEY> key_ = util::MakeSecretUniquePtr<AES_KEY>();
72 // }
73 //
74 // NOTE: SecretUniquePtr<T> will only protect the data which is stored in the
75 // memory which a T object takes on the stack. In particular, std::string and
76 // std::vector SHOULD NOT be used as arguments of T: they allocate memory
77 // on the heap, and hence the data stored in them will NOT be protected.
78 template <typename T>
79 class SecretUniquePtr {
80 private:
81 using Value = std::unique_ptr<T, internal::SanitizingDeleter<T>>;
82
83 public:
84 using pointer = typename Value::pointer;
85 using element_type = typename Value::element_type;
86 using deleter_type = typename Value::deleter_type;
87
88 SecretUniquePtr() = default;
89
get()90 pointer get() const { return value_.get(); }
get_deleter()91 deleter_type& get_deleter() { return value_.get_deleter(); }
get_deleter()92 const deleter_type& get_deleter() const { return value_.get_deleter(); }
swap(SecretUniquePtr & other)93 void swap(SecretUniquePtr& other) { value_.swap(other.value_); }
reset()94 void reset() { value_.reset(); }
95
96 typename std::add_lvalue_reference<T>::type operator*() const {
97 return value_.operator*();
98 }
99 pointer operator->() const { return value_.operator->(); }
100 explicit operator bool() const { return value_.operator bool(); }
101
102 private:
103 template <typename S, typename... Args>
104 friend SecretUniquePtr<S> MakeSecretUniquePtr(Args&&... args);
SecretUniquePtr(Value && value)105 explicit SecretUniquePtr(Value&& value) : value_(std::move(value)) {}
106 Value value_;
107 };
108
109 template <typename T, typename... Args>
MakeSecretUniquePtr(Args &&...args)110 SecretUniquePtr<T> MakeSecretUniquePtr(Args&&... args) {
111 T* ptr = internal::SanitizingAllocator<T>().allocate(1);
112 new (ptr)
113 T(std::forward<Args>(args)...); // Invoke constructor "placement new"
114 return SecretUniquePtr<T>({ptr, internal::SanitizingDeleter<T>()});
115 }
116
117 // Convenience conversion functions
SecretDataAsStringView(const SecretData & secret)118 inline absl::string_view SecretDataAsStringView(const SecretData& secret) {
119 return {reinterpret_cast<const char*>(secret.data()), secret.size()};
120 }
121
SecretDataFromStringView(absl::string_view secret)122 inline SecretData SecretDataFromStringView(absl::string_view secret) {
123 return {secret.begin(), secret.end()};
124 }
125
126 // The same as SecretUniquePtr, but with value semantics.
127 //
128 // NOTE: SecretValue<T> will only protect the data which is stored in the
129 // memory which a T object takes on the stack. In particular, std::string and
130 // std::vector SHOULD NOT be used as arguments of T: they allocate memory
131 // on the heap, and hence the data stored in them will NOT be protected.
132 template <typename T>
133 class SecretValue {
134 public:
135 explicit SecretValue(T t = T())
ptr_(MakeSecretUniquePtr<T> (std::move (t)))136 : ptr_(MakeSecretUniquePtr<T>(std::move(t))) {}
137
SecretValue(const SecretValue & other)138 SecretValue(const SecretValue& other) {
139 ptr_ = MakeSecretUniquePtr<T>(*other.ptr_);
140 }
141
142 SecretValue& operator=(const SecretValue& other) {
143 *ptr_ = *other.ptr_;
144 return *this;
145 }
146
value()147 T& value() { return *ptr_; }
value()148 const T& value() const { return *ptr_; }
149
150 private:
151 SecretUniquePtr<T> ptr_;
152 };
153
SafeZeroMemory(void * ptr,std::size_t size)154 inline void SafeZeroMemory(void* ptr, std::size_t size) {
155 internal::SafeZeroMemory(ptr, size);
156 }
157
SafeZeroString(std::string * str)158 inline void SafeZeroString(std::string* str) {
159 SafeZeroMemory(&(*str)[0], str->size());
160 }
161
162 } // namespace util
163 } // namespace tink
164 } // namespace crypto
165
166 #endif // TINK_UTIL_SECRET_DATA_H_
167