1 /*
2 * OpenPGP Codec
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7
8 #include <botan/openpgp.h>
9 #include <botan/filters.h>
10 #include <botan/basefilt.h>
11 #include <botan/charset.h>
12 #include <botan/crc24.h>
13
14 namespace Botan {
15
16 /*
17 * OpenPGP Base64 encoding
18 */
PGP_encode(const byte input[],size_t length,const std::string & label,const std::map<std::string,std::string> & headers)19 std::string PGP_encode(
20 const byte input[], size_t length,
21 const std::string& label,
22 const std::map<std::string, std::string>& headers)
23 {
24 const std::string PGP_HEADER = "-----BEGIN PGP " + label + "-----\n";
25 const std::string PGP_TRAILER = "-----END PGP " + label + "-----\n";
26 const size_t PGP_WIDTH = 64;
27
28 std::string pgp_encoded = PGP_HEADER;
29
30 if(headers.find("Version") != headers.end())
31 pgp_encoded += "Version: " + headers.find("Version")->second + '\n';
32
33 std::map<std::string, std::string>::const_iterator i = headers.begin();
34 while(i != headers.end())
35 {
36 if(i->first != "Version")
37 pgp_encoded += i->first + ": " + i->second + '\n';
38 ++i;
39 }
40 pgp_encoded += '\n';
41
42 Pipe pipe(new Fork(
43 new Base64_Encoder(true, PGP_WIDTH),
44 new Chain(new Hash_Filter(new CRC24), new Base64_Encoder)
45 )
46 );
47
48 pipe.process_msg(input, length);
49
50 pgp_encoded += pipe.read_all_as_string(0);
51 pgp_encoded += '=' + pipe.read_all_as_string(1) + '\n';
52 pgp_encoded += PGP_TRAILER;
53
54 return pgp_encoded;
55 }
56
57 /*
58 * OpenPGP Base64 encoding
59 */
PGP_encode(const byte input[],size_t length,const std::string & type)60 std::string PGP_encode(const byte input[], size_t length,
61 const std::string& type)
62 {
63 std::map<std::string, std::string> empty;
64 return PGP_encode(input, length, type, empty);
65 }
66
67 /*
68 * OpenPGP Base64 decoding
69 */
PGP_decode(DataSource & source,std::string & label,std::map<std::string,std::string> & headers)70 SecureVector<byte> PGP_decode(DataSource& source,
71 std::string& label,
72 std::map<std::string, std::string>& headers)
73 {
74 const size_t RANDOM_CHAR_LIMIT = 5;
75
76 const std::string PGP_HEADER1 = "-----BEGIN PGP ";
77 const std::string PGP_HEADER2 = "-----";
78 size_t position = 0;
79
80 while(position != PGP_HEADER1.length())
81 {
82 byte b;
83 if(!source.read_byte(b))
84 throw Decoding_Error("PGP: No PGP header found");
85 if(b == PGP_HEADER1[position])
86 ++position;
87 else if(position >= RANDOM_CHAR_LIMIT)
88 throw Decoding_Error("PGP: Malformed PGP header");
89 else
90 position = 0;
91 }
92 position = 0;
93 while(position != PGP_HEADER2.length())
94 {
95 byte b;
96 if(!source.read_byte(b))
97 throw Decoding_Error("PGP: No PGP header found");
98 if(b == PGP_HEADER2[position])
99 ++position;
100 else if(position)
101 throw Decoding_Error("PGP: Malformed PGP header");
102
103 if(position == 0)
104 label += static_cast<char>(b);
105 }
106
107 headers.clear();
108 bool end_of_headers = false;
109 while(!end_of_headers)
110 {
111 std::string this_header;
112 byte b = 0;
113 while(b != '\n')
114 {
115 if(!source.read_byte(b))
116 throw Decoding_Error("PGP: Bad armor header");
117 if(b != '\n')
118 this_header += static_cast<char>(b);
119 }
120
121 end_of_headers = true;
122 for(size_t j = 0; j != this_header.length(); ++j)
123 if(!Charset::is_space(this_header[j]))
124 end_of_headers = false;
125
126 if(!end_of_headers)
127 {
128 std::string::size_type pos = this_header.find(": ");
129 if(pos == std::string::npos)
130 throw Decoding_Error("OpenPGP: Bad headers");
131
132 std::string key = this_header.substr(0, pos);
133 std::string value = this_header.substr(pos + 2, std::string::npos);
134 headers[key] = value;
135 }
136 }
137
138 Pipe base64(new Base64_Decoder,
139 new Fork(0,
140 new Chain(new Hash_Filter(new CRC24),
141 new Base64_Encoder)
142 )
143 );
144 base64.start_msg();
145
146 const std::string PGP_TRAILER = "-----END PGP " + label + "-----";
147 position = 0;
148 bool newline_seen = 0;
149 std::string crc;
150 while(position != PGP_TRAILER.length())
151 {
152 byte b;
153 if(!source.read_byte(b))
154 throw Decoding_Error("PGP: No PGP trailer found");
155 if(b == PGP_TRAILER[position])
156 ++position;
157 else if(position)
158 throw Decoding_Error("PGP: Malformed PGP trailer");
159
160 if(b == '=' && newline_seen)
161 {
162 while(b != '\n')
163 {
164 if(!source.read_byte(b))
165 throw Decoding_Error("PGP: Bad CRC tail");
166 if(b != '\n')
167 crc += static_cast<char>(b);
168 }
169 }
170 else if(b == '\n')
171 newline_seen = true;
172 else if(position == 0)
173 {
174 base64.write(b);
175 newline_seen = false;
176 }
177 }
178 base64.end_msg();
179
180 if(crc != "" && crc != base64.read_all_as_string(1))
181 throw Decoding_Error("PGP: Corrupt CRC");
182
183 return base64.read_all();
184 }
185
186 /*
187 * OpenPGP Base64 decoding
188 */
PGP_decode(DataSource & source,std::string & label)189 SecureVector<byte> PGP_decode(DataSource& source, std::string& label)
190 {
191 std::map<std::string, std::string> ignored;
192 return PGP_decode(source, label, ignored);
193 }
194
195 }
196
197