Coverage Report

Created: 2025-08-28 07:00

/src/pdns/pdns/base32.cc
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