1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
/*
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
/* rsa.hpp provides RSA ES encrypt/decrypt, SSL (block type 1) sign and verify
*/
#ifndef TAO_CRYPT_RSA_HPP
#define TAO_CRYPT_RSA_HPP
#include "integer.hpp"
#include "random.hpp"
namespace TaoCrypt {
class Source;
// Public Key Length helper
class PK_Lengths {
const Integer& image_;
public:
explicit PK_Lengths(const Integer& i) : image_(i) {}
word32 PaddedBlockBitLength() const {return image_.BitCount() - 1;}
word32 PaddedBlockByteLength() const
{return BitsToBytes(PaddedBlockBitLength());}
word32 FixedCiphertextLength() const {return image_.ByteCount();}
word32 FixedMaxPlaintextLength() const
{return SaturatingSubtract(PaddedBlockBitLength() / 8, 10U); }
};
// RSA Public Key
class RSA_PublicKey {
protected:
Integer n_;
Integer e_;
public:
RSA_PublicKey() {}
explicit RSA_PublicKey(Source&);
void Initialize(const Integer& n, const Integer& e) {n_ = n; e_ = e;}
void Initialize(Source&);
Integer ApplyFunction(const Integer& x) const;
const Integer& GetModulus() const {return n_;}
const Integer& GetPublicExponent() const {return e_;}
void SetModulus(const Integer& n) {n_ = n;}
void SetPublicExponent(const Integer& e) {e_ = e;}
word32 FixedCiphertextLength()
{
return PK_Lengths(n_).FixedCiphertextLength();
}
RSA_PublicKey(const RSA_PublicKey& other) : n_(other.n_), e_(other.e_) {}
RSA_PublicKey& operator=(const RSA_PublicKey& that)
{
RSA_PublicKey tmp(that);
Swap(tmp);
return *this;
}
void Swap(RSA_PublicKey& other)
{
n_.Swap(other.n_);
e_.Swap(other.e_);
}
};
// RSA Private Key
class RSA_PrivateKey : public RSA_PublicKey {
Integer d_;
Integer p_;
Integer q_;
Integer dp_;
Integer dq_;
Integer u_;
public:
RSA_PrivateKey() {}
explicit RSA_PrivateKey(Source&);
void Initialize(const Integer& n, const Integer& e, const Integer& d,
const Integer& p, const Integer& q, const Integer& dp,
const Integer& dq, const Integer& u)
{n_ = n; e_ = e; d_ = d; p_ = p; q_ = q; dp_ = dp; dq_ = dq; u_ = u;}
void Initialize(Source&);
Integer CalculateInverse(RandomNumberGenerator&, const Integer&) const;
const Integer& GetPrime1() const {return p_;}
const Integer& GetPrime2() const {return q_;}
const Integer& GetPrivateExponent() const {return d_;}
const Integer& GetModPrime1PrivateExponent() const {return dp_;}
const Integer& GetModPrime2PrivateExponent() const {return dq_;}
const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const
{return u_;}
void SetPrime1(const Integer& p) {p_ = p;}
void SetPrime2(const Integer& q) {q_ = q;}
void SetPrivateExponent(const Integer& d) {d_ = d;}
void SetModPrime1PrivateExponent(const Integer& dp) {dp_ = dp;}
void SetModPrime2PrivateExponent(const Integer& dq) {dq_ = dq;}
void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer& u) {u_ = u;}
private:
RSA_PrivateKey(const RSA_PrivateKey&); // hide copy
RSA_PrivateKey& operator=(const RSA_PrivateKey&); // and assign
};
// block type 2 padding
class RSA_BlockType2 {
public:
void Pad(const byte*, word32, byte*, word32,
RandomNumberGenerator&) const;
word32 UnPad(const byte*, word32, byte*) const;
};
// block type 1 padding
class RSA_BlockType1 {
public:
void Pad(const byte*, word32, byte*, word32,
RandomNumberGenerator&) const;
word32 UnPad(const byte*, word32, byte*) const;
};
// RSA Encryptor, can use any padding
template<class Pad = RSA_BlockType2>
class RSA_Encryptor {
const RSA_PublicKey& key_;
Pad padding_;
public:
explicit RSA_Encryptor(const RSA_PublicKey& k) : key_(k) {}
void Encrypt(const byte*, word32, byte*, RandomNumberGenerator&);
bool SSL_Verify(const byte* msg, word32 sz, const byte* sig);
};
// RSA Decryptor, can use any padding
template<class Pad = RSA_BlockType2>
class RSA_Decryptor {
const RSA_PrivateKey& key_;
Pad padding_;
public:
explicit RSA_Decryptor(const RSA_PrivateKey& k) : key_(k) {}
word32 Decrypt(const byte*, word32, byte*, RandomNumberGenerator&);
void SSL_Sign(const byte*, word32, byte*, RandomNumberGenerator&);
};
// Public Encrypt
template<class Pad>
void RSA_Encryptor<Pad>::Encrypt(const byte* plain, word32 sz, byte* cipher,
RandomNumberGenerator& rng)
{
PK_Lengths lengths(key_.GetModulus());
if (sz > lengths.FixedMaxPlaintextLength())
return;
ByteBlock paddedBlock(lengths.PaddedBlockByteLength());
padding_.Pad(plain, sz, paddedBlock.get_buffer(),
lengths.PaddedBlockBitLength(), rng);
key_.ApplyFunction(Integer(paddedBlock.get_buffer(), paddedBlock.size())).
Encode(cipher, lengths.FixedCiphertextLength());
}
// Private Decrypt
template<class Pad>
word32 RSA_Decryptor<Pad>::Decrypt(const byte* cipher, word32 sz, byte* plain,
RandomNumberGenerator& rng)
{
PK_Lengths lengths(key_.GetModulus());
if (sz != lengths.FixedCiphertextLength())
return 0;
ByteBlock paddedBlock(lengths.PaddedBlockByteLength());
Integer x = key_.CalculateInverse(rng, Integer(cipher,
lengths.FixedCiphertextLength()).Ref());
if (x.ByteCount() > paddedBlock.size())
x = Integer::Zero(); // don't return false, prevents timing attack
x.Encode(paddedBlock.get_buffer(), paddedBlock.size());
return padding_.UnPad(paddedBlock.get_buffer(),
lengths.PaddedBlockBitLength(), plain);
}
// Private SSL type (block 1) Encrypt
template<class Pad>
void RSA_Decryptor<Pad>::SSL_Sign(const byte* message, word32 sz, byte* sig,
RandomNumberGenerator& rng)
{
RSA_PublicKey inverse;
inverse.Initialize(key_.GetModulus(), key_.GetPrivateExponent());
RSA_Encryptor<RSA_BlockType1> enc(inverse); // SSL Type
enc.Encrypt(message, sz, sig, rng);
}
word32 SSL_Decrypt(const RSA_PublicKey& key, const byte* sig, byte* plain);
// Public SSL type (block 1) Decrypt
template<class Pad>
bool RSA_Encryptor<Pad>::SSL_Verify(const byte* message, word32 sz,
const byte* sig)
{
ByteBlock plain(PK_Lengths(key_.GetModulus()).FixedMaxPlaintextLength());
if (SSL_Decrypt(key_, sig, plain.get_buffer()) != sz)
return false; // not right justified or bad padding
if ( (memcmp(plain.get_buffer(), message, sz)) == 0)
return true;
return false;
}
typedef RSA_Encryptor<> RSAES_Encryptor;
typedef RSA_Decryptor<> RSAES_Decryptor;
} // namespace
#endif // TAO_CRYPT_RSA_HPP
|