Coverage Report

Created: 2026-08-31 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/base32.cc
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