mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
232 lines
5.2 KiB
C++
Executable File
232 lines
5.2 KiB
C++
Executable File
// Crypto/WzAes.cpp
|
|
/*
|
|
This code implements Brian Gladman's scheme
|
|
specified in "A Password Based File Encryption Utility".
|
|
|
|
Note: you must include MyAes.cpp to project to initialize AES tables
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../C/CpuArch.h"
|
|
|
|
#include "../Common/StreamUtils.h"
|
|
|
|
#include "Pbkdf2HmacSha1.h"
|
|
#include "RandGen.h"
|
|
#include "WzAes.h"
|
|
|
|
namespace NCrypto {
|
|
namespace NWzAes {
|
|
|
|
const unsigned kAesKeySizeMax = 32;
|
|
|
|
static const UInt32 kNumKeyGenIterations = 1000;
|
|
|
|
Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
|
|
{
|
|
if (size > kPasswordSizeMax)
|
|
return E_INVALIDARG;
|
|
_key.Password.Wipe();
|
|
_key.Password.CopyFrom(data, (size_t)size);
|
|
return S_OK;
|
|
}
|
|
|
|
void CBaseCoder::Init2()
|
|
{
|
|
_hmacOverCalc = 0;
|
|
const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4;
|
|
Byte dk[dkSizeMax32 * 4];
|
|
|
|
const unsigned keySize = _key.GetKeySize();
|
|
const unsigned dkSize = 2 * keySize + ((kPwdVerifSize + 3) & ~(unsigned)3);
|
|
|
|
// for (unsigned ii = 0; ii < 1000; ii++)
|
|
{
|
|
NSha1::Pbkdf2Hmac(
|
|
_key.Password, _key.Password.Size(),
|
|
_key.Salt, _key.GetSaltSize(),
|
|
kNumKeyGenIterations,
|
|
dk, dkSize);
|
|
}
|
|
|
|
Hmac()->SetKey(dk + keySize, keySize);
|
|
memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize);
|
|
|
|
// Aes_SetKey_Enc(_aes.Aes() + 8, dk, keySize);
|
|
// AesCtr2_Init(&_aes);
|
|
_aesCoderSpec->SetKeySize(keySize);
|
|
if (_aesCoderSpec->SetKey(dk, keySize) != S_OK) throw 2;
|
|
if (_aesCoderSpec->Init() != S_OK) throw 3;
|
|
}
|
|
|
|
Z7_COM7F_IMF(CBaseCoder::Init())
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
|
|
{
|
|
unsigned saltSize = _key.GetSaltSize();
|
|
MY_RAND_GEN(_key.Salt, saltSize);
|
|
Init2();
|
|
RINOK(WriteStream(outStream, _key.Salt, saltSize))
|
|
return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize);
|
|
}
|
|
|
|
HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
|
|
{
|
|
MY_ALIGN (16)
|
|
UInt32 mac[NSha1::kNumDigestWords];
|
|
Hmac()->Final((Byte *)mac);
|
|
return WriteStream(outStream, mac, kMacSize);
|
|
}
|
|
|
|
/*
|
|
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
|
|
{
|
|
if (size != 1)
|
|
return E_INVALIDARG;
|
|
_key.Init();
|
|
return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
|
|
}
|
|
*/
|
|
|
|
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
|
|
{
|
|
const unsigned saltSize = _key.GetSaltSize();
|
|
const unsigned extraSize = saltSize + kPwdVerifSize;
|
|
Byte temp[kSaltSizeMax + kPwdVerifSize];
|
|
RINOK(ReadStream_FAIL(inStream, temp, extraSize))
|
|
unsigned i;
|
|
for (i = 0; i < saltSize; i++)
|
|
_key.Salt[i] = temp[i];
|
|
for (i = 0; i < kPwdVerifSize; i++)
|
|
_pwdVerifFromArchive[i] = temp[saltSize + i];
|
|
return S_OK;
|
|
}
|
|
|
|
static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size)
|
|
{
|
|
for (unsigned i = 0; i < size; i++)
|
|
if (p1[i] != p2[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool CDecoder::Init_and_CheckPassword()
|
|
{
|
|
Init2();
|
|
return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize);
|
|
}
|
|
|
|
HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
|
|
{
|
|
isOK = false;
|
|
MY_ALIGN (16)
|
|
Byte mac1[kMacSize];
|
|
RINOK(ReadStream_FAIL(inStream, mac1, kMacSize))
|
|
MY_ALIGN (16)
|
|
UInt32 mac2[NSha1::kNumDigestWords];
|
|
Hmac()->Final((Byte *)mac2);
|
|
isOK = CompareArrays(mac1, (const Byte *)mac2, kMacSize);
|
|
if (_hmacOverCalc)
|
|
isOK = false;
|
|
return S_OK;
|
|
}
|
|
|
|
/*
|
|
|
|
CAesCtr2::CAesCtr2():
|
|
aes((4 + AES_NUM_IVMRK_WORDS) * 4)
|
|
{
|
|
// offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
|
|
// first 16 bytes are buffer for last block data.
|
|
// so the ivAES is aligned for (Align + 16).
|
|
}
|
|
|
|
void AesCtr2_Init(CAesCtr2 *p)
|
|
{
|
|
UInt32 *ctr = p->Aes() + 4;
|
|
unsigned i;
|
|
for (i = 0; i < 4; i++)
|
|
ctr[i] = 0;
|
|
p->pos = AES_BLOCK_SIZE;
|
|
}
|
|
|
|
// (size != 16 * N) is allowed only for last call
|
|
|
|
void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
|
|
{
|
|
unsigned pos = p->pos;
|
|
UInt32 *buf32 = p->Aes();
|
|
if (size == 0)
|
|
return;
|
|
|
|
if (pos != AES_BLOCK_SIZE)
|
|
{
|
|
const Byte *buf = (const Byte *)buf32;
|
|
do
|
|
*data++ ^= buf[pos++];
|
|
while (--size != 0 && pos != AES_BLOCK_SIZE);
|
|
}
|
|
|
|
// (size == 0 || pos == AES_BLOCK_SIZE)
|
|
|
|
if (size >= 16)
|
|
{
|
|
SizeT size2 = size >> 4;
|
|
g_AesCtr_Code(buf32 + 4, data, size2);
|
|
size2 <<= 4;
|
|
data += size2;
|
|
size -= size2;
|
|
// (pos == AES_BLOCK_SIZE)
|
|
}
|
|
|
|
// (size < 16)
|
|
|
|
if (size != 0)
|
|
{
|
|
unsigned j;
|
|
const Byte *buf;
|
|
for (j = 0; j < 4; j++)
|
|
buf32[j] = 0;
|
|
g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
|
|
buf = (const Byte *)buf32;
|
|
pos = 0;
|
|
do
|
|
*data++ ^= buf[pos++];
|
|
while (--size != 0);
|
|
}
|
|
|
|
p->pos = pos;
|
|
}
|
|
*/
|
|
|
|
/* (size != 16 * N) is allowed only for last Filter() call */
|
|
|
|
Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
|
|
{
|
|
// AesCtr2_Code(&_aes, data, size);
|
|
size = _aesCoder->Filter(data, size);
|
|
Hmac()->Update(data, size);
|
|
return size;
|
|
}
|
|
|
|
Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
|
|
{
|
|
if (size >= 16)
|
|
size &= ~(UInt32)15;
|
|
if (_hmacOverCalc < size)
|
|
{
|
|
Hmac()->Update(data + _hmacOverCalc, size - _hmacOverCalc);
|
|
_hmacOverCalc = size;
|
|
}
|
|
// AesCtr2_Code(&_aes, data, size);
|
|
size = _aesCoder->Filter(data, size);
|
|
_hmacOverCalc -= size;
|
|
return size;
|
|
}
|
|
|
|
}}
|