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
|
/*
* (C) 2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
/*
Decrypt files encrypted with the 'encrypt' example application.
I'm being lazy and writing the output to stdout rather than stripping
off the ".enc" suffix and writing it there. So all diagnostics go to
stderr so there is no confusion.
*/
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <memory>
#include <botan/botan.h>
#if defined(BOTAN_HAS_COMPRESSOR_ZLIB)
#include <botan/zlib.h>
#endif
using namespace Botan;
SecureVector<byte> b64_decode(const std::string&);
int main(int argc, char* argv[])
{
if(argc < 2)
{
std::cout << "Usage: " << argv[0] << " [-p passphrase] file\n"
<< " -p : Use this passphrase to decrypt\n";
return 1;
}
Botan::LibraryInitializer init;
std::string filename, passphrase;
for(int j = 1; argv[j] != 0; j++)
{
if(std::strcmp(argv[j], "-p") == 0)
{
if(argv[j+1])
{
passphrase = argv[j+1];
j++;
}
else
{
std::cout << "No argument for -p option" << std::endl;
return 1;
}
}
else
{
if(filename != "")
{
std::cout << "You can only specify one file at a time\n";
return 1;
}
filename = argv[j];
}
}
if(passphrase == "")
{
std::cout << "You have to specify a passphrase!" << std::endl;
return 1;
}
std::ifstream in(filename.c_str());
if(!in)
{
std::cout << "ERROR: couldn't open " << filename << std::endl;
return 1;
}
std::string algo;
try {
std::string header, salt_str, mac_str;
std::getline(in, header);
std::getline(in, algo);
std::getline(in, salt_str);
std::getline(in, mac_str);
if(header != "-------- ENCRYPTED FILE --------")
{
std::cout << "ERROR: File is missing the usual header" << std::endl;
return 1;
}
const BlockCipher* cipher_proto = global_state().algorithm_factory().prototype_block_cipher(algo);
if(!cipher_proto)
{
std::cout << "Don't know about the block cipher \"" << algo << "\"\n";
return 1;
}
const u32bit key_len = cipher_proto->maximum_keylength();
const u32bit iv_len = cipher_proto->block_size();
std::auto_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-1)"));
const u32bit PBKDF2_ITERATIONS = 8192;
SecureVector<byte> salt = b64_decode(salt_str);
SymmetricKey bc_key = pbkdf->derive_key(key_len, "BLK" + passphrase,
&salt[0], salt.size(),
PBKDF2_ITERATIONS);
InitializationVector iv = pbkdf->derive_key(iv_len, "IVL" + passphrase,
&salt[0], salt.size(),
PBKDF2_ITERATIONS);
SymmetricKey mac_key = pbkdf->derive_key(16, "MAC" + passphrase,
&salt[0], salt.size(),
PBKDF2_ITERATIONS);
Pipe pipe(new Base64_Decoder,
get_cipher(algo + "/CBC", bc_key, iv, DECRYPTION),
#ifdef BOTAN_HAS_COMPRESSOR_ZLIB
new Zlib_Decompression,
#endif
new Fork(
0,
new Chain(new MAC_Filter("HMAC(SHA-1)", mac_key),
new Base64_Encoder)
)
);
pipe.start_msg();
in >> 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";
std::cout << pipe.read_all_as_string(0);
}
catch(Algorithm_Not_Found)
{
std::cout << "Don't know about the block cipher \"" << algo << "\"\n";
return 1;
}
catch(Decoding_Error)
{
std::cout << "Bad passphrase or corrupt file\n";
return 1;
}
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();
}
|