CCF
Loading...
Searching...
No Matches
base64.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
6#include "ccf/ds/logger.h"
7
8#include <openssl/err.h>
9#include <openssl/evp.h>
10#include <string>
11#include <vector>
12
13// Inspired by openssl/test/evp_test.c
14// Ref: https://www.openssl.org/docs/man1.1.1/man3/EVP_DecodeBlock.html
15
16namespace ccf::crypto
17{
19 {
20 // Decode Base64 into byte stream
21 static std::vector<uint8_t> raw_from_b64(const std::string_view& b64_string)
22 {
23 const auto data = reinterpret_cast<const uint8_t*>(b64_string.data());
24 const auto size = b64_string.size();
25
26 if (size == 0)
27 return {};
28
29 // Make sure the error queue is clean before we start
30 // Trying to ameliorate #3677 and #3368
31 ERR_clear_error();
32
33 // Initialise the encode context
35 EVP_DecodeInit(ctx);
36 int encoded_len = 0;
37
38 // Calculate the output buffer size: b64 is 6 bits per byte
39 int max_size = EVP_DECODE_LENGTH(size);
40 unsigned char output[max_size];
41 memset(output, '\0', max_size);
42
43 // Decode
44 int chunk_len = 0;
45 int rc = EVP_DecodeUpdate(ctx, output, &chunk_len, data, size);
46 if (rc < 0)
47 {
48 auto err_str = OpenSSL::error_string(ERR_get_error());
49 throw std::invalid_argument(fmt::format(
50 "OSSL: Could not decode update from base64 string: {} [{} bytes out "
51 "of {}, chunk_len = {}]",
52 err_str,
53 size,
54 max_size,
55 chunk_len));
56 }
57 encoded_len = chunk_len;
58
59 rc = EVP_DecodeFinal(ctx, output + chunk_len, &chunk_len);
60 if (rc != 1)
61 {
62 auto err_str = OpenSSL::error_string(ERR_get_error());
63 throw std::logic_error(fmt::format(
64 "OSSL: Could not decode final from base64 string: {} [{} bytes out "
65 "of {}, chunk_len = {}]",
66 err_str,
67 size,
68 max_size,
69 chunk_len));
70 }
71 encoded_len += chunk_len;
72
73 std::vector<uint8_t> ret(output, output + encoded_len);
74
75 return ret;
76 }
77
78 // Encode byte stream into Base64
79 static std::string b64_from_raw(const uint8_t* data, size_t size)
80 {
81 if (size == 0)
82 return "";
83
84 // Make sure the error queue is clean before we start
85 // Trying to ameliorate #3677 and #3368
86 ERR_clear_error();
87
88 // Initialise the encode context
90 EVP_EncodeInit(ctx);
91
92 // Calculate the output buffer size: b64 is 6 bits per byte
93 int max_size = EVP_ENCODE_LENGTH(size);
94 unsigned char output[max_size];
95 memset(output, '\0', max_size);
96
97 // Encode Main Block (if size > 48)
98 int chunk_len = 0;
99 int rc = EVP_EncodeUpdate(ctx, output, &chunk_len, data, size);
100 if (rc < 0)
101 {
102 auto err_str = OpenSSL::error_string(ERR_get_error());
103 throw std::logic_error(fmt::format(
104 "OSSL: Could not encode update to base64 string: {} [{} bytes out of "
105 "{}, chunk_len = {}]",
106 err_str,
107 size,
108 max_size,
109 chunk_len));
110 }
111
112 // Encode Final Line (after previous lines, if any)
113 EVP_EncodeFinal(ctx, output + chunk_len, &chunk_len);
114 auto err = ERR_get_error();
115 if (err != 0)
116 {
117 auto err_str = OpenSSL::error_string(err);
118 throw std::logic_error(fmt::format(
119 "OSSL: Could not encode final to base64 string: {} [{} bytes out of "
120 "{}, chunk_len = {}]",
121 err_str,
122 size,
123 max_size,
124 chunk_len));
125 }
126
127 // Clean up result (last \0, newlines)
128 std::string ret = (const char*)output;
129 ret.pop_back();
130 ret.erase(std::remove(ret.begin(), ret.end(), '\n'), ret.end());
131
132 return ret;
133 }
134 };
135}
std::string error_string(unsigned long ec)
Returns the error string from an error code.
Definition openssl_wrappers.h:35
Definition base64.h:10
Definition base64.h:19
static std::vector< uint8_t > raw_from_b64(const std::string_view &b64_string)
Definition base64.h:21
static std::string b64_from_raw(const uint8_t *data, size_t size)
Definition base64.h:79
Definition openssl_wrappers.h:402