1//
2// RSACipherImpl.cpp
3//
4// Library: Crypto
5// Package: RSA
6// Module: RSACipherImpl
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/RSACipherImpl.h"
16#include "Poco/Crypto/CryptoTransform.h"
17#include "Poco/Exception.h"
18#include <openssl/err.h>
19#include <openssl/rsa.h>
20#include <cstring>
21
22
23namespace Poco {
24namespace Crypto {
25
26
27namespace
28{
29 void throwError()
30 {
31 unsigned long err;
32 std::string msg;
33
34 while ((err = ERR_get_error()))
35 {
36 if (!msg.empty())
37 msg.append("; ");
38 msg.append(ERR_error_string(err, 0));
39 }
40
41 throw Poco::IOException(msg);
42 }
43
44
45 int mapPaddingMode(RSAPaddingMode paddingMode)
46 {
47 switch (paddingMode)
48 {
49 case RSA_PADDING_PKCS1:
50 return RSA_PKCS1_PADDING;
51 case RSA_PADDING_PKCS1_OAEP:
52 return RSA_PKCS1_OAEP_PADDING;
53 case RSA_PADDING_SSLV23:
54 return RSA_SSLV23_PADDING;
55 case RSA_PADDING_NONE:
56 return RSA_NO_PADDING;
57 default:
58 poco_bugcheck();
59 return RSA_NO_PADDING;
60 }
61 }
62
63
64 class RSAEncryptImpl: public CryptoTransform
65 {
66 public:
67 RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
68 ~RSAEncryptImpl();
69
70 std::size_t blockSize() const;
71 std::size_t maxDataSize() const;
72 std::string getTag(std::size_t);
73 void setTag(const std::string&);
74
75 std::streamsize transform(const unsigned char* input,
76 std::streamsize inputLength,
77 unsigned char* output,
78 std::streamsize outputLength);
79
80 std::streamsize finalize(unsigned char* output, std::streamsize length);
81
82 private:
83 const RSA* _pRSA;
84 RSAPaddingMode _paddingMode;
85 std::streamsize _pos;
86 unsigned char* _pBuf;
87 };
88
89
90 RSAEncryptImpl::RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
91 _pRSA(pRSA),
92 _paddingMode(paddingMode),
93 _pos(0),
94 _pBuf(0)
95 {
96 _pBuf = new unsigned char[blockSize()];
97 }
98
99
100 RSAEncryptImpl::~RSAEncryptImpl()
101 {
102 delete [] _pBuf;
103 }
104
105
106 std::size_t RSAEncryptImpl::blockSize() const
107 {
108 return RSA_size(_pRSA);
109 }
110
111
112 std::size_t RSAEncryptImpl::maxDataSize() const
113 {
114 std::size_t size = blockSize();
115 switch (_paddingMode)
116 {
117 case RSA_PADDING_PKCS1:
118 case RSA_PADDING_SSLV23:
119 size -= 11;
120 break;
121 case RSA_PADDING_PKCS1_OAEP:
122 size -= 41;
123 break;
124 default:
125 break;
126 }
127 return size;
128 }
129
130
131 std::string RSAEncryptImpl::getTag(std::size_t)
132 {
133 return std::string();
134 }
135
136
137 void RSAEncryptImpl::setTag(const std::string&)
138 {
139 }
140
141
142 std::streamsize RSAEncryptImpl::transform(const unsigned char* input, std::streamsize inputLength,
143 unsigned char* output, std::streamsize outputLength)
144 {
145 // always fill up the buffer before writing!
146 std::streamsize maxSize = static_cast<std::streamsize>(maxDataSize());
147 std::streamsize rsaSize = static_cast<std::streamsize>(blockSize());
148 poco_assert_dbg(_pos <= maxSize);
149 poco_assert (outputLength >= rsaSize);
150 int rc = 0;
151 while (inputLength > 0)
152 {
153 // check how many data bytes we are missing to get the buffer full
154 poco_assert_dbg (maxSize >= _pos);
155 std::streamsize missing = maxSize - _pos;
156 if (missing == 0)
157 {
158 poco_assert (outputLength >= rsaSize);
159 int n = RSA_public_encrypt(static_cast<int>(maxSize), _pBuf, output,
160 const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
161 if (n == -1)
162 throwError();
163 rc += n;
164 output += n;
165 outputLength -= n;
166 _pos = 0;
167
168 }
169 else
170 {
171 if (missing > inputLength) missing = inputLength;
172 std::memcpy(_pBuf + _pos, input, static_cast<std::size_t>(missing));
173 input += missing;
174 _pos += missing;
175 inputLength -= missing;
176 }
177 }
178 return rc;
179 }
180
181
182 std::streamsize RSAEncryptImpl::finalize(unsigned char* output, std::streamsize length)
183 {
184 poco_assert (length >= blockSize());
185 poco_assert (_pos <= maxDataSize());
186 int rc = 0;
187 if (_pos > 0)
188 {
189 rc = RSA_public_encrypt(static_cast<int>(_pos), _pBuf, output,
190 const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
191 if (rc == -1) throwError();
192 }
193 return rc;
194 }
195
196
197 class RSADecryptImpl: public CryptoTransform
198 {
199 public:
200 RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
201 ~RSADecryptImpl();
202
203 std::size_t blockSize() const;
204 std::string getTag(std::size_t);
205 void setTag(const std::string&);
206
207 std::streamsize transform(const unsigned char* input,
208 std::streamsize inputLength,
209 unsigned char* output,
210 std::streamsize outputLength);
211
212 std::streamsize finalize(unsigned char* output,
213 std::streamsize length);
214
215 private:
216 const RSA* _pRSA;
217 RSAPaddingMode _paddingMode;
218 std::streamsize _pos;
219 unsigned char* _pBuf;
220 };
221
222
223 RSADecryptImpl::RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
224 _pRSA(pRSA),
225 _paddingMode(paddingMode),
226 _pos(0),
227 _pBuf(0)
228 {
229 _pBuf = new unsigned char[blockSize()];
230 }
231
232
233 RSADecryptImpl::~RSADecryptImpl()
234 {
235 delete [] _pBuf;
236 }
237
238
239 std::size_t RSADecryptImpl::blockSize() const
240 {
241 return RSA_size(_pRSA);
242 }
243
244
245 std::string RSADecryptImpl::getTag(std::size_t)
246 {
247 return std::string();
248 }
249
250
251 void RSADecryptImpl::setTag(const std::string&)
252 {
253 }
254
255
256 std::streamsize RSADecryptImpl::transform(
257 const unsigned char* input,
258 std::streamsize inputLength,
259 unsigned char* output,
260 std::streamsize outputLength)
261 {
262
263 // always fill up the buffer before decrypting!
264 std::streamsize rsaSize = static_cast<std::streamsize>(blockSize());
265 poco_assert_dbg(_pos <= rsaSize);
266 poco_assert (outputLength >= rsaSize);
267 int rc = 0;
268 while (inputLength > 0)
269 {
270 // check how many data bytes we are missing to get the buffer full
271 poco_assert_dbg (rsaSize >= _pos);
272 std::streamsize missing = rsaSize - _pos;
273 if (missing == 0)
274 {
275 int tmp = RSA_private_decrypt(static_cast<int>(rsaSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
276 if (tmp == -1)
277 throwError();
278 rc += tmp;
279 output += tmp;
280 outputLength -= tmp;
281 _pos = 0;
282
283 }
284 else
285 {
286 if (missing > inputLength)
287 missing = inputLength;
288
289 std::memcpy(_pBuf + _pos, input, static_cast<std::size_t>(missing));
290 input += missing;
291 _pos += missing;
292 inputLength -= missing;
293 }
294 }
295 return rc;
296 }
297
298
299 std::streamsize RSADecryptImpl::finalize(unsigned char* output, std::streamsize length)
300 {
301 poco_assert (length >= blockSize());
302 int rc = 0;
303 if (_pos > 0)
304 {
305 rc = RSA_private_decrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
306 if (rc == -1)
307 throwError();
308 }
309 return rc;
310 }
311}
312
313
314RSACipherImpl::RSACipherImpl(const RSAKey& key, RSAPaddingMode paddingMode):
315 _key(key),
316 _paddingMode(paddingMode)
317{
318}
319
320
321RSACipherImpl::~RSACipherImpl()
322{
323}
324
325
326CryptoTransform* RSACipherImpl::createEncryptor()
327{
328 return new RSAEncryptImpl(_key.impl()->getRSA(), _paddingMode);
329}
330
331
332CryptoTransform* RSACipherImpl::createDecryptor()
333{
334 return new RSADecryptImpl(_key.impl()->getRSA(), _paddingMode);
335}
336
337
338} } // namespace Poco::Crypto
339