chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
// Crypto/RarAes.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
#include "../../../C/RotateDefs.h"
|
||||
|
||||
#include "RarAes.h"
|
||||
#include "Sha1Cls.h"
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NRar3 {
|
||||
|
||||
CDecoder::CDecoder():
|
||||
CAesCbcDecoder(kAesKeySize),
|
||||
_thereIsSalt(false),
|
||||
_needCalc(true)
|
||||
// _rar350Mode(false)
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(_salt); i++)
|
||||
_salt[i] = 0;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
bool prev = _thereIsSalt;
|
||||
_thereIsSalt = false;
|
||||
if (size == 0)
|
||||
{
|
||||
if (!_needCalc && prev)
|
||||
_needCalc = true;
|
||||
return S_OK;
|
||||
}
|
||||
if (size < 8)
|
||||
return E_INVALIDARG;
|
||||
_thereIsSalt = true;
|
||||
bool same = false;
|
||||
if (_thereIsSalt == prev)
|
||||
{
|
||||
same = true;
|
||||
if (_thereIsSalt)
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(_salt); i++)
|
||||
if (_salt[i] != data[i])
|
||||
{
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < sizeof(_salt); i++)
|
||||
_salt[i] = data[i];
|
||||
if (!_needCalc && !same)
|
||||
_needCalc = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const unsigned kPasswordLen_Bytes_MAX = 127 * 2;
|
||||
|
||||
void CDecoder::SetPassword(const Byte *data, unsigned size)
|
||||
{
|
||||
if (size > kPasswordLen_Bytes_MAX)
|
||||
size = kPasswordLen_Bytes_MAX;
|
||||
bool same = false;
|
||||
if (size == _password.Size())
|
||||
{
|
||||
same = true;
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
if (data[i] != _password[i])
|
||||
{
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_needCalc && !same)
|
||||
_needCalc = true;
|
||||
_password.Wipe();
|
||||
_password.CopyFrom(data, (size_t)size);
|
||||
}
|
||||
|
||||
Z7_COM7F_IMF(CDecoder::Init())
|
||||
{
|
||||
CalcKey();
|
||||
RINOK(SetKey(_key, kAesKeySize))
|
||||
RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
|
||||
return CAesCoder::Init();
|
||||
}
|
||||
|
||||
|
||||
// if (password_size_in_bytes + SaltSize > 64),
|
||||
// the original rar code updates password_with_salt buffer
|
||||
// with some generated data from SHA1 code.
|
||||
|
||||
// #define RAR_SHA1_REDUCE
|
||||
|
||||
#ifdef RAR_SHA1_REDUCE
|
||||
#define kNumW 16
|
||||
#define WW(i) W[(i)&15]
|
||||
#else
|
||||
#define kNumW 80
|
||||
#define WW(i) W[i]
|
||||
#endif
|
||||
|
||||
static void UpdatePswDataSha1(Byte *data)
|
||||
{
|
||||
UInt32 W[kNumW];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
|
||||
W[i] = GetBe32(data + i * 4);
|
||||
|
||||
for (i = 16; i < 80; i++)
|
||||
{
|
||||
const UInt32 t = WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16);
|
||||
WW(i) = rotlFixed(t, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
|
||||
{
|
||||
SetUi32(data + i * 4, W[kNumW - SHA1_NUM_BLOCK_WORDS + i])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CDecoder::CalcKey()
|
||||
{
|
||||
if (!_needCalc)
|
||||
return;
|
||||
|
||||
const unsigned kSaltSize = 8;
|
||||
|
||||
MY_ALIGN (16)
|
||||
Byte buf[kPasswordLen_Bytes_MAX + kSaltSize];
|
||||
|
||||
if (_password.Size() != 0)
|
||||
memcpy(buf, _password, _password.Size());
|
||||
|
||||
size_t rawSize = _password.Size();
|
||||
|
||||
if (_thereIsSalt)
|
||||
{
|
||||
memcpy(buf + rawSize, _salt, kSaltSize);
|
||||
rawSize += kSaltSize;
|
||||
}
|
||||
|
||||
MY_ALIGN (16)
|
||||
NSha1::CContext sha;
|
||||
sha.Init();
|
||||
|
||||
MY_ALIGN (16)
|
||||
Byte digest[NSha1::kDigestSize];
|
||||
// rar reverts hash for sha.
|
||||
const UInt32 kNumRounds = (UInt32)1 << 18;
|
||||
UInt32 pos = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < kNumRounds; i++)
|
||||
{
|
||||
sha.Update(buf, rawSize);
|
||||
// if (_rar350Mode)
|
||||
{
|
||||
const UInt32 kBlockSize = 64;
|
||||
const UInt32 endPos = (pos + (UInt32)rawSize) & ~(kBlockSize - 1);
|
||||
if (endPos > pos + kBlockSize)
|
||||
{
|
||||
UInt32 curPos = pos & ~(kBlockSize - 1);
|
||||
curPos += kBlockSize;
|
||||
do
|
||||
{
|
||||
UpdatePswDataSha1(buf + (curPos - pos));
|
||||
curPos += kBlockSize;
|
||||
}
|
||||
while (curPos != endPos);
|
||||
}
|
||||
}
|
||||
pos += (UInt32)rawSize;
|
||||
#if 1
|
||||
UInt32 pswNum;
|
||||
SetUi32a(&pswNum, i)
|
||||
sha.Update((const Byte *)&pswNum, 3);
|
||||
#else
|
||||
Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
|
||||
sha.Update(pswNum, 3);
|
||||
#endif
|
||||
pos += 3;
|
||||
if (i % (kNumRounds / 16) == 0)
|
||||
{
|
||||
MY_ALIGN (16)
|
||||
NSha1::CContext shaTemp = sha;
|
||||
shaTemp.Final(digest);
|
||||
_iv[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
sha.Final(digest);
|
||||
for (i = 0; i < 4; i++)
|
||||
for (unsigned j = 0; j < 4; j++)
|
||||
_key[i * 4 + j] = (digest[i * 4 + 3 - j]);
|
||||
|
||||
_needCalc = false;
|
||||
}
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user