Line | Count | Source |
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 | 15.2k | { |
38 | 15.2k | uint16_t x; |
39 | 15.2k | unsigned char cl, cc; |
40 | | |
41 | 15.2k | if(!length) |
42 | 0 | return 0; |
43 | | |
44 | 15.2k | cl = s[start / 8]; |
45 | 15.2k | if(start / 8 < (start + length-1)/8) |
46 | 7.66k | cc = s[start / 8 + 1]; |
47 | 7.60k | else |
48 | 7.60k | cc = 0; |
49 | | |
50 | 15.2k | x = (uint16_t) (cl << 8 | cc); |
51 | 15.2k | x = x >> (16 - (length + (start % 8))); |
52 | 15.2k | x = (x & (0xffff >> (16 - length))); |
53 | 15.2k | return (x); |
54 | 15.2k | } |
55 | | |
56 | | /* same, set bit ranges in a char* */ |
57 | | static void set_bits(char* s, int x, int start, int length) |
58 | 94.6k | { |
59 | 94.6k | unsigned char cl, cc, cr; |
60 | 94.6k | uint32_t y; |
61 | 94.6k | int shift; |
62 | | |
63 | 94.6k | shift = ((8 - ((start + length) % 8)) % 8); |
64 | 94.6k | y = (uint32_t) x << shift; |
65 | 94.6k | cl = (y >> 16) & 0xff; |
66 | 94.6k | cc = (y >> 8) & 0xff; |
67 | 94.6k | cr = y & 0xff; |
68 | 94.6k | 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 | 94.6k | else { |
74 | 94.6k | if (shift + length > 8) { |
75 | 47.3k | s[start / 8] |= cc; |
76 | 47.3k | s[start / 8 + 1] |= cr; |
77 | 47.3k | } else { |
78 | 47.3k | s[start / 8] |= cr; |
79 | 47.3k | } |
80 | 94.6k | } |
81 | 94.6k | } |
82 | | |
83 | | /* convert a base32 hex character to its decoded equivalent */ |
84 | | static int unbase32hex(char c) |
85 | 94.8k | { |
86 | 94.8k | if(c >= '0' && c<='9') |
87 | 2.93k | return c-'0'; |
88 | 91.8k | if(c >= 'a' && c<='z') |
89 | 87.6k | return 10 + (c-'a'); |
90 | 4.20k | if(c >= 'A' && c<='Z') |
91 | 4.07k | return 10 + (c-'A'); |
92 | 130 | if(c=='=') |
93 | 2 | return '='; |
94 | 128 | return -1; |
95 | 130 | } |
96 | | |
97 | | /* convert a binary string to base32hex */ |
98 | | string toBase32Hex(const std::string& input) |
99 | 407 | { |
100 | 407 | static const char base32hex[] = "0123456789abcdefghijklmnopqrstuv="; |
101 | 407 | string ret; |
102 | 407 | ret.reserve(4+ 8*input.length()/5); // optimization |
103 | | // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks |
104 | 2.42k | for(string::size_type offset = 0 ; offset < input.length(); offset+=5) { |
105 | 2.01k | int todo = input.length() - offset; |
106 | 2.01k | int stuffing; // how much '=' to add at the end |
107 | | |
108 | 2.01k | switch(todo) { |
109 | 99 | case 1: |
110 | 99 | stuffing = 6; break; |
111 | 30 | case 2: |
112 | 30 | stuffing = 4; break; |
113 | 37 | case 3: |
114 | 37 | stuffing = 3; break; |
115 | 19 | case 4: |
116 | 19 | stuffing = 1; break; |
117 | 1.82k | default: // -> 0 or more than 5, no stuffing |
118 | 1.82k | stuffing = 0; break; |
119 | 2.01k | } |
120 | | |
121 | 17.2k | for(int n=0; n < 8 - stuffing; ++n) |
122 | 15.2k | ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]); |
123 | 2.01k | ret.append(stuffing, '='); |
124 | 2.01k | } |
125 | | |
126 | 407 | return ret; |
127 | 407 | } |
128 | | |
129 | | // convert base32hex encoded string to normal string |
130 | | string fromBase32Hex(const std::string& input) |
131 | 214 | { |
132 | 214 | string ret; |
133 | 214 | char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time |
134 | 214 | string::size_type n, toWrite=0; |
135 | 94.8k | for(n = 0; n < input.length(); ++n) { |
136 | 94.8k | int c=unbase32hex(input[n]); |
137 | 94.8k | if(c == '=' || c < 0) // stop at stuffing or error |
138 | 130 | break; |
139 | 94.6k | set_bits(block, c , (n % 8) * 5, 5); |
140 | 94.6k | if(++toWrite == 8) { |
141 | 11.7k | ret.append(block, sizeof(block)); |
142 | 11.7k | memset(block, 0, sizeof(block)); |
143 | 11.7k | toWrite = 0; |
144 | 11.7k | } |
145 | 94.6k | } |
146 | 214 | ret.append(block, (toWrite*5)/8); |
147 | | |
148 | 214 | return ret; |
149 | 214 | } |
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 |