Coverage Report

Created: 2020-02-14 15:38

/src/botan/src/lib/utils/ct_utils.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 2018 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#include <botan/internal/ct_utils.h>
8
9
namespace Botan {
10
11
namespace CT {
12
13
secure_vector<uint8_t> copy_output(CT::Mask<uint8_t> bad_input,
14
                                   const uint8_t input[],
15
                                   size_t input_length,
16
                                   size_t offset)
17
2.66k
   {
18
2.66k
   if(input_length == 0)
19
0
      return secure_vector<uint8_t>();
20
2.66k
21
2.66k
   /*
22
2.66k
   * Ensure at runtime that offset <= input_length. This is an invalid input,
23
2.66k
   * but we can't throw without using the poisoned value. Instead, if it happens,
24
2.66k
   * set offset to be equal to the input length (so output_bytes becomes 0 and
25
2.66k
   * the returned vector is empty)
26
2.66k
   */
27
2.66k
   const auto valid_offset = CT::Mask<size_t>::is_lte(offset, input_length);
28
2.66k
   offset = valid_offset.select(offset, input_length);
29
2.66k
30
2.66k
   const size_t output_bytes = input_length - offset;
31
2.66k
32
2.66k
   secure_vector<uint8_t> output(input_length);
33
2.66k
34
2.66k
   /*
35
2.66k
   Move the desired output bytes to the front using a slow (O^n)
36
2.66k
   but constant time loop that does not leak the value of the offset
37
2.66k
   */
38
1.00M
   for(size_t i = 0; i != input_length; ++i)
39
1.00M
      {
40
1.00M
      /*
41
1.00M
      start index from i rather than 0 since we know j must be >= i + offset
42
1.00M
      to have any effect, and starting from i does not reveal information
43
1.00M
      */
44
1.27G
      for(size_t j = i; j != input_length; ++j)
45
1.27G
         {
46
1.27G
         const uint8_t b = input[j];
47
1.27G
         const auto is_eq = CT::Mask<size_t>::is_equal(j, offset + i);
48
1.27G
         output[i] |= is_eq.if_set_return(b);
49
1.27G
         }
50
1.00M
      }
51
2.66k
52
2.66k
   bad_input.if_set_zero_out(output.data(), output.size());
53
2.66k
54
2.66k
   /*
55
2.66k
   This is potentially not const time, depending on how std::vector is
56
2.66k
   implemented. But since we are always reducing length, it should
57
2.66k
   just amount to setting the member var holding the length.
58
2.66k
   */
59
2.66k
   CT::unpoison(output.data(), output.size());
60
2.66k
   CT::unpoison(output_bytes);
61
2.66k
   output.resize(output_bytes);
62
2.66k
   return output;
63
2.66k
   }
64
65
secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length)
66
2.29k
   {
67
2.29k
   size_t leading_zeros = 0;
68
2.29k
69
2.29k
   auto only_zeros = Mask<uint8_t>::set();
70
2.29k
71
599k
   for(size_t i = 0; i != length; ++i)
72
597k
      {
73
597k
      only_zeros &= CT::Mask<uint8_t>::is_zero(in[i]);
74
597k
      leading_zeros += only_zeros.if_set_return(1);
75
597k
      }
76
2.29k
77
2.29k
   return copy_output(CT::Mask<uint8_t>::cleared(), in, length, leading_zeros);
78
2.29k
   }
79
80
}
81
82
}