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