256 lines
6.5 KiB
C++
256 lines
6.5 KiB
C++
// Crypto.cpp : Implementation of CCrypto
|
|
|
|
#include "stdafx.h"
|
|
#include "Crypto.h"
|
|
|
|
|
|
// CCrypto
|
|
|
|
#include "hmac_sha1.h"
|
|
|
|
#include <math.h>
|
|
|
|
// Base64_encode from http://www.adp-gmbh.ch/cpp/common/base64.html
|
|
static const char *base64_chars =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"0123456789+/";
|
|
|
|
static inline bool is_base64(unsigned char c) {
|
|
return (isalnum(c) || (c == '+') || (c == '/'));
|
|
}
|
|
|
|
CString base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len, BOOL padding) {
|
|
CString ret;
|
|
int i = 0;
|
|
int j = 0;
|
|
unsigned char char_array_3[3];
|
|
unsigned char char_array_4[4];
|
|
|
|
while (in_len--) {
|
|
char_array_3[i++] = *(bytes_to_encode++);
|
|
if (i == 3) {
|
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
|
|
|
for(i = 0; (i <4) ; i++)
|
|
ret += base64_chars[char_array_4[i]];
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
if (i)
|
|
{
|
|
for(j = i; j < 3; j++)
|
|
char_array_3[j] = '\0';
|
|
|
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
|
|
|
for (j = 0; (j < i + 1); j++)
|
|
ret += base64_chars[char_array_4[j]];
|
|
|
|
while(padding && (i++ < 3))
|
|
ret += '=';
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
STDMETHODIMP CCrypto::b64_hmac_sha1(BSTR key, BSTR data, BSTR* pVal)
|
|
{
|
|
BYTE digest[20];
|
|
CString akey(key);
|
|
CString adata(data);
|
|
|
|
CHMAC_SHA1 HMAC_SHA1 ;
|
|
HMAC_SHA1.HMAC_SHA1((BYTE *)adata.GetBuffer(), adata.GetLength(), (BYTE *)akey.GetBuffer(), akey.GetLength(), digest) ;
|
|
CString res = base64_encode(digest, 20, false); // no padding
|
|
|
|
CComBSTR bstrString(res);
|
|
return bstrString.CopyTo(pVal);
|
|
}
|
|
|
|
const char *hex_tab = "0123456789abcdef";
|
|
STDMETHODIMP CCrypto::hex_hmac_sha1(BSTR key, BSTR data, BSTR* pVal)
|
|
{
|
|
BYTE digest[20];
|
|
CString akey(key);
|
|
CString adata(data);
|
|
|
|
CHMAC_SHA1 HMAC_SHA1 ;
|
|
HMAC_SHA1.HMAC_SHA1((BYTE *)adata.GetBuffer(), adata.GetLength(), (BYTE *)akey.GetBuffer(), akey.GetLength(), digest) ;
|
|
CString res;
|
|
|
|
for(int i = 0; i < 20; i++)
|
|
{
|
|
res = res + hex_tab[digest[i] >> 4];
|
|
res = res + hex_tab[digest[i] & 0xF];
|
|
}
|
|
|
|
CComBSTR bstrString(res);
|
|
return bstrString.CopyTo(pVal);
|
|
}
|
|
|
|
STDMETHODIMP CCrypto::hex_sha1(BSTR data, BSTR* pVal)
|
|
{
|
|
CSHA1 sha1;
|
|
|
|
CString adata(data);
|
|
sha1.Update((UINT_8*)adata.GetBuffer(), adata.GetLength());
|
|
sha1.Final();
|
|
|
|
TCHAR res[41];
|
|
sha1.ReportHash(res, CSHA1::REPORT_HEX_SHORT); // Get final hash as pre-formatted string
|
|
|
|
CComBSTR bstrString(res);
|
|
bstrString.ToLower();
|
|
|
|
return bstrString.CopyTo(pVal);
|
|
}
|
|
|
|
// Big Endian
|
|
static inline void be32enc(void *pp, uint32_t x)
|
|
{
|
|
uint8_t * p = (uint8_t *)pp;
|
|
p[3] = x & 0xff;
|
|
p[2] = (x >> 8) & 0xff;
|
|
p[1] = (x >> 16) & 0xff;
|
|
p[0] = (x >> 24) & 0xff;
|
|
}
|
|
|
|
/* F(P, S, c, i) = U1 xor U2 xor ... Uc
|
|
* U1 = PRF(P, S || i)
|
|
* U2 = PRF(P, U1)
|
|
* Uc = PRF(P, Uc-1)
|
|
*/
|
|
#define SHA1_MAC_LEN 20
|
|
STDMETHODIMP CCrypto::hex_pbkdf2(BSTR pPassword, BSTR pSalt, ULONG pCount, ULONG pLength, BSTR* pVal)
|
|
{
|
|
CString apass(pPassword);
|
|
CString asalt(pSalt);
|
|
int saltlen = asalt.GetLength();
|
|
BYTE *saltbuff = (BYTE *)asalt.GetBufferSetLength(saltlen + 4); // Ruimte maken voor counter
|
|
int passlen = apass.GetLength();
|
|
BYTE *passbuff = (BYTE *)apass.GetBuffer();
|
|
|
|
size_t i;
|
|
uint8_t U[SHA1_MAC_LEN];
|
|
uint8_t T[SHA1_MAC_LEN]; // Hierin komt het XOR resultaat
|
|
|
|
CString res;
|
|
|
|
/* Iterate through the blocks. */
|
|
for (i = 0; i * SHA1_MAC_LEN < pLength; i++)
|
|
{
|
|
/* Generate INT(i + 1). */
|
|
be32enc(saltbuff + saltlen, i + 1);
|
|
|
|
/* Compute U_1 = PRF(P, S || INT(i)). */
|
|
CHMAC_SHA1 HMAC_SHA1;
|
|
HMAC_SHA1.HMAC_SHA1(saltbuff, saltlen + 4, passbuff, passlen, U);
|
|
|
|
/* T_1 = U_1 ... */
|
|
memcpy(T, U, SHA1_MAC_LEN);
|
|
|
|
for (uint64_t j = 2; j <= pCount; j++)
|
|
{
|
|
/* Compute U_j. */
|
|
HMAC_SHA1.HMAC_SHA1(U, SHA1_MAC_LEN, passbuff, passlen, U);
|
|
|
|
/* ... xor U_j ... */
|
|
for (int k = 0; k < sizeof(U); k++)
|
|
T[k] ^= U[k];
|
|
}
|
|
|
|
/* Copy as many bytes as necessary into buf. */
|
|
int clen = pLength - i * SHA1_MAC_LEN;
|
|
if (clen > SHA1_MAC_LEN)
|
|
clen = SHA1_MAC_LEN;
|
|
|
|
for (int k = 0; k < clen; k++)
|
|
{
|
|
res = res + hex_tab[T[k] >> 4];
|
|
res = res + hex_tab[T[k] & 0xF];
|
|
}
|
|
}
|
|
|
|
CComBSTR bstrString(res);
|
|
return bstrString.CopyTo(pVal);
|
|
}
|
|
|
|
STDMETHODIMP CCrypto::hex_sha1_file(BSTR fname, BSTR* pVal)
|
|
{
|
|
CSHA1 sha1;
|
|
if (!sha1.HashFile(CString(fname))) // Hash the contents of the file
|
|
return myAtlReportError (GetObjectCLSID(), "\nCCrypto::hex_sha1_file('%ls')", (LPCSTR)fname);
|
|
|
|
sha1.Final();
|
|
|
|
TCHAR res[41];
|
|
sha1.ReportHash(res, CSHA1::REPORT_HEX_SHORT); // Get final hash as pre-formatted string
|
|
|
|
CComBSTR bstrString(res);
|
|
bstrString.ToLower();
|
|
|
|
return bstrString.CopyTo(pVal);
|
|
}
|
|
|
|
STDMETHODIMP CCrypto::hotp(BSTR hexseed, LONGLONG moving_factor, BYTE digits, BSTR* pVal)
|
|
{
|
|
BYTE digest[20];
|
|
CSHA1 sha1;
|
|
|
|
if (digits < 6 || digits > 8)
|
|
return E_INVALIDARG;
|
|
|
|
CString sseed(hexseed);
|
|
if (sseed.GetLength() > 40)
|
|
return E_INVALIDARG;
|
|
|
|
BYTE seed[20];
|
|
for(int i = 0; i < sizeof(seed); i++)
|
|
{
|
|
BYTE hi=sseed[2*i];
|
|
hi-=(hi<'A' ? '0' : 'A'-10);
|
|
BYTE lo=sseed[2*i+1];
|
|
lo-=(lo<'A' ? '0' : 'A'-10);
|
|
seed[i] = (hi<<4) | (lo & 0x0F); // " & 0x0F" deals with lower-case characters
|
|
}
|
|
|
|
ATLASSERT(sizeof(moving_factor) == 8);
|
|
BYTE counter[sizeof(moving_factor)];
|
|
for (int i = 0; i < sizeof (counter); i++)
|
|
counter[i] = (BYTE)(moving_factor >> ((sizeof (moving_factor) - i - 1) * 8)) & 0xFF;
|
|
|
|
CHMAC_SHA1 HMAC_SHA1 ;
|
|
HMAC_SHA1.HMAC_SHA1((BYTE *)(&counter), sizeof(counter), seed, sizeof(seed), digest) ;
|
|
|
|
CString res;
|
|
|
|
BYTE offset = digest[sizeof (digest) - 1] & 0x0f;
|
|
|
|
uint64_t S = (((digest[offset] & 0x7f) << 24)
|
|
| ((digest[offset + 1] & 0xff) << 16)
|
|
| ((digest[offset + 2] & 0xff) << 8) | ((digest[offset + 3] & 0xff)));
|
|
|
|
res.Format("%lld",1000000000L + S);
|
|
res = res.Right(digits);
|
|
/*
|
|
for(int i = 0; i < 20; i++)
|
|
{
|
|
res = res + hex_tab[digest[i] >> 4];
|
|
res = res + hex_tab[digest[i] & 0xF];
|
|
}
|
|
*/
|
|
CComBSTR bstrString(res);
|
|
bstrString.ToLower();
|
|
|
|
return bstrString.CopyTo(pVal);
|
|
}
|