mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 01:15:00 -06:00
15.05
This commit is contained in:
committed by
Kornel Lesiński
parent
0713a3ab80
commit
54490d51d5
@@ -4,9 +4,12 @@
|
||||
|
||||
#include "../../../C/Sha256.h"
|
||||
|
||||
#include "../../Windows/Synchronization.h"
|
||||
#include "../../Common/ComTry.h"
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
#include "../../Windows/Synchronization.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "7zAes.h"
|
||||
@@ -16,60 +19,71 @@
|
||||
#include "RandGen.h"
|
||||
#endif
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NSevenZ {
|
||||
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 (UInt32 i = 0; i < SaltSize; i++)
|
||||
for (unsigned i = 0; i < SaltSize; i++)
|
||||
if (Salt[i] != a.Salt[i])
|
||||
return false;
|
||||
return (Password == a.Password);
|
||||
}
|
||||
|
||||
void CKeyInfo::CalculateDigest()
|
||||
void CKeyInfo::CalcKey()
|
||||
{
|
||||
if (NumCyclesPower == 0x3F)
|
||||
{
|
||||
UInt32 pos;
|
||||
unsigned pos;
|
||||
for (pos = 0; pos < SaltSize; pos++)
|
||||
Key[pos] = Salt[pos];
|
||||
for (UInt32 i = 0; i < Password.Size() && pos < kKeySize; i++)
|
||||
for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++)
|
||||
Key[pos++] = Password[i];
|
||||
for (; pos < kKeySize; pos++)
|
||||
Key[pos] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t bufSize = 8 + SaltSize + Password.Size();
|
||||
CObjArray<Byte> buf(bufSize);
|
||||
memcpy(buf, Salt, SaltSize);
|
||||
memcpy(buf + SaltSize, Password, Password.Size());
|
||||
|
||||
CSha256 sha;
|
||||
Sha256_Init(&sha);
|
||||
const UInt64 numRounds = (UInt64)1 << NumCyclesPower;
|
||||
Byte temp[8] = { 0,0,0,0,0,0,0,0 };
|
||||
for (UInt64 round = 0; round < numRounds; round++)
|
||||
|
||||
Byte *ctr = buf + SaltSize + Password.Size();
|
||||
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
ctr[i] = 0;
|
||||
|
||||
UInt64 numRounds = (UInt64)1 << NumCyclesPower;
|
||||
|
||||
do
|
||||
{
|
||||
Sha256_Update(&sha, Salt, (size_t)SaltSize);
|
||||
Sha256_Update(&sha, Password, Password.Size());
|
||||
Sha256_Update(&sha, temp, 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
if (++(temp[i]) != 0)
|
||||
Sha256_Update(&sha, buf, bufSize);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
if (++(ctr[i]) != 0)
|
||||
break;
|
||||
}
|
||||
while(--numRounds != 0);
|
||||
|
||||
Sha256_Final(&sha, Key);
|
||||
}
|
||||
}
|
||||
|
||||
bool CKeyInfoCache::Find(CKeyInfo &key)
|
||||
bool CKeyInfoCache::GetKey(CKeyInfo &key)
|
||||
{
|
||||
FOR_VECTOR (i, Keys)
|
||||
{
|
||||
const CKeyInfo &cached = Keys[i];
|
||||
if (key.IsEqualTo(cached))
|
||||
{
|
||||
for (int j = 0; j < kKeySize; j++)
|
||||
for (unsigned j = 0; j < kKeySize; j++)
|
||||
key.Key[j] = cached.Key[j];
|
||||
if (i != 0)
|
||||
Keys.MoveToFront(i);
|
||||
@@ -79,40 +93,60 @@ bool CKeyInfoCache::Find(CKeyInfo &key)
|
||||
return false;
|
||||
}
|
||||
|
||||
void CKeyInfoCache::Add(CKeyInfo &key)
|
||||
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 (Find(key))
|
||||
return;
|
||||
if (Keys.Size() >= Size)
|
||||
Keys.DeleteBack();
|
||||
Keys.Insert(0, key);
|
||||
}
|
||||
|
||||
static CKeyInfoCache g_GlobalKeyCache(32);
|
||||
static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
|
||||
|
||||
#ifndef _7ZIP_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 (int i = 0; i < sizeof(_iv); i++)
|
||||
for (unsigned i = 0; i < sizeof(_iv); i++)
|
||||
_iv[i] = 0;
|
||||
}
|
||||
|
||||
void CBase::CalculateDigest()
|
||||
void CBase::PrepareKey()
|
||||
{
|
||||
NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
|
||||
if (_cachedKeys.Find(_key))
|
||||
g_GlobalKeyCache.Add(_key);
|
||||
else
|
||||
// BCJ2 threads use same password. So we use long lock.
|
||||
MT_LOCK
|
||||
|
||||
bool finded = false;
|
||||
if (!_cachedKeys.GetKey(_key))
|
||||
{
|
||||
if (!g_GlobalKeyCache.Find(_key))
|
||||
{
|
||||
_key.CalculateDigest();
|
||||
g_GlobalKeyCache.Add(_key);
|
||||
}
|
||||
finded = g_GlobalKeyCache.GetKey(_key);
|
||||
if (!finded)
|
||||
_key.CalcKey();
|
||||
_cachedKeys.Add(_key);
|
||||
}
|
||||
if (!finded)
|
||||
g_GlobalKeyCache.FindAndAdd(_key);
|
||||
}
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
@@ -128,102 +162,114 @@ STDMETHODIMP CEncoder::ResetSalt()
|
||||
|
||||
STDMETHODIMP CEncoder::ResetInitVector()
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(_iv); i++)
|
||||
_iv[i] = 0;
|
||||
_ivSize = 8;
|
||||
g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
|
||||
g_RandomGenerator.Generate(_iv, _ivSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
||||
{
|
||||
// _key.Init();
|
||||
for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
|
||||
_iv[i] = 0;
|
||||
Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
|
||||
unsigned propsSize = 1;
|
||||
|
||||
UInt32 ivSize = _ivSize;
|
||||
|
||||
// _key.NumCyclesPower = 0x3F;
|
||||
_key.NumCyclesPower = 19;
|
||||
props[0] = (Byte)(_key.NumCyclesPower
|
||||
| (_key.SaltSize == 0 ? 0 : (1 << 7))
|
||||
| (_ivSize == 0 ? 0 : (1 << 6)));
|
||||
|
||||
Byte firstByte = (Byte)(_key.NumCyclesPower |
|
||||
(((_key.SaltSize == 0) ? 0 : 1) << 7) |
|
||||
(((ivSize == 0) ? 0 : 1) << 6));
|
||||
RINOK(outStream->Write(&firstByte, 1, NULL));
|
||||
if (_key.SaltSize == 0 && ivSize == 0)
|
||||
return S_OK;
|
||||
Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
|
||||
Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
|
||||
Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
|
||||
RINOK(outStream->Write(&secondByte, 1, NULL));
|
||||
if (_key.SaltSize > 0)
|
||||
if (_key.SaltSize != 0 || _ivSize != 0)
|
||||
{
|
||||
RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
|
||||
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;
|
||||
}
|
||||
if (ivSize > 0)
|
||||
{
|
||||
RINOK(WriteStream(outStream, _iv, ivSize));
|
||||
}
|
||||
return S_OK;
|
||||
|
||||
return WriteStream(outStream, props, propsSize);
|
||||
}
|
||||
|
||||
HRESULT CEncoder::CreateFilter()
|
||||
CEncoder::CEncoder()
|
||||
{
|
||||
// _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
|
||||
// _key.NumCyclesPower = 0x3F;
|
||||
_key.NumCyclesPower = 19;
|
||||
_aesFilter = new CAesCbcEncoder(kKeySize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CDecoder::CDecoder()
|
||||
{
|
||||
_aesFilter = new CAesCbcDecoder(kKeySize);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
_key.Init();
|
||||
UInt32 i;
|
||||
_key.ClearProps();
|
||||
|
||||
_ivSize = 0;
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(_iv); i++)
|
||||
_iv[i] = 0;
|
||||
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
UInt32 pos = 0;
|
||||
Byte firstByte = data[pos++];
|
||||
|
||||
_key.NumCyclesPower = firstByte & 0x3F;
|
||||
if ((firstByte & 0xC0) == 0)
|
||||
return S_OK;
|
||||
_key.SaltSize = (firstByte >> 7) & 1;
|
||||
UInt32 ivSize = (firstByte >> 6) & 1;
|
||||
|
||||
if (pos >= size)
|
||||
return E_INVALIDARG;
|
||||
Byte secondByte = data[pos++];
|
||||
|
||||
_key.SaltSize += (secondByte >> 4);
|
||||
ivSize += (secondByte & 0x0F);
|
||||
|
||||
if (pos + _key.SaltSize + ivSize > size)
|
||||
Byte b0 = data[0];
|
||||
|
||||
_key.NumCyclesPower = b0 & 0x3F;
|
||||
if ((b0 & 0xC0) == 0)
|
||||
return size == 1 ? S_OK : E_INVALIDARG;
|
||||
|
||||
if (size <= 1)
|
||||
return E_INVALIDARG;
|
||||
for (i = 0; i < _key.SaltSize; i++)
|
||||
_key.Salt[i] = data[pos++];
|
||||
|
||||
Byte b1 = data[1];
|
||||
|
||||
unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
|
||||
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[pos++];
|
||||
return (_key.NumCyclesPower <= 24) ? S_OK : E_NOTIMPL;
|
||||
_iv[i] = *data++;
|
||||
return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX
|
||||
|| _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
_key.Password.CopyFrom(data, (size_t)size);
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CBaseCoder::Init()
|
||||
{
|
||||
CalculateDigest();
|
||||
if (_aesFilter == 0)
|
||||
{
|
||||
RINOK(CreateFilter());
|
||||
}
|
||||
COM_TRY_BEGIN
|
||||
|
||||
PrepareKey();
|
||||
CMyComPtr<ICryptoProperties> cp;
|
||||
RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
|
||||
RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
|
||||
if (!cp)
|
||||
return E_FAIL;
|
||||
RINOK(cp->SetKey(_key.Key, kKeySize));
|
||||
RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
|
||||
return _aesFilter->Init();
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
|
||||
@@ -231,10 +277,4 @@ STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
|
||||
return _aesFilter->Filter(data, size);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CreateFilter()
|
||||
{
|
||||
_aesFilter = new CAesCbcDecoder(kKeySize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -11,28 +11,30 @@
|
||||
#include "../IPassword.h"
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NSevenZ {
|
||||
namespace N7z {
|
||||
|
||||
const int kKeySize = 32;
|
||||
const unsigned kKeySize = 32;
|
||||
const unsigned kSaltSizeMax = 16;
|
||||
const unsigned kIvSizeMax = 16; // AES_BLOCK_SIZE;
|
||||
|
||||
class CKeyInfo
|
||||
{
|
||||
public:
|
||||
int NumCyclesPower;
|
||||
UInt32 SaltSize;
|
||||
Byte Salt[16];
|
||||
unsigned NumCyclesPower;
|
||||
unsigned SaltSize;
|
||||
Byte Salt[kSaltSizeMax];
|
||||
CByteBuffer Password;
|
||||
Byte Key[kKeySize];
|
||||
|
||||
bool IsEqualTo(const CKeyInfo &a) const;
|
||||
void CalculateDigest();
|
||||
void CalcKey();
|
||||
|
||||
CKeyInfo() { Init(); }
|
||||
void Init()
|
||||
CKeyInfo() { ClearProps(); }
|
||||
void ClearProps()
|
||||
{
|
||||
NumCyclesPower = 0;
|
||||
SaltSize = 0;
|
||||
for (int i = 0; i < sizeof(Salt); i++)
|
||||
for (unsigned i = 0; i < sizeof(Salt); i++)
|
||||
Salt[i] = 0;
|
||||
}
|
||||
};
|
||||
@@ -43,9 +45,9 @@ class CKeyInfoCache
|
||||
CObjectVector<CKeyInfo> Keys;
|
||||
public:
|
||||
CKeyInfoCache(unsigned size): Size(size) {}
|
||||
bool Find(CKeyInfo &key);
|
||||
// HRESULT Calculate(CKeyInfo &key);
|
||||
void Add(CKeyInfo &key);
|
||||
bool GetKey(CKeyInfo &key);
|
||||
void Add(const CKeyInfo &key);
|
||||
void FindAndAdd(const CKeyInfo &key);
|
||||
};
|
||||
|
||||
class CBase
|
||||
@@ -53,9 +55,10 @@ class CBase
|
||||
CKeyInfoCache _cachedKeys;
|
||||
protected:
|
||||
CKeyInfo _key;
|
||||
Byte _iv[16];
|
||||
UInt32 _ivSize;
|
||||
void CalculateDigest();
|
||||
Byte _iv[kIvSizeMax];
|
||||
unsigned _ivSize;
|
||||
|
||||
void PrepareKey();
|
||||
CBase();
|
||||
};
|
||||
|
||||
@@ -68,13 +71,8 @@ class CBaseCoder:
|
||||
protected:
|
||||
CMyComPtr<ICompressFilter> _aesFilter;
|
||||
|
||||
virtual HRESULT CreateFilter() = 0;
|
||||
#ifndef CRYPTO_AES
|
||||
HRESULT CreateFilterFromDLL(REFCLSID clsID);
|
||||
#endif
|
||||
public:
|
||||
STDMETHOD(Init)();
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
|
||||
INTERFACE_ICompressFilter(;)
|
||||
|
||||
STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
|
||||
};
|
||||
@@ -87,7 +85,6 @@ class CEncoder:
|
||||
// public ICryptoResetSalt,
|
||||
public ICryptoResetInitVector
|
||||
{
|
||||
virtual HRESULT CreateFilter();
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(
|
||||
ICryptoSetPassword,
|
||||
@@ -97,19 +94,21 @@ public:
|
||||
STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
|
||||
// STDMETHOD(ResetSalt)();
|
||||
STDMETHOD(ResetInitVector)();
|
||||
CEncoder();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class CDecoder:
|
||||
public CBaseCoder,
|
||||
public ICompressSetDecoderProperties2
|
||||
{
|
||||
virtual HRESULT CreateFilter();
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICryptoSetPassword,
|
||||
ICompressSetDecoderProperties2)
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
CDecoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -3,16 +3,10 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "7zAes.h"
|
||||
|
||||
static void *CreateCodec() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CDecoder()); }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CEncoder()); }
|
||||
#else
|
||||
#define CreateCodecOut 0
|
||||
#endif
|
||||
|
||||
static CCodecInfo g_CodecInfo =
|
||||
{ CreateCodec, CreateCodecOut, 0x06F10701, L"7zAES", 1, true };
|
||||
|
||||
REGISTER_CODEC(7zAES)
|
||||
REGISTER_FILTER_E(7zAES,
|
||||
NCrypto::N7z::CDecoder(),
|
||||
NCrypto::N7z::CEncoder(),
|
||||
0x6F10701, "7zAES")
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "HmacSha1.h"
|
||||
|
||||
namespace NCrypto {
|
||||
@@ -11,24 +13,29 @@ void CHmac::SetKey(const Byte *key, size_t keySize)
|
||||
{
|
||||
Byte keyTemp[kBlockSize];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < kBlockSize; i++)
|
||||
keyTemp[i] = 0;
|
||||
if(keySize > kBlockSize)
|
||||
|
||||
if (keySize > kBlockSize)
|
||||
{
|
||||
_sha.Init();
|
||||
_sha.Update(key, keySize);
|
||||
_sha.Final(keyTemp);
|
||||
keySize = kDigestSize;
|
||||
}
|
||||
else
|
||||
for (i = 0; i < keySize; i++)
|
||||
keyTemp[i] = key[i];
|
||||
|
||||
for (i = 0; i < kBlockSize; i++)
|
||||
keyTemp[i] ^= 0x36;
|
||||
|
||||
_sha.Init();
|
||||
_sha.Update(keyTemp, kBlockSize);
|
||||
|
||||
for (i = 0; i < kBlockSize; i++)
|
||||
keyTemp[i] ^= 0x36 ^ 0x5C;
|
||||
|
||||
_sha2.Init();
|
||||
_sha2.Update(keyTemp, kBlockSize);
|
||||
}
|
||||
@@ -39,18 +46,20 @@ void CHmac::Final(Byte *mac, size_t macSize)
|
||||
_sha.Final(digest);
|
||||
_sha2.Update(digest, kDigestSize);
|
||||
_sha2.Final(digest);
|
||||
for(size_t i = 0; i < macSize; i++)
|
||||
for (size_t i = 0; i < macSize; i++)
|
||||
mac[i] = digest[i];
|
||||
}
|
||||
|
||||
|
||||
void CHmac32::SetKey(const Byte *key, size_t keySize)
|
||||
{
|
||||
UInt32 keyTemp[kBlockSizeInWords];
|
||||
UInt32 keyTemp[kNumBlockWords];
|
||||
size_t i;
|
||||
for (i = 0; i < kBlockSizeInWords; i++)
|
||||
|
||||
for (i = 0; i < kNumBlockWords; i++)
|
||||
keyTemp[i] = 0;
|
||||
if(keySize > kBlockSize)
|
||||
|
||||
if (keySize > kBlockSize)
|
||||
{
|
||||
CContext sha;
|
||||
sha.Init();
|
||||
@@ -58,50 +67,52 @@ void CHmac32::SetKey(const Byte *key, size_t keySize)
|
||||
Byte digest[kDigestSize];
|
||||
sha.Final(digest);
|
||||
|
||||
for (int i = 0 ; i < kDigestSizeInWords; i++)
|
||||
keyTemp[i] =
|
||||
((UInt32)(digest[i * 4 + 0]) << 24) |
|
||||
((UInt32)(digest[i * 4 + 1]) << 16) |
|
||||
((UInt32)(digest[i * 4 + 2]) << 8) |
|
||||
((UInt32)(digest[i * 4 + 3]));
|
||||
keySize = kDigestSizeInWords;
|
||||
for (i = 0 ; i < kNumDigestWords; i++)
|
||||
keyTemp[i] = GetBe32(digest + i * 4 + 0);
|
||||
}
|
||||
else
|
||||
for (size_t i = 0; i < keySize; i++)
|
||||
for (i = 0; i < keySize; i++)
|
||||
keyTemp[i / 4] |= (key[i] << (24 - 8 * (i & 3)));
|
||||
for (i = 0; i < kBlockSizeInWords; i++)
|
||||
|
||||
for (i = 0; i < kNumBlockWords; i++)
|
||||
keyTemp[i] ^= 0x36363636;
|
||||
|
||||
_sha.Init();
|
||||
_sha.Update(keyTemp, kBlockSizeInWords);
|
||||
for (i = 0; i < kBlockSizeInWords; i++)
|
||||
_sha.Update(keyTemp, kNumBlockWords);
|
||||
|
||||
for (i = 0; i < kNumBlockWords; i++)
|
||||
keyTemp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
|
||||
|
||||
_sha2.Init();
|
||||
_sha2.Update(keyTemp, kBlockSizeInWords);
|
||||
_sha2.Update(keyTemp, kNumBlockWords);
|
||||
}
|
||||
|
||||
void CHmac32::Final(UInt32 *mac, size_t macSize)
|
||||
{
|
||||
UInt32 digest[kDigestSizeInWords];
|
||||
UInt32 digest[kNumDigestWords];
|
||||
_sha.Final(digest);
|
||||
_sha2.Update(digest, kDigestSizeInWords);
|
||||
_sha2.Update(digest, kNumDigestWords);
|
||||
_sha2.Final(digest);
|
||||
for(size_t i = 0; i < macSize; i++)
|
||||
for (size_t i = 0; i < macSize; i++)
|
||||
mac[i] = digest[i];
|
||||
}
|
||||
|
||||
void CHmac32::GetLoopXorDigest(UInt32 *mac, UInt32 numIteration)
|
||||
{
|
||||
UInt32 block[kBlockSizeInWords];
|
||||
UInt32 block2[kBlockSizeInWords];
|
||||
_sha.PrepareBlock(block, kDigestSizeInWords);
|
||||
_sha2.PrepareBlock(block2, kDigestSizeInWords);
|
||||
for(unsigned int s = 0; s < kDigestSizeInWords; s++)
|
||||
UInt32 block[kNumBlockWords];
|
||||
UInt32 block2[kNumBlockWords];
|
||||
|
||||
_sha.PrepareBlock(block, kNumDigestWords);
|
||||
_sha2.PrepareBlock(block2, kNumDigestWords);
|
||||
|
||||
for (unsigned s = 0; s < kNumDigestWords; s++)
|
||||
block[s] = mac[s];
|
||||
for(UInt32 i = 0; i < numIteration; i++)
|
||||
|
||||
for (UInt32 i = 0; i < numIteration; i++)
|
||||
{
|
||||
_sha.GetBlockDigest(block, block2);
|
||||
_sha2.GetBlockDigest(block2, block);
|
||||
for (unsigned int s = 0; s < kDigestSizeInWords; s++)
|
||||
for (unsigned s = 0; s < kNumDigestWords; s++)
|
||||
mac[s] ^= block[s];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#ifndef __CRYPTO_HMAC_SHA1_H
|
||||
#define __CRYPTO_HMAC_SHA1_H
|
||||
|
||||
#include "Sha1.h"
|
||||
#include "Sha1Cls.h"
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NSha1 {
|
||||
@@ -28,9 +28,9 @@ class CHmac32
|
||||
public:
|
||||
void SetKey(const Byte *key, size_t keySize);
|
||||
void Update(const UInt32 *data, size_t dataSize) { _sha.Update(data, dataSize); }
|
||||
void Final(UInt32 *mac, size_t macSize = kDigestSizeInWords);
|
||||
void Final(UInt32 *mac, size_t macSize = kNumDigestWords);
|
||||
|
||||
// It'sa for hmac function. in,out: mac[kDigestSizeInWords].
|
||||
// It'sa for hmac function. in,out: mac[kNumDigestWords].
|
||||
void GetLoopXorDigest(UInt32 *mac, UInt32 numIteration);
|
||||
};
|
||||
|
||||
|
||||
@@ -26,13 +26,17 @@ class CAesCbcCoder:
|
||||
Byte _iv[AES_BLOCK_SIZE];
|
||||
|
||||
bool SetFunctions(UInt32 algo);
|
||||
|
||||
public:
|
||||
CAesCbcCoder(bool encodeMode, unsigned keySize);
|
||||
|
||||
MY_UNKNOWN_IMP2(ICryptoProperties, ICompressSetCoderProperties)
|
||||
STDMETHOD(Init)();
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
|
||||
|
||||
INTERFACE_ICompressFilter(;)
|
||||
|
||||
STDMETHOD(SetKey)(const Byte *data, UInt32 size);
|
||||
STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);
|
||||
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
};
|
||||
|
||||
@@ -46,7 +50,6 @@ struct CAesCbcDecoder: public CAesCbcCoder
|
||||
CAesCbcDecoder(unsigned keySize = 0): CAesCbcCoder(false, keySize) {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,14 +6,7 @@
|
||||
|
||||
#include "MyAes.h"
|
||||
|
||||
static void *CreateCodecCbc() { return (void *)(ICompressFilter *)(new NCrypto::CAesCbcDecoder(32)); }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static void *CreateCodecCbcOut() { return (void *)(ICompressFilter *)(new NCrypto::CAesCbcEncoder(32)); }
|
||||
#else
|
||||
#define CreateCodecCbcOut 0
|
||||
#endif
|
||||
|
||||
static CCodecInfo g_CodecInfo =
|
||||
{ CreateCodecCbc, CreateCodecCbcOut, 0x06F00181, L"AES256CBC", 1, true };
|
||||
REGISTER_CODEC(AES256CBC)
|
||||
|
||||
REGISTER_FILTER_E(AES256CBC,
|
||||
NCrypto::CAesCbcDecoder(32),
|
||||
NCrypto::CAesCbcEncoder(32),
|
||||
0x6F00181, "AES256CBC")
|
||||
@@ -2,26 +2,34 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "HmacSha1.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)
|
||||
void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize,
|
||||
const Byte *salt, size_t saltSize,
|
||||
UInt32 numIterations,
|
||||
Byte *key, size_t keySize)
|
||||
{
|
||||
CHmac baseCtx;
|
||||
baseCtx.SetKey(pwd, pwdSize);
|
||||
for (UInt32 i = 1; keySize > 0; i++)
|
||||
|
||||
for (UInt32 i = 1; keySize != 0; i++)
|
||||
{
|
||||
CHmac ctx = baseCtx;
|
||||
ctx.Update(salt, saltSize);
|
||||
Byte u[kDigestSize] = { (Byte)(i >> 24), (Byte)(i >> 16), (Byte)(i >> 8), (Byte)(i) };
|
||||
const unsigned int curSize = (keySize < kDigestSize) ? (unsigned int)keySize : kDigestSize;
|
||||
|
||||
Byte u[kDigestSize];
|
||||
SetBe32(u, i);
|
||||
|
||||
ctx.Update(u, 4);
|
||||
ctx.Final(u, kDigestSize);
|
||||
|
||||
unsigned int s;
|
||||
const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize;
|
||||
unsigned s;
|
||||
for (s = 0; s < curSize; s++)
|
||||
key[s] = u[s];
|
||||
|
||||
@@ -39,26 +47,32 @@ void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSi
|
||||
}
|
||||
}
|
||||
|
||||
void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize,
|
||||
UInt32 numIterations, UInt32 *key, size_t keySize)
|
||||
void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize,
|
||||
const UInt32 *salt, size_t saltSize,
|
||||
UInt32 numIterations,
|
||||
UInt32 *key, size_t keySize)
|
||||
{
|
||||
CHmac32 baseCtx;
|
||||
baseCtx.SetKey(pwd, pwdSize);
|
||||
for (UInt32 i = 1; keySize > 0; i++)
|
||||
|
||||
for (UInt32 i = 1; keySize != 0; i++)
|
||||
{
|
||||
CHmac32 ctx = baseCtx;
|
||||
ctx.Update(salt, saltSize);
|
||||
UInt32 u[kDigestSizeInWords] = { i };
|
||||
const unsigned int curSize = (keySize < kDigestSizeInWords) ? (unsigned int)keySize : kDigestSizeInWords;
|
||||
|
||||
UInt32 u[kNumDigestWords];
|
||||
u[0] = i;
|
||||
|
||||
ctx.Update(u, 1);
|
||||
ctx.Final(u, kDigestSizeInWords);
|
||||
ctx.Final(u, kNumDigestWords);
|
||||
|
||||
// Speed-optimized code start
|
||||
ctx = baseCtx;
|
||||
ctx.GetLoopXorDigest(u, numIterations - 1);
|
||||
// Speed-optimized code end
|
||||
|
||||
unsigned int s;
|
||||
const unsigned curSize = (keySize < kNumDigestWords) ? (unsigned)keySize : kNumDigestWords;
|
||||
unsigned s;
|
||||
for (s = 0; s < curSize; s++)
|
||||
key[s] = u[s];
|
||||
|
||||
@@ -67,8 +81,8 @@ void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t sa
|
||||
for (UInt32 j = numIterations; j > 1; j--)
|
||||
{
|
||||
ctx = baseCtx;
|
||||
ctx.Update(u, kDigestSizeInWords);
|
||||
ctx.Final(u, kDigestSizeInWords);
|
||||
ctx.Update(u, kNumDigestWords);
|
||||
ctx.Final(u, kNumDigestWords);
|
||||
for (s = 0; s < curSize; s++)
|
||||
key[s] ^= u[s];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
#include "../../Windows/Synchronization.h"
|
||||
#endif
|
||||
|
||||
#include "RandGen.h"
|
||||
|
||||
@@ -85,14 +87,20 @@ void CRandomGenerator::Init()
|
||||
_needInit = false;
|
||||
}
|
||||
|
||||
static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
|
||||
#ifndef _7ZIP_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)
|
||||
{
|
||||
g_CriticalSection.Enter();
|
||||
MT_LOCK
|
||||
|
||||
if (_needInit)
|
||||
Init();
|
||||
while (size > 0)
|
||||
while (size != 0)
|
||||
{
|
||||
CSha256 hash;
|
||||
|
||||
@@ -106,10 +114,9 @@ void CRandomGenerator::Generate(Byte *data, unsigned size)
|
||||
Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
|
||||
Byte buff[SHA256_DIGEST_SIZE];
|
||||
Sha256_Final(&hash, buff);
|
||||
for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size > 0; i++, size--)
|
||||
for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
|
||||
*data++ = buff[i];
|
||||
}
|
||||
g_CriticalSection.Leave();
|
||||
}
|
||||
|
||||
CRandomGenerator g_RandomGenerator;
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
namespace NCrypto {
|
||||
namespace NRar20 {
|
||||
|
||||
static const int kNumRounds = 32;
|
||||
static const unsigned kNumRounds = 32;
|
||||
|
||||
static const Byte InitSubstTable[256] = {
|
||||
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,
|
||||
@@ -34,8 +34,8 @@ static const Byte InitSubstTable[256] = {
|
||||
|
||||
void CData::UpdateKeys(const Byte *data)
|
||||
{
|
||||
for (int i = 0; i < 16; i += 4)
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (unsigned i = 0; i < 16; i += 4)
|
||||
for (unsigned j = 0; j < 4; j++)
|
||||
Keys[j] ^= g_CrcTable[data[i + j]];
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ static void Swap(Byte *b1, Byte *b2)
|
||||
*b2 = b;
|
||||
}
|
||||
|
||||
void CData::SetPassword(const Byte *password, UInt32 passwordLen)
|
||||
void CData::SetPassword(const Byte *data, UInt32 size)
|
||||
{
|
||||
Keys[0] = 0xD3A3B879L;
|
||||
Keys[1] = 0x3F6D12F7L;
|
||||
@@ -54,19 +54,22 @@ void CData::SetPassword(const Byte *password, UInt32 passwordLen)
|
||||
Keys[3] = 0xA4E7F123L;
|
||||
|
||||
Byte psw[256];
|
||||
if (size >= sizeof(psw))
|
||||
size = sizeof(psw) - 1;
|
||||
memset(psw, 0, sizeof(psw));
|
||||
memcpy(psw, password, passwordLen);
|
||||
memcpy(SubstTable, InitSubstTable, sizeof(SubstTable));
|
||||
if (size != 0)
|
||||
memcpy(psw, data, size);
|
||||
memcpy(SubstTable, g_InitSubstTable, sizeof(SubstTable));
|
||||
|
||||
for (UInt32 j = 0; j < 256; j++)
|
||||
for (UInt32 i = 0; i < passwordLen; i += 2)
|
||||
for (UInt32 i = 0; i < size; i += 2)
|
||||
{
|
||||
UInt32 n2 = (Byte)g_CrcTable[(psw[i + 1] + j) & 0xFF];
|
||||
UInt32 n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF];
|
||||
for (UInt32 k = 1; (n1 & 0xFF) != n2; n1++, k++)
|
||||
Swap(&SubstTable[n1 & 0xFF], &SubstTable[(n1 + i + k) & 0xFF]);
|
||||
}
|
||||
for (UInt32 i = 0; i < passwordLen; i+= 16)
|
||||
for (UInt32 i = 0; i < size; i += 16)
|
||||
EncryptBlock(&psw[i]);
|
||||
}
|
||||
|
||||
@@ -83,7 +86,7 @@ void CData::CryptBlock(Byte *buf, bool encrypt)
|
||||
if (!encrypt)
|
||||
memcpy(inBuf, buf, sizeof(inBuf));
|
||||
|
||||
for (int i = 0; i < kNumRounds; i++)
|
||||
for (unsigned i = 0; i < kNumRounds; i++)
|
||||
{
|
||||
UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
|
||||
T = ((C + rotlFixed(D, 11)) ^ key);
|
||||
|
||||
@@ -11,17 +11,20 @@
|
||||
namespace NCrypto {
|
||||
namespace NRar20 {
|
||||
|
||||
/* ICompressFilter::Init() does nothing for this filter.
|
||||
Call CryptoSetPassword() to initialize filter. */
|
||||
|
||||
class CData
|
||||
{
|
||||
Byte SubstTable[256];
|
||||
UInt32 Keys[4];
|
||||
|
||||
UInt32 SubstLong(UInt32 t)
|
||||
UInt32 SubstLong(UInt32 t) const
|
||||
{
|
||||
return (UInt32)SubstTable[(int)t & 255] |
|
||||
((UInt32)SubstTable[(int)(t >> 8) & 255] << 8) |
|
||||
((UInt32)SubstTable[(int)(t >> 16) & 255] << 16) |
|
||||
((UInt32)SubstTable[(int)(t >> 24) & 255] << 24);
|
||||
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) & 255] << 24);
|
||||
}
|
||||
void UpdateKeys(const Byte *data);
|
||||
void CryptBlock(Byte *buf, bool encrypt);
|
||||
@@ -34,7 +37,8 @@ public:
|
||||
class CDecoder:
|
||||
public ICompressFilter,
|
||||
public ICryptoSetPassword,
|
||||
public CMyUnknownImp
|
||||
public CMyUnknownImp,
|
||||
public CData
|
||||
{
|
||||
CData _cipher;
|
||||
public:
|
||||
|
||||
@@ -4,32 +4,36 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "RarAes.h"
|
||||
#include "Sha1.h"
|
||||
#include "Sha1Cls.h"
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NRar29 {
|
||||
|
||||
CDecoder::CDecoder():
|
||||
CAesCbcDecoder(kRarAesKeySize),
|
||||
_thereIsSalt(false),
|
||||
_needCalculate(true),
|
||||
_rar350Mode(false)
|
||||
CAesCbcDecoder(kRarAesKeySize),
|
||||
_thereIsSalt(false),
|
||||
_needCalc(true),
|
||||
_rar350Mode(false)
|
||||
{
|
||||
for (int i = 0; i < sizeof(_salt); i++)
|
||||
for (unsigned i = 0; i < sizeof(_salt); i++)
|
||||
_salt[i] = 0;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
bool thereIsSaltPrev = _thereIsSalt;
|
||||
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 == thereIsSaltPrev)
|
||||
if (_thereIsSalt == prev)
|
||||
{
|
||||
same = true;
|
||||
if (_thereIsSalt)
|
||||
@@ -44,91 +48,88 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
}
|
||||
for (unsigned i = 0; i < sizeof(_salt); i++)
|
||||
_salt[i] = data[i];
|
||||
if (!_needCalculate && !same)
|
||||
_needCalculate = true;
|
||||
if (!_needCalc && !same)
|
||||
_needCalc = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const unsigned kMaxPasswordLength = 127 * 2;
|
||||
static const unsigned kPasswordLen_MAX = 127 * 2;
|
||||
|
||||
STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size > kMaxPasswordLength)
|
||||
size = kMaxPasswordLength;
|
||||
if (size > kPasswordLen_MAX)
|
||||
size = kPasswordLen_MAX;
|
||||
bool same = false;
|
||||
if (size == buffer.Size())
|
||||
if (size == _password.Size())
|
||||
{
|
||||
same = true;
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
if (data[i] != buffer[i])
|
||||
if (data[i] != _password[i])
|
||||
{
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_needCalculate && !same)
|
||||
_needCalculate = true;
|
||||
buffer.CopyFrom(data, (size_t)size);
|
||||
if (!_needCalc && !same)
|
||||
_needCalc = true;
|
||||
_password.CopyFrom(data, (size_t)size);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Init()
|
||||
{
|
||||
Calculate();
|
||||
RINOK(SetKey(aesKey, kRarAesKeySize));
|
||||
RINOK(SetInitVector(_aesInit, AES_BLOCK_SIZE));
|
||||
CalcKey();
|
||||
RINOK(SetKey(_key, kRarAesKeySize));
|
||||
RINOK(SetInitVector(_iv, AES_BLOCK_SIZE));
|
||||
return CAesCbcCoder::Init();
|
||||
}
|
||||
|
||||
void CDecoder::Calculate()
|
||||
void CDecoder::CalcKey()
|
||||
{
|
||||
if (_needCalculate)
|
||||
{
|
||||
const unsigned kSaltSize = 8;
|
||||
|
||||
Byte rawPassword[kMaxPasswordLength + kSaltSize];
|
||||
|
||||
memcpy(rawPassword, buffer, buffer.Size());
|
||||
|
||||
size_t rawLength = buffer.Size();
|
||||
|
||||
if (_thereIsSalt)
|
||||
{
|
||||
memcpy(rawPassword + rawLength, _salt, kSaltSize);
|
||||
rawLength += kSaltSize;
|
||||
}
|
||||
|
||||
NSha1::CContext sha;
|
||||
sha.Init();
|
||||
if (!_needCalc)
|
||||
return;
|
||||
|
||||
// rar reverts hash for sha.
|
||||
const unsigned kNumRounds = (1 << 18);
|
||||
unsigned i;
|
||||
for (i = 0; i < kNumRounds; i++)
|
||||
{
|
||||
sha.UpdateRar(rawPassword, rawLength, _rar350Mode);
|
||||
Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
|
||||
sha.UpdateRar(pswNum, 3, _rar350Mode);
|
||||
if (i % (kNumRounds / 16) == 0)
|
||||
{
|
||||
NSha1::CContext shaTemp = sha;
|
||||
Byte digest[NSha1::kDigestSize];
|
||||
shaTemp.Final(digest);
|
||||
_aesInit[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3];
|
||||
}
|
||||
}
|
||||
/*
|
||||
// it's test message for sha
|
||||
const char *message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||
sha.Update((const Byte *)message, strlen(message));
|
||||
*/
|
||||
Byte digest[20];
|
||||
sha.Final(digest);
|
||||
for (i = 0; i < 4; i++)
|
||||
for (unsigned j = 0; j < 4; j++)
|
||||
aesKey[i * 4 + j] = (digest[i * 4 + 3 - j]);
|
||||
const unsigned kSaltSize = 8;
|
||||
|
||||
Byte buf[kPasswordLen_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;
|
||||
}
|
||||
_needCalculate = false;
|
||||
|
||||
NSha1::CContext sha;
|
||||
sha.Init();
|
||||
|
||||
Byte digest[NSha1::kDigestSize];
|
||||
// rar reverts hash for sha.
|
||||
const UInt32 kNumRounds = (1 << 18);
|
||||
UInt32 i;
|
||||
for (i = 0; i < kNumRounds; i++)
|
||||
{
|
||||
sha.UpdateRar(buf, rawSize, _rar350Mode);
|
||||
Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
|
||||
sha.UpdateRar(pswNum, 3, _rar350Mode);
|
||||
if (i % (kNumRounds / 16) == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -18,22 +18,24 @@ const UInt32 kRarAesKeySize = 16;
|
||||
|
||||
class CDecoder:
|
||||
public CAesCbcDecoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
// public ICompressSetDecoderProperties2,
|
||||
public ICryptoSetPassword
|
||||
{
|
||||
Byte _salt[8];
|
||||
bool _thereIsSalt;
|
||||
CByteBuffer buffer;
|
||||
Byte aesKey[kRarAesKeySize];
|
||||
Byte _aesInit[AES_BLOCK_SIZE];
|
||||
bool _needCalculate;
|
||||
bool _needCalc;
|
||||
bool _rar350Mode;
|
||||
|
||||
CByteBuffer _password;
|
||||
|
||||
Byte _key[kRarAesKeySize];
|
||||
Byte _iv[AES_BLOCK_SIZE];
|
||||
|
||||
void Calculate();
|
||||
void CalcKey();
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICryptoSetPassword,
|
||||
ICompressSetDecoderProperties2)
|
||||
MY_UNKNOWN_IMP1(
|
||||
ICryptoSetPassword)
|
||||
// ICompressSetDecoderProperties2
|
||||
STDMETHOD(Init)();
|
||||
STDMETHOD(CryptoSetPassword)(const Byte *aData, UInt32 aSize);
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
// Crypto/Sha1.cpp
|
||||
// This file is based on public domain
|
||||
// Steve Reid and Wei Dai's code from Crypto++
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/RotateDefs.h"
|
||||
|
||||
#include "Sha1.h"
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NSha1 {
|
||||
|
||||
// define it for speed optimization
|
||||
// #define _SHA1_UNROLL
|
||||
|
||||
static const unsigned kNumW =
|
||||
#ifdef _SHA1_UNROLL
|
||||
16;
|
||||
#else
|
||||
80;
|
||||
#endif
|
||||
|
||||
|
||||
#define w0(i) (W[(i)] = data[(i)])
|
||||
|
||||
#ifdef _SHA1_UNROLL
|
||||
#define w1(i) (W[(i)&15] = rotlFixed(W[((i)-3)&15] ^ W[((i)-8)&15] ^ W[((i)-14)&15] ^ W[((i)-16)&15], 1))
|
||||
#else
|
||||
#define w1(i) (W[(i)] = rotlFixed(W[(i)-3] ^ W[(i)-8] ^ W[(i)-14] ^ W[(i)-16], 1))
|
||||
#endif
|
||||
|
||||
#define f1(x,y,z) (z^(x&(y^z)))
|
||||
#define f2(x,y,z) (x^y^z)
|
||||
#define f3(x,y,z) ((x&y)|(z&(x|y)))
|
||||
#define f4(x,y,z) (x^y^z)
|
||||
|
||||
#define RK1(a,b,c,d,e,i, f, w, k) e += f(b,c,d) + w(i) + k + rotlFixed(a,5); b = rotlFixed(b,30);
|
||||
|
||||
#define R0(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f1, w0, 0x5A827999)
|
||||
#define R1(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f1, w1, 0x5A827999)
|
||||
#define R2(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f2, w1, 0x6ED9EBA1)
|
||||
#define R3(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f3, w1, 0x8F1BBCDC)
|
||||
#define R4(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f4, w1, 0xCA62C1D6)
|
||||
|
||||
#define RX_1_4(rx1, rx4, i) rx1(a,b,c,d,e,i); rx4(e,a,b,c,d,i+1); rx4(d,e,a,b,c,i+2); rx4(c,d,e,a,b,i+3); rx4(b,c,d,e,a,i+4);
|
||||
#define RX_5(rx, i) RX_1_4(rx, rx, i);
|
||||
|
||||
void CContextBase::Init()
|
||||
{
|
||||
_state[0] = 0x67452301;
|
||||
_state[1] = 0xEFCDAB89;
|
||||
_state[2] = 0x98BADCFE;
|
||||
_state[3] = 0x10325476;
|
||||
_state[4] = 0xC3D2E1F0;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
void CContextBase::GetBlockDigest(UInt32 *data, UInt32 *destDigest, bool returnRes)
|
||||
{
|
||||
UInt32 a, b, c, d, e;
|
||||
UInt32 W[kNumW];
|
||||
|
||||
a = _state[0];
|
||||
b = _state[1];
|
||||
c = _state[2];
|
||||
d = _state[3];
|
||||
e = _state[4];
|
||||
#ifdef _SHA1_UNROLL
|
||||
RX_5(R0, 0); RX_5(R0, 5); RX_5(R0, 10);
|
||||
#else
|
||||
int i;
|
||||
for (i = 0; i < 15; i += 5) { RX_5(R0, i); }
|
||||
#endif
|
||||
|
||||
RX_1_4(R0, R1, 15);
|
||||
|
||||
|
||||
#ifdef _SHA1_UNROLL
|
||||
RX_5(R2, 20); RX_5(R2, 25); RX_5(R2, 30); RX_5(R2, 35);
|
||||
RX_5(R3, 40); RX_5(R3, 45); RX_5(R3, 50); RX_5(R3, 55);
|
||||
RX_5(R4, 60); RX_5(R4, 65); RX_5(R4, 70); RX_5(R4, 75);
|
||||
#else
|
||||
i = 20;
|
||||
for (; i < 40; i += 5) { RX_5(R2, i); }
|
||||
for (; i < 60; i += 5) { RX_5(R3, i); }
|
||||
for (; i < 80; i += 5) { RX_5(R4, i); }
|
||||
#endif
|
||||
|
||||
destDigest[0] = _state[0] + a;
|
||||
destDigest[1] = _state[1] + b;
|
||||
destDigest[2] = _state[2] + c;
|
||||
destDigest[3] = _state[3] + d;
|
||||
destDigest[4] = _state[4] + e;
|
||||
|
||||
if (returnRes)
|
||||
for (int i = 0 ; i < 16; i++)
|
||||
data[i] = W[kNumW - 16 + i];
|
||||
|
||||
// Wipe variables
|
||||
// a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
void CContextBase::PrepareBlock(UInt32 *block, unsigned size) const
|
||||
{
|
||||
unsigned curBufferPos = size & 0xF;
|
||||
block[curBufferPos++] = 0x80000000;
|
||||
while (curBufferPos != (16 - 2))
|
||||
block[curBufferPos++] = 0;
|
||||
const UInt64 lenInBits = (_count << 9) + ((UInt64)size << 5);
|
||||
block[curBufferPos++] = (UInt32)(lenInBits >> 32);
|
||||
block[curBufferPos++] = (UInt32)(lenInBits);
|
||||
}
|
||||
|
||||
void CContext::Update(const Byte *data, size_t size)
|
||||
{
|
||||
unsigned curBufferPos = _count2;
|
||||
while (size--)
|
||||
{
|
||||
unsigned pos = (curBufferPos & 3);
|
||||
if (pos == 0)
|
||||
_buffer[curBufferPos >> 2] = 0;
|
||||
_buffer[curBufferPos >> 2] |= ((UInt32)*data++) << (8 * (3 - pos));
|
||||
if (++curBufferPos == kBlockSize)
|
||||
{
|
||||
curBufferPos = 0;
|
||||
CContextBase::UpdateBlock(_buffer, false);
|
||||
}
|
||||
}
|
||||
_count2 = curBufferPos;
|
||||
}
|
||||
|
||||
void CContext::UpdateRar(Byte *data, size_t size, bool rar350Mode)
|
||||
{
|
||||
bool returnRes = false;
|
||||
unsigned curBufferPos = _count2;
|
||||
while (size--)
|
||||
{
|
||||
unsigned pos = (curBufferPos & 3);
|
||||
if (pos == 0)
|
||||
_buffer[curBufferPos >> 2] = 0;
|
||||
_buffer[curBufferPos >> 2] |= ((UInt32)*data++) << (8 * (3 - pos));
|
||||
if (++curBufferPos == kBlockSize)
|
||||
{
|
||||
curBufferPos = 0;
|
||||
CContextBase::UpdateBlock(_buffer, returnRes);
|
||||
if (returnRes)
|
||||
for (unsigned i = 0; i < kBlockSizeInWords; i++)
|
||||
{
|
||||
UInt32 d = _buffer[i];
|
||||
data[(int)i * 4 + 0 - (int)kBlockSize] = (Byte)(d);
|
||||
data[(int)i * 4 + 1 - (int)kBlockSize] = (Byte)(d >> 8);
|
||||
data[(int)i * 4 + 2 - (int)kBlockSize] = (Byte)(d >> 16);
|
||||
data[(int)i * 4 + 3 - (int)kBlockSize] = (Byte)(d >> 24);
|
||||
}
|
||||
returnRes = rar350Mode;
|
||||
}
|
||||
}
|
||||
_count2 = curBufferPos;
|
||||
}
|
||||
|
||||
void CContext::Final(Byte *digest)
|
||||
{
|
||||
const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 3);
|
||||
unsigned curBufferPos = _count2;
|
||||
unsigned pos = (curBufferPos & 3);
|
||||
curBufferPos >>= 2;
|
||||
if (pos == 0)
|
||||
_buffer[curBufferPos] = 0;
|
||||
_buffer[curBufferPos++] |= ((UInt32)0x80) << (8 * (3 - pos));
|
||||
|
||||
while (curBufferPos != (16 - 2))
|
||||
{
|
||||
curBufferPos &= 0xF;
|
||||
if (curBufferPos == 0)
|
||||
UpdateBlock();
|
||||
_buffer[curBufferPos++] = 0;
|
||||
}
|
||||
_buffer[curBufferPos++] = (UInt32)(lenInBits >> 32);
|
||||
_buffer[curBufferPos++] = (UInt32)(lenInBits);
|
||||
UpdateBlock();
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < kDigestSizeInWords; i++)
|
||||
{
|
||||
UInt32 state = _state[i] & 0xFFFFFFFF;
|
||||
*digest++ = (Byte)(state >> 24);
|
||||
*digest++ = (Byte)(state >> 16);
|
||||
*digest++ = (Byte)(state >> 8);
|
||||
*digest++ = (Byte)(state);
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Words version
|
||||
|
||||
void CContext32::Update(const UInt32 *data, size_t size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
_buffer[_count2++] = *data++;
|
||||
if (_count2 == kBlockSizeInWords)
|
||||
{
|
||||
_count2 = 0;
|
||||
UpdateBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CContext32::Final(UInt32 *digest)
|
||||
{
|
||||
const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 5);
|
||||
unsigned curBufferPos = _count2;
|
||||
_buffer[curBufferPos++] = 0x80000000;
|
||||
while (curBufferPos != (16 - 2))
|
||||
{
|
||||
curBufferPos &= 0xF;
|
||||
if (curBufferPos == 0)
|
||||
UpdateBlock();
|
||||
_buffer[curBufferPos++] = 0;
|
||||
}
|
||||
_buffer[curBufferPos++] = (UInt32)(lenInBits >> 32);
|
||||
_buffer[curBufferPos++] = (UInt32)(lenInBits);
|
||||
GetBlockDigest(_buffer, digest);
|
||||
Init();
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Crypto/Sha1.h
|
||||
// This file is based on public domain
|
||||
// Steve Reid and Wei Dai's code from Crypto++
|
||||
|
||||
#ifndef __CRYPTO_SHA1_H
|
||||
#define __CRYPTO_SHA1_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../../Common/MyTypes.h"
|
||||
|
||||
// Sha1 implementation in RAR before version 3.60 has bug:
|
||||
// it changes data bytes in some cases.
|
||||
// So this class supports both versions: normal_SHA and rar3Mode
|
||||
|
||||
namespace NCrypto {
|
||||
namespace NSha1 {
|
||||
|
||||
const unsigned kBlockSize = 64;
|
||||
const unsigned kDigestSize = 20;
|
||||
|
||||
const unsigned kBlockSizeInWords = (kBlockSize >> 2);
|
||||
const unsigned kDigestSizeInWords = (kDigestSize >> 2);
|
||||
|
||||
class CContextBase
|
||||
{
|
||||
protected:
|
||||
UInt32 _state[5];
|
||||
UInt64 _count;
|
||||
void UpdateBlock(UInt32 *data, bool returnRes = false)
|
||||
{
|
||||
GetBlockDigest(data, _state, returnRes);
|
||||
_count++;
|
||||
}
|
||||
public:
|
||||
void Init();
|
||||
void GetBlockDigest(UInt32 *blockData, UInt32 *destDigest, bool returnRes = false);
|
||||
// PrepareBlock can be used only when size <= 13. size in Words
|
||||
void PrepareBlock(UInt32 *block, unsigned int size) const;
|
||||
};
|
||||
|
||||
class CContextBase2: public CContextBase
|
||||
{
|
||||
protected:
|
||||
unsigned _count2;
|
||||
UInt32 _buffer[kBlockSizeInWords];
|
||||
void UpdateBlock() { CContextBase::UpdateBlock(_buffer); }
|
||||
public:
|
||||
void Init() { CContextBase::Init(); _count2 = 0; }
|
||||
};
|
||||
|
||||
class CContext: public CContextBase2
|
||||
{
|
||||
public:
|
||||
void Update(const Byte *data, size_t size);
|
||||
void UpdateRar(Byte *data, size_t size, bool rar350Mode);
|
||||
void Final(Byte *digest);
|
||||
};
|
||||
|
||||
class CContext32: public CContextBase2
|
||||
{
|
||||
public:
|
||||
void Update(const UInt32 *data, size_t size);
|
||||
void Final(UInt32 *digest);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
51
CPP/7zip/Crypto/Sha1Cls.h
Normal file
51
CPP/7zip/Crypto/Sha1Cls.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Crypto/Sha1.h
|
||||
|
||||
#ifndef __CRYPTO_SHA1_H
|
||||
#define __CRYPTO_SHA1_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 CContextBase
|
||||
{
|
||||
protected:
|
||||
CSha1 _s;
|
||||
|
||||
public:
|
||||
void Init() throw() { Sha1_Init(&_s); }
|
||||
void GetBlockDigest(const UInt32 *blockData, UInt32 *destDigest) throw() { Sha1_GetBlockDigest(&_s, blockData, destDigest); }
|
||||
};
|
||||
|
||||
class CContext: public CContextBase
|
||||
{
|
||||
public:
|
||||
void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); }
|
||||
void UpdateRar(Byte *data, size_t size, bool rar350Mode) throw() { Sha1_Update_Rar(&_s, data, size, rar350Mode ? 1 : 0); }
|
||||
void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); }
|
||||
};
|
||||
|
||||
class CContext32: public CContextBase
|
||||
{
|
||||
public:
|
||||
void Update(const UInt32 *data, size_t size) throw() { Sha1_32_Update(&_s, data, size); }
|
||||
void Final(UInt32 *digest) throw() { Sha1_32_Final(&_s, digest); }
|
||||
|
||||
/* PrepareBlock can be used only when size <= 13. size in Words
|
||||
_buffer must be empty (_count & 0xF) == 0) */
|
||||
void PrepareBlock(UInt32 *block, unsigned size) const throw()
|
||||
{
|
||||
Sha1_32_PrepareBlock(&_s, block, size);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
// Sha1Reg.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "Sha1.h"
|
||||
|
||||
using namespace NCrypto;
|
||||
using namespace NSha1;
|
||||
|
||||
class CSha1Hasher:
|
||||
public IHasher,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CContext _sha;
|
||||
public:
|
||||
CSha1Hasher() { Init(); }
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD_(void, Init)();
|
||||
STDMETHOD_(void, Update)(const void *data, UInt32 size);
|
||||
STDMETHOD_(void, Final)(Byte *digest);
|
||||
STDMETHOD_(UInt32, GetDigestSize)();
|
||||
};
|
||||
|
||||
STDMETHODIMP_(void) CSha1Hasher::Init()
|
||||
{
|
||||
_sha.Init();
|
||||
}
|
||||
|
||||
STDMETHODIMP_(void) CSha1Hasher::Update(const void *data, UInt32 size)
|
||||
{
|
||||
_sha.Update((const Byte *)data, size);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(void) CSha1Hasher::Final(Byte *digest)
|
||||
{
|
||||
_sha.Final(digest);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CSha1Hasher::GetDigestSize()
|
||||
{
|
||||
return kDigestSize;
|
||||
}
|
||||
|
||||
static IHasher *CreateHasher() { return new CSha1Hasher; }
|
||||
|
||||
static CHasherInfo g_HasherInfo = { CreateHasher, 0x201, L"SHA1", kDigestSize };
|
||||
|
||||
REGISTER_HASHER(Sha1)
|
||||
@@ -1,21 +1,22 @@
|
||||
// Crypto/WzAes.cpp
|
||||
/*
|
||||
This code implements Brian Gladman's scheme
|
||||
specified in password Based File Encryption Utility.
|
||||
specified in "A Password Based File Encryption Utility".
|
||||
|
||||
Note: you must include MyAes.cpp to project to initialize AES tables
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/StreamObjects.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Pbkdf2HmacSha1.h"
|
||||
#include "RandGen.h"
|
||||
#include "WzAes.h"
|
||||
|
||||
// define it if you don't want to use speed-optimized version of Pbkdf2HmacSha1
|
||||
// define it if you don't want to use speed-optimized version of NSha1::Pbkdf2Hmac
|
||||
// #define _NO_WZAES_OPTIMIZATIONS
|
||||
|
||||
namespace NCrypto {
|
||||
@@ -33,69 +34,72 @@ STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef _NO_WZAES_OPTIMIZATIONS
|
||||
|
||||
static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, unsigned destSize)
|
||||
void CBaseCoder::Init2()
|
||||
{
|
||||
for (unsigned i = 0; i < destSize; i++)
|
||||
dest[i] =
|
||||
((UInt32)(src[i * 4 + 0]) << 24) |
|
||||
((UInt32)(src[i * 4 + 1]) << 16) |
|
||||
((UInt32)(src[i * 4 + 2]) << 8) |
|
||||
((UInt32)(src[i * 4 + 3]));
|
||||
}
|
||||
const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4;
|
||||
Byte dk[dkSizeMax32 * 4];
|
||||
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CBaseCoder::Init()
|
||||
{
|
||||
UInt32 keySize = _key.GetKeySize();
|
||||
UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize;
|
||||
Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize];
|
||||
const unsigned keySize = _key.GetKeySize();
|
||||
const unsigned dkSize = 2 * keySize + kPwdVerifSize;
|
||||
|
||||
// for (unsigned ii = 0; ii < 1000; ii++)
|
||||
{
|
||||
#ifdef _NO_WZAES_OPTIMIZATIONS
|
||||
|
||||
NSha1::Pbkdf2Hmac(
|
||||
_key.Password, _key.Password.Size(),
|
||||
_key.Salt, _key.GetSaltSize(),
|
||||
kNumKeyGenIterations,
|
||||
buf, keysTotalSize);
|
||||
_key.Password, _key.Password.Size(),
|
||||
_key.Salt, _key.GetSaltSize(),
|
||||
kNumKeyGenIterations,
|
||||
dk, dkSize);
|
||||
|
||||
#else
|
||||
|
||||
UInt32 buf32[(2 * kAesKeySizeMax + kPwdVerifCodeSize + 3) / 4];
|
||||
UInt32 key32SizeTotal = (keysTotalSize + 3) / 4;
|
||||
UInt32 salt[kSaltSizeMax * 4];
|
||||
UInt32 saltSizeInWords = _key.GetSaltSize() / 4;
|
||||
BytesToBeUInt32s(_key.Salt, salt, saltSizeInWords);
|
||||
UInt32 dk32[dkSizeMax32];
|
||||
const unsigned dkSize32 = (dkSize + 3) / 4;
|
||||
UInt32 salt[kSaltSizeMax / 4];
|
||||
unsigned numSaltWords = _key.GetNumSaltWords();
|
||||
|
||||
for (unsigned i = 0; i < numSaltWords; i++)
|
||||
{
|
||||
const Byte *src = _key.Salt + i * 4;
|
||||
salt[i] = GetBe32(src);
|
||||
}
|
||||
|
||||
NSha1::Pbkdf2Hmac32(
|
||||
_key.Password, _key.Password.Size(),
|
||||
salt, saltSizeInWords,
|
||||
kNumKeyGenIterations,
|
||||
buf32, key32SizeTotal);
|
||||
for (UInt32 j = 0; j < keysTotalSize; j++)
|
||||
buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3)));
|
||||
_key.Password, _key.Password.Size(),
|
||||
salt, numSaltWords,
|
||||
kNumKeyGenIterations,
|
||||
dk32, dkSize32);
|
||||
|
||||
/*
|
||||
for (unsigned j = 0; j < dkSize; j++)
|
||||
dk[j] = (Byte)(dk32[j / 4] >> (24 - 8 * (j & 3)));
|
||||
*/
|
||||
for (unsigned j = 0; j < dkSize32; j++)
|
||||
SetBe32(dk + j * 4, dk32[j]);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
_hmac.SetKey(buf + keySize, keySize);
|
||||
memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize);
|
||||
_hmac.SetKey(dk + keySize, keySize);
|
||||
memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize);
|
||||
|
||||
Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, buf, keySize);
|
||||
Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, dk, keySize);
|
||||
AesCtr2_Init(&_aes);
|
||||
}
|
||||
|
||||
STDMETHODIMP CBaseCoder::Init()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
|
||||
{
|
||||
UInt32 saltSize = _key.GetSaltSize();
|
||||
unsigned saltSize = _key.GetSaltSize();
|
||||
g_RandomGenerator.Generate(_key.Salt, saltSize);
|
||||
Init();
|
||||
Init2();
|
||||
RINOK(WriteStream(outStream, _key.Salt, saltSize));
|
||||
return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize);
|
||||
return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize);
|
||||
}
|
||||
|
||||
HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
|
||||
@@ -105,6 +109,7 @@ HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
|
||||
return WriteStream(outStream, mac, kMacSize);
|
||||
}
|
||||
|
||||
/*
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size != 1)
|
||||
@@ -112,32 +117,34 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
_key.Init();
|
||||
return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
|
||||
}
|
||||
*/
|
||||
|
||||
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
|
||||
{
|
||||
UInt32 saltSize = _key.GetSaltSize();
|
||||
UInt32 extraSize = saltSize + kPwdVerifCodeSize;
|
||||
Byte temp[kSaltSizeMax + kPwdVerifCodeSize];
|
||||
unsigned saltSize = _key.GetSaltSize();
|
||||
unsigned extraSize = saltSize + kPwdVerifSize;
|
||||
Byte temp[kSaltSizeMax + kPwdVerifSize];
|
||||
RINOK(ReadStream_FAIL(inStream, temp, extraSize));
|
||||
UInt32 i;
|
||||
unsigned i;
|
||||
for (i = 0; i < saltSize; i++)
|
||||
_key.Salt[i] = temp[i];
|
||||
for (i = 0; i < kPwdVerifCodeSize; i++)
|
||||
for (i = 0; i < kPwdVerifSize; i++)
|
||||
_pwdVerifFromArchive[i] = temp[saltSize + i];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size)
|
||||
static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size)
|
||||
{
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
if (p1[i] != p2[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDecoder::CheckPasswordVerifyCode()
|
||||
bool CDecoder::Init_and_CheckPassword()
|
||||
{
|
||||
return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize);
|
||||
Init2();
|
||||
return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
|
||||
@@ -165,12 +172,15 @@ void AesCtr2_Init(CAesCtr2 *p)
|
||||
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 + p->offset;
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
if (pos != AES_BLOCK_SIZE)
|
||||
{
|
||||
const Byte *buf = (const Byte *)buf32;
|
||||
@@ -178,6 +188,7 @@ void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
|
||||
*data++ ^= buf[pos++];
|
||||
while (--size != 0 && pos != AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (size >= 16)
|
||||
{
|
||||
SizeT size2 = size >> 4;
|
||||
@@ -187,6 +198,7 @@ void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
|
||||
size -= size2;
|
||||
pos = AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
unsigned j;
|
||||
@@ -200,9 +212,12 @@ void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
|
||||
*data++ ^= buf[pos++];
|
||||
while (--size != 0);
|
||||
}
|
||||
|
||||
p->pos = pos;
|
||||
}
|
||||
|
||||
/* (size != 16 * N) is allowed only for last Filter() call */
|
||||
|
||||
STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
AesCtr2_Code(&_aes, data, size);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Crypto/WzAes.h
|
||||
/*
|
||||
This code implements Brian Gladman's scheme
|
||||
specified in password Based File Encryption Utility:
|
||||
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
|
||||
@@ -25,13 +25,24 @@ specified in password Based File Encryption Utility:
|
||||
namespace NCrypto {
|
||||
namespace NWzAes {
|
||||
|
||||
const unsigned kSaltSizeMax = 16;
|
||||
const unsigned kMacSize = 10;
|
||||
/* 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;
|
||||
|
||||
// Password Verification Code Size
|
||||
const unsigned kPwdVerifCodeSize = 2;
|
||||
const unsigned kSaltSizeMax = 16;
|
||||
const unsigned kPwdVerifSize = 2;
|
||||
const unsigned kMacSize = 10;
|
||||
|
||||
enum EKeySizeMode
|
||||
{
|
||||
@@ -40,20 +51,19 @@ enum EKeySizeMode
|
||||
kKeySizeMode_AES256 = 3
|
||||
};
|
||||
|
||||
class CKeyInfo
|
||||
struct CKeyInfo
|
||||
{
|
||||
public:
|
||||
EKeySizeMode KeySizeMode;
|
||||
Byte Salt[kSaltSizeMax];
|
||||
Byte PwdVerifComputed[kPwdVerifCodeSize];
|
||||
Byte PwdVerifComputed[kPwdVerifSize];
|
||||
|
||||
CByteBuffer Password;
|
||||
|
||||
UInt32 GetKeySize() const { return (8 * (KeySizeMode & 3) + 8); }
|
||||
UInt32 GetSaltSize() const { return (4 * (KeySizeMode & 3) + 4); }
|
||||
unsigned GetKeySize() const { return (8 * KeySizeMode + 8); }
|
||||
unsigned GetSaltSize() const { return (4 * KeySizeMode + 4); }
|
||||
unsigned GetNumSaltWords() const { return (KeySizeMode + 1); }
|
||||
|
||||
CKeyInfo() { Init(); }
|
||||
void Init() { KeySizeMode = kKeySizeMode_AES256; }
|
||||
CKeyInfo(): KeySizeMode(kKeySizeMode_AES256) {}
|
||||
};
|
||||
|
||||
struct CAesCtr2
|
||||
@@ -75,16 +85,19 @@ class CBaseCoder:
|
||||
protected:
|
||||
CKeyInfo _key;
|
||||
NSha1::CHmac _hmac;
|
||||
Byte _pwdVerifFromArchive[kPwdVerifCodeSize];
|
||||
CAesCtr2 _aes;
|
||||
|
||||
void Init2();
|
||||
public:
|
||||
STDMETHOD(Init)();
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) = 0;
|
||||
|
||||
MY_UNKNOWN_IMP1(ICryptoSetPassword)
|
||||
|
||||
STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
|
||||
|
||||
UInt32 GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifCodeSize; }
|
||||
STDMETHOD(Init)();
|
||||
|
||||
unsigned GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifSize; }
|
||||
unsigned GetAddPackSize() const { return GetHeaderSize() + kMacSize; }
|
||||
|
||||
bool SetKeyMode(unsigned mode)
|
||||
{
|
||||
if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
|
||||
@@ -98,24 +111,22 @@ class CEncoder:
|
||||
public CBaseCoder
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICryptoSetPassword)
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
|
||||
HRESULT WriteHeader(ISequentialOutStream *outStream);
|
||||
HRESULT WriteFooter(ISequentialOutStream *outStream);
|
||||
};
|
||||
|
||||
class CDecoder:
|
||||
public CBaseCoder,
|
||||
public ICompressSetDecoderProperties2
|
||||
public CBaseCoder
|
||||
// public ICompressSetDecoderProperties2
|
||||
{
|
||||
Byte _pwdVerifFromArchive[kPwdVerifSize];
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICryptoSetPassword,
|
||||
ICompressSetDecoderProperties2)
|
||||
// ICompressSetDecoderProperties2
|
||||
// STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
HRESULT ReadHeader(ISequentialInStream *inStream);
|
||||
bool CheckPasswordVerifyCode();
|
||||
bool Init_and_CheckPassword();
|
||||
HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
|
||||
};
|
||||
|
||||
|
||||
@@ -12,23 +12,27 @@
|
||||
namespace NCrypto {
|
||||
namespace NZip {
|
||||
|
||||
void CCipher::UpdateKeys(Byte b)
|
||||
{
|
||||
Keys[0] = CRC_UPDATE_BYTE(Keys[0], b);
|
||||
Keys[1] = (Keys[1] + (Keys[0] & 0xFF)) * 0x8088405 + 1;
|
||||
Keys[2] = CRC_UPDATE_BYTE(Keys[2], (Byte)(Keys[1] >> 24));
|
||||
}
|
||||
#define UPDATE_KEYS(b) { \
|
||||
Key0 = CRC_UPDATE_BYTE(Key0, b); \
|
||||
Key1 = (Key1 + (Key0 & 0xFF)) * 0x8088405 + 1; \
|
||||
Key2 = CRC_UPDATE_BYTE(Key2, (Byte)(Key1 >> 24)); } \
|
||||
|
||||
STDMETHODIMP CCipher::CryptoSetPassword(const Byte *password, UInt32 passwordLen)
|
||||
#define DECRYPT_BYTE_1 UInt32 temp = Key2 | 2;
|
||||
#define DECRYPT_BYTE_2 ((Byte)((temp * (temp ^ 1)) >> 8))
|
||||
|
||||
STDMETHODIMP CCipher::CryptoSetPassword(const Byte *data, UInt32 size)
|
||||
{
|
||||
Keys[0] = 0x12345678;
|
||||
Keys[1] = 0x23456789;
|
||||
Keys[2] = 0x34567890;
|
||||
UInt32 i;
|
||||
for (i = 0; i < passwordLen; i++)
|
||||
UpdateKeys(password[i]);
|
||||
for (i = 0; i < 3; i++)
|
||||
Keys2[i] = Keys[i];
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -37,18 +41,18 @@ STDMETHODIMP CCipher::Init()
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Byte CCipher::DecryptByteSpec()
|
||||
{
|
||||
UInt32 temp = Keys[2] | 2;
|
||||
return (Byte)((temp * (temp ^ 1)) >> 8);
|
||||
}
|
||||
|
||||
HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream, UInt32 crc)
|
||||
HRESULT CEncoder::WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc)
|
||||
{
|
||||
Byte h[kHeaderSize];
|
||||
g_RandomGenerator.Generate(h, kHeaderSize - 2);
|
||||
h[kHeaderSize - 1] = (Byte)(crc >> 24);
|
||||
h[kHeaderSize - 2] = (Byte)(crc >> 16);
|
||||
|
||||
/* 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. */
|
||||
|
||||
g_RandomGenerator.Generate(h, kHeaderSize - 1);
|
||||
// h[kHeaderSize - 2] = (Byte)(crc);
|
||||
h[kHeaderSize - 1] = (Byte)(crc >> 8);
|
||||
|
||||
RestoreKeys();
|
||||
Filter(h, kHeaderSize);
|
||||
return WriteStream(outStream, h, kHeaderSize);
|
||||
@@ -56,32 +60,54 @@ HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream, UInt32 crc)
|
||||
|
||||
STDMETHODIMP_(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];
|
||||
data[i] = (Byte)(b ^ DecryptByteSpec());;
|
||||
UpdateKeys(b);
|
||||
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)
|
||||
{
|
||||
Byte h[kHeaderSize];
|
||||
RINOK(ReadStream_FAIL(inStream, h, kHeaderSize));
|
||||
return ReadStream_FAIL(inStream, _header, kHeaderSize);
|
||||
}
|
||||
|
||||
void CDecoder::Init_BeforeDecode()
|
||||
{
|
||||
RestoreKeys();
|
||||
Filter(h, kHeaderSize);
|
||||
return S_OK;
|
||||
Filter(_header, kHeaderSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(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++)
|
||||
{
|
||||
Byte c = (Byte)(data[i] ^ DecryptByteSpec());
|
||||
UpdateKeys(c);
|
||||
data[i] = c;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,24 +13,41 @@ 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
|
||||
{
|
||||
UInt32 Keys[3];
|
||||
UInt32 Keys2[3];
|
||||
|
||||
protected:
|
||||
void UpdateKeys(Byte b);
|
||||
Byte DecryptByteSpec();
|
||||
UInt32 Key0;
|
||||
UInt32 Key1;
|
||||
UInt32 Key2;
|
||||
|
||||
UInt32 KeyMem0;
|
||||
UInt32 KeyMem1;
|
||||
UInt32 KeyMem2;
|
||||
|
||||
void RestoreKeys()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
Keys[i] = Keys2[i];
|
||||
Key0 = KeyMem0;
|
||||
Key1 = KeyMem1;
|
||||
Key2 = KeyMem2;
|
||||
}
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICryptoSetPassword)
|
||||
STDMETHOD(Init)();
|
||||
STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
|
||||
};
|
||||
@@ -38,17 +55,17 @@ public:
|
||||
class CEncoder: public CCipher
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICryptoSetPassword)
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
|
||||
HRESULT WriteHeader(ISequentialOutStream *outStream, UInt32 crc);
|
||||
HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc);
|
||||
};
|
||||
|
||||
class CDecoder: public CCipher
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICryptoSetPassword)
|
||||
Byte _header[kHeaderSize];
|
||||
STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
|
||||
HRESULT ReadHeader(ISequentialInStream *inStream);
|
||||
void Init_BeforeDecode();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "MyAes.h"
|
||||
#include "Sha1.h"
|
||||
#include "Sha1Cls.h"
|
||||
#include "ZipStrong.h"
|
||||
|
||||
namespace NCrypto {
|
||||
@@ -57,25 +56,22 @@ STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 /* crc */, UInt64 /* unpackSize */)
|
||||
STDMETHODIMP CBaseCoder::Init()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize)
|
||||
{
|
||||
Byte temp[4];
|
||||
RINOK(ReadStream_FALSE(inStream, temp, 2));
|
||||
_ivSize = GetUi16(temp);
|
||||
if (_ivSize == 0)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
|
||||
/* we don't know how to decode that case:
|
||||
From Appnote: If IVSize is 0,then IV = CRC32 + Uncompressed File Size (as a 64 bit little-endian, unsigned integer value).
|
||||
But it doesn't work. If you know solution, please write about it to 7-Zip developers. */
|
||||
|
||||
/*
|
||||
memset(_iv, 0, 16);
|
||||
// unpackSize += crc;
|
||||
SetUi32(_iv + 0, crc);
|
||||
SetUi64(_iv + 4, unpackSize);
|
||||
*/
|
||||
_ivSize = 12;
|
||||
}
|
||||
else if (_ivSize == 16)
|
||||
{
|
||||
@@ -96,7 +92,7 @@ HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 /* crc */, UI
|
||||
return ReadStream_FALSE(inStream, _bufAligned, _remSize);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CheckPassword(bool &passwOK)
|
||||
HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK)
|
||||
{
|
||||
passwOK = false;
|
||||
if (_remSize < 16)
|
||||
@@ -146,7 +142,7 @@ HRESULT CDecoder::CheckPassword(bool &passwOK)
|
||||
Byte fileKey[32];
|
||||
NSha1::CContext sha;
|
||||
sha.Init();
|
||||
sha.Update(_iv, 16);
|
||||
sha.Update(_iv, _ivSize);
|
||||
sha.Update(p, rdSize - 16); // we don't use last 16 bytes (PAD bytes)
|
||||
DeriveKey(sha, fileKey);
|
||||
|
||||
@@ -161,8 +157,6 @@ HRESULT CDecoder::CheckPassword(bool &passwOK)
|
||||
if (GetUi32(validData + validSize) != CrcCalc(validData, validSize))
|
||||
return S_OK;
|
||||
passwOK = true;
|
||||
/* 9.31: The BUG in 9.24-9.30 was fixed.
|
||||
We don't need to call CAesCbcCoder::Init() to reset IV for data. */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,20 @@
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -28,6 +38,7 @@ protected:
|
||||
CByteBuffer _buf;
|
||||
Byte *_bufAligned;
|
||||
public:
|
||||
STDMETHOD(Init)();
|
||||
STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
|
||||
};
|
||||
|
||||
@@ -39,7 +50,7 @@ class CDecoder: public CBaseCoder
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICryptoSetPassword)
|
||||
HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize);
|
||||
HRESULT CheckPassword(bool &passwOK);
|
||||
HRESULT Init_and_CheckPassword(bool &passwOK);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user