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