libkeepass 0.2.0
KeePass key database importer/exporter library
Loading...
Searching...
No Matches
stream.hh
Go to the documentation of this file.
1/*
2 * libkeepass - KeePass key database importer/exporter
3 * Copyright (C) 2014 Christian Kindahl
4 * Copyright (C) 2024 Dominik Krümpelmann
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
22#pragma once
23#include <algorithm>
24#include <array>
25#include <cassert>
26#include <cstring>
27#include <istream>
28#include <memory>
29#include <ostream>
30#include <vector>
31
32#include <zlib.h>
33
35#include "libkeepass/export.hh"
36#include "util.hh"
37
38namespace keepass {
39
40template <std::size_t N> class Cipher;
41class ChaCha20Cipher;
42
51template <std::size_t N>
52class array_iostreambuf : public std::basic_streambuf<char, std::char_traits<char>> {
53private:
54 std::array<uint8_t, N>& buffer_;
55
56protected:
57 std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way,
58 std::ios_base::openmode which) override {
59 if (which == 0)
60 return {std::streamoff(-1)};
61
62 off = clamp<std::streamoff>(0, static_cast<long long>(buffer_.size()), off);
63
64 std::streamoff lin_off = 0;
65 switch (way) {
66 case std::ios_base::beg:
67 lin_off = clamp<std::streamoff>(0, static_cast<long long>(buffer_.size()), off);
68 break;
69 case std::ios_base::cur:
70 lin_off = clamp<std::streamoff>(0, static_cast<long long>(buffer_.size()),
71 (gptr() - eback()) + off);
72 break;
73 case std::ios_base::end:
74 lin_off = clamp<std::streamoff>(0, static_cast<std::streamoff>(buffer_.size()),
75 static_cast<std::streamoff>(buffer_.size()) - off);
76 break;
77 default:
78 assert(false);
79 break;
80 };
81
82 if (which & std::ios_base::in) {
83 char* buffer_ptr = reinterpret_cast<char*>(buffer_.data());
84 setg(buffer_ptr, buffer_ptr + lin_off, buffer_ptr + buffer_.size());
85 }
86
87 return lin_off;
88 }
89
90 std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) override {
91 if (which == 0 || sp < 0 || sp >= static_cast<std::streamoff>(buffer_.size())) {
92 return {std::streamoff(-1)};
93 ;
94 }
95
96 if (which & std::ios_base::in) {
97 char* buffer_ptr = reinterpret_cast<char*>(buffer_.data());
98 setg(buffer_ptr, buffer_ptr + sp, buffer_ptr + buffer_.size());
99 }
100
101 return sp;
102 }
103
104public:
110 explicit array_iostreambuf(std::array<uint8_t, N>& buffer) : buffer_(buffer) {
111 char* buffer_ptr = reinterpret_cast<char*>(buffer.data());
112 setg(buffer_ptr, buffer_ptr, buffer_ptr + buffer.size());
113 setp(buffer_ptr, buffer_ptr + buffer.size());
114 }
115};
116
124protected:
128 struct BlockHeader {
129 uint32_t block_index{};
130 std::array<uint8_t, 32> block_hash{};
131 uint32_t block_size = 0;
132 };
133
134 uint32_t block_index_ = 0;
135 std::vector<char> block_;
136
138 std::array<uint8_t, 32> GetBlockHash() const;
139
140public:
143};
144
153 : private hashed_basic_streambuf,
154 public std::basic_streambuf<char, std::char_traits<char>> {
155private:
156 std::istream& src_;
158
160 uint64_t decoded_bytes_ = 0;
161
165 bool budget_exceeded_ = false;
166
167public:
173 explicit hashed_istreambuf(std::istream& src) : src_(src) {}
174
176 bool BudgetExceeded() const { return budget_exceeded_; }
177
184 hashed_istreambuf(std::istream& src, const detail::ResourceLimits& limits)
185 : src_(src), limits_(limits) {}
186
188 int underflow() override;
189};
190
199 : private hashed_basic_streambuf,
200 public std::basic_streambuf<char, std::char_traits<char>> {
201private:
202 static constexpr uint32_t kDefaultBlockSize = 1024 * 1024;
203
204 std::ostream& dst_;
205 const uint32_t block_size_;
206
208 bool FlushBlock();
209
210public:
216 explicit hashed_ostreambuf(std::ostream& dst) : dst_(dst), block_size_(kDefaultBlockSize) {}
217
224 hashed_ostreambuf(std::ostream& dst, uint32_t block_size) : dst_(dst), block_size_(block_size) {}
225
227 int overflow(int c) override;
228
230 int sync() override;
231};
232
241 : public std::basic_streambuf<char, std::char_traits<char>> {
242private:
243 std::istream& src_;
244 std::array<uint8_t, 64> hmac_key_ = {{0}};
246
247 uint64_t block_index_ = 0;
248 std::vector<char> block_;
249
251 uint64_t decoded_bytes_ = 0;
252
254 bool budget_exceeded_ = false;
255
257 std::array<uint8_t, 64> GetCurrentHmacKey() const;
258
259public:
266 hmac_istreambuf(std::istream& src, const uint8_t* hmac_key) : src_(src) {
267 if (hmac_key != nullptr)
268 std::memcpy(hmac_key_.data(), hmac_key, hmac_key_.size());
269 }
270
272 bool BudgetExceeded() const { return budget_exceeded_; }
273
281 hmac_istreambuf(std::istream& src, const uint8_t* hmac_key, const detail::ResourceLimits& limits)
282 : src_(src), limits_(limits) {
283 if (hmac_key != nullptr)
284 std::memcpy(hmac_key_.data(), hmac_key, hmac_key_.size());
285 }
286
289
291 int underflow() override;
292};
293
302 : public std::basic_streambuf<char, std::char_traits<char>> {
303private:
304 static constexpr uint32_t kDefaultBlockSize = 1024 * 1024;
305
306 std::ostream& dst_;
307 std::array<uint8_t, 64> hmac_key_ = {{0}};
308 const uint32_t block_size_;
309
310 uint64_t block_index_ = 0;
311 std::vector<char> block_;
312
314 std::array<uint8_t, 64> GetCurrentHmacKey() const;
315
317 bool FlushBlock();
318
319public:
326 hmac_ostreambuf(std::ostream& dst, const uint8_t* hmac_key)
327 : dst_(dst), block_size_(kDefaultBlockSize) {
328 if (hmac_key != nullptr)
329 std::memcpy(hmac_key_.data(), hmac_key, hmac_key_.size());
330 }
331
339 hmac_ostreambuf(std::ostream& dst, const uint8_t* hmac_key, uint32_t block_size)
340 : dst_(dst), block_size_(block_size) {
341 if (hmac_key != nullptr)
342 std::memcpy(hmac_key_.data(), hmac_key, hmac_key_.size());
343 }
344
347
349 int overflow(int c) override;
350
352 int sync() override;
353};
354
362 : public std::basic_streambuf<char, std::char_traits<char>> {
363private:
364 static const std::size_t kBufferSize = 16384;
365
366 std::istream& src_;
368 z_stream z_stream_{};
369
371 std::array<char, kBufferSize> input_ = {{0}};
373 std::array<char, kBufferSize> output_ = {{0}};
374
376 uint64_t decoded_bytes_ = 0;
377
379 bool budget_exceeded_ = false;
380
382 void Init();
383
384public:
391 explicit gzip_istreambuf(std::istream& src) : src_(src) { Init(); }
392
400 gzip_istreambuf(std::istream& src, const detail::ResourceLimits& limits)
401 : src_(src), limits_(limits) {
402 Init();
403 }
404
407
409 bool BudgetExceeded() const { return budget_exceeded_; }
410
412 int underflow() override;
413};
414
422 : public std::basic_streambuf<char, std::char_traits<char>> {
423private:
424 static const std::size_t kBufferSize = 16384;
425
426 std::ostream& dst_;
427 z_stream z_stream_{};
428
429 std::vector<char> buffer_;
430
437 bool WriteOutput(bool flush);
438
439public:
446 explicit gzip_ostreambuf(std::ostream& dst);
447
450
452 int overflow(int c) override;
453
455 int sync() override;
456};
457
469 : public std::basic_streambuf<char, std::char_traits<char>> {
470private:
471 static constexpr std::size_t kChaChaBlockSize = 64;
472
473 std::ostream& dst_;
474 Cipher<16>* const block_cipher_;
475 ChaCha20Cipher* const chacha_cipher_;
476
477 std::array<uint8_t, 64> pending_{};
478 std::size_t pending_n_ = 0;
479 std::array<uint8_t, 16> prev_block_{};
480 bool finalized_ = false;
481
483 bool FlushPending();
484
485public:
492 encrypt_ostreambuf(std::ostream& dst, Cipher<16>& cipher);
493
500 encrypt_ostreambuf(std::ostream& dst, ChaCha20Cipher& cipher);
501
504
506 int overflow(int c) override;
507
509 std::streamsize xsputn(const char* s, std::streamsize count) override;
510
512 int sync() override;
513};
514
515} // namespace keepass
ChaCha20 stream cipher implementation (RFC 8439, 32-bit counter).
Definition cipher.hh:326
Abstract base class for 16-byte block ciphers.
Definition cipher.hh:113
A std::streambuf backed by a fixed-size std::array.
Definition stream.hh:52
array_iostreambuf(std::array< uint8_t, N > &buffer)
Constructs a streambuf over the given array.
Definition stream.hh:110
Input streambuf that encrypts on the fly (streaming counterpart of the whole-buffer encrypt_cbc / Cha...
Definition stream.hh:469
~encrypt_ostreambuf() override
Zeroizes the transient plaintext and chaining state.
std::streamsize xsputn(const char *s, std::streamsize count) override
Writes several characters, applying cipher respectively.
encrypt_ostreambuf(std::ostream &dst, ChaCha20Cipher &cipher)
Constructs a ChaCha20 encrypting streambuf.
int overflow(int c) override
Buffers a character, encrypting one block when it reaches capacity.
encrypt_ostreambuf(std::ostream &dst, Cipher< 16 > &cipher)
Constructs a CBC-mode encrypting streambuf.
int sync() override
Finalizes the stream (PKCS #7 padding for CBC, partial block for ChaCha20).
Input streambuf that decompresses gzip-compressed data on the fly.
Definition stream.hh:362
int underflow() override
Inflates compressed data into the output buffer when the get area is exhausted.
~gzip_istreambuf() override
Destroys the streambuf and releases the zlib inflate context.
gzip_istreambuf(std::istream &src, const detail::ResourceLimits &limits)
Constructs a gzip-decompressing streambuf with resource limits.
Definition stream.hh:400
gzip_istreambuf(std::istream &src)
Constructs a gzip-decompressing streambuf.
Definition stream.hh:391
bool BudgetExceeded() const
Returns true if the decompressed size budget was exceeded while reading.
Definition stream.hh:409
Output streambuf that compresses data with gzip on the fly.
Definition stream.hh:422
int overflow(int c) override
Buffers a character; deflates and writes the buffer when it reaches capacity.
gzip_ostreambuf(std::ostream &dst)
Constructs a gzip-compressing streambuf.
~gzip_ostreambuf() override
Destroys the streambuf, finalizing the gzip stream and releasing the zlib context.
int sync() override
Flushes any buffered data and finalizes the gzip stream.
Base class providing SHA-256 hashing for block-oriented stream buffers.
Definition stream.hh:123
virtual ~hashed_basic_streambuf()
Destroys the streambuf, zeroizing any buffered block bytes.
std::array< uint8_t, 32 > GetBlockHash() const
Computes the SHA-256 hash of the current block.
Input streambuf that reads SHA-256-hashed, block-structured data.
Definition stream.hh:154
bool BudgetExceeded() const
Returns true if a resource budget was exceeded while reading.
Definition stream.hh:176
int underflow() override
Reads and verifies the next block when the get area is exhausted.
hashed_istreambuf(std::istream &src, const detail::ResourceLimits &limits)
Constructs an input streambuf with explicit resource limits.
Definition stream.hh:184
hashed_istreambuf(std::istream &src)
Constructs an input streambuf that reads from the given stream.
Definition stream.hh:173
Output streambuf that writes SHA-256-hashed, block-structured data.
Definition stream.hh:200
hashed_ostreambuf(std::ostream &dst, uint32_t block_size)
Constructs an output streambuf with a custom block size.
Definition stream.hh:224
int overflow(int c) override
Buffers a character; flushes the current block when it reaches capacity.
hashed_ostreambuf(std::ostream &dst)
Constructs an output streambuf with the default 1 MiB block size.
Definition stream.hh:216
int sync() override
Flushes any buffered data and writes the trailing empty end-of-stream block.
Input streambuf that reads HMAC-verified, block-structured data (KDBX4 format).
Definition stream.hh:241
hmac_istreambuf(std::istream &src, const uint8_t *hmac_key)
Constructs an HMAC-verifying input streambuf.
Definition stream.hh:266
~hmac_istreambuf()
Zeroizes the stored master HMAC key.
int underflow() override
Reads and HMAC-verifies the next block when the get area is exhausted.
bool BudgetExceeded() const
Returns true if a resource budget was exceeded while reading.
Definition stream.hh:272
hmac_istreambuf(std::istream &src, const uint8_t *hmac_key, const detail::ResourceLimits &limits)
Constructs an HMAC-verifying input streambuf with resource limits.
Definition stream.hh:281
Output streambuf that writes HMAC-authenticated, block-structured data (KDBX4 format).
Definition stream.hh:302
hmac_ostreambuf(std::ostream &dst, const uint8_t *hmac_key)
Constructs an HMAC-signing output streambuf with the default 1 MiB block size.
Definition stream.hh:326
int sync() override
Flushes any buffered data and writes the trailing empty end-of-stream block.
int overflow(int c) override
Buffers a character; flushes the current block when it reaches capacity.
~hmac_ostreambuf()
Zeroizes the stored master HMAC key.
hmac_ostreambuf(std::ostream &dst, const uint8_t *hmac_key, uint32_t block_size)
Constructs an HMAC-signing output streambuf with a custom block size.
Definition stream.hh:339
Visibility/export macro for the shared library.
#define LIBKEEPASS_API
Marks a class, function or variable as part of the public ABI.
Definition export.hh:43
Resource budgets enforced while importing (and parsing) databases.
Configurable resource budgets for database import and XML parsing.
Definition limits.hh:45
Header written before each data block in the hashed stream format.
Definition stream.hh:128
Utility functions for clamp, comparison, traversal, and time formatting.