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
|
/*
* (C) 2002 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
/*
Decrypt an encrypted RSA private key. Then use that key to decrypt a
message. This program can decrypt messages generated by rsa_enc, and uses the
same key format as that generated by rsa_kgen.
*/
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
#include <botan/botan.h>
#include <botan/look_pk.h> // for get_kdf
#include <botan/rsa.h>
using namespace Botan;
SecureVector<byte> b64_decode(const std::string&);
SymmetricKey derive_key(const std::string&, const SymmetricKey&, u32bit);
const std::string SUFFIX = ".enc";
int main(int argc, char* argv[])
{
if(argc != 4)
{
std::cout << "Usage: " << argv[0] << " keyfile messagefile passphrase"
<< std::endl;
return 1;
}
Botan::LibraryInitializer init;
try
{
AutoSeeded_RNG rng;
std::auto_ptr<PKCS8_PrivateKey> key(
PKCS8::load_key(argv[1], rng, argv[3]));
RSA_PrivateKey* rsakey = dynamic_cast<RSA_PrivateKey*>(key.get());
if(!rsakey)
{
std::cout << "The loaded key is not a RSA key!\n";
return 1;
}
std::ifstream message(argv[2]);
if(!message)
{
std::cout << "Couldn't read the message file." << std::endl;
return 1;
}
std::string outfile(argv[2]);
outfile = outfile.replace(outfile.find(SUFFIX), SUFFIX.length(), "");
std::ofstream plaintext(outfile.c_str());
if(!plaintext)
{
std::cout << "Couldn't write the plaintext to "
<< outfile << std::endl;
return 1;
}
std::string enc_masterkey_str;
std::getline(message, enc_masterkey_str);
std::string mac_str;
std::getline(message, mac_str);
SecureVector<byte> enc_masterkey = b64_decode(enc_masterkey_str);
std::auto_ptr<PK_Decryptor> decryptor(get_pk_decryptor(*rsakey,
"EME1(SHA-1)"));
SecureVector<byte> masterkey = decryptor->decrypt(enc_masterkey);
SymmetricKey cast_key = derive_key("CAST", masterkey, 16);
InitializationVector iv = derive_key("IV", masterkey, 8);
SymmetricKey mac_key = derive_key("MAC", masterkey, 16);
Pipe pipe(new Base64_Decoder,
get_cipher("CAST-128/CBC/PKCS7", cast_key, iv, DECRYPTION),
new Fork(
0,
new Chain(
new MAC_Filter("HMAC(SHA-1)", mac_key, 12),
new Base64_Encoder
)
)
);
pipe.start_msg();
message >> pipe;
pipe.end_msg();
std::string our_mac = pipe.read_all_as_string(1);
if(our_mac != mac_str)
std::cout << "WARNING: MAC in message failed to verify\n";
plaintext << pipe.read_all_as_string(0);
}
catch(std::exception& e)
{
std::cout << "Exception caught: " << e.what() << std::endl;
return 1;
}
return 0;
}
SecureVector<byte> b64_decode(const std::string& in)
{
Pipe pipe(new Base64_Decoder);
pipe.process_msg(in);
return pipe.read_all();
}
SymmetricKey derive_key(const std::string& param,
const SymmetricKey& masterkey,
u32bit outputlength)
{
std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)"));
return kdf->derive_key(outputlength, masterkey.bits_of(), param);
}
|