Home | History | Annotate | Download | only in unittests
      1 /*############################################################################
      2 # Copyright 2017 Intel Corporation
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #     http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 ############################################################################*/
     16 /// One time pad class
     17 /*! \file */
     18 
     19 #ifndef EPID_MEMBER_TINY_MATH_UNITTESTS_ONETIMEPAD_H_
     20 #define EPID_MEMBER_TINY_MATH_UNITTESTS_ONETIMEPAD_H_
     21 
     22 #include <climits>  // for CHAR_BIT
     23 #include <cstdint>
     24 #include <random>
     25 #include <stdexcept>
     26 #include <vector>
     27 
     28 #if defined(_WIN32) || defined(_WIN64)
     29 #define __STDCALL __stdcall
     30 #else
     31 #define __STDCALL
     32 #endif
     33 
     34 /// One time pad with Bitsupplier interface
     35 class OneTimePad {
     36  public:
     37   /// Default constructor
     38   OneTimePad() : bytes_consumed_(0), reported_having_no_data_(false) {}
     39   /// Construct using mersenne twister
     40   explicit OneTimePad(size_t num_bytes)
     41       : bytes_consumed_(0), reported_having_no_data_(false) {
     42     data_.resize(num_bytes);
     43     std::mt19937 generator;
     44     generator.seed(1);
     45     for (size_t i = 0; i < num_bytes; i++)
     46       data_[i] = static_cast<uint8_t>(generator() & 0x000000ff);
     47   }
     48   /// Construct with data
     49   explicit OneTimePad(std::vector<uint8_t> const& uint8_data)
     50       : reported_having_no_data_(false) {
     51     InitUint8(uint8_data);
     52   }
     53   /// Re-initialize with unit8 data
     54   void InitUint8(std::vector<uint8_t> const& uint8_data) {
     55     if (uint8_data.size() > SIZE_MAX / CHAR_BIT)
     56       throw std::invalid_argument("input exceeded SIZE_MAX bits");
     57     bytes_consumed_ = 0;
     58     data_.clear();
     59     data_ = uint8_data;
     60     reported_having_no_data_ = false;
     61   }
     62   /// Re-initialize with unit32 data
     63   void InitUint32(std::vector<uint32_t> const& uint32_data) {
     64     if (uint32_data.size() * sizeof(uint32_t) > SIZE_MAX / CHAR_BIT)
     65       throw std::invalid_argument("input exceeded SIZE_MAX bits");
     66     bytes_consumed_ = 0;
     67     data_.clear();
     68     for (auto u32 : uint32_data) {
     69       data_.push_back((uint8_t)(u32 & 0xFF));
     70       data_.push_back((uint8_t)((u32 & 0xFF00) >> 8));
     71       data_.push_back((uint8_t)((u32 & 0xFF0000) >> 16));
     72       data_.push_back((uint8_t)((u32 & 0xFF000000) >> 24));
     73       reported_having_no_data_ = false;
     74     }
     75   }
     76   /// Destructor
     77   ~OneTimePad() {}
     78   /// returns bits consumed
     79   size_t BitsConsumed() const { return bytes_consumed_ * CHAR_BIT; }
     80   /// Generates random number
     81   static int __STDCALL Generate(unsigned int* random_data, int num_bits,
     82                                 void* user_data) {
     83     size_t num_bytes = num_bits / CHAR_BIT;
     84     size_t extra_bits = num_bits % CHAR_BIT;
     85     uint8_t* random_bytes = reinterpret_cast<uint8_t*>(random_data);
     86     OneTimePad* myprng = (OneTimePad*)user_data;
     87     if ((!random_data) || (num_bits <= 0)) {
     88       return -5;  // bad arg
     89     }
     90     if (myprng->reported_having_no_data_) {
     91       throw std::runtime_error(
     92           "request for random data after being informed random data was "
     93           "exhausted");
     94     }
     95     if ((size_t)num_bits > myprng->BitsAvailable()) {
     96       // cause an exception to be thrown on next invocation
     97       myprng->reported_having_no_data_ = true;
     98       return -1;  // out of random data
     99     }
    100     if (0 != extra_bits) {
    101       // can only handle even number of byte requests
    102       return -5;
    103     }
    104 
    105     for (unsigned int n = 0; n < num_bytes; n++) {
    106       random_bytes[n] = myprng->data_[myprng->bytes_consumed_++];
    107     }
    108     return 0;
    109   }
    110 
    111  private:
    112   /// returns bits available
    113   size_t BitsAvailable() const {
    114     return (data_.size() - bytes_consumed_) * CHAR_BIT;
    115   }
    116 
    117   size_t bytes_consumed_ = 0;
    118   std::vector<uint8_t> data_;
    119   bool reported_having_no_data_ = false;
    120 };
    121 
    122 #endif  // EPID_MEMBER_TINY_MATH_UNITTESTS_ONETIMEPAD_H_
    123