libkeepass 0.2.0
KeePass key database importer/exporter library
Loading...
Searching...
No Matches
base64.hh
Go to the documentation of this file.
1/*
2 * libkeepass - KeePass key database importer/exporter
3 * Copyright (C) 2014 Christian Kindahl
4 * Copyright (C) 2024 Dominik Krümpelmann
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
25#pragma once
26#include <algorithm>
27#include <locale>
28#include <string>
29#include <string_view>
30#include <type_traits>
31
32#include "exception.hh"
33
34namespace keepass {
35
44template <typename InputIterator>
45std::string base64_encode(InputIterator first, InputIterator last) {
46 static const std::string kBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47 "abcdefghijklmnopqrstuvwxyz"
48 "0123456789+/";
49
50 std::string dst;
51
52 while (first != last) {
53 auto c0 = static_cast<uint8_t>(*first++);
54 if (first == last) {
55 dst.push_back(kBase64[static_cast<std::string::size_type>(c0 >> 2)]);
56 dst.push_back(kBase64[static_cast<std::string::size_type>(((c0 & 0x3) << 4))]);
57 dst.push_back('=');
58 dst.push_back('=');
59 } else {
60 auto c1 = static_cast<uint8_t>(*first++);
61 if (first == last) {
62 dst.push_back(kBase64[static_cast<std::string::size_type>(c0 >> 2)]);
63 dst.push_back(kBase64[static_cast<std::string::size_type>(((c0 & 0x3) << 4) | (c1 >> 4))]);
64 dst.push_back(kBase64[static_cast<std::string::size_type>(((c1 & 0xf) << 2))]);
65 dst.push_back('=');
66 } else {
67 auto c2 = static_cast<uint8_t>(*first++);
68 dst.push_back(kBase64[static_cast<std::string::size_type>(c0 >> 2)]);
69 dst.push_back(kBase64[static_cast<std::string::size_type>(((c0 & 0x3) << 4) | (c1 >> 4))]);
70 dst.push_back(kBase64[static_cast<std::string::size_type>(((c1 & 0xf) << 2) | (c2 >> 6))]);
71 dst.push_back(kBase64[static_cast<std::string::size_type>(c2 & 0x3f)]);
72 }
73 }
74 }
75
76 return dst;
77}
78
88template <typename OutputIterator, typename Type>
89void base64_decode(std::string_view src, OutputIterator result) {
90 static const std::string kBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
91 "abcdefghijklmnopqrstuvwxyz"
92 "0123456789+/";
93
94 std::string src_trimmed;
95 std::copy_if(src.begin(), src.end(), std::back_inserter<std::string>(src_trimmed),
96 [](char c) { return !std::isspace(c, std::locale::classic()); });
97
98 if (src_trimmed.size() % 4 != 0)
99 throw FormatError("Base64 data must be a multiple of four in size.");
100
101 uint32_t bits24 = 0;
102 std::size_t i = 0;
103
104 for (char c : src_trimmed) {
105 if (c == '=') {
106 *result = static_cast<Type>(bits24 >> 16);
107 ++result;
108 if (i > 2) {
109 *result = static_cast<Type>((bits24 >> 8) & 0xff);
110 ++result;
111 }
112 if (i > 3) {
113 *result = static_cast<Type>(bits24 & 0xff);
114 ++result;
115 }
116 break;
117 }
118
119 std::size_t v = kBase64.find(c);
120 if (v == std::string::npos)
121 throw FormatError("Illegal character in base64 stream.");
122
123 bits24 |= static_cast<uint32_t>(v) << (18 - i++ * 6);
124 if (i == 4) {
125 *result = static_cast<Type>(bits24 >> 16);
126 ++result;
127 *result = static_cast<Type>((bits24 >> 8) & 0xff);
128 ++result;
129 *result = static_cast<Type>(bits24 & 0xff);
130 ++result;
131
132 bits24 = 0;
133 i = 0;
134 }
135 }
136}
137
139inline std::string base64_encode(const std::string& src) {
140 return base64_encode(src.begin(), src.end());
141}
142
144inline std::string base64_decode(std::string_view src) {
145 std::string dst;
146 base64_decode<std::back_insert_iterator<std::string>, char>(src, std::back_inserter(dst));
147 return dst;
148}
149
150} // namespace keepass
void base64_decode(std::string_view src, OutputIterator result)
Decodes a base64 string into an output sequence.
Definition base64.hh:89
std::string base64_encode(InputIterator first, InputIterator last)
Encodes a range of bytes into a base64 string.
Definition base64.hh:45
Thrown when a database or stream has an invalid format.
Definition exception.hh:79
Exception types thrown by the library.