Home | History | Annotate | Download | only in support
      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 {
     43         static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
     44     };
     45     template <typename T>
     46     struct pointer_initializer {
     47         static T init() { return nullptr; }
     48     };
     49     template <typename T>
     50     struct value_initializer {
     51         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:
     60     NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
     61     template <typename T>
     62     NullOr(T&& value) : value_(std::forward<T>(value)), null_(false) {}
     63 
     64     bool isOk() const { return !null_; }
     65 
     66     const ValueT& value() const & { return value_; }
     67     ValueT& value() & { return 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:
     83     array() : data_{} {}
     84     array(const T (&data)[elements]) { std::copy(data, data + elements, data_); }
     85     explicit array(const T& v) { fill(v); }
     86 
     87     T* data() { return data_; }
     88     const T* data() const { return data_; }
     89     constexpr size_t size() const { return elements; }
     90 
     91     T* begin() { return data_; }
     92     T* end() { return data_ + elements; }
     93     const T* begin() const { return data_; }
     94     const T* end() const { return data_ + elements; }
     95 
     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>
    119         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>
    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>
    152     ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {}
    153 
    154     ByteBufferProxy() : data_(nullptr), size_(0) {}
    155 
    156     const uint8_t* data() const { return data_; }
    157     size_t size() const { return size_; }
    158 
    159     const uint8_t* begin() const { return data_; }
    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>
    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