| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| #pragma once |
| |
| #include <openssl/aes.h> |
| #include <openssl/bio.h> |
| #include <openssl/evp.h> |
| #include <openssl/sha.h> |
| #include <openssl/crypto.h> |
| #include <openssl/md5.h> |
| #include <openssl/hmac.h> |
| |
| #include "tsutil/StringConvert.h" |
| #include "ts/ts.h" |
| #include "ts/remap.h" |
| |
| #include "cripts/Lulu.hpp" |
| |
| namespace cripts::Crypto |
| { |
| class Base64 |
| { |
| using self_type = Base64; |
| |
| public: |
| Base64() = delete; |
| Base64(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| static cripts::string Encode(cripts::string_view str); |
| static cripts::string Decode(cripts::string_view str); |
| |
| }; // End class Crypto::Base64 |
| |
| class Escape |
| { |
| using self_type = Escape; |
| |
| public: |
| Escape() = delete; |
| Escape(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| static cripts::string Encode(cripts::string_view str); |
| static cripts::string Decode(cripts::string_view str); |
| |
| }; // End class Crypto::Escape |
| |
| // These are various (real) crypto functions, all using the Crypto::Base class |
| namespace detail |
| { |
| class Digest |
| { |
| using self_type = Digest; |
| |
| public: |
| Digest() = delete; |
| void operator=(const self_type &) = delete; |
| Digest(self_type &&that) = default; // For later use |
| |
| Digest(size_t len) : _length(len) { TSAssert(len <= EVP_MAX_MD_SIZE); } |
| |
| [[nodiscard]] cripts::string |
| Hex() const |
| { |
| return ts::hex({reinterpret_cast<const char *>(_hash), _length}); |
| } |
| |
| operator cripts::string() const { return Hex(); } |
| |
| [[nodiscard]] cripts::string |
| String() const |
| { |
| return {reinterpret_cast<const char *>(_hash), _length}; |
| } |
| |
| [[nodiscard]] cripts::string |
| Base64() const |
| { |
| return Crypto::Base64::Encode(cripts::string_view(reinterpret_cast<const char *>(_hash), _length)); |
| } |
| |
| [[nodiscard]] const unsigned char * |
| Hash() const |
| { |
| return _hash; |
| } |
| |
| protected: |
| // Size for the bigest digest |
| unsigned char _hash[EVP_MAX_MD_SIZE] = {}; |
| size_t _length = EVP_MAX_MD_SIZE; |
| |
| }; // End class Crypto::Digest; |
| |
| class Cipher |
| { |
| using self_type = Cipher; |
| |
| public: |
| Cipher() = delete; |
| void operator=(const self_type &) = delete; |
| |
| ~Cipher() { EVP_CIPHER_CTX_free(_ctx); } |
| |
| virtual void Encrypt(cripts::string_view str); |
| virtual cripts::string_view Finalize(); |
| |
| operator cripts::string_view() const { return {_message}; } |
| |
| [[nodiscard]] cripts::string |
| Message() const |
| { |
| return _message; |
| } |
| |
| [[nodiscard]] cripts::string |
| Base64() const |
| { |
| return Crypto::Base64::Encode(_message); |
| } |
| |
| [[nodiscard]] cripts::string |
| Hex() const |
| { |
| return ts::hex(_message); |
| } |
| |
| operator cripts::string() const { return Hex(); } |
| |
| protected: |
| Cipher(const unsigned char *key, int len) : _key_len(len) { memcpy(_key, key, len); } |
| virtual void _initialize(); |
| |
| cripts::string _message; |
| unsigned char _key[EVP_MAX_KEY_LENGTH]; |
| int _key_len = 0; |
| int _length = 0; |
| EVP_CIPHER_CTX *_ctx = nullptr; |
| const EVP_CIPHER *_cipher = nullptr; |
| |
| }; // End class Cipher |
| |
| } // namespace detail |
| |
| class SHA256 : public detail::Digest |
| { |
| using super_type = detail::Digest; |
| using self_type = SHA256; |
| |
| SHA256(SHA256 &&that) = default; |
| |
| public: |
| SHA256() : detail::Digest(SHA256_DIGEST_LENGTH){}; |
| |
| SHA256(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| static self_type Encode(cripts::string_view str); |
| }; // End class SHA256 |
| |
| class SHA512 : public detail::Digest |
| { |
| using super_type = detail::Digest; |
| using self_type = SHA512; |
| |
| SHA512(SHA512 &&that) = default; |
| |
| public: |
| SHA512() : detail::Digest(SHA512_DIGEST_LENGTH){}; |
| |
| SHA512(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| static self_type Encode(cripts::string_view str); |
| }; // End class SHA512 |
| |
| class MD5 : public detail::Digest |
| { |
| using self_type = MD5; |
| using super_type = detail::Digest; |
| |
| MD5(MD5 &&that) = default; |
| |
| public: |
| MD5() : detail::Digest(MD5_DIGEST_LENGTH){}; |
| |
| MD5(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| static self_type Encode(cripts::string_view str); |
| }; // End class MD5 |
| |
| class AES256 : public detail::Cipher |
| { |
| using super_type = detail::Cipher; |
| using self_type = AES256; |
| |
| AES256(AES256 &&that) noexcept = default; |
| |
| public: |
| using super_type::Cipher; |
| using super_type::Encrypt; |
| |
| AES256(const SHA256 &key) : super_type(key.Hash(), SHA256_DIGEST_LENGTH) {} |
| AES256(const unsigned char *key) : super_type(key, SHA256_DIGEST_LENGTH) {} |
| |
| AES256(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| // The key has to be 256-bit afaik |
| static self_type Encrypt(cripts::string_view str, const unsigned char *key); |
| |
| static self_type |
| Encrypt(cripts::string_view str, SHA256 &key) |
| { |
| return Encrypt(str, key.Hash()); |
| } |
| |
| private: |
| // The initialization has to be deferred, since it's virtual, after the ctor. |
| void |
| _initialize() override |
| { |
| _cipher = EVP_aes_256_cbc(); |
| super_type::_initialize(); |
| } |
| }; // End class AES256 |
| |
| namespace HMAC |
| { |
| class SHA256 : public detail::Digest |
| { |
| using super_type = detail::Digest; |
| using self_type = SHA256; |
| |
| SHA256(SHA256 &&that) = default; |
| |
| public: |
| SHA256() : detail::Digest(SHA256_DIGEST_LENGTH){}; |
| |
| SHA256(const self_type &) = delete; |
| void operator=(const self_type &) = delete; |
| |
| static self_type Encrypt(cripts::string_view str, const cripts::string &key); |
| }; // End class SHA256 |
| } // namespace HMAC |
| |
| } // namespace cripts::Crypto |
| |
| // Formatters for {fmt} |
| namespace fmt |
| { |
| template <> struct formatter<cripts::Crypto::SHA256> { |
| constexpr auto |
| parse(format_parse_context &ctx) -> decltype(ctx.begin()) |
| { |
| return ctx.begin(); |
| } |
| |
| template <typename FormatContext> |
| auto |
| format(cripts::Crypto::SHA256 &sha, FormatContext &ctx) const -> decltype(ctx.out()) |
| { |
| return fmt::format_to(ctx.out(), "{}", sha.Hex()); |
| } |
| }; |
| |
| template <> struct formatter<cripts::Crypto::SHA512> { |
| constexpr auto |
| parse(format_parse_context &ctx) -> decltype(ctx.begin()) |
| { |
| return ctx.begin(); |
| } |
| |
| template <typename FormatContext> |
| auto |
| format(cripts::Crypto::SHA512 &sha, FormatContext &ctx) const -> decltype(ctx.out()) |
| { |
| return fmt::format_to(ctx.out(), "{}", sha.Hex()); |
| } |
| }; |
| |
| template <> struct formatter<cripts::Crypto::AES256> { |
| constexpr auto |
| parse(format_parse_context &ctx) -> decltype(ctx.begin()) |
| { |
| return ctx.begin(); |
| } |
| |
| template <typename FormatContext> |
| auto |
| format(cripts::Crypto::AES256 &sha, FormatContext &ctx) const -> decltype(ctx.out()) |
| { |
| return fmt::format_to(ctx.out(), "{}", cripts::Crypto::Base64::Encode(sha.Message())); |
| } |
| }; |
| |
| } // namespace fmt |