]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/base32.cc
initial drop of dnssec keying infrastructure - mostly ceremonial
[thirdparty/pdns.git] / pdns / base32.cc
CommitLineData
4691b2df
BH
1#include <stdint.h>
2#include <stdio.h>
3#include <string>
4#include <cstring>
5#include <stdlib.h>
6#include <iostream>
7#include "base32.hh"
8using namespace std;
9
10/* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */
11uint32_t extract_bits(const char *s, int start, int length)
12{
13 uint32_t x;
14 unsigned char cl, cc, cr;
15
16 cl = s[start / 8];
17 cc = s[start / 8 + 1];
18 cr = s[start / 8 + 2];
19 x = ((uint32_t) (cl << 8 | cc) << 8 | cr);
20 x = x >> (24 - (length + (start % 8)));
21 x = (x & (0xffff >> (16 - length)));
22 return (x);
23}
24
25/* same, set bit ranges in a char* */
26static void set_bits(char* s, int x, int start, int length)
27{
28 unsigned char cl, cc, cr;
29 uint32_t y;
30 int shift;
31
32 shift = ((8 - ((start + length) % 8)) % 8);
33 y = (uint32_t) x << shift;
34 cl = (y >> 16) & 0xff;
35 cc = (y >> 8) & 0xff;
36 cr = y & 0xff;
37 if (shift + length > 16) {
38 s[start / 8] |= cl;
39 s[start / 8 + 1] |= cc;
40 s[start / 8 + 2] |= cr;
41 }
42 else {
43 if (shift + length > 8) {
44 s[start / 8] |= cc;
45 s[start / 8 + 1] |= cr;
46 } else {
47 s[start / 8] |= cr;
48 }
49 }
50}
51
52/* convert a base32 hex character to its decoded equivalent */
53static int unbase32hex(char c)
54{
55 if(c >= '0' && c<='9')
56 return c-'0';
57 if(c >= 'a' && c<='z')
58 return 10 + (c-'a');
59 if(c >= 'A' && c<='Z')
60 return 10 + (c-'A');
61 if(c=='=')
62 return '=';
63 return -1;
64}
65
66/* convert a binary string to base32hex */
67string toBase32Hex(const std::string& input)
68{
69 static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV=";
70 string ret;
71 ret.reserve(4+ 8*input.length()/5); // optimization
72 // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks
73 for(string::size_type offset = 0 ; offset < input.length(); offset+=5) {
74 int todo = input.length() - offset;
75 int stuffing; // how much '=' to add at the end
76
77 switch(todo) {
78 case 1:
79 stuffing = 6; break;
80 case 2:
81 stuffing = 4; break;
82 case 3:
83 stuffing = 3; break;
84 case 4:
85 stuffing = 1; break;
86 default: // -> 0 or more than 5, no stuffing
87 stuffing = 0; break;
88 }
89
90 for(int n=0; n < 8 - stuffing; ++n)
91 ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]);
92 ret.append(stuffing, '=');
93 }
94
95 return ret;
96}
97
98// convert base32hex encoded string to normal string
99string fromBase32Hex(const std::string& input)
100{
101 string ret;
102 char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time
103 string::size_type n, toWrite=0;
104 for(n = 0; n < input.length(); ++n) {
105 int c=unbase32hex(input[n]);
106 if(c == '=' || c < 0) // stop at stuffing or error
107 break;
108 set_bits(block, c , (n % 8) * 5, 5);
109 if(++toWrite == 8) {
110 ret.append(block, sizeof(block));
111 memset(block, 0, sizeof(block));
112 toWrite = 0;
113 }
114 }
115 ret.append(block, (7+toWrite*5)/8); // round up
116
117 return ret;
118}
119
120#if 0
121int main(int argc, char **argv)
122{
123 if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) {
124 printf("syntax: base32 from|to string\n");
125 exit(0);
126 }
127 if(!strcmp(argv[1],"to")) {
128 printf("input: '%s'\noutput: '%s'\n",
129 argv[2],
130 toBase32Hex(argv[2]).c_str());
131 }
132 else {
133 cout<<"input: '"<<argv[2]<<"'\noutput: '"<<fromBase32Hex(argv[2])<<"'\n";
134 }
135}
136#endif