]>
Commit | Line | Data |
---|---|---|
12471842 PL |
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 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
4691b2df BH |
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" | |
10f4eea8 | 32 | #include "namespaces.hh" |
4691b2df BH |
33 | |
34 | /* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */ | |
79fe6bef | 35 | /* NOTE: length should not exceed 8; all callers inside PowerDNS only pass length=5 though */ |
c8722b89 | 36 | unsigned char extract_bits(const char *s, int start, int length) |
4691b2df | 37 | { |
c8722b89 PD |
38 | uint16_t x; |
39 | unsigned char cl, cc; | |
40 | ||
41 | if(!length) | |
42 | return 0; | |
4691b2df BH |
43 | |
44 | cl = s[start / 8]; | |
c8722b89 PD |
45 | if(start / 8 < (start + length-1)/8) |
46 | cc = s[start / 8 + 1]; | |
79fe6bef PD |
47 | else |
48 | cc = 0; | |
c8722b89 PD |
49 | |
50 | x = (uint16_t) (cl << 8 | cc); | |
51 | x = x >> (16 - (length + (start % 8))); | |
4691b2df BH |
52 | x = (x & (0xffff >> (16 - length))); |
53 | return (x); | |
54 | } | |
55 | ||
56 | /* same, set bit ranges in a char* */ | |
57 | static void set_bits(char* s, int x, int start, int length) | |
58 | { | |
59 | unsigned char cl, cc, cr; | |
60 | uint32_t y; | |
61 | int shift; | |
62 | ||
63 | shift = ((8 - ((start + length) % 8)) % 8); | |
64 | y = (uint32_t) x << shift; | |
65 | cl = (y >> 16) & 0xff; | |
66 | cc = (y >> 8) & 0xff; | |
67 | cr = y & 0xff; | |
68 | if (shift + length > 16) { | |
69 | s[start / 8] |= cl; | |
70 | s[start / 8 + 1] |= cc; | |
71 | s[start / 8 + 2] |= cr; | |
72 | } | |
73 | else { | |
74 | if (shift + length > 8) { | |
75 | s[start / 8] |= cc; | |
76 | s[start / 8 + 1] |= cr; | |
77 | } else { | |
78 | s[start / 8] |= cr; | |
79 | } | |
80 | } | |
81 | } | |
82 | ||
83 | /* convert a base32 hex character to its decoded equivalent */ | |
84 | static int unbase32hex(char c) | |
85 | { | |
86 | if(c >= '0' && c<='9') | |
87 | return c-'0'; | |
88 | if(c >= 'a' && c<='z') | |
89 | return 10 + (c-'a'); | |
90 | if(c >= 'A' && c<='Z') | |
91 | return 10 + (c-'A'); | |
92 | if(c=='=') | |
93 | return '='; | |
94 | return -1; | |
95 | } | |
96 | ||
97 | /* convert a binary string to base32hex */ | |
98 | string toBase32Hex(const std::string& input) | |
99 | { | |
1bad4190 | 100 | static const char base32hex[] = "0123456789abcdefghijklmnopqrstuv="; |
4691b2df BH |
101 | string ret; |
102 | ret.reserve(4+ 8*input.length()/5); // optimization | |
103 | // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks | |
104 | for(string::size_type offset = 0 ; offset < input.length(); offset+=5) { | |
105 | int todo = input.length() - offset; | |
106 | int stuffing; // how much '=' to add at the end | |
107 | ||
108 | switch(todo) { | |
109 | case 1: | |
110 | stuffing = 6; break; | |
111 | case 2: | |
112 | stuffing = 4; break; | |
113 | case 3: | |
114 | stuffing = 3; break; | |
115 | case 4: | |
116 | stuffing = 1; break; | |
117 | default: // -> 0 or more than 5, no stuffing | |
118 | stuffing = 0; break; | |
119 | } | |
120 | ||
121 | for(int n=0; n < 8 - stuffing; ++n) | |
122 | ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]); | |
123 | ret.append(stuffing, '='); | |
124 | } | |
125 | ||
126 | return ret; | |
127 | } | |
128 | ||
129 | // convert base32hex encoded string to normal string | |
130 | string fromBase32Hex(const std::string& input) | |
131 | { | |
132 | string ret; | |
133 | char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time | |
134 | string::size_type n, toWrite=0; | |
135 | for(n = 0; n < input.length(); ++n) { | |
136 | int c=unbase32hex(input[n]); | |
137 | if(c == '=' || c < 0) // stop at stuffing or error | |
138 | break; | |
139 | set_bits(block, c , (n % 8) * 5, 5); | |
140 | if(++toWrite == 8) { | |
141 | ret.append(block, sizeof(block)); | |
142 | memset(block, 0, sizeof(block)); | |
143 | toWrite = 0; | |
144 | } | |
145 | } | |
f4ae4ec2 | 146 | ret.append(block, (toWrite*5)/8); |
4691b2df BH |
147 | |
148 | return ret; | |
149 | } | |
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", | |
232f0877 CH |
160 | argv[2], |
161 | toBase32Hex(argv[2]).c_str()); | |
4691b2df BH |
162 | } |
163 | else { | |
164 | cout<<"input: '"<<argv[2]<<"'\noutput: '"<<fromBase32Hex(argv[2])<<"'\n"; | |
165 | } | |
166 | } | |
167 | #endif |