1//
2// CryptoStream.cpp
3//
4// Library: Crypto
5// Package: Cipher
6// Module: CryptoStream
7//
8// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Crypto/CryptoStream.h"
16#include "Poco/Crypto/CryptoTransform.h"
17#include "Poco/Crypto/Cipher.h"
18#include "Poco/Exception.h"
19#include <algorithm>
20
21
22#undef min
23#undef max
24
25
26namespace Poco {
27namespace Crypto {
28
29
30//
31// CryptoStreamBuf
32//
33
34
35CryptoStreamBuf::CryptoStreamBuf(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize):
36 Poco::BufferedStreamBuf(bufferSize, std::ios::in),
37 _pTransform(pTransform),
38 _pIstr(&istr),
39 _pOstr(0),
40 _eof(false),
41 _buffer(static_cast<std::size_t>(bufferSize))
42{
43 poco_check_ptr (pTransform);
44 poco_assert (bufferSize > 2 * pTransform->blockSize());
45}
46
47
48CryptoStreamBuf::CryptoStreamBuf(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize):
49 Poco::BufferedStreamBuf(bufferSize, std::ios::out),
50 _pTransform(pTransform),
51 _pIstr(0),
52 _pOstr(&ostr),
53 _eof(false),
54 _buffer(static_cast<std::size_t>(bufferSize))
55{
56 poco_check_ptr (pTransform);
57 poco_assert (bufferSize > 2 * pTransform->blockSize());
58}
59
60
61CryptoStreamBuf::~CryptoStreamBuf()
62{
63 try
64 {
65 close();
66 }
67 catch (...)
68 {
69 }
70 delete _pTransform;
71}
72
73
74void CryptoStreamBuf::close()
75{
76 sync();
77
78 if (_pIstr)
79 {
80 _pIstr = 0;
81 }
82 else if (_pOstr)
83 {
84 // Close can be called multiple times. By zeroing the pointer we make
85 // sure that we call finalize() only once, even if an exception is
86 // thrown.
87 std::ostream* pOstr = _pOstr;
88 _pOstr = 0;
89
90 // Finalize transformation.
91 std::streamsize n = _pTransform->finalize(_buffer.begin(), static_cast<std::streamsize>(_buffer.size()));
92
93 if (n > 0)
94 {
95 pOstr->write(reinterpret_cast<char*>(_buffer.begin()), n);
96 if (!pOstr->good())
97 throw Poco::IOException("Output stream failure");
98 }
99 }
100}
101
102
103int CryptoStreamBuf::readFromDevice(char* buffer, std::streamsize length)
104{
105 if (!_pIstr)
106 return 0;
107
108 int count = 0;
109
110 while (!_eof)
111 {
112 int m = (static_cast<int>(length) - count)/2 - static_cast<int>(_pTransform->blockSize());
113
114 // Make sure we can read at least one more block. Explicitely check
115 // for m < 0 since blockSize() returns an unsigned int and the
116 // comparison might give false results for m < 0.
117 if (m <= 0)
118 break;
119
120 int n = 0;
121
122 if (_pIstr->good())
123 {
124 _pIstr->read(reinterpret_cast<char*>(_buffer.begin()), m);
125 n = static_cast<int>(_pIstr->gcount());
126 }
127
128 if (n == 0)
129 {
130 _eof = true;
131
132 // No more data, finalize transformation
133 count += static_cast<int>(_pTransform->finalize(
134 reinterpret_cast<unsigned char*>(buffer + count),
135 static_cast<int>(length) - count));
136 }
137 else
138 {
139 // Transform next chunk of data
140 count += static_cast<int>(_pTransform->transform(
141 _buffer.begin(),
142 n,
143 reinterpret_cast<unsigned char*>(buffer + count),
144 static_cast<int>(length) - count));
145 }
146 }
147
148 return count;
149}
150
151
152int CryptoStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
153{
154 if (!_pOstr)
155 return 0;
156
157 std::size_t maxChunkSize = _buffer.size()/2;
158 std::size_t count = 0;
159
160 while (count < length)
161 {
162 // Truncate chunk size so that the maximum output fits into _buffer.
163 std::size_t n = static_cast<std::size_t>(length) - count;
164 if (n > maxChunkSize)
165 n = maxChunkSize;
166
167 // Transform next chunk of data
168 std::streamsize k = _pTransform->transform(
169 reinterpret_cast<const unsigned char*>(buffer + count),
170 static_cast<std::streamsize>(n),
171 _buffer.begin(),
172 static_cast<std::streamsize>(_buffer.size()));
173
174 // Attention: (n != k) might be true. In count, we have to track how
175 // many bytes from buffer have been consumed, not how many bytes have
176 // been written to _pOstr!
177 count += n;
178
179 if (k > 0)
180 {
181 _pOstr->write(reinterpret_cast<const char*>(_buffer.begin()), k);
182 if (!_pOstr->good())
183 throw Poco::IOException("Output stream failure");
184 }
185 }
186
187 return static_cast<int>(count);
188}
189
190
191//
192// CryptoIOS
193//
194
195
196CryptoIOS::CryptoIOS(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize):
197 _buf(istr, pTransform, bufferSize)
198{
199 poco_ios_init(&_buf);
200}
201
202
203CryptoIOS::CryptoIOS(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize):
204 _buf(ostr, pTransform, bufferSize)
205{
206 poco_ios_init(&_buf);
207}
208
209
210CryptoIOS::~CryptoIOS()
211{
212}
213
214
215CryptoStreamBuf* CryptoIOS::rdbuf()
216{
217 return &_buf;
218}
219
220
221//
222// CryptoInputStream
223//
224
225
226CryptoInputStream::CryptoInputStream(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize):
227 CryptoIOS(istr, pTransform, bufferSize),
228 std::istream(&_buf)
229{
230}
231
232
233CryptoInputStream::CryptoInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
234 CryptoIOS(istr, cipher.createEncryptor(), bufferSize),
235 std::istream(&_buf)
236{
237}
238
239
240CryptoInputStream::~CryptoInputStream()
241{
242}
243
244
245//
246// CryptoOutputStream
247//
248
249
250CryptoOutputStream::CryptoOutputStream(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize):
251 CryptoIOS(ostr, pTransform, bufferSize),
252 std::ostream(&_buf)
253{
254}
255
256
257CryptoOutputStream::CryptoOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
258 CryptoIOS(ostr, cipher.createDecryptor(), bufferSize),
259 std::ostream(&_buf)
260{
261}
262
263
264CryptoOutputStream::~CryptoOutputStream()
265{
266}
267
268
269void CryptoOutputStream::close()
270{
271 _buf.close();
272}
273
274
275//
276// EncryptingInputStream
277//
278
279
280EncryptingInputStream::EncryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
281 CryptoIOS(istr, cipher.createEncryptor(), bufferSize),
282 std::istream(&_buf)
283{
284}
285
286
287EncryptingInputStream::~EncryptingInputStream()
288{
289}
290
291
292//
293// EncryptingOuputStream
294//
295
296
297EncryptingOutputStream::EncryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
298 CryptoIOS(ostr, cipher.createEncryptor(), bufferSize),
299 std::ostream(&_buf)
300{
301}
302
303
304EncryptingOutputStream::~EncryptingOutputStream()
305{
306}
307
308
309void EncryptingOutputStream::close()
310{
311 _buf.close();
312}
313
314
315//
316// DecryptingInputStream
317//
318
319
320DecryptingInputStream::DecryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
321 CryptoIOS(istr, cipher.createDecryptor(), bufferSize),
322 std::istream(&_buf)
323{
324}
325
326
327DecryptingInputStream::~DecryptingInputStream()
328{
329}
330
331
332//
333// DecryptingOuputStream
334//
335
336
337DecryptingOutputStream::DecryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
338 CryptoIOS(ostr, cipher.createDecryptor(), bufferSize),
339 std::ostream(&_buf)
340{
341}
342
343
344DecryptingOutputStream::~DecryptingOutputStream()
345{
346}
347
348
349void DecryptingOutputStream::close()
350{
351 _buf.close();
352}
353
354
355} } // namespace Poco::Crypto
356