xref: /aosp_15_r20/external/ot-br-posix/third_party/Simple-web-server/repo/crypto.hpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker #ifndef SIMPLE_WEB_CRYPTO_HPP
2*4a64e381SAndroid Build Coastguard Worker #define SIMPLE_WEB_CRYPTO_HPP
3*4a64e381SAndroid Build Coastguard Worker 
4*4a64e381SAndroid Build Coastguard Worker #include <cmath>
5*4a64e381SAndroid Build Coastguard Worker #include <iomanip>
6*4a64e381SAndroid Build Coastguard Worker #include <istream>
7*4a64e381SAndroid Build Coastguard Worker #include <memory>
8*4a64e381SAndroid Build Coastguard Worker #include <sstream>
9*4a64e381SAndroid Build Coastguard Worker #include <string>
10*4a64e381SAndroid Build Coastguard Worker #include <vector>
11*4a64e381SAndroid Build Coastguard Worker 
12*4a64e381SAndroid Build Coastguard Worker #include <openssl/buffer.h>
13*4a64e381SAndroid Build Coastguard Worker #include <openssl/evp.h>
14*4a64e381SAndroid Build Coastguard Worker #include <openssl/md5.h>
15*4a64e381SAndroid Build Coastguard Worker #include <openssl/sha.h>
16*4a64e381SAndroid Build Coastguard Worker 
17*4a64e381SAndroid Build Coastguard Worker namespace SimpleWeb {
18*4a64e381SAndroid Build Coastguard Worker // TODO 2017: remove workaround for MSVS 2012
19*4a64e381SAndroid Build Coastguard Worker #if _MSC_VER == 1700                       // MSVS 2012 has no definition for round()
round(double x)20*4a64e381SAndroid Build Coastguard Worker   inline double round(double x) noexcept { // Custom definition of round() for positive numbers
21*4a64e381SAndroid Build Coastguard Worker     return floor(x + 0.5);
22*4a64e381SAndroid Build Coastguard Worker   }
23*4a64e381SAndroid Build Coastguard Worker #endif
24*4a64e381SAndroid Build Coastguard Worker 
25*4a64e381SAndroid Build Coastguard Worker   class Crypto {
26*4a64e381SAndroid Build Coastguard Worker     const static std::size_t buffer_size = 131072;
27*4a64e381SAndroid Build Coastguard Worker 
28*4a64e381SAndroid Build Coastguard Worker   public:
29*4a64e381SAndroid Build Coastguard Worker     class Base64 {
30*4a64e381SAndroid Build Coastguard Worker     public:
31*4a64e381SAndroid Build Coastguard Worker       /// Returns Base64 encoded string from input string.
encode(const std::string & input)32*4a64e381SAndroid Build Coastguard Worker       static std::string encode(const std::string &input) noexcept {
33*4a64e381SAndroid Build Coastguard Worker         std::string base64;
34*4a64e381SAndroid Build Coastguard Worker 
35*4a64e381SAndroid Build Coastguard Worker         BIO *bio, *b64;
36*4a64e381SAndroid Build Coastguard Worker         auto bptr = BUF_MEM_new();
37*4a64e381SAndroid Build Coastguard Worker 
38*4a64e381SAndroid Build Coastguard Worker         b64 = BIO_new(BIO_f_base64());
39*4a64e381SAndroid Build Coastguard Worker         BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
40*4a64e381SAndroid Build Coastguard Worker         bio = BIO_new(BIO_s_mem());
41*4a64e381SAndroid Build Coastguard Worker         BIO_push(b64, bio);
42*4a64e381SAndroid Build Coastguard Worker         BIO_set_mem_buf(b64, bptr, BIO_CLOSE);
43*4a64e381SAndroid Build Coastguard Worker 
44*4a64e381SAndroid Build Coastguard Worker         // Write directly to base64-buffer to avoid copy
45*4a64e381SAndroid Build Coastguard Worker         auto base64_length = static_cast<std::size_t>(round(4 * ceil(static_cast<double>(input.size()) / 3.0)));
46*4a64e381SAndroid Build Coastguard Worker         base64.resize(base64_length);
47*4a64e381SAndroid Build Coastguard Worker         bptr->length = 0;
48*4a64e381SAndroid Build Coastguard Worker         bptr->max = base64_length + 1;
49*4a64e381SAndroid Build Coastguard Worker         bptr->data = &base64[0];
50*4a64e381SAndroid Build Coastguard Worker 
51*4a64e381SAndroid Build Coastguard Worker         if(BIO_write(b64, &input[0], static_cast<int>(input.size())) <= 0 || BIO_flush(b64) <= 0)
52*4a64e381SAndroid Build Coastguard Worker           base64.clear();
53*4a64e381SAndroid Build Coastguard Worker 
54*4a64e381SAndroid Build Coastguard Worker         // To keep &base64[0] through BIO_free_all(b64)
55*4a64e381SAndroid Build Coastguard Worker         bptr->length = 0;
56*4a64e381SAndroid Build Coastguard Worker         bptr->max = 0;
57*4a64e381SAndroid Build Coastguard Worker         bptr->data = nullptr;
58*4a64e381SAndroid Build Coastguard Worker 
59*4a64e381SAndroid Build Coastguard Worker         BIO_free_all(b64);
60*4a64e381SAndroid Build Coastguard Worker 
61*4a64e381SAndroid Build Coastguard Worker         return base64;
62*4a64e381SAndroid Build Coastguard Worker       }
63*4a64e381SAndroid Build Coastguard Worker 
64*4a64e381SAndroid Build Coastguard Worker       /// Returns Base64 decoded string from base64 input.
decode(const std::string & base64)65*4a64e381SAndroid Build Coastguard Worker       static std::string decode(const std::string &base64) noexcept {
66*4a64e381SAndroid Build Coastguard Worker         std::string ascii((6 * base64.size()) / 8, '\0'); // The size is a up to two bytes too large.
67*4a64e381SAndroid Build Coastguard Worker 
68*4a64e381SAndroid Build Coastguard Worker         BIO *b64, *bio;
69*4a64e381SAndroid Build Coastguard Worker 
70*4a64e381SAndroid Build Coastguard Worker         b64 = BIO_new(BIO_f_base64());
71*4a64e381SAndroid Build Coastguard Worker         BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
72*4a64e381SAndroid Build Coastguard Worker // TODO: Remove in 2022 or later
73*4a64e381SAndroid Build Coastguard Worker #if(defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x1000214fL) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2080000fL)
74*4a64e381SAndroid Build Coastguard Worker         bio = BIO_new_mem_buf(const_cast<char *>(&base64[0]), static_cast<int>(base64.size()));
75*4a64e381SAndroid Build Coastguard Worker #else
76*4a64e381SAndroid Build Coastguard Worker         bio = BIO_new_mem_buf(&base64[0], static_cast<int>(base64.size()));
77*4a64e381SAndroid Build Coastguard Worker #endif
78*4a64e381SAndroid Build Coastguard Worker         bio = BIO_push(b64, bio);
79*4a64e381SAndroid Build Coastguard Worker 
80*4a64e381SAndroid Build Coastguard Worker         auto decoded_length = BIO_read(bio, &ascii[0], static_cast<int>(ascii.size()));
81*4a64e381SAndroid Build Coastguard Worker         if(decoded_length > 0)
82*4a64e381SAndroid Build Coastguard Worker           ascii.resize(static_cast<std::size_t>(decoded_length));
83*4a64e381SAndroid Build Coastguard Worker         else
84*4a64e381SAndroid Build Coastguard Worker           ascii.clear();
85*4a64e381SAndroid Build Coastguard Worker 
86*4a64e381SAndroid Build Coastguard Worker         BIO_free_all(b64);
87*4a64e381SAndroid Build Coastguard Worker 
88*4a64e381SAndroid Build Coastguard Worker         return ascii;
89*4a64e381SAndroid Build Coastguard Worker       }
90*4a64e381SAndroid Build Coastguard Worker     };
91*4a64e381SAndroid Build Coastguard Worker 
92*4a64e381SAndroid Build Coastguard Worker     /// Returns hex string from bytes in input string.
to_hex_string(const std::string & input)93*4a64e381SAndroid Build Coastguard Worker     static std::string to_hex_string(const std::string &input) noexcept {
94*4a64e381SAndroid Build Coastguard Worker       std::stringstream hex_stream;
95*4a64e381SAndroid Build Coastguard Worker       hex_stream << std::hex << std::internal << std::setfill('0');
96*4a64e381SAndroid Build Coastguard Worker       for(auto &byte : input)
97*4a64e381SAndroid Build Coastguard Worker         hex_stream << std::setw(2) << static_cast<int>(static_cast<unsigned char>(byte));
98*4a64e381SAndroid Build Coastguard Worker       return hex_stream.str();
99*4a64e381SAndroid Build Coastguard Worker     }
100*4a64e381SAndroid Build Coastguard Worker 
101*4a64e381SAndroid Build Coastguard Worker     /// Return hash value using specific EVP_MD from input string.
message_digest(const std::string & str,const EVP_MD * evp_md,std::size_t digest_length)102*4a64e381SAndroid Build Coastguard Worker     static std::string message_digest(const std::string &str, const EVP_MD *evp_md, std::size_t digest_length) noexcept {
103*4a64e381SAndroid Build Coastguard Worker       std::string md(digest_length, '\0');
104*4a64e381SAndroid Build Coastguard Worker 
105*4a64e381SAndroid Build Coastguard Worker       auto ctx = EVP_MD_CTX_create();
106*4a64e381SAndroid Build Coastguard Worker       EVP_MD_CTX_init(ctx);
107*4a64e381SAndroid Build Coastguard Worker       EVP_DigestInit_ex(ctx, evp_md, nullptr);
108*4a64e381SAndroid Build Coastguard Worker       EVP_DigestUpdate(ctx, str.data(), str.size());
109*4a64e381SAndroid Build Coastguard Worker       EVP_DigestFinal_ex(ctx, reinterpret_cast<unsigned char *>(&md[0]), nullptr);
110*4a64e381SAndroid Build Coastguard Worker       EVP_MD_CTX_destroy(ctx);
111*4a64e381SAndroid Build Coastguard Worker 
112*4a64e381SAndroid Build Coastguard Worker       return md;
113*4a64e381SAndroid Build Coastguard Worker     }
114*4a64e381SAndroid Build Coastguard Worker 
115*4a64e381SAndroid Build Coastguard Worker     /// Return hash value using specific EVP_MD from input stream.
stream_digest(std::istream & stream,const EVP_MD * evp_md,std::size_t digest_length)116*4a64e381SAndroid Build Coastguard Worker     static std::string stream_digest(std::istream &stream, const EVP_MD *evp_md, std::size_t digest_length) noexcept {
117*4a64e381SAndroid Build Coastguard Worker       std::string md(digest_length, '\0');
118*4a64e381SAndroid Build Coastguard Worker       std::unique_ptr<char[]> buffer(new char[buffer_size]);
119*4a64e381SAndroid Build Coastguard Worker       std::streamsize read_length;
120*4a64e381SAndroid Build Coastguard Worker 
121*4a64e381SAndroid Build Coastguard Worker       auto ctx = EVP_MD_CTX_create();
122*4a64e381SAndroid Build Coastguard Worker       EVP_MD_CTX_init(ctx);
123*4a64e381SAndroid Build Coastguard Worker       EVP_DigestInit_ex(ctx, evp_md, nullptr);
124*4a64e381SAndroid Build Coastguard Worker       while((read_length = stream.read(buffer.get(), buffer_size).gcount()) > 0)
125*4a64e381SAndroid Build Coastguard Worker         EVP_DigestUpdate(ctx, buffer.get(), static_cast<std::size_t>(read_length));
126*4a64e381SAndroid Build Coastguard Worker       EVP_DigestFinal_ex(ctx, reinterpret_cast<unsigned char *>(&md[0]), nullptr);
127*4a64e381SAndroid Build Coastguard Worker       EVP_MD_CTX_destroy(ctx);
128*4a64e381SAndroid Build Coastguard Worker 
129*4a64e381SAndroid Build Coastguard Worker       return md;
130*4a64e381SAndroid Build Coastguard Worker     }
131*4a64e381SAndroid Build Coastguard Worker 
132*4a64e381SAndroid Build Coastguard Worker     /// Returns md5 hash value from input string.
md5(const std::string & input,std::size_t iterations=1)133*4a64e381SAndroid Build Coastguard Worker     static std::string md5(const std::string &input, std::size_t iterations = 1) noexcept {
134*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_md5();
135*4a64e381SAndroid Build Coastguard Worker       auto hash = message_digest(input, evp_md, MD5_DIGEST_LENGTH);
136*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
137*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, MD5_DIGEST_LENGTH);
138*4a64e381SAndroid Build Coastguard Worker       return hash;
139*4a64e381SAndroid Build Coastguard Worker     }
140*4a64e381SAndroid Build Coastguard Worker 
141*4a64e381SAndroid Build Coastguard Worker     /// Returns md5 hash value from input stream.
md5(std::istream & stream,std::size_t iterations=1)142*4a64e381SAndroid Build Coastguard Worker     static std::string md5(std::istream &stream, std::size_t iterations = 1) noexcept {
143*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_md5();
144*4a64e381SAndroid Build Coastguard Worker       auto hash = stream_digest(stream, evp_md, MD5_DIGEST_LENGTH);
145*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
146*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, MD5_DIGEST_LENGTH);
147*4a64e381SAndroid Build Coastguard Worker       return hash;
148*4a64e381SAndroid Build Coastguard Worker     }
149*4a64e381SAndroid Build Coastguard Worker 
150*4a64e381SAndroid Build Coastguard Worker     /// Returns sha1 hash value from input string.
sha1(const std::string & input,std::size_t iterations=1)151*4a64e381SAndroid Build Coastguard Worker     static std::string sha1(const std::string &input, std::size_t iterations = 1) noexcept {
152*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_sha1();
153*4a64e381SAndroid Build Coastguard Worker       auto hash = message_digest(input, evp_md, SHA_DIGEST_LENGTH);
154*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
155*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, SHA_DIGEST_LENGTH);
156*4a64e381SAndroid Build Coastguard Worker       return hash;
157*4a64e381SAndroid Build Coastguard Worker     }
158*4a64e381SAndroid Build Coastguard Worker 
159*4a64e381SAndroid Build Coastguard Worker     /// Returns sha1 hash value from input stream.
sha1(std::istream & stream,std::size_t iterations=1)160*4a64e381SAndroid Build Coastguard Worker     static std::string sha1(std::istream &stream, std::size_t iterations = 1) noexcept {
161*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_sha1();
162*4a64e381SAndroid Build Coastguard Worker       auto hash = stream_digest(stream, evp_md, SHA_DIGEST_LENGTH);
163*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
164*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, SHA_DIGEST_LENGTH);
165*4a64e381SAndroid Build Coastguard Worker       return hash;
166*4a64e381SAndroid Build Coastguard Worker     }
167*4a64e381SAndroid Build Coastguard Worker 
168*4a64e381SAndroid Build Coastguard Worker     /// Returns sha256 hash value from input string.
sha256(const std::string & input,std::size_t iterations=1)169*4a64e381SAndroid Build Coastguard Worker     static std::string sha256(const std::string &input, std::size_t iterations = 1) noexcept {
170*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_sha256();
171*4a64e381SAndroid Build Coastguard Worker       auto hash = message_digest(input, evp_md, SHA256_DIGEST_LENGTH);
172*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
173*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, SHA256_DIGEST_LENGTH);
174*4a64e381SAndroid Build Coastguard Worker       return hash;
175*4a64e381SAndroid Build Coastguard Worker     }
176*4a64e381SAndroid Build Coastguard Worker 
177*4a64e381SAndroid Build Coastguard Worker     /// Returns sha256 hash value from input stream.
sha256(std::istream & stream,std::size_t iterations=1)178*4a64e381SAndroid Build Coastguard Worker     static std::string sha256(std::istream &stream, std::size_t iterations = 1) noexcept {
179*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_sha256();
180*4a64e381SAndroid Build Coastguard Worker       auto hash = stream_digest(stream, evp_md, SHA256_DIGEST_LENGTH);
181*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
182*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, SHA256_DIGEST_LENGTH);
183*4a64e381SAndroid Build Coastguard Worker       return hash;
184*4a64e381SAndroid Build Coastguard Worker     }
185*4a64e381SAndroid Build Coastguard Worker 
186*4a64e381SAndroid Build Coastguard Worker     /// Returns sha512 hash value from input string.
sha512(const std::string & input,std::size_t iterations=1)187*4a64e381SAndroid Build Coastguard Worker     static std::string sha512(const std::string &input, std::size_t iterations = 1) noexcept {
188*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_sha512();
189*4a64e381SAndroid Build Coastguard Worker       auto hash = message_digest(input, evp_md, SHA512_DIGEST_LENGTH);
190*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
191*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, SHA512_DIGEST_LENGTH);
192*4a64e381SAndroid Build Coastguard Worker       return hash;
193*4a64e381SAndroid Build Coastguard Worker     }
194*4a64e381SAndroid Build Coastguard Worker 
195*4a64e381SAndroid Build Coastguard Worker     /// Returns sha512 hash value from input stream.
sha512(std::istream & stream,std::size_t iterations=1)196*4a64e381SAndroid Build Coastguard Worker     static std::string sha512(std::istream &stream, std::size_t iterations = 1) noexcept {
197*4a64e381SAndroid Build Coastguard Worker       auto evp_md = EVP_sha512();
198*4a64e381SAndroid Build Coastguard Worker       auto hash = stream_digest(stream, evp_md, SHA512_DIGEST_LENGTH);
199*4a64e381SAndroid Build Coastguard Worker       for(std::size_t i = 1; i < iterations; ++i)
200*4a64e381SAndroid Build Coastguard Worker         hash = message_digest(hash, evp_md, SHA512_DIGEST_LENGTH);
201*4a64e381SAndroid Build Coastguard Worker       return hash;
202*4a64e381SAndroid Build Coastguard Worker     }
203*4a64e381SAndroid Build Coastguard Worker 
204*4a64e381SAndroid Build Coastguard Worker     /**
205*4a64e381SAndroid Build Coastguard Worker      * Returns PBKDF2 derived key from the given password.
206*4a64e381SAndroid Build Coastguard Worker      *
207*4a64e381SAndroid Build Coastguard Worker      * @param password   The password to derive key from.
208*4a64e381SAndroid Build Coastguard Worker      * @param salt       The salt to be used in the algorithm.
209*4a64e381SAndroid Build Coastguard Worker      * @param iterations Number of iterations to be used in the algorithm.
210*4a64e381SAndroid Build Coastguard Worker      * @param key_size   Number of bytes of the returned key.
211*4a64e381SAndroid Build Coastguard Worker      *
212*4a64e381SAndroid Build Coastguard Worker      * @return The PBKDF2 derived key.
213*4a64e381SAndroid Build Coastguard Worker      */
pbkdf2(const std::string & password,const std::string & salt,int iterations,int key_size)214*4a64e381SAndroid Build Coastguard Worker     static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept {
215*4a64e381SAndroid Build Coastguard Worker       std::string key(static_cast<std::size_t>(key_size), '\0');
216*4a64e381SAndroid Build Coastguard Worker       PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
217*4a64e381SAndroid Build Coastguard Worker                              reinterpret_cast<const unsigned char *>(salt.c_str()), salt.size(), iterations,
218*4a64e381SAndroid Build Coastguard Worker                              key_size, reinterpret_cast<unsigned char *>(&key[0]));
219*4a64e381SAndroid Build Coastguard Worker       return key;
220*4a64e381SAndroid Build Coastguard Worker     }
221*4a64e381SAndroid Build Coastguard Worker   };
222*4a64e381SAndroid Build Coastguard Worker } // namespace SimpleWeb
223*4a64e381SAndroid Build Coastguard Worker #endif /* SIMPLE_WEB_CRYPTO_HPP */
224