Skip to content

Commit 15dab32

Browse files
authored
feat(encoding): add Base64 and Base32 helpers
1 parent d4cb7c9 commit 15dab32

9 files changed

Lines changed: 688 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [Unreleased]
4+
### Added
5+
- Base64 and Base32 encoding/decoding utilities with secure_buffer overloads.
6+
37
## [0.3.0] - 2025-09-05
48
### Added
59
- PBKDF2 implementation.

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(HMAC_SOURCES
1111
src/sha512.cpp
1212
src/hmac.cpp
1313
src/hmac_utils.cpp
14+
src/encoding.cpp
1415
)
1516

1617
set(HMAC_HEADERS
@@ -21,6 +22,7 @@ set(HMAC_HEADERS
2122
include/hmac_cpp/sha256.hpp
2223
include/hmac_cpp/sha512.hpp
2324
include/hmac_cpp/secure_buffer.hpp
25+
include/hmac_cpp/encoding.hpp
2426
)
2527

2628
add_library(hmac_cpp ${HMAC_SOURCES})
@@ -58,6 +60,10 @@ endif()
5860
add_executable(example_pbkdf2 example_pbkdf2.cpp)
5961
target_link_libraries(example_pbkdf2 PRIVATE hmac_cpp)
6062
target_include_directories(example_pbkdf2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
63+
64+
add_executable(example_encoding example_encoding.cpp)
65+
target_link_libraries(example_encoding PRIVATE hmac_cpp)
66+
target_include_directories(example_encoding PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
6167
endif()
6268

6369
include(CMakePackageConfigHelpers)

README-RU.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,19 @@ auto prk = hmac::hkdf_extract_sha256(ikm, salt);
151151
auto okm = hmac::hkdf_expand_sha256(prk, /*info=*/{}, /*L=*/32); // L ≤ 255*HashLen
152152
```
153153
154+
### Base64 / Base32
155+
156+
Утилиты для кодирования/декодирования Base64 (обычный и URL-алфавит) и Base32.
157+
158+
```cpp
159+
#include <hmac_cpp/encoding.hpp>
160+
161+
std::vector<uint8_t> key = {0xff, 0xee};
162+
std::string b64 = hmac_cpp::base64_encode(key, hmac_cpp::Base64Alphabet::Url, false);
163+
hmac_cpp::secure_buffer<uint8_t> raw;
164+
hmac_cpp::base64_decode(b64, raw, hmac_cpp::Base64Alphabet::Url, false);
165+
```
166+
154167
### 🕓 HOTP / TOTP
155168

156169
OTP по RFC 4226/6238. **Секреты должны быть случайными** (не паролями). Если получаете Base32 (otpauth URI), декодируйте перед вызовом.

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ auto prk = hmac::hkdf_extract_sha256(ikm, salt);
172172
auto okm = hmac::hkdf_expand_sha256(prk, /*info=*/{}, /*L=*/32); // L ≤ 255*HashLen
173173
```
174174
175+
### Base64 / Base32
176+
177+
Utility helpers for Base64 (standard or URL alphabet) and Base32.
178+
179+
```cpp
180+
#include <hmac_cpp/encoding.hpp>
181+
182+
std::vector<uint8_t> key = {0xff, 0xee};
183+
std::string b64 = hmac_cpp::base64_encode(key, hmac_cpp::Base64Alphabet::Url, false);
184+
hmac_cpp::secure_buffer<uint8_t> raw;
185+
hmac_cpp::base64_decode(b64, raw, hmac_cpp::Base64Alphabet::Url, false);
186+
```
187+
175188
### 🕓 HOTP / TOTP
176189

177190
OTP per RFC 4226/6238. **Secrets should be random** (not passwords). If you receive Base32 (otpauth URI), decode before calling.

example_encoding.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <iostream>
2+
#include <string>
3+
#include <vector>
4+
#include <hmac_cpp/encoding.hpp>
5+
#include <hmac_cpp/secure_buffer.hpp>
6+
7+
int main() {
8+
std::vector<uint8_t> data = {'f','o','o','b','a','r'};
9+
std::string b64 = hmac_cpp::base64_encode(data);
10+
std::cout << "Base64: " << b64 << std::endl;
11+
12+
std::vector<uint8_t> decoded;
13+
hmac_cpp::base64_decode(b64, decoded);
14+
std::cout << "Decoded: " << std::string(decoded.begin(), decoded.end()) << std::endl;
15+
16+
std::string b32 = hmac_cpp::base32_encode(data);
17+
std::cout << "Base32: " << b32 << std::endl;
18+
19+
hmac_cpp::secure_buffer<uint8_t> sec;
20+
hmac_cpp::base32_decode(b32, sec);
21+
std::cout << "Decoded secure size: " << sec.size() << std::endl;
22+
return 0;
23+
}

include/hmac_cpp/encoding.hpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#ifndef _HMAC_ENCODING_HPP_INCLUDED
2+
#define _HMAC_ENCODING_HPP_INCLUDED
3+
4+
#include "api.hpp"
5+
#include "secure_buffer.hpp"
6+
#include <cstdint>
7+
#include <string>
8+
#include <vector>
9+
10+
namespace hmac_cpp {
11+
12+
/// \brief Alphabet variant for Base64.
13+
enum class Base64Alphabet { Standard, Url }; // Standard: "+/", Url: "-_"
14+
15+
// -------------------------
16+
// Base64 — encode / decode
17+
// -------------------------
18+
19+
/// \brief Base64-encode a byte buffer (RFC 4648).
20+
/// \param data Pointer to input bytes.
21+
/// \param len Number of input bytes.
22+
/// \param alphabet Standard ("+/") or URL-safe ("-_") alphabet.
23+
/// \param pad If true, append '=' padding to a multiple of 4 chars.
24+
/// \return Encoded string.
25+
HMAC_CPP_API std::string base64_encode(const uint8_t* data, size_t len,
26+
Base64Alphabet alphabet = Base64Alphabet::Standard,
27+
bool pad = true);
28+
29+
/// \brief Base64-encode a vector.
30+
inline std::string base64_encode(const std::vector<uint8_t>& v,
31+
Base64Alphabet alphabet = Base64Alphabet::Standard,
32+
bool pad = true) {
33+
return base64_encode(v.data(), v.size(), alphabet, pad);
34+
}
35+
36+
/// \brief Base64-encode a secure_buffer.
37+
inline std::string base64_encode(const secure_buffer<uint8_t>& v,
38+
Base64Alphabet alphabet = Base64Alphabet::Standard,
39+
bool pad = true) {
40+
return base64_encode(v.data(), v.size(), alphabet, pad);
41+
}
42+
43+
/// \brief Decode a Base64 string (RFC 4648).
44+
/// \param in Input string (raw Base64 chars).
45+
/// \param out Output byte vector (overwritten).
46+
/// \param alphabet Standard ("+/") or URL-safe ("-_") alphabet.
47+
/// \param require_padding If true, input must have proper '=' padding and length % 4 == 0.
48+
/// \param strict If true, disallow whitespaces and enforce '=' only in the last quartet.
49+
/// If false, ignore ASCII spaces and CR/LF/TAB and allow missing padding.
50+
/// \return true on success, false on invalid input.
51+
HMAC_CPP_API bool base64_decode(const std::string& in, std::vector<uint8_t>& out,
52+
Base64Alphabet alphabet = Base64Alphabet::Standard,
53+
bool require_padding = false,
54+
bool strict = true) noexcept;
55+
56+
/// \brief Decode Base64 into secure_buffer.
57+
HMAC_CPP_API bool base64_decode(const std::string& in, secure_buffer<uint8_t>& out,
58+
Base64Alphabet alphabet = Base64Alphabet::Standard,
59+
bool require_padding = false,
60+
bool strict = true) noexcept;
61+
62+
// -------------------------
63+
// Base32 — encode / decode
64+
// -------------------------
65+
66+
/// \brief Base32-encode a byte buffer (RFC 4648; alphabet A–Z, 2–7).
67+
/// \param data Pointer to input bytes.
68+
/// \param len Number of input bytes.
69+
/// \param pad If true, append '=' padding to a multiple of 8 chars.
70+
/// \return Encoded string (upper-case).
71+
HMAC_CPP_API std::string base32_encode(const uint8_t* data, size_t len,
72+
bool pad = true);
73+
74+
/// \brief Base32-encode a vector.
75+
inline std::string base32_encode(const std::vector<uint8_t>& v, bool pad = true) {
76+
return base32_encode(v.data(), v.size(), pad);
77+
}
78+
79+
/// \brief Base32-encode a secure_buffer.
80+
inline std::string base32_encode(const secure_buffer<uint8_t>& v, bool pad = true) {
81+
return base32_encode(v.data(), v.size(), pad);
82+
}
83+
84+
/// \brief Decode a Base32 string (RFC 4648).
85+
/// \param in Input string (Base32; upper-case preferred).
86+
/// \param out Output byte vector (overwritten).
87+
/// \param require_padding If true, input must have proper '=' padding and length % 8 == 0.
88+
/// \param strict If true, disallow whitespaces and lower-case; enforce '=' only in the last block.
89+
/// If false, ignore ASCII spaces and CR/LF/TAB and accept lower-case letters.
90+
/// \return true on success, false on invalid input.
91+
HMAC_CPP_API bool base32_decode(const std::string& in, std::vector<uint8_t>& out,
92+
bool require_padding = false,
93+
bool strict = true) noexcept;
94+
95+
/// \brief Decode Base32 into secure_buffer.
96+
HMAC_CPP_API bool base32_decode(const std::string& in, secure_buffer<uint8_t>& out,
97+
bool require_padding = false,
98+
bool strict = true) noexcept;
99+
100+
} // namespace hmac_cpp
101+
102+
#endif // _HMAC_ENCODING_HPP_INCLUDED

include/hmac_cpp/secure_buffer.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define HMAC_CPP_SECURE_BUFFER_HPP
33

44
#include <cstddef>
5+
#include <cstdint>
56
#include <vector>
67
#include <type_traits>
78
#include <string>

0 commit comments

Comments
 (0)