diff options
author | lloyd <[email protected]> | 2010-09-03 13:15:08 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2010-09-03 13:15:08 +0000 |
commit | 466548a644640fc73b24c8a4185a317f780a698f (patch) | |
tree | 27e29d709e334d4a6ece30d51b3be57e4aedd3bb /src | |
parent | daad01ef80771fb709e7cb6f2f7d5f6fcd6fd52f (diff) |
Add a standalone version of hex encoding and decoding, defining the filters
in terms of these calls.
The header for the hex filter is renamed hex_filt.h. This probably
won't affect people because filters.h (included by botan.h) already
included hex.h, and now just includes hex_filt.h instead.
Diffstat (limited to 'src')
-rw-r--r-- | src/codec/hex/hex.cpp | 180 | ||||
-rw-r--r-- | src/codec/hex/hex.h | 108 | ||||
-rw-r--r-- | src/codec/hex/info.txt | 1 | ||||
-rw-r--r-- | src/filters/filters.h | 4 | ||||
-rw-r--r-- | src/filters/hex/hex_char.cpp | 48 | ||||
-rw-r--r-- | src/filters/hex_filt/hex_filt.cpp (renamed from src/filters/hex/hex.cpp) | 104 | ||||
-rw-r--r-- | src/filters/hex_filt/hex_filt.h (renamed from src/filters/hex/hex.h) | 24 | ||||
-rw-r--r-- | src/filters/hex_filt/info.txt (renamed from src/filters/hex/info.txt) | 2 |
8 files changed, 334 insertions, 137 deletions
diff --git a/src/codec/hex/hex.cpp b/src/codec/hex/hex.cpp new file mode 100644 index 000000000..70e819906 --- /dev/null +++ b/src/codec/hex/hex.cpp @@ -0,0 +1,180 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/hex.h> +#include <botan/mem_ops.h> +#include <stdexcept> + +namespace Botan { + +void hex_encode(char output[], + const byte input[], + u32bit input_length, + bool uppercase) + { + static const byte BIN_TO_HEX_UPPER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' }; + + static const byte BIN_TO_HEX_LOWER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + + const byte* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER; + + for(u32bit i = 0; i != input_length; ++i) + { + byte x = input[i]; + output[2*i ] = tbl[(x >> 4) & 0x0F]; + output[2*i+1] = tbl[(x ) & 0x0F]; + } + } + +std::string hex_encode(const byte input[], + u32bit input_length, + bool uppercase) + { + std::string output(2 * input_length, 0); + hex_encode(&output[0], input, input_length, uppercase); + return output; + } + +u32bit hex_decode(byte output[], + const char input[], + u32bit input_length, + u32bit& input_consumed, + bool ignore_ws) + { + /* + * Mapping of hex characters to either their binary equivalent + * or to an error code. + * If valid hex (0-9 A-F a-f), the value. + * If whitespace, then 0x80 + * Otherwise 0xFF + * Warning: this table assumes ASCII character encodings + */ + + static const byte HEX_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + byte* out_ptr = output; + bool top_nibble = true; + + clear_mem(output, input_length / 2); + + for(u32bit i = 0; i != input_length; ++i) + { + const byte bin = HEX_TO_BIN[(byte)input[i]]; + + if(bin >= 0x10) + { + if(bin == 0x80 && ignore_ws) + continue; + + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + + throw std::invalid_argument( + std::string("hex_decode: invalid hex character '") + + bad_char + "'"); + } + + *out_ptr |= bin << (top_nibble*4); + + top_nibble = !top_nibble; + if(top_nibble) + ++out_ptr; + } + + input_consumed = input_length; + u32bit written = (out_ptr - output); + + /* + * We only got half of a byte at the end; zap the half-written + * output and mark it as unread + */ + if(!top_nibble) + { + *out_ptr = 0; + input_consumed -= 1; + } + + return written; + } + +u32bit hex_decode(byte output[], + const char input[], + u32bit input_length, + bool ignore_ws) + { + u32bit consumed = 0; + u32bit written = hex_decode(output, input, input_length, + consumed, ignore_ws); + + if(consumed != input_length) + throw std::invalid_argument("hex_decode: input did not have full bytes"); + + return written; + } + +u32bit hex_decode(byte output[], + const std::string& input, + bool ignore_ws) + { + return hex_decode(output, &input[0], input.length(), ignore_ws); + } + +SecureVector<byte> hex_decode(const char input[], + u32bit input_length, + bool ignore_ws) + { + SecureVector<byte> bin(input_length / 2); + + u32bit written = hex_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.truncate(written); + return bin; + } + +SecureVector<byte> hex_decode(const std::string& input, + bool ignore_ws) + { + return hex_decode(&input[0], input.size(), ignore_ws); + } + +} diff --git a/src/codec/hex/hex.h b/src/codec/hex/hex.h new file mode 100644 index 000000000..91a743b45 --- /dev/null +++ b/src/codec/hex/hex.h @@ -0,0 +1,108 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HEX_CODEC_H__ +#define BOTAN_HEX_CODEC_H__ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Perform hex encoding +* @param output an array of at least input_length*2 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +*/ +void BOTAN_DLL hex_encode(char output[], + const byte input[], + u32bit input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +std::string BOTAN_DLL hex_encode(const byte input[], + u32bit input_length, + bool uppercase = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +u32bit BOTAN_DLL hex_decode(byte output[], + const char input[], + u32bit input_length, + u32bit& input_consumed, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +u32bit BOTAN_DLL hex_decode(byte output[], + const char input[], + u32bit input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +u32bit BOTAN_DLL hex_decode(byte output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +SecureVector<byte> BOTAN_DLL hex_decode(const char input[], + u32bit input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +SecureVector<byte> BOTAN_DLL hex_decode(const std::string& input, + bool ignore_ws = true); + +} + +#endif diff --git a/src/codec/hex/info.txt b/src/codec/hex/info.txt new file mode 100644 index 000000000..c9eb8fb73 --- /dev/null +++ b/src/codec/hex/info.txt @@ -0,0 +1 @@ +define HEX_CODEC diff --git a/src/filters/filters.h b/src/filters/filters.h index e2c7cb5ec..51b4f00fe 100644 --- a/src/filters/filters.h +++ b/src/filters/filters.h @@ -24,8 +24,8 @@ #include <botan/base64.h> #endif -#if defined(BOTAN_HAS_HEX_CODEC) - #include <botan/hex.h> +#if defined(BOTAN_HAS_HEX_FILTER) + #include <botan/hex_filt.h> #endif namespace Botan { diff --git a/src/filters/hex/hex_char.cpp b/src/filters/hex/hex_char.cpp deleted file mode 100644 index c28efc5f7..000000000 --- a/src/filters/hex/hex_char.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* -* Hex Character Table -* (C) 1999-2008 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/hex.h> - -namespace Botan { - -/* -* Hex Encoder Lookup Tables -*/ -const byte Hex_Encoder::BIN_TO_HEX_UPPER[16] = { -0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, -0x44, 0x45, 0x46 }; - -const byte Hex_Encoder::BIN_TO_HEX_LOWER[16] = { -0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, -0x64, 0x65, 0x66 }; - -/* -* Hex Decoder Lookup Table -*/ -const byte Hex_Decoder::HEX_TO_BIN[256] = { -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, -0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; - -} diff --git a/src/filters/hex/hex.cpp b/src/filters/hex_filt/hex_filt.cpp index 7191e1554..0f3daa464 100644 --- a/src/filters/hex/hex.cpp +++ b/src/filters/hex_filt/hex_filt.cpp @@ -5,6 +5,7 @@ * Distributed under the terms of the Botan license */ +#include <botan/hex_filt.h> #include <botan/hex.h> #include <botan/parsing.h> #include <botan/charset.h> @@ -40,24 +41,13 @@ Hex_Encoder::Hex_Encoder(Case c) : casing(c), line_length(0) } /* -* Hex Encoding Operation -*/ -void Hex_Encoder::encode(byte in, byte out[2], Hex_Encoder::Case casing) - { - const byte* BIN_TO_HEX = ((casing == Uppercase) ? BIN_TO_HEX_UPPER : - BIN_TO_HEX_LOWER); - - out[0] = BIN_TO_HEX[((in >> 4) & 0x0F)]; - out[1] = BIN_TO_HEX[((in ) & 0x0F)]; - } - -/* * Encode and send a block */ void Hex_Encoder::encode_and_send(const byte block[], u32bit length) { - for(u32bit j = 0; j != length; ++j) - encode(block[j], out + 2*j, casing); + hex_encode(reinterpret_cast<char*>(&out[0]), + block, length, + casing == Uppercase); if(line_length == 0) send(out, 2*length); @@ -125,62 +115,35 @@ Hex_Decoder::Hex_Decoder(Decoder_Checking c) : checking(c) } /* -* Check if a character is a valid hex char -*/ -bool Hex_Decoder::is_valid(byte in) - { - return (HEX_TO_BIN[in] != 0x80); - } - -/* -* Handle processing an invalid character -*/ -void Hex_Decoder::handle_bad_char(byte c) - { - if(checking == NONE) - return; - - if((checking == IGNORE_WS) && Charset::is_space(c)) - return; - - throw Decoding_Error("Hex_Decoder: Invalid hex character: " + - to_string(c)); - } - -/* -* Hex Decoding Operation -*/ -byte Hex_Decoder::decode(const byte hex[2]) - { - return ((HEX_TO_BIN[hex[0]] << 4) | HEX_TO_BIN[hex[1]]); - } - -/* -* Decode and send a block -*/ -void Hex_Decoder::decode_and_send(const byte block[], u32bit length) - { - for(u32bit j = 0; j != length / 2; ++j) - out[j] = decode(block + 2*j); - send(out, length / 2); - } - -/* * Convert some data from hex format */ void Hex_Decoder::write(const byte input[], u32bit length) { - for(u32bit j = 0; j != length; ++j) + while(length) { - if(is_valid(input[j])) - in[position++] = input[j]; - else - handle_bad_char(input[j]); - if(position == in.size()) + u32bit to_copy = std::min(length, in.size() - position); + copy_mem(&in[position], input, to_copy); + position += to_copy; + + u32bit consumed = 0; + u32bit written = hex_decode(&out[0], + reinterpret_cast<const char*>(&in[0]), + position, + consumed, + checking != FULL_CHECK); + + send(out, written); + + if(consumed != position) { - decode_and_send(in, in.size()); - position = 0; + copy_mem(&in[0], &in[consumed], position - consumed); + position = position - consumed; } + else + position = 0; + + length -= to_copy; + input += to_copy; } } @@ -189,8 +152,21 @@ void Hex_Decoder::write(const byte input[], u32bit length) */ void Hex_Decoder::end_msg() { - decode_and_send(in, position); + u32bit consumed = 0; + u32bit written = hex_decode(&out[0], + reinterpret_cast<const char*>(&in[0]), + position, + consumed, + checking != FULL_CHECK); + + send(out, written); + + const bool not_full_bytes = consumed != position; + position = 0; + + if(not_full_bytes) + throw std::invalid_argument("Hex_Decoder: Input not full bytes"); } } diff --git a/src/filters/hex/hex.h b/src/filters/hex_filt/hex_filt.h index 6698a61be..2a7300ddb 100644 --- a/src/filters/hex/hex.h +++ b/src/filters/hex_filt/hex_filt.h @@ -5,8 +5,8 @@ * Distributed under the terms of the Botan license */ -#ifndef BOTAN_HEX_H__ -#define BOTAN_HEX_H__ +#ifndef BOTAN_HEX_FILTER_H__ +#define BOTAN_HEX_FILTER_H__ #include <botan/filter.h> @@ -50,8 +50,6 @@ class BOTAN_DLL Hex_Encoder : public Filter Case the_case = Uppercase); private: void encode_and_send(const byte[], u32bit); - static const byte BIN_TO_HEX_UPPER[16]; - static const byte BIN_TO_HEX_LOWER[16]; const Case casing; const u32bit line_length; @@ -65,20 +63,6 @@ class BOTAN_DLL Hex_Encoder : public Filter class BOTAN_DLL Hex_Decoder : public Filter { public: - /** - * Decode a pair of hex chars to a byte - * @param in an array of two hex chars - * @return byte formed by decoding in - */ - static byte decode(const byte in[2]); - - /** - * Check if this character is a valid hex input - * @param c a single character - * @return true iff c is a valid hex char - */ - static bool is_valid(byte c); - std::string name() const { return "Hex_Decoder"; } void write(const byte[], u32bit); @@ -91,10 +75,6 @@ class BOTAN_DLL Hex_Decoder : public Filter */ Hex_Decoder(Decoder_Checking checking = NONE); private: - void decode_and_send(const byte[], u32bit); - void handle_bad_char(byte); - static const byte HEX_TO_BIN[256]; - const Decoder_Checking checking; SecureVector<byte> in, out; u32bit position; diff --git a/src/filters/hex/info.txt b/src/filters/hex_filt/info.txt index 0a4205669..7f5f47fa1 100644 --- a/src/filters/hex/info.txt +++ b/src/filters/hex_filt/info.txt @@ -1,4 +1,4 @@ -define HEX_CODEC +define HEX_FILTER <requires> filters |