Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * This file is part of PowerDNS or dnsdist. |
3 | | * Copyright -- PowerDNS.COM B.V. and its contributors |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of version 2 of the GNU General Public License as |
7 | | * published by the Free Software Foundation. |
8 | | * |
9 | | * In addition, for the avoidance of any doubt, permission is granted to |
10 | | * link this program with OpenSSL and to (re)distribute the binaries |
11 | | * produced as the result of such linking. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
21 | | */ |
22 | | #ifdef HAVE_CONFIG_H |
23 | | #include "config.h" |
24 | | #endif |
25 | | #include <stdint.h> |
26 | | #include <stdio.h> |
27 | | #include <string> |
28 | | #include <cstring> |
29 | | #include <stdlib.h> |
30 | | #include <iostream> |
31 | | #include "base32.hh" |
32 | | #include "namespaces.hh" |
33 | | |
34 | | /* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */ |
35 | | /* NOTE: length should not exceed 8; all callers inside PowerDNS only pass length=5 though */ |
36 | | static unsigned char extract_bits(const char *s, int start, int length) |
37 | 0 | { |
38 | 0 | uint16_t x; |
39 | 0 | unsigned char cl, cc; |
40 | |
|
41 | 0 | if(!length) |
42 | 0 | return 0; |
43 | | |
44 | 0 | cl = s[start / 8]; |
45 | 0 | if(start / 8 < (start + length-1)/8) |
46 | 0 | cc = s[start / 8 + 1]; |
47 | 0 | else |
48 | 0 | cc = 0; |
49 | |
|
50 | 0 | x = (uint16_t) (cl << 8 | cc); |
51 | 0 | x = x >> (16 - (length + (start % 8))); |
52 | 0 | x = (x & (0xffff >> (16 - length))); |
53 | 0 | return (x); |
54 | 0 | } |
55 | | |
56 | | /* same, set bit ranges in a char* */ |
57 | | static void set_bits(char* s, int x, int start, int length) |
58 | 0 | { |
59 | 0 | unsigned char cl, cc, cr; |
60 | 0 | uint32_t y; |
61 | 0 | int shift; |
62 | |
|
63 | 0 | shift = ((8 - ((start + length) % 8)) % 8); |
64 | 0 | y = (uint32_t) x << shift; |
65 | 0 | cl = (y >> 16) & 0xff; |
66 | 0 | cc = (y >> 8) & 0xff; |
67 | 0 | cr = y & 0xff; |
68 | 0 | if (shift + length > 16) { |
69 | 0 | s[start / 8] |= cl; |
70 | 0 | s[start / 8 + 1] |= cc; |
71 | 0 | s[start / 8 + 2] |= cr; |
72 | 0 | } |
73 | 0 | else { |
74 | 0 | if (shift + length > 8) { |
75 | 0 | s[start / 8] |= cc; |
76 | 0 | s[start / 8 + 1] |= cr; |
77 | 0 | } else { |
78 | 0 | s[start / 8] |= cr; |
79 | 0 | } |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | /* convert a base32 hex character to its decoded equivalent */ |
84 | | static int unbase32hex(char c) |
85 | 0 | { |
86 | 0 | if(c >= '0' && c<='9') |
87 | 0 | return c-'0'; |
88 | 0 | if(c >= 'a' && c<='z') |
89 | 0 | return 10 + (c-'a'); |
90 | 0 | if(c >= 'A' && c<='Z') |
91 | 0 | return 10 + (c-'A'); |
92 | 0 | if(c=='=') |
93 | 0 | return '='; |
94 | 0 | return -1; |
95 | 0 | } |
96 | | |
97 | | /* convert a binary string to base32hex */ |
98 | | string toBase32Hex(const std::string& input) |
99 | 0 | { |
100 | 0 | static const char base32hex[] = "0123456789abcdefghijklmnopqrstuv="; |
101 | 0 | string ret; |
102 | 0 | ret.reserve(4+ 8*input.length()/5); // optimization |
103 | | // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks |
104 | 0 | for(string::size_type offset = 0 ; offset < input.length(); offset+=5) { |
105 | 0 | int todo = input.length() - offset; |
106 | 0 | int stuffing; // how much '=' to add at the end |
107 | | |
108 | 0 | switch(todo) { |
109 | 0 | case 1: |
110 | 0 | stuffing = 6; break; |
111 | 0 | case 2: |
112 | 0 | stuffing = 4; break; |
113 | 0 | case 3: |
114 | 0 | stuffing = 3; break; |
115 | 0 | case 4: |
116 | 0 | stuffing = 1; break; |
117 | 0 | default: // -> 0 or more than 5, no stuffing |
118 | 0 | stuffing = 0; break; |
119 | 0 | } |
120 | | |
121 | 0 | for(int n=0; n < 8 - stuffing; ++n) |
122 | 0 | ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]); |
123 | 0 | ret.append(stuffing, '='); |
124 | 0 | } |
125 | | |
126 | 0 | return ret; |
127 | 0 | } |
128 | | |
129 | | // convert base32hex encoded string to normal string |
130 | | string fromBase32Hex(const std::string& input) |
131 | 0 | { |
132 | 0 | string ret; |
133 | 0 | char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time |
134 | 0 | string::size_type n, toWrite=0; |
135 | 0 | for(n = 0; n < input.length(); ++n) { |
136 | 0 | int c=unbase32hex(input[n]); |
137 | 0 | if(c == '=' || c < 0) // stop at stuffing or error |
138 | 0 | break; |
139 | 0 | set_bits(block, c , (n % 8) * 5, 5); |
140 | 0 | if(++toWrite == 8) { |
141 | 0 | ret.append(block, sizeof(block)); |
142 | 0 | memset(block, 0, sizeof(block)); |
143 | 0 | toWrite = 0; |
144 | 0 | } |
145 | 0 | } |
146 | 0 | ret.append(block, (toWrite*5)/8); |
147 | |
|
148 | 0 | return ret; |
149 | 0 | } |
150 | | |
151 | | #if 0 |
152 | | int main(int argc, char **argv) |
153 | | { |
154 | | if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) { |
155 | | printf("syntax: base32 from|to string\n"); |
156 | | exit(0); |
157 | | } |
158 | | if(!strcmp(argv[1],"to")) { |
159 | | printf("input: '%s'\noutput: '%s'\n", |
160 | | argv[2], |
161 | | toBase32Hex(argv[2]).c_str()); |
162 | | } |
163 | | else { |
164 | | cout<<"input: '"<<argv[2]<<"'\noutput: '"<<fromBase32Hex(argv[2])<<"'\n"; |
165 | | } |
166 | | } |
167 | | #endif |