1 /*
2 * Hex Encoder/Decoder
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8 #include <botan/filters.h>
9 #include <botan/hex.h>
10 #include <botan/exceptn.h>
11 #include <algorithm>
12
13 namespace Botan {
14
15 /**
16 * Size used for internal buffer in hex encoder/decoder
17 */
18 const size_t HEX_CODEC_BUFFER_SIZE = 256;
19
20 /*
21 * Hex_Encoder Constructor
22 */
Hex_Encoder(bool breaks,size_t length,Case c)23 Hex_Encoder::Hex_Encoder(bool breaks, size_t length, Case c) :
24 m_casing(c), m_line_length(breaks ? length : 0)
25 {
26 m_in.resize(HEX_CODEC_BUFFER_SIZE);
27 m_out.resize(2*m_in.size());
28 m_counter = m_position = 0;
29 }
30
31 /*
32 * Hex_Encoder Constructor
33 */
Hex_Encoder(Case c)34 Hex_Encoder::Hex_Encoder(Case c) : m_casing(c), m_line_length(0)
35 {
36 m_in.resize(HEX_CODEC_BUFFER_SIZE);
37 m_out.resize(2*m_in.size());
38 m_counter = m_position = 0;
39 }
40
41 /*
42 * Encode and send a block
43 */
encode_and_send(const uint8_t block[],size_t length)44 void Hex_Encoder::encode_and_send(const uint8_t block[], size_t length)
45 {
46 hex_encode(cast_uint8_ptr_to_char(m_out.data()),
47 block, length,
48 m_casing == Uppercase);
49
50 if(m_line_length == 0)
51 send(m_out, 2*length);
52 else
53 {
54 size_t remaining = 2*length, offset = 0;
55 while(remaining)
56 {
57 size_t sent = std::min(m_line_length - m_counter, remaining);
58 send(&m_out[offset], sent);
59 m_counter += sent;
60 remaining -= sent;
61 offset += sent;
62 if(m_counter == m_line_length)
63 {
64 send('\n');
65 m_counter = 0;
66 }
67 }
68 }
69 }
70
71 /*
72 * Convert some data into hex format
73 */
write(const uint8_t input[],size_t length)74 void Hex_Encoder::write(const uint8_t input[], size_t length)
75 {
76 buffer_insert(m_in, m_position, input, length);
77 if(m_position + length >= m_in.size())
78 {
79 encode_and_send(m_in.data(), m_in.size());
80 input += (m_in.size() - m_position);
81 length -= (m_in.size() - m_position);
82 while(length >= m_in.size())
83 {
84 encode_and_send(input, m_in.size());
85 input += m_in.size();
86 length -= m_in.size();
87 }
88 copy_mem(m_in.data(), input, length);
89 m_position = 0;
90 }
91 m_position += length;
92 }
93
94 /*
95 * Flush buffers
96 */
end_msg()97 void Hex_Encoder::end_msg()
98 {
99 encode_and_send(m_in.data(), m_position);
100 if(m_counter && m_line_length)
101 send('\n');
102 m_counter = m_position = 0;
103 }
104
105 /*
106 * Hex_Decoder Constructor
107 */
Hex_Decoder(Decoder_Checking c)108 Hex_Decoder::Hex_Decoder(Decoder_Checking c) : m_checking(c)
109 {
110 m_in.resize(HEX_CODEC_BUFFER_SIZE);
111 m_out.resize(m_in.size() / 2);
112 m_position = 0;
113 }
114
115 /*
116 * Convert some data from hex format
117 */
write(const uint8_t input[],size_t length)118 void Hex_Decoder::write(const uint8_t input[], size_t length)
119 {
120 while(length)
121 {
122 size_t to_copy = std::min<size_t>(length, m_in.size() - m_position);
123 copy_mem(&m_in[m_position], input, to_copy);
124 m_position += to_copy;
125
126 size_t consumed = 0;
127 size_t written = hex_decode(m_out.data(),
128 cast_uint8_ptr_to_char(m_in.data()),
129 m_position,
130 consumed,
131 m_checking != FULL_CHECK);
132
133 send(m_out, written);
134
135 if(consumed != m_position)
136 {
137 copy_mem(m_in.data(), m_in.data() + consumed, m_position - consumed);
138 m_position = m_position - consumed;
139 }
140 else
141 m_position = 0;
142
143 length -= to_copy;
144 input += to_copy;
145 }
146 }
147
148 /*
149 * Flush buffers
150 */
end_msg()151 void Hex_Decoder::end_msg()
152 {
153 size_t consumed = 0;
154 size_t written = hex_decode(m_out.data(),
155 cast_uint8_ptr_to_char(m_in.data()),
156 m_position,
157 consumed,
158 m_checking != FULL_CHECK);
159
160 send(m_out, written);
161
162 const bool not_full_bytes = consumed != m_position;
163
164 m_position = 0;
165
166 if(not_full_bytes)
167 throw Invalid_Argument("Hex_Decoder: Input not full bytes");
168 }
169
170 }
171