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:
Simone
2026-04-29 14:07:51 +02:00
commit d074cc7c07
3848 changed files with 1076682 additions and 0 deletions
+315
View File
@@ -0,0 +1,315 @@
// 7zAes.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#include "../../../C/Sha256.h"
#include "../../Common/ComTry.h"
#include "../../Common/MyBuffer2.h"
#ifndef Z7_ST
#include "../../Windows/Synchronization.h"
#endif
#include "../Common/StreamUtils.h"
#include "7zAes.h"
#include "MyAes.h"
#ifndef Z7_EXTRACT_ONLY
#include "RandGen.h"
#endif
namespace NCrypto {
namespace N7z {
static const unsigned k_NumCyclesPower_Supported_MAX = 24;
bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
{
if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
return false;
for (unsigned i = 0; i < SaltSize; i++)
if (Salt[i] != a.Salt[i])
return false;
return (Password == a.Password);
}
void CKeyInfo::CalcKey()
{
if (NumCyclesPower == 0x3F)
{
unsigned pos;
for (pos = 0; pos < SaltSize; pos++)
Key[pos] = Salt[pos];
for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++)
Key[pos++] = Password[i];
for (; pos < kKeySize; pos++)
Key[pos] = 0;
}
else
{
const unsigned kUnrPow = 6;
const UInt32 numUnroll = (UInt32)1 << (NumCyclesPower <= kUnrPow ? (unsigned)NumCyclesPower : kUnrPow);
const size_t bufSize = 8 + SaltSize + Password.Size();
const size_t unrollSize = bufSize * numUnroll;
// MY_ALIGN (16)
// CSha256 sha;
const size_t shaAllocSize = sizeof(CSha256) + unrollSize + bufSize * 2;
CAlignedBuffer1 sha(shaAllocSize);
Byte *buf = sha + sizeof(CSha256);
memcpy(buf, Salt, SaltSize);
memcpy(buf + SaltSize, Password, Password.Size());
memset(buf + bufSize - 8, 0, 8);
Sha256_Init((CSha256 *)(void *)(Byte *)sha);
{
{
Byte *dest = buf;
for (UInt32 i = 1; i < numUnroll; i++)
{
dest += bufSize;
memcpy(dest, buf, bufSize);
}
}
const UInt32 numRounds = (UInt32)1 << NumCyclesPower;
UInt32 r = 0;
do
{
Byte *dest = buf + bufSize - 8;
UInt32 i = r;
r += numUnroll;
do
{
SetUi32(dest, i) i++; dest += bufSize;
// SetUi32(dest, i) i++; dest += bufSize;
}
while (i < r);
Sha256_Update((CSha256 *)(void *)(Byte *)sha, buf, unrollSize);
}
while (r < numRounds);
}
/*
UInt64 numRounds = (UInt64)1 << NumCyclesPower;
do
{
Sha256_Update((CSha256 *)(Byte *)sha, buf, bufSize);
for (unsigned i = 0; i < 8; i++)
if (++(ctr[i]) != 0)
break;
}
while (--numRounds != 0);
*/
Sha256_Final((CSha256 *)(void *)(Byte *)sha, Key);
memset(sha, 0, shaAllocSize);
}
}
bool CKeyInfoCache::GetKey(CKeyInfo &key)
{
FOR_VECTOR (i, Keys)
{
const CKeyInfo &cached = Keys[i];
if (key.IsEqualTo(cached))
{
for (unsigned j = 0; j < kKeySize; j++)
key.Key[j] = cached.Key[j];
if (i != 0)
Keys.MoveToFront(i);
return true;
}
}
return false;
}
void CKeyInfoCache::FindAndAdd(const CKeyInfo &key)
{
FOR_VECTOR (i, Keys)
{
const CKeyInfo &cached = Keys[i];
if (key.IsEqualTo(cached))
{
if (i != 0)
Keys.MoveToFront(i);
return;
}
}
Add(key);
}
void CKeyInfoCache::Add(const CKeyInfo &key)
{
if (Keys.Size() >= Size)
Keys.DeleteBack();
Keys.Insert(0, key);
}
static CKeyInfoCache g_GlobalKeyCache(32);
#ifndef Z7_ST
static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
#define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
#else
#define MT_LOCK
#endif
CBase::CBase():
_cachedKeys(16),
_ivSize(0)
{
for (unsigned i = 0; i < sizeof(_iv); i++)
_iv[i] = 0;
}
void CBase::PrepareKey()
{
// BCJ2 threads use same password. So we use long lock.
MT_LOCK
bool finded = false;
if (!_cachedKeys.GetKey(_key))
{
finded = g_GlobalKeyCache.GetKey(_key);
if (!finded)
_key.CalcKey();
_cachedKeys.Add(_key);
}
if (!finded)
g_GlobalKeyCache.FindAndAdd(_key);
}
#ifndef Z7_EXTRACT_ONLY
/*
Z7_COM7F_IMF(CEncoder::ResetSalt())
{
_key.SaltSize = 4;
g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
return S_OK;
}
*/
Z7_COM7F_IMF(CEncoder::ResetInitVector())
{
for (unsigned i = 0; i < sizeof(_iv); i++)
_iv[i] = 0;
_ivSize = 16;
MY_RAND_GEN(_iv, _ivSize);
return S_OK;
}
Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
{
Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
unsigned propsSize = 1;
props[0] = (Byte)(_key.NumCyclesPower
| (_key.SaltSize == 0 ? 0 : (1 << 7))
| (_ivSize == 0 ? 0 : (1 << 6)));
if (_key.SaltSize != 0 || _ivSize != 0)
{
props[1] = (Byte)(
((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4)
| (_ivSize == 0 ? 0 : _ivSize - 1));
memcpy(props + 2, _key.Salt, _key.SaltSize);
propsSize = 2 + _key.SaltSize;
memcpy(props + propsSize, _iv, _ivSize);
propsSize += _ivSize;
}
return WriteStream(outStream, props, propsSize);
}
CEncoder::CEncoder()
{
// _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
// _key.NumCyclesPower = 0x3F;
_key.NumCyclesPower = 19;
_aesFilter = new CAesCbcEncoder(kKeySize);
}
#endif
CDecoder::CDecoder()
{
_aesFilter = new CAesCbcDecoder(kKeySize);
}
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
{
_key.ClearProps();
_ivSize = 0;
unsigned i;
for (i = 0; i < sizeof(_iv); i++)
_iv[i] = 0;
if (size == 0)
return S_OK;
const unsigned b0 = data[0];
_key.NumCyclesPower = b0 & 0x3F;
if ((b0 & 0xC0) == 0)
return size == 1 ? S_OK : E_INVALIDARG;
if (size <= 1)
return E_INVALIDARG;
const unsigned b1 = data[1];
const unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
const unsigned ivSize = ((b0 >> 6) & 1) + (b1 & 0x0F);
if (size != 2 + saltSize + ivSize)
return E_INVALIDARG;
_key.SaltSize = saltSize;
data += 2;
for (i = 0; i < saltSize; i++)
_key.Salt[i] = *data++;
for (i = 0; i < ivSize; i++)
_iv[i] = *data++;
return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX
|| _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL;
}
Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
{
COM_TRY_BEGIN
_key.Password.Wipe();
_key.Password.CopyFrom(data, (size_t)size);
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CBaseCoder::Init())
{
COM_TRY_BEGIN
PrepareKey();
CMyComPtr<ICryptoProperties> cp;
RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp))
if (!cp)
return E_FAIL;
RINOK(cp->SetKey(_key.Key, kKeySize))
RINOK(cp->SetInitVector(_iv, sizeof(_iv)))
return _aesFilter->Init();
COM_TRY_END
}
Z7_COM7F_IMF2(UInt32, CBaseCoder::Filter(Byte *data, UInt32 size))
{
return _aesFilter->Filter(data, size);
}
}}
+130
View File
@@ -0,0 +1,130 @@
// 7zAes.h
#ifndef ZIP7_INC_CRYPTO_7Z_AES_H
#define ZIP7_INC_CRYPTO_7Z_AES_H
#include "../../Common/MyBuffer.h"
#include "../../Common/MyCom.h"
#include "../../Common/MyVector.h"
#include "../ICoder.h"
#include "../IPassword.h"
namespace NCrypto {
namespace N7z {
const unsigned kKeySize = 32;
const unsigned kSaltSizeMax = 16;
const unsigned kIvSizeMax = 16; // AES_BLOCK_SIZE;
class CKeyInfo
{
public:
unsigned NumCyclesPower;
unsigned SaltSize;
Byte Salt[kSaltSizeMax];
CByteBuffer Password;
Byte Key[kKeySize];
bool IsEqualTo(const CKeyInfo &a) const;
void CalcKey();
CKeyInfo() { ClearProps(); }
void ClearProps()
{
NumCyclesPower = 0;
SaltSize = 0;
for (unsigned i = 0; i < sizeof(Salt); i++)
Salt[i] = 0;
}
void Wipe()
{
Password.Wipe();
NumCyclesPower = 0;
SaltSize = 0;
Z7_memset_0_ARRAY(Salt);
Z7_memset_0_ARRAY(Key);
}
#ifdef Z7_CPP_IS_SUPPORTED_default
CKeyInfo(const CKeyInfo &) = default;
#endif
~CKeyInfo() { Wipe(); }
};
class CKeyInfoCache
{
unsigned Size;
CObjectVector<CKeyInfo> Keys;
public:
CKeyInfoCache(unsigned size): Size(size) {}
bool GetKey(CKeyInfo &key);
void Add(const CKeyInfo &key);
void FindAndAdd(const CKeyInfo &key);
};
class CBase
{
CKeyInfoCache _cachedKeys;
protected:
CKeyInfo _key;
Byte _iv[kIvSizeMax];
unsigned _ivSize;
void PrepareKey();
CBase();
};
class CBaseCoder:
public ICompressFilter,
public ICryptoSetPassword,
public CMyUnknownImp,
public CBase
{
Z7_IFACE_COM7_IMP(ICompressFilter)
Z7_IFACE_COM7_IMP(ICryptoSetPassword)
protected:
virtual ~CBaseCoder() {}
CMyComPtr<ICompressFilter> _aesFilter;
};
#ifndef Z7_EXTRACT_ONLY
class CEncoder Z7_final:
public CBaseCoder,
public ICompressWriteCoderProperties,
// public ICryptoResetSalt,
public ICryptoResetInitVector
{
Z7_COM_UNKNOWN_IMP_4(
ICompressFilter,
ICryptoSetPassword,
ICompressWriteCoderProperties,
// ICryptoResetSalt,
ICryptoResetInitVector)
Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties)
// Z7_IFACE_COM7_IMP(ICryptoResetSalt)
Z7_IFACE_COM7_IMP(ICryptoResetInitVector)
public:
CEncoder();
};
#endif
class CDecoder Z7_final:
public CBaseCoder,
public ICompressSetDecoderProperties2
{
Z7_COM_UNKNOWN_IMP_3(
ICompressFilter,
ICryptoSetPassword,
ICompressSetDecoderProperties2)
Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
public:
CDecoder();
};
}}
#endif
@@ -0,0 +1,17 @@
// 7zAesRegister.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "7zAes.h"
namespace NCrypto {
namespace N7z {
REGISTER_FILTER_E(SzAES,
CDecoder,
CEncoder,
0x6F10701, "7zAES")
}}
+4
View File
@@ -0,0 +1,4 @@
EXPORTS
CreateObject PRIVATE
GetNumberOfMethods PRIVATE
GetMethodProperty PRIVATE
@@ -0,0 +1,94 @@
// HmacSha1.cpp
#include "StdAfx.h"
#include <string.h>
#include "../../../C/CpuArch.h"
#include "HmacSha1.h"
namespace NCrypto {
namespace NSha1 {
void CHmac::SetKey(const Byte *key, size_t keySize)
{
MY_ALIGN (16)
UInt32 temp[SHA1_NUM_BLOCK_WORDS];
size_t i;
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
temp[i] = 0;
if (keySize > kBlockSize)
{
_sha.Init();
_sha.Update(key, keySize);
_sha.Final((Byte *)temp);
}
else
memcpy(temp, key, keySize);
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
temp[i] ^= 0x36363636;
_sha.Init();
_sha.Update((const Byte *)temp, kBlockSize);
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
temp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
_sha2.Init();
_sha2.Update((const Byte *)temp, kBlockSize);
}
void CHmac::Final(Byte *mac)
{
_sha.Final(mac);
_sha2.Update(mac, kDigestSize);
_sha2.Final(mac);
}
void CHmac::GetLoopXorDigest1(void *mac, UInt32 numIteration)
{
MY_ALIGN (16) UInt32 block [SHA1_NUM_BLOCK_WORDS];
MY_ALIGN (16) UInt32 block2[SHA1_NUM_BLOCK_WORDS];
MY_ALIGN (16) UInt32 mac2 [SHA1_NUM_BLOCK_WORDS];
_sha. PrepareBlock((Byte *)block, SHA1_DIGEST_SIZE);
_sha2.PrepareBlock((Byte *)block2, SHA1_DIGEST_SIZE);
block[0] = ((const UInt32 *)mac)[0];
block[1] = ((const UInt32 *)mac)[1];
block[2] = ((const UInt32 *)mac)[2];
block[3] = ((const UInt32 *)mac)[3];
block[4] = ((const UInt32 *)mac)[4];
mac2[0] = block[0];
mac2[1] = block[1];
mac2[2] = block[2];
mac2[3] = block[3];
mac2[4] = block[4];
for (UInt32 i = 0; i < numIteration; i++)
{
_sha. GetBlockDigest((const Byte *)block, (Byte *)block2);
_sha2.GetBlockDigest((const Byte *)block2, (Byte *)block);
mac2[0] ^= block[0];
mac2[1] ^= block[1];
mac2[2] ^= block[2];
mac2[3] ^= block[3];
mac2[4] ^= block[4];
}
((UInt32 *)mac)[0] = mac2[0];
((UInt32 *)mac)[1] = mac2[1];
((UInt32 *)mac)[2] = mac2[2];
((UInt32 *)mac)[3] = mac2[3];
((UInt32 *)mac)[4] = mac2[4];
}
}}
+31
View File
@@ -0,0 +1,31 @@
// HmacSha1.h
// Implements HMAC-SHA-1 (RFC2104, FIPS-198)
#ifndef ZIP7_INC_CRYPTO_HMAC_SHA1_H
#define ZIP7_INC_CRYPTO_HMAC_SHA1_H
#include "Sha1Cls.h"
namespace NCrypto {
namespace NSha1 {
// Use: SetKey(key, keySize); for () Update(data, size); FinalFull(mac);
class CHmac
{
CContext _sha;
CContext _sha2;
public:
void SetKey(const Byte *key, size_t keySize);
void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); }
// Final() : mac is recommended to be aligned for 4 bytes
// GetLoopXorDigest1() : mac is required to be aligned for 4 bytes
// The caller can use: UInt32 mac[NSha1::kNumDigestWords] and typecast to (Byte *) and (void *);
void Final(Byte *mac);
void GetLoopXorDigest1(void *mac, UInt32 numIteration);
};
}}
#endif
@@ -0,0 +1,53 @@
// HmacSha256.cpp
#include "StdAfx.h"
#include <string.h>
#include "../../../C/CpuArch.h"
#include "HmacSha256.h"
namespace NCrypto {
namespace NSha256 {
void CHmac::SetKey(const Byte *key, size_t keySize)
{
MY_ALIGN (16)
UInt32 temp[SHA256_NUM_BLOCK_WORDS];
size_t i;
for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++)
temp[i] = 0;
if (keySize > kBlockSize)
{
Sha256_Init(&_sha);
Sha256_Update(&_sha, key, keySize);
Sha256_Final(&_sha, (Byte *)temp);
}
else
memcpy(temp, key, keySize);
for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++)
temp[i] ^= 0x36363636;
Sha256_Init(&_sha);
Sha256_Update(&_sha, (const Byte *)temp, kBlockSize);
for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++)
temp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
Sha256_Init(&_sha2);
Sha256_Update(&_sha2, (const Byte *)temp, kBlockSize);
}
void CHmac::Final(Byte *mac)
{
Sha256_Final(&_sha, mac);
Sha256_Update(&_sha2, mac, SHA256_DIGEST_SIZE);
Sha256_Final(&_sha2, mac);
}
}}
@@ -0,0 +1,27 @@
// HmacSha256.h
// Implements HMAC-SHA-256 (RFC2104, FIPS-198)
#ifndef ZIP7_INC_CRYPTO_HMAC_SHA256_H
#define ZIP7_INC_CRYPTO_HMAC_SHA256_H
#include "../../../C/Sha256.h"
namespace NCrypto {
namespace NSha256 {
const unsigned kBlockSize = SHA256_BLOCK_SIZE;
const unsigned kDigestSize = SHA256_DIGEST_SIZE;
class CHmac
{
CSha256 _sha;
CSha256 _sha2;
public:
void SetKey(const Byte *key, size_t keySize);
void Update(const Byte *data, size_t dataSize) { Sha256_Update(&_sha, data, dataSize); }
void Final(Byte *mac);
};
}}
#endif
+277
View File
@@ -0,0 +1,277 @@
// Crypto/MyAes.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#include "MyAes.h"
namespace NCrypto {
static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
CAesCoder::CAesCoder(
// bool encodeMode,
unsigned keySize
// , bool ctrMode
):
_keyIsSet(false),
// _encodeMode(encodeMode),
// _ctrMode(ctrMode),
_keySize(keySize),
// _ctrPos(0), // _ctrPos =0 will be set in Init()
_aes(AES_NUM_IVMRK_WORDS * 4 + AES_BLOCK_SIZE * 2)
{
// _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
memset(_iv, 0, AES_BLOCK_SIZE);
/*
// we can use the following code to test 32-bit overflow case for AES-CTR
for (unsigned i = 0; i < 16; i++) _iv[i] = (Byte)(i + 1);
_iv[0] = 0xFE; _iv[1] = _iv[2] = _iv[3] = 0xFF;
*/
}
Z7_COM7F_IMF(CAesCoder::Init())
{
_ctrPos = 0;
AesCbc_Init(Aes(), _iv);
return _keyIsSet ? S_OK : E_NOTIMPL; // E_FAIL
}
Z7_COM7F_IMF2(UInt32, CAesCoder::Filter(Byte *data, UInt32 size))
{
if (!_keyIsSet)
return 0;
if (size < AES_BLOCK_SIZE)
{
if (size == 0)
return 0;
return AES_BLOCK_SIZE;
}
size >>= 4;
// (data) must be aligned for 16-bytes here
_codeFunc(Aes(), data, size);
return size << 4;
}
Z7_COM7F_IMF(CAesCoder::SetKey(const Byte *data, UInt32 size))
{
if ((size & 0x7) != 0 || size < 16 || size > 32)
return E_INVALIDARG;
if (_keySize != 0 && size != _keySize)
return E_INVALIDARG;
_setKeyFunc(Aes() + 4, data, size);
_keyIsSet = true;
return S_OK;
}
Z7_COM7F_IMF(CAesCoder::SetInitVector(const Byte *data, UInt32 size))
{
if (size != AES_BLOCK_SIZE)
return E_INVALIDARG;
memcpy(_iv, data, size);
/* we allow SetInitVector() call before SetKey() call.
so we ignore possible error in Init() here */
CAesCoder::Init(); // don't call virtual function here !!!
return S_OK;
}
#ifndef Z7_SFX
/*
Z7_COM7F_IMF(CAesCtrCoder::Init())
{
_ctrPos = 0;
return CAesCoder::Init();
}
*/
Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size))
{
if (!_keyIsSet)
return 0;
if (size == 0)
return 0;
if (_ctrPos != 0)
{
/* Optimized caller will not call here */
const Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS);
unsigned num = 0;
for (unsigned i = _ctrPos; i != AES_BLOCK_SIZE; i++)
{
if (num == size)
{
_ctrPos = i;
return num;
}
data[num++] ^= ctr[i];
}
_ctrPos = 0;
/* if (num < size) {
we can filter more data with _codeFunc().
But it's supposed that the caller can work correctly,
even if we do only partial filtering here.
So we filter data only for current 16-byte block. }
*/
/*
size -= num;
size >>= 4;
// (data) must be aligned for 16-bytes here
_codeFunc(Aes(), data + num, size);
return num + (size << 4);
*/
return num;
}
if (size < AES_BLOCK_SIZE)
{
/* The good optimized caller can call here only in last Filter() call.
But we support also non-optimized callers,
where another Filter() calls are allowed after this call.
*/
Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS);
memset(ctr, 0, AES_BLOCK_SIZE);
memcpy(ctr, data, size);
_codeFunc(Aes(), ctr, 1);
memcpy(data, ctr, size);
_ctrPos = size;
return size;
}
size >>= 4;
// (data) must be aligned for 16-bytes here
_codeFunc(Aes(), data, size);
return size << 4;
}
#endif // Z7_SFX
#ifndef Z7_EXTRACT_ONLY
#ifdef MY_CPU_X86_OR_AMD64
#if defined(__INTEL_COMPILER)
#if (__INTEL_COMPILER >= 1110)
#define USE_HW_AES
#if (__INTEL_COMPILER >= 1900)
#define USE_HW_VAES
#endif
#endif
#elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
|| defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400)
#define USE_HW_AES
#if defined(__clang__) && (__clang_major__ >= 8) \
|| defined(__GNUC__) && (__GNUC__ >= 8)
#define USE_HW_VAES
#endif
#elif defined(_MSC_VER)
#define USE_HW_AES
#define USE_HW_VAES
#endif
#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
#if defined(__ARM_FEATURE_AES) \
|| defined(__ARM_FEATURE_CRYPTO)
#define USE_HW_AES
#else
#if defined(MY_CPU_ARM64) \
|| defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \
|| defined(Z7_MSC_VER_ORIGINAL)
#if defined(__ARM_FP) && \
( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
|| defined(__GNUC__) && (__GNUC__ >= 6) \
) \
|| defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910)
#if defined(MY_CPU_ARM64) \
|| !defined(Z7_CLANG_VERSION) \
|| defined(__ARM_NEON) && \
(Z7_CLANG_VERSION < 170000 || \
Z7_CLANG_VERSION > 170001)
#define USE_HW_AES
#endif
#endif
#endif
#endif
#endif
#ifdef USE_HW_AES
// #pragma message("=== MyAES.c USE_HW_AES === ")
#define SET_AES_FUNC_2(f2) \
if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \
{ f = f2; }
#ifdef USE_HW_VAES
#define SET_AES_FUNC_23(f2, f3) \
SET_AES_FUNC_2(f2) \
if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \
{ f = f3; }
#else // USE_HW_VAES
#define SET_AES_FUNC_23(f2, f3) \
SET_AES_FUNC_2(f2)
#endif // USE_HW_VAES
#else // USE_HW_AES
#define SET_AES_FUNC_23(f2, f3)
#endif // USE_HW_AES
#define SET_AES_FUNCS(c, f0, f1, f2, f3) \
bool c::SetFunctions(UInt32 algo) { \
_codeFunc = f0; if (algo < 1) return true; \
AES_CODE_FUNC f = NULL; \
if (algo == 1) { f = f1; } \
SET_AES_FUNC_23(f2, f3) \
if (f) { _codeFunc = f; return true; } \
return false; }
#ifndef Z7_SFX
SET_AES_FUNCS(
CAesCtrCoder,
g_AesCtr_Code,
AesCtr_Code,
AesCtr_Code_HW,
AesCtr_Code_HW_256)
#endif
SET_AES_FUNCS(
CAesCbcEncoder,
g_AesCbc_Encode,
AesCbc_Encode,
AesCbc_Encode_HW,
AesCbc_Encode_HW)
SET_AES_FUNCS(
CAesCbcDecoder,
g_AesCbc_Decode,
AesCbc_Decode,
AesCbc_Decode_HW,
AesCbc_Decode_HW_256)
Z7_COM7F_IMF(CAesCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
{
UInt32 algo = 0;
for (UInt32 i = 0; i < numProps; i++)
{
if (propIDs[i] == NCoderPropID::kDefaultProp)
{
const PROPVARIANT &prop = coderProps[i];
if (prop.vt != VT_UI4)
return E_INVALIDARG;
if (prop.ulVal > 3)
return E_NOTIMPL;
algo = prop.ulVal;
}
}
if (!SetFunctions(algo))
return E_NOTIMPL;
return S_OK;
}
#endif // Z7_EXTRACT_ONLY
}
+122
View File
@@ -0,0 +1,122 @@
// Crypto/MyAes.h
#ifndef ZIP7_INC_CRYPTO_MY_AES_H
#define ZIP7_INC_CRYPTO_MY_AES_H
#include "../../../C/Aes.h"
#include "../../Common/MyBuffer2.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCrypto {
#ifdef Z7_EXTRACT_ONLY
#define Z7_IFACEN_IAesCoderSetFunctions(x)
#else
#define Z7_IFACEN_IAesCoderSetFunctions(x) \
virtual bool SetFunctions(UInt32 algo) x
#endif
class CAesCoder:
public ICompressFilter,
public ICryptoProperties,
#ifndef Z7_EXTRACT_ONLY
public ICompressSetCoderProperties,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressFilter)
Z7_COM_QI_ENTRY(ICryptoProperties)
#ifndef Z7_EXTRACT_ONLY
Z7_COM_QI_ENTRY(ICompressSetCoderProperties)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
public:
Z7_IFACE_COM7_IMP_NONFINAL(ICompressFilter)
Z7_IFACE_COM7_IMP(ICryptoProperties)
private:
#ifndef Z7_EXTRACT_ONLY
Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
#endif
protected:
bool _keyIsSet;
// bool _encodeMode;
// bool _ctrMode;
// unsigned _offset;
unsigned _keySize;
unsigned _ctrPos; // we need _ctrPos here for Init() / SetInitVector()
AES_CODE_FUNC _codeFunc;
AES_SET_KEY_FUNC _setKeyFunc;
private:
// UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];
CAlignedBuffer1 _aes;
Byte _iv[AES_BLOCK_SIZE];
// UInt32 *Aes() { return _aes + _offset; }
protected:
UInt32 *Aes() { return (UInt32 *)(void *)(Byte *)_aes; }
Z7_IFACE_PURE(IAesCoderSetFunctions)
public:
CAesCoder(
// bool encodeMode,
unsigned keySize
// , bool ctrMode
);
virtual ~CAesCoder() {} // we need virtual destructor for derived classes
void SetKeySize(unsigned size) { _keySize = size; }
};
#ifndef Z7_EXTRACT_ONLY
struct CAesCbcEncoder: public CAesCoder
{
CAesCbcEncoder(unsigned keySize = 0): CAesCoder(keySize)
{
_setKeyFunc = Aes_SetKey_Enc;
_codeFunc = g_AesCbc_Encode;
}
Z7_IFACE_IMP(IAesCoderSetFunctions)
};
#endif
struct CAesCbcDecoder: public CAesCoder
{
CAesCbcDecoder(unsigned keySize = 0): CAesCoder(keySize)
{
_setKeyFunc = Aes_SetKey_Dec;
_codeFunc = g_AesCbc_Decode;
}
Z7_IFACE_IMP(IAesCoderSetFunctions)
};
#ifndef Z7_SFX
struct CAesCtrCoder: public CAesCoder
{
private:
// unsigned _ctrPos;
// Z7_IFACE_COM7_IMP(ICompressFilter)
// Z7_COM7F_IMP(Init())
Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
public:
CAesCtrCoder(unsigned keySize = 0): CAesCoder(keySize)
{
_ctrPos = 0;
_setKeyFunc = Aes_SetKey_Enc;
_codeFunc = g_AesCtr_Code;
}
Z7_IFACE_IMP(IAesCoderSetFunctions)
};
#endif
}
#endif
@@ -0,0 +1,29 @@
// MyAesReg.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "MyAes.h"
namespace NCrypto {
#ifndef Z7_SFX
#define REGISTER_AES_2(name, nameString, keySize) \
REGISTER_FILTER_E(name, \
CAesCbcDecoder(keySize), \
CAesCbcEncoder(keySize), \
0x6F00100 | ((keySize - 16) * 8) | (/* isCtr */ 0 ? 4 : 1), \
nameString) \
#define REGISTER_AES(name, nameString) \
/* REGISTER_AES_2(AES128 ## name, "AES128" nameString, 16) */ \
/* REGISTER_AES_2(AES192 ## name, "AES192" nameString, 24) */ \
REGISTER_AES_2(AES256 ## name, "AES256" nameString, 32) \
REGISTER_AES(CBC, "CBC")
#endif
}
@@ -0,0 +1,48 @@
// Pbkdf2HmacSha1.cpp
#include "StdAfx.h"
#include <string.h>
#include "../../../C/CpuArch.h"
#include "HmacSha1.h"
#include "Pbkdf2HmacSha1.h"
namespace NCrypto {
namespace NSha1 {
void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize,
const Byte *salt, size_t saltSize,
UInt32 numIterations,
Byte *key, size_t keySize)
{
MY_ALIGN (16)
CHmac baseCtx;
baseCtx.SetKey(pwd, pwdSize);
for (UInt32 i = 1; keySize != 0; i++)
{
MY_ALIGN (16)
CHmac ctx;
ctx = baseCtx;
ctx.Update(salt, saltSize);
MY_ALIGN (16)
UInt32 u[kNumDigestWords];
SetBe32(u, i)
ctx.Update((const Byte *)u, 4);
ctx.Final((Byte *)u);
ctx = baseCtx;
ctx.GetLoopXorDigest1((void *)u, numIterations - 1);
const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize;
memcpy(key, (const Byte *)u, curSize);
key += curSize;
keySize -= curSize;
}
}
}}
@@ -0,0 +1,19 @@
// Pbkdf2HmacSha1.h
// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1
#ifndef ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H
#define ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H
#include <stddef.h>
#include "../../Common/MyTypes.h"
namespace NCrypto {
namespace NSha1 {
void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize,
UInt32 numIterations, Byte *key, size_t keySize);
}}
#endif
+241
View File
@@ -0,0 +1,241 @@
// RandGen.cpp
#include "StdAfx.h"
#include "RandGen.h"
#ifndef USE_STATIC_SYSTEM_RAND
#ifndef Z7_ST
#include "../../Windows/Synchronization.h"
#endif
#ifdef _WIN32
#ifdef _WIN64
#define USE_STATIC_RtlGenRandom
#endif
#ifdef USE_STATIC_RtlGenRandom
// #include <NTSecAPI.h>
EXTERN_C_BEGIN
#ifndef RtlGenRandom
#define RtlGenRandom SystemFunction036
BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
#endif
EXTERN_C_END
#else
EXTERN_C_BEGIN
typedef BOOLEAN (WINAPI * Func_RtlGenRandom)(PVOID RandomBuffer, ULONG RandomBufferLength);
EXTERN_C_END
#endif
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define USE_POSIX_TIME
#define USE_POSIX_TIME2
#endif
#ifdef USE_POSIX_TIME
#include <time.h>
#ifdef USE_POSIX_TIME2
#include <sys/time.h>
#endif
#endif
// The seed and first generated data block depend from processID,
// theadID, timer and system random generator, if available.
// Other generated data blocks depend from previous state
#define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x));
void CRandomGenerator::Init()
{
MY_ALIGN (16)
CSha256 hash;
Sha256_Init(&hash);
unsigned numIterations = 1000;
{
#ifndef UNDER_CE
const unsigned kNumIterations_Small = 100;
const unsigned kBufSize = 32;
MY_ALIGN (16)
Byte buf[kBufSize];
#endif
#ifdef _WIN32
DWORD w = ::GetCurrentProcessId();
HASH_UPD(w)
w = ::GetCurrentThreadId();
HASH_UPD(w)
#ifdef UNDER_CE
/*
if (CeGenRandom(kBufSize, buf))
{
numIterations = kNumIterations_Small;
Sha256_Update(&hash, buf, kBufSize);
}
*/
#elif defined(USE_STATIC_RtlGenRandom)
if (RtlGenRandom(buf, kBufSize))
{
numIterations = kNumIterations_Small;
Sha256_Update(&hash, buf, kBufSize);
}
#else
{
const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll"));
if (hModule)
{
// SystemFunction036() is real name of RtlGenRandom() function
const
Func_RtlGenRandom
my_RtlGenRandom = Z7_GET_PROC_ADDRESS(
Func_RtlGenRandom, hModule, "SystemFunction036");
if (my_RtlGenRandom)
{
if (my_RtlGenRandom(buf, kBufSize))
{
numIterations = kNumIterations_Small;
Sha256_Update(&hash, buf, kBufSize);
}
}
::FreeLibrary(hModule);
}
}
#endif
#else
pid_t pid = getpid();
HASH_UPD(pid)
pid = getppid();
HASH_UPD(pid)
{
int f = open("/dev/urandom", O_RDONLY);
unsigned numBytes = kBufSize;
if (f >= 0)
{
do
{
ssize_t n = read(f, buf, numBytes);
if (n <= 0)
break;
Sha256_Update(&hash, buf, (size_t)n);
numBytes -= (unsigned)n;
}
while (numBytes);
close(f);
if (numBytes == 0)
numIterations = kNumIterations_Small;
}
}
/*
{
int n = getrandom(buf, kBufSize, 0);
if (n > 0)
{
Sha256_Update(&hash, buf, n);
if (n == kBufSize)
numIterations = kNumIterations_Small;
}
}
*/
#endif
}
#ifdef _DEBUG
numIterations = 2;
#endif
do
{
#ifdef _WIN32
LARGE_INTEGER v;
if (::QueryPerformanceCounter(&v))
HASH_UPD(v.QuadPart)
#endif
#ifdef USE_POSIX_TIME
#ifdef USE_POSIX_TIME2
timeval v;
if (gettimeofday(&v, NULL) == 0)
{
HASH_UPD(v.tv_sec)
HASH_UPD(v.tv_usec)
}
#endif
const time_t v2 = time(NULL);
HASH_UPD(v2)
#endif
#ifdef _WIN32
const DWORD tickCount = ::GetTickCount();
HASH_UPD(tickCount)
#endif
for (unsigned j = 0; j < 100; j++)
{
Sha256_Final(&hash, _buff);
Sha256_Init(&hash);
Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
}
}
while (--numIterations);
Sha256_Final(&hash, _buff);
_needInit = false;
}
#ifndef Z7_ST
static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
#define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
#else
#define MT_LOCK
#endif
void CRandomGenerator::Generate(Byte *data, unsigned size)
{
MT_LOCK
if (_needInit)
Init();
while (size != 0)
{
MY_ALIGN (16)
CSha256 hash;
Sha256_Init(&hash);
Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
Sha256_Final(&hash, _buff);
Sha256_Init(&hash);
UInt32 salt = 0xF672ABD1;
HASH_UPD(salt)
Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
MY_ALIGN (16)
Byte buff[SHA256_DIGEST_SIZE];
Sha256_Final(&hash, buff);
for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
*data++ = buff[i];
}
}
MY_ALIGN (16)
CRandomGenerator g_RandomGenerator;
#endif
+41
View File
@@ -0,0 +1,41 @@
// RandGen.h
#ifndef ZIP7_INC_CRYPTO_RAND_GEN_H
#define ZIP7_INC_CRYPTO_RAND_GEN_H
#include "../../../C/Sha256.h"
#ifdef _WIN64
// #define USE_STATIC_SYSTEM_RAND
#endif
#ifdef USE_STATIC_SYSTEM_RAND
#ifdef _WIN32
#include <ntsecapi.h>
#define MY_RAND_GEN(data, size) RtlGenRandom(data, size)
#else
#define MY_RAND_GEN(data, size) getrandom(data, size, 0)
#endif
#else
class CRandomGenerator
{
Byte _buff[SHA256_DIGEST_SIZE];
bool _needInit;
void Init();
public:
CRandomGenerator(): _needInit(true) {}
void Generate(Byte *data, unsigned size);
};
MY_ALIGN (16)
extern CRandomGenerator g_RandomGenerator;
#define MY_RAND_GEN(data, size) g_RandomGenerator.Generate(data, size)
#endif
#endif
@@ -0,0 +1,130 @@
// Crypto/Rar20Crypto.cpp
#include "StdAfx.h"
#include "../../../C/7zCrc.h"
#include "../../../C/CpuArch.h"
#include "../../../C/RotateDefs.h"
#include "Rar20Crypto.h"
namespace NCrypto {
namespace NRar2 {
static const unsigned kNumRounds = 32;
static const Byte g_InitSubstTable[256] = {
215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
};
void CData::UpdateKeys(const Byte *data)
{
for (unsigned i = 0; i < 16; i += 4)
for (unsigned j = 0; j < 4; j++)
Keys[j] ^= g_CrcTable[data[i + j]];
}
static inline void Swap(Byte &b1, Byte &b2)
{
Byte b = b1;
b1 = b2;
b2 = b;
}
void CData::SetPassword(const Byte *data, unsigned size)
{
Keys[0] = 0xD3A3B879L;
Keys[1] = 0x3F6D12F7L;
Keys[2] = 0x7515A235L;
Keys[3] = 0xA4E7F123L;
Byte psw[128];
Z7_memset_0_ARRAY(psw);
if (size != 0)
{
if (size >= sizeof(psw))
size = sizeof(psw) - 1;
memcpy(psw, data, size);
}
memcpy(SubstTable, g_InitSubstTable, sizeof(SubstTable));
for (unsigned j = 0; j < 256; j++)
for (unsigned i = 0; i < size; i += 2)
{
unsigned n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF];
unsigned n2 = (Byte)g_CrcTable[(psw[(size_t)i + 1] + j) & 0xFF];
for (unsigned k = 1; (n1 & 0xFF) != n2; n1++, k++)
Swap(SubstTable[n1 & 0xFF], SubstTable[(n1 + i + k) & 0xFF]);
}
for (unsigned i = 0; i < size; i += 16)
EncryptBlock(psw + i);
}
void CData::CryptBlock(Byte *buf, bool encrypt)
{
Byte inBuf[16];
UInt32 A, B, C, D;
A = GetUi32(buf + 0) ^ Keys[0];
B = GetUi32(buf + 4) ^ Keys[1];
C = GetUi32(buf + 8) ^ Keys[2];
D = GetUi32(buf + 12) ^ Keys[3];
if (!encrypt)
memcpy(inBuf, buf, sizeof(inBuf));
for (unsigned i = 0; i < kNumRounds; i++)
{
UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
UInt32 TA = A ^ SubstLong((C + rotlFixed(D, 11)) ^ key);
UInt32 TB = B ^ SubstLong((D ^ rotlFixed(C, 17)) + key);
A = C; C = TA;
B = D; D = TB;
}
SetUi32(buf + 0, C ^ Keys[0])
SetUi32(buf + 4, D ^ Keys[1])
SetUi32(buf + 8, A ^ Keys[2])
SetUi32(buf + 12, B ^ Keys[3])
UpdateKeys(encrypt ? buf : inBuf);
}
Z7_COM7F_IMF(CDecoder::Init())
{
return S_OK;
}
static const UInt32 kBlockSize = 16;
Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
{
if (size == 0)
return 0;
if (size < kBlockSize)
return kBlockSize;
size -= kBlockSize;
UInt32 i;
for (i = 0; i <= size; i += kBlockSize)
DecryptBlock(data + i);
return i;
}
}}
@@ -0,0 +1,54 @@
// Crypto/Rar20Crypto.h
#ifndef ZIP7_INC_CRYPTO_RAR20_CRYPTO_H
#define ZIP7_INC_CRYPTO_RAR20_CRYPTO_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCrypto {
namespace NRar2 {
/* ICompressFilter::Init() does nothing for this filter.
Call SetPassword() to initialize filter. */
class CData
{
Byte SubstTable[256];
UInt32 Keys[4];
UInt32 SubstLong(UInt32 t) const
{
return (UInt32)SubstTable[(unsigned)t & 255]
| ((UInt32)SubstTable[(unsigned)(t >> 8) & 255] << 8)
| ((UInt32)SubstTable[(unsigned)(t >> 16) & 255] << 16)
| ((UInt32)SubstTable[(unsigned)(t >> 24) ] << 24);
}
void UpdateKeys(const Byte *data);
void CryptBlock(Byte *buf, bool encrypt);
public:
~CData() { Wipe(); }
void Wipe()
{
Z7_memset_0_ARRAY(SubstTable);
Z7_memset_0_ARRAY(Keys);
}
void EncryptBlock(Byte *buf) { CryptBlock(buf, true); }
void DecryptBlock(Byte *buf) { CryptBlock(buf, false); }
void SetPassword(const Byte *password, unsigned passwordLen);
};
class CDecoder Z7_final:
public ICompressFilter,
public CMyUnknownImp,
public CData
{
Z7_COM_UNKNOWN_IMP_0
Z7_IFACE_COM7_IMP(ICompressFilter)
};
}}
#endif
+272
View File
@@ -0,0 +1,272 @@
// Crypto/Rar5Aes.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#ifndef Z7_ST
#include "../../Windows/Synchronization.h"
#endif
#include "HmacSha256.h"
#include "Rar5Aes.h"
#define MY_ALIGN_FOR_SHA256 MY_ALIGN(16)
namespace NCrypto {
namespace NRar5 {
static const unsigned kNumIterationsLog_Max = 24;
static const unsigned kPswCheckCsumSize32 = 1;
static const unsigned kCheckSize32 = kPswCheckSize32 + kPswCheckCsumSize32;
CKey::CKey():
_needCalc(true),
_numIterationsLog(0)
{
for (unsigned i = 0; i < sizeof(_salt); i++)
_salt[i] = 0;
}
CKey::~CKey()
{
Wipe();
}
void CKey::Wipe()
{
_password.Wipe();
Z7_memset_0_ARRAY(_salt);
// Z7_memset_0_ARRAY(_key32);
// Z7_memset_0_ARRAY(_check_Calced32);
// Z7_memset_0_ARRAY(_hashKey32);
CKeyBase::Wipe();
}
CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {}
static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val)
{
*val = 0;
for (unsigned i = 0; i < maxSize && i < 10;)
{
const Byte b = p[i];
*val |= (UInt64)(b & 0x7F) << (7 * i);
i++;
if ((b & 0x80) == 0)
return i;
}
return 0;
}
HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV, bool isService)
{
UInt64 Version;
unsigned num = ReadVarInt(p, size, &Version);
if (num == 0)
return E_NOTIMPL;
p += num;
size -= num;
if (Version != 0)
return E_NOTIMPL;
num = ReadVarInt(p, size, &Flags);
if (num == 0)
return E_NOTIMPL;
p += num;
size -= num;
bool isCheck = IsThereCheck();
if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize32 * 4 : 0))
return E_NOTIMPL;
if (_numIterationsLog != p[0])
{
_numIterationsLog = p[0];
_needCalc = true;
}
p++;
if (memcmp(_salt, p, kSaltSize) != 0)
{
memcpy(_salt, p, kSaltSize);
_needCalc = true;
}
p += kSaltSize;
if (includeIV)
{
memcpy(_iv, p, AES_BLOCK_SIZE);
p += AES_BLOCK_SIZE;
}
_canCheck = true;
if (isCheck)
{
memcpy(_check32, p, sizeof(_check32));
MY_ALIGN_FOR_SHA256
CSha256 sha;
MY_ALIGN_FOR_SHA256
Byte digest[SHA256_DIGEST_SIZE];
Sha256_Init(&sha);
Sha256_Update(&sha, (const Byte *)_check32, sizeof(_check32));
Sha256_Final(&sha, digest);
_canCheck = (memcmp(digest, p + sizeof(_check32), kPswCheckCsumSize32 * 4) == 0);
if (_canCheck && isService)
{
// There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros.
// so we disable password checking for such bad records.
_canCheck = false;
for (unsigned i = 0; i < kPswCheckSize32 * 4; i++)
if (p[i] != 0)
{
_canCheck = true;
break;
}
}
}
return (_numIterationsLog <= kNumIterationsLog_Max ? S_OK : E_NOTIMPL);
}
void CDecoder::SetPassword(const Byte *data, size_t size)
{
if (size != _password.Size() || memcmp(data, _password, size) != 0)
{
_needCalc = true;
_password.Wipe();
_password.CopyFrom(data, size);
}
}
Z7_COM7F_IMF(CDecoder::Init())
{
CalcKey_and_CheckPassword();
RINOK(SetKey((const Byte *)_key32, kAesKeySize))
RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
return CAesCoder::Init();
}
UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const
{
MY_ALIGN_FOR_SHA256
NSha256::CHmac ctx;
ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize);
UInt32 v;
SetUi32a(&v, crc)
ctx.Update((const Byte *)&v, 4);
MY_ALIGN_FOR_SHA256
UInt32 h[SHA256_NUM_DIGEST_WORDS];
ctx.Final((Byte *)h);
crc = 0;
for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++)
crc ^= (UInt32)GetUi32a(h + i);
return crc;
}
void CDecoder::Hmac_Convert_32Bytes(Byte *data) const
{
MY_ALIGN_FOR_SHA256
NSha256::CHmac ctx;
ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize);
ctx.Update(data, NSha256::kDigestSize);
ctx.Final(data);
}
static CKey g_Key;
#ifndef Z7_ST
static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
#define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
#else
#define MT_LOCK
#endif
bool CDecoder::CalcKey_and_CheckPassword()
{
if (_needCalc)
{
{
MT_LOCK
if (!g_Key._needCalc && IsKeyEqualTo(g_Key))
{
CopyCalcedKeysFrom(g_Key);
_needCalc = false;
}
}
if (_needCalc)
{
MY_ALIGN_FOR_SHA256
UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS];
{
// Pbkdf HMAC-SHA-256
MY_ALIGN_FOR_SHA256
NSha256::CHmac baseCtx;
baseCtx.SetKey(_password, _password.Size());
MY_ALIGN_FOR_SHA256
NSha256::CHmac ctx;
ctx = baseCtx;
ctx.Update(_salt, sizeof(_salt));
MY_ALIGN_FOR_SHA256
UInt32 u[SHA256_NUM_DIGEST_WORDS];
MY_ALIGN_FOR_SHA256
UInt32 key[SHA256_NUM_DIGEST_WORDS];
// u[0] = 0;
// u[1] = 0;
// u[2] = 0;
// u[3] = 1;
SetUi32a(u, 0x1000000)
ctx.Update((const Byte *)(const void *)u, 4);
ctx.Final((Byte *)(void *)u);
memcpy(key, u, NSha256::kDigestSize);
UInt32 numIterations = ((UInt32)1 << _numIterationsLog) - 1;
for (unsigned i = 0; i < 3; i++)
{
for (; numIterations != 0; numIterations--)
{
ctx = baseCtx;
ctx.Update((const Byte *)(const void *)u, NSha256::kDigestSize);
ctx.Final((Byte *)(void *)u);
for (unsigned s = 0; s < Z7_ARRAY_SIZE(u); s++)
key[s] ^= u[s];
}
// RAR uses additional iterations for additional keys
memcpy(i == 0 ? _key32 : i == 1 ? _hashKey32 : pswCheck,
key, NSha256::kDigestSize);
numIterations = 16;
}
}
_check_Calced32[0] = pswCheck[0] ^ pswCheck[2] ^ pswCheck[4] ^ pswCheck[6];
_check_Calced32[1] = pswCheck[1] ^ pswCheck[3] ^ pswCheck[5] ^ pswCheck[7];
_needCalc = false;
{
MT_LOCK
g_Key = *this;
}
}
}
if (IsThereCheck() && _canCheck)
return memcmp(_check_Calced32, _check32, sizeof(_check32)) == 0;
return true;
}
}}
+97
View File
@@ -0,0 +1,97 @@
// Crypto/Rar5Aes.h
#ifndef ZIP7_INC_CRYPTO_RAR5_AES_H
#define ZIP7_INC_CRYPTO_RAR5_AES_H
#include "../../../C/Sha256.h"
#include "../../Common/MyBuffer.h"
#include "MyAes.h"
namespace NCrypto {
namespace NRar5 {
const unsigned kSaltSize = 16;
const unsigned kPswCheckSize32 = 2;
const unsigned kAesKeySize = 32;
namespace NCryptoFlags
{
const unsigned kPswCheck = 1 << 0;
const unsigned kUseMAC = 1 << 1;
}
struct CKeyBase
{
protected:
UInt32 _key32[kAesKeySize / 4];
UInt32 _hashKey32[SHA256_NUM_DIGEST_WORDS];
UInt32 _check_Calced32[kPswCheckSize32];
void Wipe()
{
memset(this, 0, sizeof(*this));
}
void CopyCalcedKeysFrom(const CKeyBase &k)
{
*this = k;
}
};
struct CKey: public CKeyBase
{
CByteBuffer _password;
bool _needCalc;
unsigned _numIterationsLog;
Byte _salt[kSaltSize];
bool IsKeyEqualTo(const CKey &key)
{
return _numIterationsLog == key._numIterationsLog
&& memcmp(_salt, key._salt, sizeof(_salt)) == 0
&& _password == key._password;
}
CKey();
~CKey();
void Wipe();
#ifdef Z7_CPP_IS_SUPPORTED_default
// CKey(const CKey &) = default;
CKey& operator =(const CKey &) = default;
#endif
};
class CDecoder Z7_final:
public CAesCbcDecoder,
public CKey
{
UInt32 _check32[kPswCheckSize32];
bool _canCheck;
UInt64 Flags;
bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
public:
Byte _iv[AES_BLOCK_SIZE];
CDecoder();
Z7_COM7F_IMP(Init())
void SetPassword(const Byte *data, size_t size);
HRESULT SetDecoderProps(const Byte *data, unsigned size, bool includeIV, bool isService);
bool CalcKey_and_CheckPassword();
bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
UInt32 Hmac_Convert_Crc32(UInt32 crc) const;
void Hmac_Convert_32Bytes(Byte *data) const;
};
}}
#endif
+202
View File
@@ -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;
}
}}
+54
View File
@@ -0,0 +1,54 @@
// Crypto/RarAes.h
#ifndef ZIP7_INC_CRYPTO_RAR_AES_H
#define ZIP7_INC_CRYPTO_RAR_AES_H
#include "../../../C/Aes.h"
#include "../../Common/MyBuffer.h"
#include "../IPassword.h"
#include "MyAes.h"
namespace NCrypto {
namespace NRar3 {
const unsigned kAesKeySize = 16;
class CDecoder Z7_final:
public CAesCbcDecoder
{
Byte _salt[8];
bool _thereIsSalt;
bool _needCalc;
// bool _rar350Mode;
CByteBuffer _password;
Byte _key[kAesKeySize];
Byte _iv[AES_BLOCK_SIZE];
void CalcKey();
public:
Z7_COM7F_IMP(Init())
void SetPassword(const Byte *data, unsigned size);
HRESULT SetDecoderProperties2(const Byte *data, UInt32 size);
CDecoder();
~CDecoder() Z7_DESTRUCTOR_override { Wipe(); }
void Wipe()
{
_password.Wipe();
Z7_memset_0_ARRAY(_salt);
Z7_memset_0_ARRAY(_key);
Z7_memset_0_ARRAY(_iv);
}
// void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; }
};
}}
#endif
+37
View File
@@ -0,0 +1,37 @@
// Crypto/Sha1Cls.h
#ifndef ZIP7_INC_CRYPTO_SHA1_CLS_H
#define ZIP7_INC_CRYPTO_SHA1_CLS_H
#include "../../../C/Sha1.h"
namespace NCrypto {
namespace NSha1 {
const unsigned kNumBlockWords = SHA1_NUM_BLOCK_WORDS;
const unsigned kNumDigestWords = SHA1_NUM_DIGEST_WORDS;
const unsigned kBlockSize = SHA1_BLOCK_SIZE;
const unsigned kDigestSize = SHA1_DIGEST_SIZE;
class CContext
{
CSha1 _s;
public:
void Init() throw() { Sha1_Init(&_s); }
void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); }
void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); }
void PrepareBlock(Byte *block, unsigned size) const throw()
{
Sha1_PrepareBlock(&_s, block, size);
}
void GetBlockDigest(const Byte *blockData, Byte *destDigest) const throw()
{
Sha1_GetBlockDigest(&_s, blockData, destDigest);
}
};
}}
#endif
+11
View File
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../Common/Common.h"
#endif
+231
View File
@@ -0,0 +1,231 @@
// 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;
}
}}
+161
View File
@@ -0,0 +1,161 @@
// Crypto/WzAes.h
/*
This code implements Brian Gladman's scheme
specified in "A Password Based File Encryption Utility":
- AES encryption (128,192,256-bit) in Counter (CTR) mode.
- HMAC-SHA1 authentication for encrypted data (10 bytes)
- Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and
Salt (saltSize = aesKeySize / 2).
- 2 bytes contain Password Verifier's Code
*/
#ifndef ZIP7_INC_CRYPTO_WZ_AES_H
#define ZIP7_INC_CRYPTO_WZ_AES_H
#include "../../Common/MyBuffer.h"
#include "../IPassword.h"
#include "HmacSha1.h"
#include "MyAes.h"
namespace NCrypto {
namespace NWzAes {
/* ICompressFilter::Init() does nothing for this filter.
Call to init:
Encoder:
CryptoSetPassword();
WriteHeader();
Decoder:
[CryptoSetPassword();]
ReadHeader();
[CryptoSetPassword();] Init_and_CheckPassword();
[CryptoSetPassword();] Init_and_CheckPassword();
*/
const UInt32 kPasswordSizeMax = 99; // 128;
const unsigned kSaltSizeMax = 16;
const unsigned kPwdVerifSize = 2;
const unsigned kMacSize = 10;
enum EKeySizeMode
{
kKeySizeMode_AES128 = 1,
kKeySizeMode_AES192 = 2,
kKeySizeMode_AES256 = 3
};
struct CKeyInfo
{
EKeySizeMode KeySizeMode;
Byte Salt[kSaltSizeMax];
Byte PwdVerifComputed[kPwdVerifSize];
CByteBuffer Password;
unsigned GetKeySize() const { return (8 * KeySizeMode + 8); }
unsigned GetSaltSize() const { return (4 * KeySizeMode + 4); }
unsigned GetNumSaltWords() const { return (KeySizeMode + 1); }
CKeyInfo(): KeySizeMode(kKeySizeMode_AES256) {}
void Wipe()
{
Password.Wipe();
Z7_memset_0_ARRAY(Salt);
Z7_memset_0_ARRAY(PwdVerifComputed);
}
~CKeyInfo() { Wipe(); }
};
/*
struct CAesCtr2
{
unsigned pos;
CAlignedBuffer aes;
UInt32 *Aes() { return (UInt32 *)(Byte *)aes; }
// unsigned offset;
// UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3];
// UInt32 *Aes() { return aes + offset; }
CAesCtr2();
};
void AesCtr2_Init(CAesCtr2 *p);
void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size);
*/
class CBaseCoder:
public ICompressFilter,
public ICryptoSetPassword,
public CMyUnknownImp
{
Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword)
Z7_COM7F_IMP(Init())
public:
Z7_IFACE_COM7_IMP(ICryptoSetPassword)
protected:
CKeyInfo _key;
// NSha1::CHmac _hmac;
// NSha1::CHmac *Hmac() { return &_hmac; }
CAlignedBuffer1 _hmacBuf;
UInt32 _hmacOverCalc;
NSha1::CHmac *Hmac() { return (NSha1::CHmac *)(void *)(Byte *)_hmacBuf; }
// CAesCtr2 _aes;
CAesCoder *_aesCoderSpec;
CMyComPtr<ICompressFilter> _aesCoder;
CBaseCoder():
_hmacBuf(sizeof(NSha1::CHmac))
{
_aesCoderSpec = new CAesCtrCoder(32);
_aesCoder = _aesCoderSpec;
}
void Init2();
public:
unsigned GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifSize; }
unsigned GetAddPackSize() const { return GetHeaderSize() + kMacSize; }
bool SetKeyMode(unsigned mode)
{
if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
return false;
_key.KeySizeMode = (EKeySizeMode)mode;
return true;
}
virtual ~CBaseCoder() {}
};
class CEncoder Z7_final:
public CBaseCoder
{
Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
public:
HRESULT WriteHeader(ISequentialOutStream *outStream);
HRESULT WriteFooter(ISequentialOutStream *outStream);
};
class CDecoder Z7_final:
public CBaseCoder
// public ICompressSetDecoderProperties2
{
Byte _pwdVerifFromArchive[kPwdVerifSize];
Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
public:
// Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
HRESULT ReadHeader(ISequentialInStream *inStream);
bool Init_and_CheckPassword();
HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
};
}}
#endif
@@ -0,0 +1,114 @@
// Crypto/ZipCrypto.cpp
#include "StdAfx.h"
#include "../../../C/7zCrc.h"
#include "../Common/StreamUtils.h"
#include "RandGen.h"
#include "ZipCrypto.h"
namespace NCrypto {
namespace NZip {
#define UPDATE_KEYS(b) { \
key0 = CRC_UPDATE_BYTE(key0, b); \
key1 = (key1 + (key0 & 0xFF)) * 0x8088405 + 1; \
key2 = CRC_UPDATE_BYTE(key2, (Byte)(key1 >> 24)); } \
#define DECRYPT_BYTE_1 UInt32 temp = key2 | 2;
#define DECRYPT_BYTE_2 ((Byte)((temp * (temp ^ 1)) >> 8))
Z7_COM7F_IMF(CCipher::CryptoSetPassword(const Byte *data, UInt32 size))
{
UInt32 key0 = 0x12345678;
UInt32 key1 = 0x23456789;
UInt32 key2 = 0x34567890;
for (UInt32 i = 0; i < size; i++)
UPDATE_KEYS(data[i])
KeyMem0 = key0;
KeyMem1 = key1;
KeyMem2 = key2;
return S_OK;
}
Z7_COM7F_IMF(CCipher::Init())
{
return S_OK;
}
HRESULT CEncoder::WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc)
{
Byte h[kHeaderSize];
/* PKZIP before 2.0 used 2 byte CRC check.
PKZIP 2.0+ used 1 byte CRC check. It's more secure.
We also use 1 byte CRC. */
MY_RAND_GEN(h, kHeaderSize - 1);
// h[kHeaderSize - 2] = (Byte)(crc);
h[kHeaderSize - 1] = (Byte)(crc >> 8);
RestoreKeys();
Filter(h, kHeaderSize);
return WriteStream(outStream, h, kHeaderSize);
}
Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
{
UInt32 key0 = this->Key0;
UInt32 key1 = this->Key1;
UInt32 key2 = this->Key2;
for (UInt32 i = 0; i < size; i++)
{
Byte b = data[i];
DECRYPT_BYTE_1
data[i] = (Byte)(b ^ DECRYPT_BYTE_2);
UPDATE_KEYS(b)
}
this->Key0 = key0;
this->Key1 = key1;
this->Key2 = key2;
return size;
}
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
{
return ReadStream_FAIL(inStream, _header, kHeaderSize);
}
void CDecoder::Init_BeforeDecode()
{
RestoreKeys();
Filter(_header, kHeaderSize);
}
Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
{
UInt32 key0 = this->Key0;
UInt32 key1 = this->Key1;
UInt32 key2 = this->Key2;
for (UInt32 i = 0; i < size; i++)
{
DECRYPT_BYTE_1
Byte b = (Byte)(data[i] ^ DECRYPT_BYTE_2);
UPDATE_KEYS(b)
data[i] = b;
}
this->Key0 = key0;
this->Key1 = key1;
this->Key2 = key2;
return size;
}
}}
@@ -0,0 +1,80 @@
// Crypto/ZipCrypto.h
#ifndef ZIP7_INC_CRYPTO_ZIP_CRYPTO_H
#define ZIP7_INC_CRYPTO_ZIP_CRYPTO_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../IPassword.h"
namespace NCrypto {
namespace NZip {
const unsigned kHeaderSize = 12;
/* ICompressFilter::Init() does nothing for this filter.
Call to init:
Encoder:
CryptoSetPassword();
WriteHeader();
Decoder:
[CryptoSetPassword();]
ReadHeader();
[CryptoSetPassword();] Init_and_GetCrcByte();
[CryptoSetPassword();] Init_and_GetCrcByte();
*/
class CCipher:
public ICompressFilter,
public ICryptoSetPassword,
public CMyUnknownImp
{
Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword)
Z7_COM7F_IMP(Init())
public:
Z7_IFACE_COM7_IMP(ICryptoSetPassword)
protected:
UInt32 Key0;
UInt32 Key1;
UInt32 Key2;
UInt32 KeyMem0;
UInt32 KeyMem1;
UInt32 KeyMem2;
void RestoreKeys()
{
Key0 = KeyMem0;
Key1 = KeyMem1;
Key2 = KeyMem2;
}
public:
virtual ~CCipher()
{
Key0 = KeyMem0 =
Key1 = KeyMem1 =
Key2 = KeyMem2 = 0;
}
};
class CEncoder Z7_final: public CCipher
{
Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
public:
HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc);
};
class CDecoder Z7_final: public CCipher
{
Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
public:
Byte _header[kHeaderSize];
HRESULT ReadHeader(ISequentialInStream *inStream);
void Init_BeforeDecode();
};
}}
#endif
@@ -0,0 +1,265 @@
// Crypto/ZipStrong.cpp
#include "StdAfx.h"
#include "../../../C/7zCrc.h"
#include "../../../C/CpuArch.h"
#include "../Common/StreamUtils.h"
#include "Sha1Cls.h"
#include "ZipStrong.h"
namespace NCrypto {
namespace NZipStrong {
static const UInt16 kAES128 = 0x660E;
/*
DeriveKey() function is similar to CryptDeriveKey() from Windows.
New version of MSDN contains the following condition in CryptDeriveKey() description:
"If the hash is not a member of the SHA-2 family and the required key is for either 3DES or AES".
Now we support ZipStrong for AES only. And it uses SHA1.
Our DeriveKey() code is equal to CryptDeriveKey() in Windows for such conditions: (SHA1 + AES).
if (method != AES && method != 3DES), probably we need another code.
*/
static void DeriveKey2(const UInt32 *digest32, Byte c, UInt32 *dest32)
{
const unsigned kBufSize = 64;
MY_ALIGN (16)
UInt32 buf32[kBufSize / 4];
memset(buf32, c, kBufSize);
for (unsigned i = 0; i < NSha1::kNumDigestWords; i++)
buf32[i] ^= digest32[i];
MY_ALIGN (16)
NSha1::CContext sha;
sha.Init();
sha.Update((const Byte *)buf32, kBufSize);
sha.Final((Byte *)dest32);
}
static void DeriveKey(NSha1::CContext &sha, Byte *key)
{
MY_ALIGN (16)
UInt32 digest32[NSha1::kNumDigestWords];
sha.Final((Byte *)digest32);
MY_ALIGN (16)
UInt32 temp32[NSha1::kNumDigestWords * 2];
DeriveKey2(digest32, 0x36, temp32);
DeriveKey2(digest32, 0x5C, temp32 + NSha1::kNumDigestWords);
memcpy(key, temp32, 32);
}
void CKeyInfo::SetPassword(const Byte *data, UInt32 size)
{
MY_ALIGN (16)
NSha1::CContext sha;
sha.Init();
sha.Update(data, size);
DeriveKey(sha, MasterKey);
}
CDecoder::CDecoder()
{
CAesCbcDecoder *d = new CAesCbcDecoder();
_cbcDecoder = d;
_aesFilter = d;
}
Z7_COM7F_IMF(CDecoder::CryptoSetPassword(const Byte *data, UInt32 size))
{
_key.SetPassword(data, size);
return S_OK;
}
Z7_COM7F_IMF(CDecoder::Init())
{
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
{
return _aesFilter->Filter(data, size);
}
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize)
{
Byte temp[4];
RINOK(ReadStream_FALSE(inStream, temp, 2))
_ivSize = GetUi16(temp);
if (_ivSize == 0)
{
memset(_iv, 0, 16);
SetUi32(_iv + 0, crc)
SetUi64(_iv + 4, unpackSize)
_ivSize = 12;
}
else if (_ivSize == 16)
{
RINOK(ReadStream_FALSE(inStream, _iv, _ivSize))
}
else
return E_NOTIMPL;
RINOK(ReadStream_FALSE(inStream, temp, 4))
_remSize = GetUi32(temp);
// const UInt32 kAlign = 16;
if (_remSize < 16 || _remSize > (1 << 18))
return E_NOTIMPL;
if (_remSize > _bufAligned.Size())
{
_bufAligned.AllocAtLeast(_remSize);
if (!(Byte *)_bufAligned)
return E_OUTOFMEMORY;
}
return ReadStream_FALSE(inStream, _bufAligned, _remSize);
}
HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK)
{
passwOK = false;
if (_remSize < 16)
return E_NOTIMPL;
Byte * const p = _bufAligned;
const unsigned format = GetUi16a(p);
if (format != 3)
return E_NOTIMPL;
unsigned algId = GetUi16a(p + 2);
if (algId < kAES128)
return E_NOTIMPL;
algId -= kAES128;
if (algId > 2)
return E_NOTIMPL;
const unsigned bitLen = GetUi16a(p + 4);
const unsigned flags = GetUi16a(p + 6);
if (algId * 64 + 128 != bitLen)
return E_NOTIMPL;
_key.KeySize = 16 + algId * 8;
const bool cert = ((flags & 2) != 0);
if (flags & 0x4000)
{
// Use 3DES for rd data
return E_NOTIMPL;
}
if (cert)
{
return E_NOTIMPL;
}
else
{
if ((flags & 1) == 0)
return E_NOTIMPL;
}
UInt32 rdSize = GetUi16a(p + 8);
if (rdSize + 16 > _remSize)
return E_NOTIMPL;
const unsigned kPadSize = kAesPadAllign; // is equal to blockSize of cipher for rd
/*
if (cert)
{
if ((rdSize & 0x7) != 0)
return E_NOTIMPL;
}
else
*/
{
// PKCS7 padding
if (rdSize < kPadSize)
return E_NOTIMPL;
if (rdSize & (kPadSize - 1))
return E_NOTIMPL;
}
memmove(p, p + 10, rdSize);
const Byte *p2 = p + rdSize + 10;
UInt32 reserved = GetUi32(p2);
p2 += 4;
/*
if (cert)
{
UInt32 numRecipients = reserved;
if (numRecipients == 0)
return E_NOTIMPL;
{
UInt32 hashAlg = GetUi16(p2);
hashAlg = hashAlg;
UInt32 hashSize = GetUi16(p2 + 2);
hashSize = hashSize;
p2 += 4;
reserved = reserved;
// return E_NOTIMPL;
for (unsigned r = 0; r < numRecipients; r++)
{
UInt32 specSize = GetUi16(p2);
p2 += 2;
p2 += specSize;
}
}
}
else
*/
{
if (reserved != 0)
return E_NOTIMPL;
}
UInt32 validSize = GetUi16(p2);
p2 += 2;
const size_t validOffset = (size_t)(p2 - p);
if ((validSize & 0xF) != 0 || validOffset + validSize != _remSize)
return E_NOTIMPL;
{
RINOK(_cbcDecoder->SetKey(_key.MasterKey, _key.KeySize))
RINOK(_cbcDecoder->SetInitVector(_iv, 16))
// SetInitVector() calls also Init()
RINOK(_cbcDecoder->Init()) // it's optional
Filter(p, rdSize);
rdSize -= kPadSize;
for (unsigned i = 0; i < kPadSize; i++)
if (p[(size_t)rdSize + i] != kPadSize)
return S_OK; // passwOK = false;
}
MY_ALIGN (16)
Byte fileKey[32];
MY_ALIGN (16)
NSha1::CContext sha;
sha.Init();
sha.Update(_iv, _ivSize);
sha.Update(p, rdSize);
DeriveKey(sha, fileKey);
RINOK(_cbcDecoder->SetKey(fileKey, _key.KeySize))
RINOK(_cbcDecoder->SetInitVector(_iv, 16))
// SetInitVector() calls also Init()
RINOK(_cbcDecoder->Init()) // it's optional
memmove(p, p + validOffset, validSize);
Filter(p, validSize);
if (validSize < 4)
return E_NOTIMPL;
validSize -= 4;
if (GetUi32(p + validSize) != CrcCalc(p, validSize))
return S_OK;
passwOK = true;
return S_OK;
}
}}
@@ -0,0 +1,73 @@
// Crypto/ZipStrong.h
#ifndef ZIP7_INC_CRYPTO_ZIP_STRONG_H
#define ZIP7_INC_CRYPTO_ZIP_STRONG_H
#include "../../Common/MyBuffer2.h"
#include "../IPassword.h"
#include "MyAes.h"
namespace NCrypto {
namespace NZipStrong {
/* ICompressFilter::Init() does nothing for this filter.
Call to init:
Decoder:
[CryptoSetPassword();]
ReadHeader();
[CryptoSetPassword();] Init_and_CheckPassword();
[CryptoSetPassword();] Init_and_CheckPassword();
*/
struct CKeyInfo
{
Byte MasterKey[32];
UInt32 KeySize;
void SetPassword(const Byte *data, UInt32 size);
void Wipe()
{
Z7_memset_0_ARRAY(MasterKey);
}
};
const unsigned kAesPadAllign = AES_BLOCK_SIZE;
Z7_CLASS_IMP_COM_2(
CDecoder
, ICompressFilter
, ICryptoSetPassword
)
CAesCbcDecoder *_cbcDecoder;
CMyComPtr<ICompressFilter> _aesFilter;
CKeyInfo _key;
CAlignedBuffer _bufAligned;
UInt32 _ivSize;
Byte _iv[16];
UInt32 _remSize;
public:
HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize);
HRESULT Init_and_CheckPassword(bool &passwOK);
UInt32 GetPadSize(UInt32 packSize32) const
{
// Padding is to align to blockSize of cipher.
// Change it, if is not AES
return kAesPadAllign - (packSize32 & (kAesPadAllign - 1));
}
CDecoder();
~CDecoder() { Wipe(); }
void Wipe()
{
Z7_memset_0_ARRAY(_iv);
_key.Wipe();
}
};
}}
#endif