• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5230455705

10 Jun 2023 02:30PM UTC coverage: 91.715% (-0.03%) from 91.746%
5230455705

push

github

randombit
Merge GH #3584 Change clang-format AllowShortFunctionsOnASingleLine config from All to Inline

77182 of 84154 relevant lines covered (91.72%)

11975295.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.4
/src/lib/ffi/ffi_cipher.cpp
1
/*
2
* (C) 2015,2017 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/ffi.h>
8

9
#include <botan/aead.h>
10
#include <botan/internal/ffi_util.h>
11

12
extern "C" {
13

14
using namespace Botan_FFI;
15

16
struct botan_cipher_struct final : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C> {
17
   public:
18
      explicit botan_cipher_struct(std::unique_ptr<Botan::Cipher_Mode> x, size_t update_size) :
18✔
19
            botan_struct(std::move(x)), m_update_size(update_size) {
18✔
20
         m_buf.reserve(m_update_size);
18✔
21
      }
18✔
22

23
      Botan::secure_vector<uint8_t>& buf() { return m_buf; }
32✔
24

25
      size_t update_size() const { return m_update_size; }
8✔
26

27
   private:
28
      Botan::secure_vector<uint8_t> m_buf;
29
      size_t m_update_size;
30
};
31

32
namespace {
33

34
size_t ffi_choose_update_size(Botan::Cipher_Mode& mode) {
18✔
35
   const size_t update_granularity = mode.update_granularity();
18✔
36
   const size_t minimum_final_size = mode.minimum_final_size();
18✔
37

38
   /*
39
   * Return the minimum possible granularity given the FFI API constraints that
40
   * we require the returned size be > minimum final size.
41
   *
42
   * If the minimum final size is zero, or the update_granularity is
43
   * already greater, just use that.
44
   *
45
   * Otherwise scale the update_granularity to a sufficient size
46
   * to be greater than the minimum.
47
   */
48
   if(minimum_final_size == 0 || update_granularity > minimum_final_size) {
18✔
49
      BOTAN_ASSERT_NOMSG(update_granularity > 0);
9✔
50
      return update_granularity;
51
   }
52

53
   size_t buf_size = std::max(update_granularity, minimum_final_size + 1);
9✔
54
   if(buf_size % update_granularity != 0) {
9✔
55
      buf_size += update_granularity - (buf_size % update_granularity);
6✔
56
   }
57

58
   return buf_size;
59
}
60

61
}  // namespace
62

63
int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags) {
18✔
64
   return ffi_guard_thunk(__func__, [=]() -> int {
18✔
65
      const bool encrypt_p = ((flags & BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION) == BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
18✔
66
      const Botan::Cipher_Dir dir = encrypt_p ? Botan::Cipher_Dir::Encryption : Botan::Cipher_Dir::Decryption;
18✔
67

68
      std::unique_ptr<Botan::Cipher_Mode> mode(Botan::Cipher_Mode::create(cipher_name, dir));
18✔
69
      if(!mode) {
18✔
70
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
71
      }
72

73
      const size_t update_size = ffi_choose_update_size(*mode);
18✔
74

75
      *cipher = new botan_cipher_struct(std::move(mode), update_size);
18✔
76
      return BOTAN_FFI_SUCCESS;
18✔
77
   });
36✔
78
}
79

80
int botan_cipher_destroy(botan_cipher_t cipher) {
18✔
81
   return BOTAN_FFI_CHECKED_DELETE(cipher);
18✔
82
}
83

84
int botan_cipher_clear(botan_cipher_t cipher) {
6✔
85
   return BOTAN_FFI_VISIT(cipher, [](auto& c) { c.clear(); });
12✔
86
}
87

88
int botan_cipher_reset(botan_cipher_t cipher) {
2✔
89
   return BOTAN_FFI_VISIT(cipher, [](auto& c) { c.reset(); });
4✔
90
}
91

92
int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t* out_len) {
4✔
93
   if(out_len == nullptr) {
4✔
94
      return BOTAN_FFI_ERROR_NULL_POINTER;
95
   }
96

97
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *out_len = c.output_length(in_len); });
8✔
98
}
99

100
int botan_cipher_query_keylen(botan_cipher_t cipher, size_t* out_minimum_keylength, size_t* out_maximum_keylength) {
7✔
101
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
14✔
102
      *out_minimum_keylength = c.key_spec().minimum_keylength();
103
      *out_maximum_keylength = c.key_spec().maximum_keylength();
104
   });
105
}
106

107
int botan_cipher_get_keyspec(botan_cipher_t cipher,
1✔
108
                             size_t* out_minimum_keylength,
109
                             size_t* out_maximum_keylength,
110
                             size_t* out_keylength_modulo) {
111
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) {
2✔
112
      if(out_minimum_keylength)
113
         *out_minimum_keylength = c.key_spec().minimum_keylength();
114
      if(out_maximum_keylength)
115
         *out_maximum_keylength = c.key_spec().maximum_keylength();
116
      if(out_keylength_modulo)
117
         *out_keylength_modulo = c.key_spec().keylength_multiple();
118
   });
119
}
120

121
int botan_cipher_set_key(botan_cipher_t cipher, const uint8_t* key, size_t key_len) {
27✔
122
   return BOTAN_FFI_VISIT(cipher, [=](auto& c) { c.set_key(key, key_len); });
54✔
123
}
124

125
int botan_cipher_start(botan_cipher_t cipher_obj, const uint8_t* nonce, size_t nonce_len) {
29✔
126
   return ffi_guard_thunk(__func__, [=]() -> int {
29✔
127
      Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
29✔
128
      cipher.start(nonce, nonce_len);
29✔
129
      return BOTAN_FFI_SUCCESS;
29✔
130
   });
29✔
131
}
132

133
int botan_cipher_update(botan_cipher_t cipher_obj,
32✔
134
                        uint32_t flags,
135
                        uint8_t output_ptr[],
136
                        size_t orig_output_size,
137
                        size_t* output_written,
138
                        const uint8_t input_ptr[],
139
                        size_t orig_input_size,
140
                        size_t* input_consumed) {
141
   return ffi_guard_thunk(__func__, [=]() -> int {
32✔
142
      size_t input_size = orig_input_size;
32✔
143
      size_t output_size = orig_output_size;
32✔
144
      const uint8_t* input = input_ptr;
32✔
145
      uint8_t* output = output_ptr;
32✔
146

147
      using namespace Botan;
32✔
148
      Cipher_Mode& cipher = safe_get(cipher_obj);
32✔
149
      secure_vector<uint8_t>& mbuf = cipher_obj->buf();
32✔
150

151
      const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL);
32✔
152

153
      if(final_input) {
32✔
154
         mbuf.assign(input, input + input_size);
20✔
155
         *input_consumed = input_size;
28✔
156
         *output_written = 0;
52✔
157

158
         try {
20✔
159
            cipher.finish(mbuf);
20✔
160
         } catch(Invalid_Authentication_Tag&) {
×
161
            return BOTAN_FFI_ERROR_BAD_MAC;
×
162
         }
×
163

164
         *output_written = mbuf.size();
20✔
165

166
         if(mbuf.size() <= output_size) {
20✔
167
            copy_mem(output, mbuf.data(), mbuf.size());
20✔
168
            mbuf.clear();
20✔
169
            return BOTAN_FFI_SUCCESS;
20✔
170
         }
171

172
         return -1;
173
      }
174

175
      if(input_size == 0) {
12✔
176
         // Currently must take entire buffer in this case
177
         *output_written = mbuf.size();
4✔
178
         if(output_size >= mbuf.size()) {
4✔
179
            copy_mem(output, mbuf.data(), mbuf.size());
4✔
180
            mbuf.clear();
4✔
181
            return BOTAN_FFI_SUCCESS;
4✔
182
         }
183

184
         return -1;
185
      }
186

187
      const size_t ud = cipher_obj->update_size();
8✔
188

189
      mbuf.resize(ud);
8✔
190
      size_t taken = 0, written = 0;
8✔
191

192
      while(input_size >= ud && output_size >= ud) {
138✔
193
         // FIXME we can use process here and avoid the copy
194
         copy_mem(mbuf.data(), input, ud);
122✔
195
         cipher.update(mbuf);
122✔
196

197
         input_size -= ud;
122✔
198
         copy_mem(output, mbuf.data(), ud);
122✔
199
         input += ud;
122✔
200
         taken += ud;
122✔
201

202
         output_size -= ud;
122✔
203
         output += ud;
122✔
204
         written += ud;
122✔
205
      }
206

207
      *output_written = written;
8✔
208
      *input_consumed = taken;
8✔
209

210
      return BOTAN_FFI_SUCCESS;
8✔
211
   });
32✔
212
}
213

214
int botan_cipher_set_associated_data(botan_cipher_t cipher, const uint8_t* ad, size_t ad_len) {
4✔
215
   return BOTAN_FFI_VISIT(cipher, [=](auto& c) {
8✔
216
      if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c)) {
217
         aead->set_associated_data(ad, ad_len);
218
         return BOTAN_FFI_SUCCESS;
219
      }
220
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
221
   });
222
}
223

224
int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl) {
6✔
225
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return c.valid_nonce_length(nl) ? 1 : 0; });
12✔
226
}
227

228
int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl) {
6✔
229
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *nl = c.default_nonce_length(); });
12✔
230
}
231

232
int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug) {
×
233
   return BOTAN_FFI_VISIT(cipher, [=](const auto& /*c*/) { *ug = cipher->update_size(); });
×
234
}
235

236
int botan_cipher_get_ideal_update_granularity(botan_cipher_t cipher, size_t* ug) {
×
237
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *ug = c.ideal_granularity(); });
×
238
}
239

240
int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl) {
6✔
241
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { *tl = c.tag_size(); });
12✔
242
}
243

244
int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len) {
6✔
245
   return BOTAN_FFI_VISIT(cipher, [=](const auto& c) { return write_str_output(name, name_len, c.name()); });
14✔
246
}
247
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc