Coverage Report

Created: 2021-10-13 08:49

/src/botan/src/lib/pk_pad/emsa1/emsa1.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* EMSA1
3
* (C) 1999-2007,2021 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/internal/emsa1.h>
9
#include <botan/exceptn.h>
10
#include <botan/pk_keys.h>
11
#include <botan/internal/padding.h>
12
13
namespace Botan {
14
15
namespace {
16
17
secure_vector<uint8_t> emsa1_encoding(const secure_vector<uint8_t>& msg,
18
                                  size_t output_bits)
19
511
   {
20
511
   const size_t msg_bits = 8*msg.size();
21
511
   if(msg_bits <= output_bits)
22
365
      return msg;
23
24
146
   const size_t shift = msg_bits - output_bits;
25
146
   const size_t byte_shift = shift / 8;
26
146
   const size_t bit_shift = shift % 8;
27
28
146
   secure_vector<uint8_t> digest(msg.size() - byte_shift);
29
30
4.05k
   for(size_t i = 0; i != msg.size() - byte_shift; ++i)
31
3.90k
      digest[i] = msg[i];
32
33
146
   if(bit_shift)
34
50
      {
35
50
      uint8_t carry = 0;
36
1.27k
      for(size_t i = 0; i != digest.size(); ++i)
37
1.22k
         {
38
1.22k
         uint8_t temp = digest[i];
39
1.22k
         digest[i] = (temp >> bit_shift) | carry;
40
1.22k
         carry = (temp << (8 - bit_shift));
41
1.22k
         }
42
50
      }
43
146
   return digest;
44
511
   }
45
46
}
47
48
std::string EMSA1::name() const
49
0
   {
50
0
   return "EMSA1(" + m_hash->name() + ")";
51
0
   }
52
53
std::unique_ptr<EMSA> EMSA1::new_object()
54
0
   {
55
0
   return std::make_unique<EMSA1>(m_hash->new_object());
56
0
   }
57
58
void EMSA1::update(const uint8_t input[], size_t length)
59
725
   {
60
725
   m_hash->update(input, length);
61
725
   }
62
63
secure_vector<uint8_t> EMSA1::raw_data()
64
511
   {
65
511
   return m_hash->final();
66
511
   }
67
68
secure_vector<uint8_t> EMSA1::encoding_of(const secure_vector<uint8_t>& msg,
69
                                       size_t output_bits,
70
                                       RandomNumberGenerator&)
71
511
   {
72
511
   if(msg.size() != hash_output_length())
73
0
      throw Encoding_Error("EMSA1::encoding_of: Invalid size for input");
74
511
   return emsa1_encoding(msg, output_bits);
75
511
   }
76
77
bool EMSA1::verify(const secure_vector<uint8_t>& input,
78
                   const secure_vector<uint8_t>& raw,
79
                   size_t key_bits)
80
0
   {
81
0
   if(raw.size() != m_hash->output_length())
82
0
      return false;
83
84
   // Call emsa1_encoding to handle any required bit shifting
85
0
   const secure_vector<uint8_t> our_coding = emsa1_encoding(raw, key_bits);
86
87
0
   if(our_coding.size() < input.size())
88
0
      return false;
89
90
0
   const size_t offset = our_coding.size() - input.size(); // must be >= 0 per check above
91
92
   // If our encoding is longer, all the bytes in it must be zero
93
0
   for(size_t i = 0; i != offset; ++i)
94
0
      if(our_coding[i] != 0)
95
0
         return false;
96
97
0
   return constant_time_compare(input.data(), &our_coding[offset], input.size());
98
0
   }
99
100
AlgorithmIdentifier EMSA1::config_for_x509(const Private_Key& key,
101
                                           const std::string& cert_hash_name) const
102
0
   {
103
0
   if(cert_hash_name != m_hash->name())
104
0
      throw Invalid_Argument("Hash function from opts and hash_fn argument"
105
0
         " need to be identical");
106
   // check that the signature algorithm and the padding scheme fit
107
0
   if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA1"))
108
0
      {
109
0
      throw Invalid_Argument("Encoding scheme with canonical name EMSA1"
110
0
         " not supported for signature algorithm " + key.algo_name());
111
0
      }
112
113
0
   const OID oid = OID::from_string(key.algo_name() + "/" + name());
114
115
0
   const std::string algo_name = key.algo_name();
116
0
   std::vector<uint8_t> parameters;
117
0
   if(algo_name == "DSA" ||
118
0
      algo_name == "ECDSA" ||
119
0
      algo_name == "ECGDSA" ||
120
0
      algo_name == "ECKCDSA" ||
121
0
      algo_name == "GOST-34.10" ||
122
0
      algo_name == "GOST-34.10-2012-256" ||
123
0
      algo_name == "GOST-34.10-2012-512")
124
0
      {
125
      // for DSA, ECDSA, GOST parameters "SHALL" be empty
126
0
      }
127
0
   else
128
0
      {
129
0
      parameters = key.algorithm_identifier().get_parameters();
130
0
      }
131
132
0
   return AlgorithmIdentifier(oid, parameters);
133
0
   }
134
135
}