1 /* 2 ** 3 ** Copyright 2017, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #ifndef CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_ 19 #define CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_ 20 21 #include <stddef.h> 22 #include <stdint.h> 23 #include <algorithm> 24 #include <initializer_list> 25 #include <type_traits> 26 27 namespace android { 28 namespace hardware { 29 namespace confirmationui { 30 namespace support { 31 32 /** 33 * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out 34 * of band. Note that if the wrapped value is a reference it is unsafe to access the value if 35 * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the 36 * wrapped value. In this case the pointer will be NULL though, and the value will be default 37 * constructed. 38 */ 39 template <typename ValueT> 40 class NullOr { 41 template <typename T> 42 struct reference_initializer { initreference_initializer43 static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); } 44 }; 45 template <typename T> 46 struct pointer_initializer { initpointer_initializer47 static T init() { return nullptr; } 48 }; 49 template <typename T> 50 struct value_initializer { initvalue_initializer51 static T init() { return T(); } 52 }; 53 template <typename T> 54 using initializer_t = 55 std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>, 56 std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>, 57 value_initializer<T>>>; 58 59 public: NullOr()60 NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {} 61 template <typename T> NullOr(T && value)62 NullOr(T&& value) : value_(std::forward<T>(value)), null_(false) {} 63 isOk()64 bool isOk() const { return !null_; } 65 value()66 const ValueT& value() const & { return value_; } value()67 ValueT& value() & { return value_; } value()68 ValueT&& value() && { return std::move(value_); } 69 70 const std::remove_reference_t<ValueT>* operator->() const { return &value_; } 71 std::remove_reference_t<ValueT>* operator->() { return &value_; } 72 73 private: 74 ValueT value_; 75 bool null_; 76 }; 77 78 template <typename T, size_t elements> 79 class array { 80 using array_type = T[elements]; 81 82 public: array()83 array() : data_{} {} array(const T (& data)[elements])84 array(const T (&data)[elements]) { std::copy(data, data + elements, data_); } array(const T & v)85 explicit array(const T& v) { fill(v); } 86 data()87 T* data() { return data_; } data()88 const T* data() const { return data_; } size()89 constexpr size_t size() const { return elements; } 90 begin()91 T* begin() { return data_; } end()92 T* end() { return data_ + elements; } begin()93 const T* begin() const { return data_; } end()94 const T* end() const { return data_ + elements; } 95 fill(const T & v)96 void fill(const T& v) { 97 for (size_t i = 0; i < elements; ++i) { 98 data_[i] = v; 99 } 100 } 101 102 private: 103 array_type data_; 104 }; 105 106 template <typename T> 107 auto bytes_cast(const T& v) -> const uint8_t (&)[sizeof(T)] { 108 return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v); 109 } 110 template <typename T> 111 auto bytes_cast(T& v) -> uint8_t (&)[sizeof(T)] { 112 return *reinterpret_cast<uint8_t(*)[sizeof(T)]>(&v); 113 } 114 115 class ByteBufferProxy { 116 template <typename T> 117 struct has_data { 118 template <typename U> fhas_data119 static int f(const U*, const void*) { 120 return 0; 121 } 122 template <typename U> 123 static int* f(const U* u, decltype(u->data())) { 124 return nullptr; 125 } 126 static constexpr bool value = std::is_pointer<decltype(f((T*)nullptr, ""))>::value; 127 }; 128 129 public: 130 template <typename T> 131 ByteBufferProxy(const T& buffer, decltype(buffer.data()) = nullptr) 132 : data_(reinterpret_cast<const uint8_t*>(buffer.data())), size_(buffer.size()) { 133 static_assert(sizeof(decltype(*buffer.data())) == 1, "elements to large"); 134 } 135 136 // this overload kicks in for types that have .c_str() but not .data(), such as hidl_string. 137 // std::string has both so we need to explicitly disable this overload if .data() is present. 138 template <typename T> 139 ByteBufferProxy(const T& buffer, 140 std::enable_if_t<!has_data<T>::value, decltype(buffer.c_str())> = nullptr) 141 : data_(reinterpret_cast<const uint8_t*>(buffer.c_str())), size_(buffer.size()) { 142 static_assert(sizeof(decltype(*buffer.c_str())) == 1, "elements to large"); 143 } 144 145 template <size_t size> ByteBufferProxy(const char (& buffer)[size])146 ByteBufferProxy(const char (&buffer)[size]) 147 : data_(reinterpret_cast<const uint8_t*>(buffer)), size_(size - 1) { 148 static_assert(size > 0, "even an empty string must be 0-terminated"); 149 } 150 151 template <size_t size> ByteBufferProxy(const uint8_t (& buffer)[size])152 ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {} 153 ByteBufferProxy()154 ByteBufferProxy() : data_(nullptr), size_(0) {} 155 data()156 const uint8_t* data() const { return data_; } size()157 size_t size() const { return size_; } 158 begin()159 const uint8_t* begin() const { return data_; } end()160 const uint8_t* end() const { return data_ + size_; } 161 162 private: 163 const uint8_t* data_; 164 size_t size_; 165 }; 166 167 constexpr uint8_t auth_token_key_size = 32; 168 constexpr uint8_t hmac_size_bytes = support::auth_token_key_size; 169 using auth_token_key_t = array<uint8_t, auth_token_key_size>; 170 using hmac_t = auth_token_key_t; 171 172 /** 173 * Implementer are expected to provide an implementation with the following prototype: 174 * static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32], 175 * std::initializer_list<ByteBufferProxy> buffers); 176 */ 177 template <typename Impl> 178 class HMac { 179 public: 180 template <typename... Data> hmac256(const auth_token_key_t & key,const Data &...data)181 static NullOr<hmac_t> hmac256(const auth_token_key_t& key, const Data&... data) { 182 return Impl::hmac256(key, {data...}); 183 } 184 }; 185 186 bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs); 187 188 template <typename IntType, uint32_t byteOrder> 189 struct choose_hton; 190 191 template <typename IntType> 192 struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> { 193 inline static IntType hton(const IntType& value) { 194 IntType result = {}; 195 const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value); 196 unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result); 197 for (int i = sizeof(IntType) - 1; i >= 0; --i) { 198 *(outbytes++) = inbytes[i]; 199 } 200 return result; 201 } 202 }; 203 204 template <typename IntType> 205 struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> { 206 inline static IntType hton(const IntType& value) { return value; } 207 }; 208 209 template <typename IntType> 210 inline IntType hton(const IntType& value) { 211 return choose_hton<IntType, __BYTE_ORDER__>::hton(value); 212 } 213 214 template <typename IntType> 215 inline IntType ntoh(const IntType& value) { 216 // same operation as hton 217 return choose_hton<IntType, __BYTE_ORDER__>::hton(value); 218 } 219 220 } // namespace support 221 } // namespace confirmationui 222 } // namespace hardware 223 } // namespace android 224 225 #endif // CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_ 226