blob: d4e4de29779a400c751dd508b62bc8ba9d82b1ff [file] [log] [blame]
/*
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