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