Botan  2.1.0
Crypto and TLS for C++11
compress_utils.cpp
Go to the documentation of this file.
1 /*
2 * Compression Utils
3 * (C) 2014,2016 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/internal/compress_utils.h>
9 #include <botan/exceptn.h>
10 
11 namespace Botan {
12 
13 void* Compression_Alloc_Info::do_malloc(size_t n, size_t size)
14  {
15  const size_t total_size = n * size;
16 
17  BOTAN_ASSERT_EQUAL(total_size / size, n, "Overflow check");
18 
19  // TODO maximum length check here?
20 
21  void* ptr = std::malloc(total_size);
22 
23  /*
24  * Return null rather than throwing here as we are being called by a
25  * C library and it may not be possible for an exception to unwind
26  * the call stack from here. The compression library is expecting a
27  * function written in C and a null return on error, which it will
28  * send upwards to the compression wrappers.
29  */
30 
31  if(ptr)
32  {
33  std::memset(ptr, 0, total_size);
34  m_current_allocs[ptr] = total_size;
35  }
36 
37  return ptr;
38  }
39 
40 void Compression_Alloc_Info::do_free(void* ptr)
41  {
42  if(ptr)
43  {
44  auto i = m_current_allocs.find(ptr);
45 
46  if(i == m_current_allocs.end())
47  throw Exception("Compression_Alloc_Info::free got pointer not allocated by us");
48 
49  secure_scrub_memory(ptr, i->second);
50  std::free(ptr);
51  m_current_allocs.erase(i);
52  }
53  }
54 
56  {
57  m_stream.reset();
58  }
59 
60 void Stream_Compression::start(size_t level)
61  {
62  m_stream.reset(make_stream(level));
63  }
64 
65 void Stream_Compression::process(secure_vector<uint8_t>& buf, size_t offset, uint32_t flags)
66  {
67  BOTAN_ASSERT(m_stream, "Initialized");
68  BOTAN_ASSERT(buf.size() >= offset, "Offset is sane");
69 
70  if(m_buffer.size() < buf.size() + offset)
71  m_buffer.resize(buf.size() + offset);
72 
73  // If the output buffer has zero length, .data() might return nullptr. This would
74  // make some compression algorithms (notably those provided by zlib) fail.
75  // Any small positive value works fine, but we choose 32 as it is the smallest power
76  // of two that is large enough to hold all the headers and trailers of the common
77  // formats, preventing further resizings to make room for output data.
78  if(m_buffer.size() == 0)
79  m_buffer.resize(32);
80 
81  m_stream->next_in(buf.data() + offset, buf.size() - offset);
82  m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);
83 
84  while(true)
85  {
86  m_stream->run(flags);
87 
88  if(m_stream->avail_out() == 0)
89  {
90  const size_t added = 8 + m_buffer.size();
91  m_buffer.resize(m_buffer.size() + added);
92  m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
93  }
94  else if(m_stream->avail_in() == 0)
95  {
96  m_buffer.resize(m_buffer.size() - m_stream->avail_out());
97  break;
98  }
99  }
100 
101  copy_mem(m_buffer.data(), buf.data(), offset);
102  buf.swap(m_buffer);
103  }
104 
105 void Stream_Compression::update(secure_vector<uint8_t>& buf, size_t offset, bool flush)
106  {
107  BOTAN_ASSERT(m_stream, "Initialized");
108  process(buf, offset, flush ? m_stream->flush_flag() : m_stream->run_flag());
109  }
110 
112  {
113  BOTAN_ASSERT(m_stream, "Initialized");
114  process(buf, offset, m_stream->finish_flag());
115  clear();
116  }
117 
119  {
120  m_stream.reset();
121  }
122 
123 void Stream_Decompression::start()
124  {
125  m_stream.reset(make_stream());
126  }
127 
128 void Stream_Decompression::process(secure_vector<uint8_t>& buf, size_t offset, uint32_t flags)
129  {
130  BOTAN_ASSERT(m_stream, "Initialized");
131  BOTAN_ASSERT(buf.size() >= offset, "Offset is sane");
132 
133  if(m_buffer.size() < buf.size() + offset)
134  m_buffer.resize(buf.size() + offset);
135 
136  m_stream->next_in(buf.data() + offset, buf.size() - offset);
137  m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);
138 
139  while(true)
140  {
141  const bool stream_end = m_stream->run(flags);
142 
143  if(stream_end)
144  {
145  if(m_stream->avail_in() == 0) // all data consumed?
146  {
147  m_buffer.resize(m_buffer.size() - m_stream->avail_out());
148  clear();
149  break;
150  }
151 
152  // More data follows: try to process as a following stream
153  const size_t read = (buf.size() - offset) - m_stream->avail_in();
154  start();
155  m_stream->next_in(buf.data() + offset + read, buf.size() - offset - read);
156  }
157 
158  if(m_stream->avail_out() == 0)
159  {
160  const size_t added = 8 + m_buffer.size();
161  m_buffer.resize(m_buffer.size() + added);
162  m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
163  }
164  else if(m_stream->avail_in() == 0)
165  {
166  m_buffer.resize(m_buffer.size() - m_stream->avail_out());
167  break;
168  }
169  }
170 
171  copy_mem(m_buffer.data(), buf.data(), offset);
172  buf.swap(m_buffer);
173  }
174 
176  {
177  process(buf, offset, m_stream->run_flag());
178  }
179 
181  {
182  if(buf.size() != offset || m_stream.get())
183  process(buf, offset, m_stream->finish_flag());
184 
185  if(m_stream.get())
186  throw Exception(name() + " finished but not at stream end");
187  }
188 
189 }
void secure_scrub_memory(void *ptr, size_t n)
Definition: mem_ops.cpp:17
void finish(secure_vector< uint8_t > &buf, size_t offset) finaloverride
void update(secure_vector< uint8_t > &buf, size_t offset) finaloverride
void update(secure_vector< uint8_t > &buf, size_t offset, bool flush) finaloverride
Flags flags(Flag flags)
Definition: p11.h:858
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition: assert.h:53
void finish(secure_vector< uint8_t > &buf, size_t offset) finaloverride
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:68
Definition: alg_id.cpp:13
void clear() finaloverride
virtual std::string name() const =0
void clear() finaloverride