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
41String DerivedKey::ToString ()
const
45 result <<
"key: "sv << fKey;
46 result <<
", IV: "sv << fIV;
57#if qStroika_HasComponent_OpenSSL
59 pair<BLOB, BLOB> mkWinCryptDeriveKey_ (
size_t keyLen, [[maybe_unused]] DigestAlgorithm digestAlgorithm,
const BLOB& passwd)
80 size_t usePWDLen = min (passwd.
length (),
static_cast<size_t> (64));
81 const byte* passwordBytes = passwd.
begin ();
84 std::fill_n (buf1, NEltsOf (buf1),
static_cast<byte> (0x36));
85 for (
unsigned long i = 0; i < usePWDLen; ++i) {
86 buf1[i] ^= passwordBytes[i];
91 std::fill_n (buf2, NEltsOf (buf2),
static_cast<byte> (0x5C));
92 for (
unsigned long i = 0; i < usePWDLen; ++i) {
93 buf2[i] ^= passwordBytes[i];
96 Require (digestAlgorithm == DigestAlgorithms::kMD5);
98 Digest::ComputeDigest<Digest::Algorithm::MD5> (begin (buf1), end (buf1)),
99 Digest::ComputeDigest<Digest::Algorithm::MD5> (begin (buf2), end (buf2))};
100 Assert (keyLen <=
sizeof (encodedResults));
101 const byte* encodedResultBytes =
reinterpret_cast<const byte*
> (begin (encodedResults));
102 BLOB resultKey{encodedResultBytes, encodedResultBytes + std::min (
sizeof (encodedResults), keyLen)};
104 return pair<BLOB, BLOB>{resultKey, iv};
106 size_t mkDefKeyLen_ (WinCryptDeriveKey::Provider provider, CipherAlgorithm cipherAlgorithm)
111 case WinCryptDeriveKey::Provider::Base: {
112 if (cipherAlgorithm == CipherAlgorithms::kRC2_CBC () or cipherAlgorithm == CipherAlgorithms::kRC2_CFB () or
113 cipherAlgorithm == CipherAlgorithms::kRC2_ECB () or cipherAlgorithm == CipherAlgorithms::kRC2_OFB () or
114 cipherAlgorithm == CipherAlgorithms::kRC4 ()) {
118 case CipherAlgorithm::eDES {
123 case WinCryptDeriveKey::Provider::Enhanced: {
124 if (cipherAlgorithm == CipherAlgorithms::kRC2_CBC () or cipherAlgorithm == CipherAlgorithms::kRC2_CFB () or
125 cipherAlgorithm == CipherAlgorithms::kRC2_ECB () or cipherAlgorithm == CipherAlgorithms::kRC2_OFB () or
126 cipherAlgorithm == CipherAlgorithms::kRC4 ()) {
135WinCryptDeriveKey::WinCryptDeriveKey (
size_t keyLen, DigestAlgorithm digestAlgorithm,
const BLOB& passwd)
136 : DerivedKey{mkWinCryptDeriveKey_ (keyLen, digestAlgorithm, passwd)}
140WinCryptDeriveKey::WinCryptDeriveKey (Provider provider, CipherAlgorithm cipherAlgorithm, DigestAlgorithm digestAlgorithm,
const BLOB& passwd)
141 : DerivedKey{WinCryptDeriveKey{mkDefKeyLen_ (provider, cipherAlgorithm), digestAlgorithm, passwd}}
146#if qStroika_HasComponent_OpenSSL
153 pair<BLOB, BLOB> mkEVP_BytesToKey_ (CipherAlgorithm cipherAlgorithm, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
154 unsigned int nRounds,
const optional<BLOB>& salt)
156 Require (nRounds >= 1);
159 if (salt and salt->GetSize () != 8) [[unlikely]] {
163 int i = ::EVP_BytesToKey (cipherAlgorithm, digestAlgorithm,
164 reinterpret_cast<const unsigned char*
> (salt ? NullCoalesce (salt).begin () : nullptr),
165 reinterpret_cast<const unsigned char*> (passwd.begin ()), static_cast<int> (passwd.size ()), nRounds,
166 reinterpret_cast<unsigned char*> (useKey.begin ()), reinterpret_cast<unsigned char*> (useIV.begin ()));
169 Cryptography::Providers::OpenSSL::Exception::ThrowLastError ();
171 Assert (i ==
static_cast<int> (cipherAlgorithm.KeyLength ()));
172 return pair<BLOB, BLOB>{
BLOB{useKey.
begin (), useKey.end ()},
BLOB{useIV.
begin (), useIV.end ()}};
176EVP_BytesToKey::EVP_BytesToKey (CipherAlgorithm cipherAlgorithm, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
unsigned int nRounds,
177 const optional<BLOB>& salt)
178 : DerivedKey{mkEVP_BytesToKey_ (cipherAlgorithm, digestAlgorithm, passwd, nRounds, salt)}
188 pair<BLOB, BLOB> mkPKCS5_PBKDF2_HMAC_ (
size_t keyLen,
size_t ivLen, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
189 unsigned int nRounds,
const optional<BLOB>& salt)
192 Assert (keyLen + ivLen <
size_t (numeric_limits<int>::max ()));
193 int a = ::PKCS5_PBKDF2_HMAC (
reinterpret_cast<const char*
> (passwd.
begin ()),
static_cast<int> (passwd.
length ()),
194 reinterpret_cast<const unsigned char*
> (salt ? salt->begin () : nullptr),
195 static_cast<int> (salt ? salt->size () : 0), nRounds, digestAlgorithm,
196 static_cast<int> (keyLen + ivLen), reinterpret_cast<unsigned char*> (outBuf.begin ()));
197 if (a == 0) [[unlikely]] {
200 const byte* p = outBuf.begin ();
201 return pair<BLOB, BLOB> (
BLOB{p, p + keyLen},
BLOB{p + keyLen, p + keyLen + ivLen});
205PKCS5_PBKDF2_HMAC::PKCS5_PBKDF2_HMAC (
size_t keyLen,
size_t ivLen, DigestAlgorithm digestAlgorithm,
const BLOB& passwd,
206 unsigned int nRounds,
const optional<BLOB>& salt)
207 : 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...