diff options
Diffstat (limited to 'src/openpgp.cpp')
-rw-r--r-- | src/openpgp.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/openpgp.cpp b/src/openpgp.cpp new file mode 100644 index 000000000..fec292d1e --- /dev/null +++ b/src/openpgp.cpp @@ -0,0 +1,194 @@ +/************************************************* +* OpenPGP Source File * +* (C) 1999-2006 The Botan Project * +*************************************************/ + +#include <botan/openpgp.h> +#include <botan/filters.h> +#include <botan/charset.h> + +namespace Botan { + +namespace OpenPGP { + +/************************************************* +* OpenPGP Base64 encoding * +*************************************************/ +std::string encode(const byte input[], u32bit length, + const std::string& label, + const std::map<std::string, std::string>& headers) + { + const std::string PGP_HEADER = "-----BEGIN PGP " + label + "-----\n"; + const std::string PGP_TRAILER = "-----END PGP " + label + "-----\n"; + const u32bit PGP_WIDTH = 64; + + std::string pgp_encoded = PGP_HEADER; + + if(headers.find("Version") != headers.end()) + pgp_encoded += "Version: " + headers.find("Version")->second + '\n'; + + std::map<std::string, std::string>::const_iterator i = headers.begin(); + while(i != headers.end()) + { + if(i->first != "Version") + pgp_encoded += i->first + ": " + i->second + '\n'; + ++i; + } + pgp_encoded += '\n'; + + Pipe pipe(new Fork( + new Base64_Encoder(true, PGP_WIDTH), + new Chain(new Hash_Filter("CRC24"), new Base64_Encoder) + ) + ); + + pipe.process_msg(input, length); + + pgp_encoded += pipe.read_all_as_string(0); + pgp_encoded += '=' + pipe.read_all_as_string(1) + '\n'; + pgp_encoded += PGP_TRAILER; + + return pgp_encoded; + } + +/************************************************* +* OpenPGP Base64 encoding * +*************************************************/ +std::string encode(const byte input[], u32bit length, + const std::string& type) + { + std::map<std::string, std::string> empty; + return encode(input, length, type, empty); + } + +/************************************************* +* OpenPGP Base64 decoding * +*************************************************/ +SecureVector<byte> decode(DataSource& source, std::string& label, + std::map<std::string, std::string>& headers) + { + const u32bit RANDOM_CHAR_LIMIT = 5; + + const std::string PGP_HEADER1 = "-----BEGIN PGP "; + const std::string PGP_HEADER2 = "-----"; + u32bit position = 0; + + while(position != PGP_HEADER1.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP header found"); + if(b == PGP_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PGP: Malformed PGP header"); + else + position = 0; + } + position = 0; + while(position != PGP_HEADER2.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP header found"); + if(b == PGP_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PGP: Malformed PGP header"); + + if(position == 0) + label += (char)b; + } + + headers.clear(); + bool end_of_headers = false; + while(!end_of_headers) + { + std::string this_header; + byte b = 0; + while(b != '\n') + { + if(!source.read_byte(b)) + throw Decoding_Error("PGP: Bad armor header"); + if(b != '\n') + this_header += (char)b; + } + + end_of_headers = true; + for(u32bit j = 0; j != this_header.length(); ++j) + if(!is_space(this_header[j])) + end_of_headers = false; + + if(!end_of_headers) + { + std::string::size_type pos = this_header.find(": "); + if(pos == std::string::npos) + throw Decoding_Error("OpenPGP: Bad headers"); + + std::string key = this_header.substr(0, pos); + std::string value = this_header.substr(pos + 2, std::string::npos); + headers[key] = value; + } + } + + Pipe base64(new Base64_Decoder, + new Fork(0, + new Chain(new Hash_Filter("CRC24"), + new Base64_Encoder) + ) + ); + base64.start_msg(); + + const std::string PGP_TRAILER = "-----END PGP " + label + "-----"; + position = 0; + bool newline_seen = 0; + std::string crc; + while(position != PGP_TRAILER.length()) + { + byte b; + if(!source.read_byte(b)) + throw Decoding_Error("PGP: No PGP trailer found"); + if(b == PGP_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PGP: Malformed PGP trailer"); + + if(b == '=' && newline_seen) + { + while(b != '\n') + { + if(!source.read_byte(b)) + throw Decoding_Error("PGP: Bad CRC tail"); + if(b != '\n') + crc += (char)b; + } + } + else if(b == '\n') + newline_seen = true; + else if(position == 0) + { + base64.write(b); + newline_seen = false; + } + } + base64.end_msg(); + + if(crc != "" && crc != base64.read_all_as_string(1)) + throw Decoding_Error("PGP: Corrupt CRC"); + + return base64.read_all(); + } + +/************************************************* +* OpenPGP Base64 decoding * +*************************************************/ +SecureVector<byte> decode(DataSource& source, std::string& label) + { + std::map<std::string, std::string> ignored; + return decode(source, label, ignored); + } + +} + +} + |