Skip to content

Commit d258e0e

Browse files
committed
[x509] Add base64 encode and decode helpers
1 parent e7e9640 commit d258e0e

File tree

4 files changed

+184
-0
lines changed

4 files changed

+184
-0
lines changed

src/tools/x509/Base64.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
Copyright (c) 2020 Cedric Jimenez
3+
This file is part of OpenOCPP.
4+
5+
OpenOCPP is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
OpenOCPP is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License
16+
along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "Base64.h"
20+
21+
#include <openssl/evp.h>
22+
23+
namespace ocpp
24+
{
25+
namespace x509
26+
{
27+
namespace base64
28+
{
29+
30+
/** @brief Encode an array of bytes in Base64 */
31+
std::string encode(const void* data, size_t size)
32+
{
33+
std::string b64_str;
34+
35+
// Check input parameters
36+
if (data && (size != 0))
37+
{
38+
// Prepare buffer at the maximum data length
39+
b64_str.resize((4u * size) / 3u + 10u);
40+
41+
// Encode data
42+
int encoded_size = EVP_EncodeBlock(
43+
reinterpret_cast<unsigned char*>(&b64_str[0]), reinterpret_cast<const unsigned char*>(data), static_cast<int>(size));
44+
if (encoded_size >= 0)
45+
{
46+
// Resize output
47+
b64_str.resize(encoded_size);
48+
}
49+
else
50+
{
51+
b64_str.clear();
52+
}
53+
}
54+
55+
return b64_str;
56+
}
57+
58+
/** @brief Decode a Base64 string into an array of bytes */
59+
std::vector<uint8_t> decode(const std::string& b64_str)
60+
{
61+
std::vector<uint8_t> data;
62+
63+
// Check input parameters
64+
if (b64_str.size() != 0)
65+
{
66+
// Prepare buffer at the maximum data length
67+
data.resize((3u * b64_str.size()) / 4u + 10u);
68+
69+
// Decode data
70+
int decoded_size =
71+
EVP_DecodeBlock(&data[0], reinterpret_cast<const unsigned char*>(b64_str.c_str()), static_cast<int>(b64_str.size()));
72+
if (decoded_size >= 0)
73+
{
74+
// Resize output
75+
data.resize(decoded_size);
76+
}
77+
else
78+
{
79+
data.clear();
80+
}
81+
}
82+
83+
return data;
84+
}
85+
86+
} // namespace base64
87+
} // namespace x509
88+
} // namespace ocpp

src/tools/x509/Base64.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright (c) 2020 Cedric Jimenez
3+
This file is part of OpenOCPP.
4+
5+
OpenOCPP is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
OpenOCPP is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License
16+
along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#ifndef BASE64_H
20+
#define BASE64_H
21+
22+
#include <cstdint>
23+
#include <string>
24+
#include <vector>
25+
26+
namespace ocpp
27+
{
28+
namespace x509
29+
{
30+
namespace base64
31+
{
32+
33+
/**
34+
* @brief Encode an array of bytes in Base64
35+
* @param data Data to encode
36+
* @param size Size in bytes of the data to encode
37+
* @return Base64 representation of the input array
38+
*/
39+
std::string encode(const void* data, size_t size);
40+
41+
/**
42+
* @brief Decode a Base64 string into an array of bytes
43+
* @param b64_str Base64 string to decode
44+
* @return Corresponding array of bytes or empty array if the string
45+
* format is invalid
46+
*/
47+
std::vector<uint8_t> decode(const std::string& b64_str);
48+
49+
} // namespace base64
50+
} // namespace x509
51+
} // namespace ocpp
52+
53+
#endif // BASE64_H

src/tools/x509/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# X509 library
33
include_directories(impl)
44
add_library(x509 STATIC
5+
Base64.cpp
56
Certificate.cpp
67
CertificateRequest.cpp
78
PrivateKey.cpp

tests/tools/test_x509.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ You should have received a copy of the GNU Lesser General Public License
1616
along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
1717
*/
1818

19+
#include "Base64.h"
1920
#include "Certificate.h"
2021
#include "CertificateRequest.h"
2122
#include "PrivateKey.h"
@@ -717,3 +718,44 @@ TEST_SUITE("Certificate generation")
717718
CHECK(cert.verify(data_signature, data.c_str(), data.size()));
718719
}
719720
}
721+
722+
TEST_SUITE("Base64")
723+
{
724+
TEST_CASE("Encode/Decode nominal")
725+
{
726+
// Data to encode
727+
const std::string input_data =
728+
"This string could have been some binary data but it is way more easier to do it with human readable data instead :) !";
729+
730+
// Expected result
731+
const std::string expected_result = "VGhpcyBzdHJpbmcgY291bGQgaGF2ZSBiZWVuIHNvbWUgYmluYXJ5IGRhdGEgYnV0IGl0IGlzIHdheSBtb3JlIGVhc2llci"
732+
"B0byBkbyBpdCB3aXRoIGh1bWFuIHJlYWRhYmxlIGRhdGEgaW5zdGVhZCA6KSAh";
733+
734+
// Check encoding
735+
CHECK_EQ(ocpp::x509::base64::encode(input_data.c_str(), input_data.size()), expected_result);
736+
737+
// Check decoding
738+
std::vector<uint8_t> decoded_data = ocpp::x509::base64::decode(expected_result);
739+
std::string decoded_data_str(reinterpret_cast<char*>(&decoded_data[0]), decoded_data.size());
740+
CHECK_EQ(decoded_data_str, input_data);
741+
}
742+
743+
TEST_CASE("Encode/Decode limits")
744+
{
745+
// Empty buffer to encode
746+
std::string encoded_null = ocpp::x509::base64::encode("hjkl", 0u);
747+
CHECK(encoded_null.empty());
748+
749+
// NULL buffer to encode
750+
encoded_null = ocpp::x509::base64::encode(nullptr, 10u);
751+
CHECK(encoded_null.empty());
752+
753+
// Empty buffer to decode
754+
std::vector<uint8_t> decoded_null = ocpp::x509::base64::decode("");
755+
CHECK(decoded_null.empty());
756+
757+
// Invalid input data to decode
758+
decoded_null = ocpp::x509::base64::decode("VGh");
759+
CHECK(decoded_null.empty());
760+
}
761+
}

0 commit comments

Comments
 (0)