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,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);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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")
|
||||
|
||||
}}
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user