4#include <openssl/pem.h>
68 std::vector<unsigned char> array;
81 string(
const size_t& l = 0) {
for (
size_t x = 0; x < l; ++x) array.emplace_back(0);}
89 for (
size_t x = 0; x <
string.length(); ++x) array.emplace_back(
unsigned(
string[x]));
100 string(
const unsigned char*
string,
const size_t& l) {
101 for (
size_t x = 0; x < l; ++x) array.emplace_back(
string[x]);
114 for (
size_t x = 0; x < strlen(
string); ++x) array.emplace_back(
string[x]);
160 string substr(
const size_t& start,
const size_t& count = std::string::npos)
const {
171 string ret = count == std::string::npos ? array.size() - start : count;
172 for (
size_t x = 0; x < count && x + start < array.size(); ++x) {
173 ret.
bytes()[x] = array[x + start];
184 void resize(
const size_t& n,
const unsigned char& v=0) {array.resize(n, v);}
192 for (
const auto& x : s.array) array.emplace_back(x);
201 std::stringstream out;
202 for (
const auto&
byte : array) out << std::hex << int(
byte);
211 const size_t length()
const {
return array.size();}
220 unsigned char*
bytes() {
return &array[0];}
237 const unsigned char*
bytes()
const {
return &array[0];}
244 std::string
to()
const {
return std::string(
reinterpret_cast<const char*
>(
bytes()), array.size());}
254 if (pos >= array.size())
255 throw std::out_of_range(
"Index into crypto::string out of range!");
265 const bool operator == (
const string& cmp)
const {
return array == cmp.array;}
293 keypair(
const string& private_key,
const string& public_key) : P(private_key), p(public_key) {}
296 string& priv() {
return P;}
297 const string& priv()
const {
return P;}
300 string& pub() {
return p;}
301 const string& pub()
const {
return p;}
304 string& first() {
return P;}
305 const string& first()
const {
return P;}
308 string& second() {
return p;}
309 const string& second()
const {
return p;}
342 string DH(
const string& priv,
const string& pub) {
344 if (crypto_scalarmult(product.
bytes(), priv.
bytes(), pub.
bytes()) != 0)
345 throw std::runtime_error(
"Failed to multiply keys!");
391 string pub = 32, priv = 32;
394 randombytes_buf(priv.bytes(), priv.length());
395 crypto_scalarmult_base(pub.
bytes(), priv.bytes());
415 string IV(uint64_t counter) {
421 for (
size_t x = 0; x < 8; ++x) {
422 iv[4 + x] = counter >> 56;
450 string ENCRYPT(
string key,
const uint64_t& counter,
const string& plain,
const string& data) {
452 key.
resize(crypto_aead_chacha20poly1305_ietf_KEYBYTES);
455 string cipher = plain.
length() + crypto_aead_chacha20poly1305_ietf_ABYTES;
456 long long unsigned int length = cipher.
length();
459 string nonce =
IV(counter);
462 crypto_aead_chacha20poly1305_ietf_encrypt(
463 cipher.
bytes(), &length,
486 string DECRYPT(
string key,
const uint64_t& counter,
const string& cipher,
const string& data) {
487 key.
resize(crypto_aead_chacha20poly1305_ietf_KEYBYTES);
490 string plain = cipher.
length() - crypto_aead_chacha20poly1305_ietf_ABYTES;
491 long long unsigned int length = plain.
length();
493 auto nonce =
IV(counter);
495 if (crypto_aead_chacha20poly1305_ietf_decrypt(
496 plain.
bytes(), &length,
500 nonce.bytes(), key.
bytes()) != 0) {
501 throw std::runtime_error(
"Modified message! Refusing to decrypt!");
524 key.
resize(crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
527 string cipher = plain.
length() + crypto_aead_xchacha20poly1305_ietf_ABYTES;
528 long long unsigned int length = cipher.
length();
531 string nonce = crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
535 crypto_aead_xchacha20poly1305_ietf_encrypt(
536 cipher.
bytes(), &length,
545 return {cipher, nonce};
558 key.
resize(crypto_aead_xchacha20poly1305_ietf_KEYBYTES);
560 const auto& cipher = pair.first();
561 const auto& nonce = pair.second();
564 string plain = cipher.length() - crypto_aead_xchacha20poly1305_ietf_ABYTES;
565 long long unsigned int length = plain.
length();
567 if (crypto_aead_xchacha20poly1305_ietf_decrypt(
568 plain.
bytes(), &length,
570 cipher.bytes(), cipher.length(),
572 nonce.bytes(), key.
bytes()) != 0) {
573 throw std::runtime_error(
"Modified message! Refusing to decrypt!");
605 string HASH(
const string& in) {
608 EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
609 if (mdctx ==
nullptr) {
610 throw std::runtime_error(
"Failed to initialize context!");
615 auto DIGEST = [&in, &hash, &mdctx]() {
618 if (EVP_DigestInit_ex(mdctx, EVP_blake2s256(),
nullptr) != 1)
return -1;
621 if (EVP_DigestUpdate(mdctx, in.bytes(), in.length()) != 1)
return -2;
624 unsigned int length = 32;
625 if (EVP_DigestFinal_ex(mdctx, hash.
bytes(), &length) != 1)
return -3;
626 if (length != 32)
return -3;
632 auto result = DIGEST();
633 EVP_MD_CTX_free(mdctx);
637 std::string reason =
"BLAKE2s256: Failed to Hash: ";
639 case -1: reason +=
"Failed to initiailze!";
break;
640 case -2: reason +=
"Failed to digest!";
break;
641 case -3: reason +=
"Failed to extract hash!";
break;
642 default: reason +=
"Unknown reason!";
break;
644 throw std::runtime_error(reason);
675 string HMAC(
const string& key,
const string& input,
const size_t& size=32) {
676 if (size > 32 || size == 0)
677 throw std::out_of_range(
"HMAC can only output sizes from 1-32 inclusive!");
680 EVP_MAC *mac = EVP_MAC_fetch(
nullptr,
"BLAKE2SMAC",
nullptr);
681 if (mac ==
nullptr) {
682 throw std::runtime_error(
"Failed to fetch MAC!");
686 EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);
687 if (ctx ==
nullptr) {
689 throw std::runtime_error(
"Failed to initialize context!");
694 auto GENERATE = [&key, &input, &hmac, &ctx, &size]() {
695 if (EVP_MAC_init(ctx, key.
bytes(), key.
length(),
nullptr) != 1)
return -1;
697 if (EVP_MAC_update(ctx, input.bytes(), input.length()) != 1)
return -2;
699 size_t length = hmac.
length();
700 if (EVP_MAC_final(ctx, hmac.
bytes(), &length, hmac.
length()) != 1)
return -3;
701 if (length != hmac.
length())
return -3;
706 auto result = GENERATE();
707 EVP_MAC_CTX_free(ctx);
712 std::string reason =
"BLAKE2s256-HMAC: Failed to Hash: ";
714 case -1: reason +=
"Failed to initiailze!";
break;
715 case -2: reason +=
"Failed to digest input!";
break;
716 case -3: reason +=
"Failed to extract hmac!";
break;
717 default: reason +=
"Unknown reason!";
break;
719 throw std::runtime_error(reason);
723 return hmac.
substr(0, size);
743 string MAC(
const string& key,
const string& input) {
return HMAC(key, input, 16);}
767 std::vector<string>
KDF(
const size_t& n,
const string& key,
const string& input) {
768 std::vector<string> ret;
771 string g0 =
HMAC(key, input);
772 ret.emplace_back(g0);
773 if (n == 1)
return ret;
776 ret.emplace_back(
HMAC(g0, 0x1));
779 while (ret.size() != n) {
782 auto last = ret.back();
783 auto size = ret.size();
784 last.append({
reinterpret_cast<const unsigned char*
>(&size),
sizeof(size)});
787 ret.emplace_back(
HMAC(g0, last));
A simple private-public keypair.
Definition crypto.h:284
A cryptographically secure string.
Definition crypto.h:63
~string()
Destroy the string.
Definition crypto.h:150
const unsigned char * bytes() const
Return a immutable byte array of the internal values.
Definition crypto.h:237
std::string to() const
Return a std::string representation of the string.
Definition crypto.h:244
string substr(const size_t &start, const size_t &count=std::string::npos) const
Return a subset of the string.
Definition crypto.h:160
void append(const string &s)
Append another string to end of the caller.
Definition crypto.h:191
string(const char *string)
Construct a string from a character array.
Definition crypto.h:113
string(const std::string &string)
Construct a string from a std::string.
Definition crypto.h:88
std::string str()
Return a hexadecimal representation of the crypto::string.
Definition crypto.h:200
void resize(const size_t &n, const unsigned char &v=0)
Resize the string.
Definition crypto.h:184
unsigned char * bytes()
Return a mutable byte array that can be directly manipulated.
Definition crypto.h:220
unsigned char & operator[](const size_t &pos)
Index the string.
Definition crypto.h:253
string(const unsigned char *string, const size_t &l)
Construct a string from a character array and size.
Definition crypto.h:100
string operator+(const string &a) const
Concatonation operator.
Definition crypto.h:273
const bool operator==(const string &cmp) const
Equivalence operator.
Definition crypto.h:265
const size_t length() const
Return the length of the string.
Definition crypto.h:211
string(const size_t &l=0)
Construct a string with a fixed, zeroed size.
Definition crypto.h:81
The cryptographic implementations for WireGuard.
Definition crypto.h:42
string XDECRYPT(string key, const keypair &pair, const string &data)
Decrypt with XChaCha20-Poly1305.
Definition crypto.h:557
std::vector< string > KDF(const size_t &n, const string &key, const string &input)
Perform the HKDF scheme on our HMAC function.
Definition crypto.h:767
string DH(const string &priv, const string &pub)
Definition crypto.h:342
string HMAC(const string &key, const string &input, const size_t &size=32)
Compute an HMAC using BLAKE and a key.
Definition crypto.h:675
keypair DH_GENERATE()
Generate a Curve25519 keypair.
Definition crypto.h:388
string ENCRYPT(string key, const uint64_t &counter, const string &plain, const string &data)
Encrypt with ChaCha20-Poly1305.
Definition crypto.h:450
string HASH(const string &in)
Generate a BLAKE2s256 Hash of the input.
Definition crypto.h:605
keypair XENCRYPT(string key, const string &plain, const string &data)
Encrypt with XChaCha20-Poly1305.
Definition crypto.h:521
string DECRYPT(string key, const uint64_t &counter, const string &cipher, const string &data)
Decrypt with ChaCha20-Poly1305.
Definition crypto.h:486
string IV(uint64_t counter)
Format the IV array given the WireGuard Counter.
Definition crypto.h:415
string MAC(const string &key, const string &input)
OpenSSL makes no difference between HMAC-BLAKE2s256 and Keyed BLAKE2s256 Besides setting the size....
Definition crypto.h:743