4#include "Stroika/Foundation/StroikaPreComp.h"
6#if qStroika_HasComponent_OpenSSL
7#include <openssl/evp.h>
12#include "Stroika/Foundation/Containers/Common.h"
14#include "Stroika/Foundation/Cryptography/Digest/Digester.h"
15#include "Stroika/Foundation/Cryptography/Digest/Hash.h"
17#include "Stroika/Foundation/Execution/Common.h"
28using namespace Stroika::Foundation::Cryptography;
29using namespace Stroika::Foundation::Cryptography::Providers::OpenSSL;
30using namespace Stroika::Foundation::Memory;
35#if qStroika_HasComponent_OpenSSL && defined(_MSC_VER)
37#if OPENSSL_VERSION_NUMBER < 0x1010000fL
38#pragma comment(lib, "libeay32.lib")
39#pragma comment(lib, "ssleay32.lib")
41#pragma comment(lib, "libcrypto.lib")
42#pragma comment(lib, "libssl.lib")
43#pragma comment(lib, "ws2_32.lib")
44#pragma comment(lib, "crypt32.lib")
48#if qStroika_HasComponent_OpenSSL
54String DerivedKey::ToString ()
const
58 result <<
"key: "sv << fKey;
59 result <<
", IV: "sv << fIV;
70#if qStroika_HasComponent_OpenSSL
72 pair<BLOB, BLOB> mkWinCryptDeriveKey_ (
size_t keyLen, [[maybe_unused]] DigestAlgorithm digestAlgorithm,
const BLOB& passwd)
93 size_t usePWDLen = min (passwd.
length (),
static_cast<size_t> (64));
94 const byte* passwordBytes = passwd.
begin ();
97 std::fill_n (buf1, NEltsOf (buf1),
static_cast<byte> (0x36));
98 for (
unsigned long i = 0; i < usePWDLen; ++i) {
99 buf1[i] ^= passwordBytes[i];
104 std::fill_n (buf2, NEltsOf (buf2),
static_cast<byte> (0x5C));
105 for (
unsigned long i = 0; i < usePWDLen; ++i) {
106 buf2[i] ^= passwordBytes[i];
109 Require (digestAlgorithm == DigestAlgorithms::kMD5);
111 Digest::ComputeDigest<Digest::Algorithm::MD5> (begin (buf1), end (buf1)),
112 Digest::ComputeDigest<Digest::Algorithm::MD5> (begin (buf2), end (buf2))};
113 Assert (keyLen <=
sizeof (encodedResults));
114 const byte* encodedResultBytes =
reinterpret_cast<const byte*
> (begin (encodedResults));
115 BLOB resultKey{encodedResultBytes, encodedResultBytes + std::min (
sizeof (encodedResults), keyLen)};
117 return pair<BLOB, BLOB>{resultKey, iv};
119 size_t mkDefKeyLen_ (WinCryptDeriveKey::Provider provider, CipherAlgorithm cipherAlgorithm)
124 case WinCryptDeriveKey::Provider::Base: {
125 if (cipherAlgorithm == CipherAlgorithms::kRC2_CBC () or cipherAlgorithm == CipherAlgorithms::kRC2_CFB () or
126 cipherAlgorithm == CipherAlgorithms::kRC2_ECB () or cipherAlgorithm == CipherAlgorithms::kRC2_OFB () or
127 cipherAlgorithm == CipherAlgorithms::kRC4 ()) {
131 case CipherAlgorithm::eDES {
136 case WinCryptDeriveKey::Provider::Enhanced: {
137 if (cipherAlgorithm == CipherAlgorithms::kRC2_CBC () or cipherAlgorithm == CipherAlgorithms::kRC2_CFB () or
138 cipherAlgorithm == CipherAlgorithms::kRC2_ECB () or cipherAlgorithm == CipherAlgorithms::kRC2_OFB () or
139 cipherAlgorithm == CipherAlgorithms::kRC4 ()) {
148WinCryptDeriveKey::WinCryptDeriveKey (
size_t keyLen, DigestAlgorithm digestAlgorithm,
const BLOB& passwd)
149 : DerivedKey{mkWinCryptDeriveKey_ (keyLen, digestAlgorithm, passwd)}
153WinCryptDeriveKey::WinCryptDeriveKey (Provider provider, CipherAlgorithm cipherAlgorithm, DigestAlgorithm digestAlgorithm,
const BLOB& passwd)
154 : DerivedKey{WinCryptDeriveKey{mkDefKeyLen_ (provider, cipherAlgorithm), digestAlgorithm, passwd}}
159#if qStroika_HasComponent_OpenSSL
166 pair<BLOB, BLOB> mkEVP_BytesToKey_ (CipherAlgorithm cipherAlgorithm, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
167 unsigned int nRounds,
const optional<BLOB>& salt)
169 Require (nRounds >= 1);
172 if (salt and salt->GetSize () != 8) [[unlikely]] {
176 int i = ::EVP_BytesToKey (cipherAlgorithm, digestAlgorithm,
177 reinterpret_cast<const unsigned char*
> (salt ? NullCoalesce (salt).begin () : nullptr),
178 reinterpret_cast<const unsigned char*> (passwd.begin ()), static_cast<int> (passwd.size ()), nRounds,
179 reinterpret_cast<unsigned char*> (useKey.begin ()), reinterpret_cast<unsigned char*> (useIV.begin ()));
182 Cryptography::Providers::OpenSSL::Exception::ThrowLastError ();
184 Assert (i ==
static_cast<int> (cipherAlgorithm.KeyLength ()));
185 return pair<BLOB, BLOB>{
BLOB{useKey.
begin (), useKey.end ()},
BLOB{useIV.
begin (), useIV.end ()}};
189EVP_BytesToKey::EVP_BytesToKey (CipherAlgorithm cipherAlgorithm, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
unsigned int nRounds,
190 const optional<BLOB>& salt)
191 : DerivedKey{mkEVP_BytesToKey_ (cipherAlgorithm, digestAlgorithm, passwd, nRounds, salt)}
201 pair<BLOB, BLOB> mkPKCS5_PBKDF2_HMAC_ (
size_t keyLen,
size_t ivLen, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
202 unsigned int nRounds,
const optional<BLOB>& salt)
205 Assert (keyLen + ivLen <
size_t (numeric_limits<int>::max ()));
206 int a = ::PKCS5_PBKDF2_HMAC (
reinterpret_cast<const char*
> (passwd.
begin ()),
static_cast<int> (passwd.
length ()),
207 reinterpret_cast<const unsigned char*
> (salt ? salt->begin () : nullptr),
208 static_cast<int> (salt ? salt->size () : 0), nRounds, digestAlgorithm,
209 static_cast<int> (keyLen + ivLen), reinterpret_cast<unsigned char*> (outBuf.begin ()));
210 if (a == 0) [[unlikely]] {
213 const byte* p = outBuf.begin ();
214 return pair<BLOB, BLOB> (
BLOB{p, p + keyLen},
BLOB{p + keyLen, p + keyLen + ivLen});
218PKCS5_PBKDF2_HMAC::PKCS5_PBKDF2_HMAC (
size_t keyLen,
size_t ivLen, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
219 unsigned int nRounds,
const optional<BLOB>& salt)
220 : DerivedKey{mkPKCS5_PBKDF2_HMAC_ (keyLen, ivLen, digestAlgorithm, passwd, nRounds, salt)}
#define AssertNotImplemented()
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
DigesterAlgorithm is specialized for each algorithm; generally don't use this directly,...
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
nonvirtual size_t length() const
nonvirtual const byte * begin() const
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...