This commit is contained in:
Igor Pavlov
2015-06-15 00:00:00 +00:00
committed by Kornel Lesiński
parent 0713a3ab80
commit 54490d51d5
591 changed files with 34932 additions and 16390 deletions

View File

@@ -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;
}
}}

View File

@@ -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();
};
}}

View File

@@ -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")

View File

@@ -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];
}
}

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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")

View File

@@ -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];
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;
}
}}

View File

@@ -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);

View File

@@ -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();
}
}}

View File

@@ -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
View 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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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;
}

View File

@@ -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();
};
}}

View File

@@ -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;
}

View File

@@ -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);
};
}}