diff options
Diffstat (limited to 'installerbuilder/libinstaller/3rdparty/p7zip_9.04/unix/CPP/7zip/Crypto/ZipStrong.cpp')
-rw-r--r-- | installerbuilder/libinstaller/3rdparty/p7zip_9.04/unix/CPP/7zip/Crypto/ZipStrong.cpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/installerbuilder/libinstaller/3rdparty/p7zip_9.04/unix/CPP/7zip/Crypto/ZipStrong.cpp b/installerbuilder/libinstaller/3rdparty/p7zip_9.04/unix/CPP/7zip/Crypto/ZipStrong.cpp new file mode 100644 index 000000000..be5b42754 --- /dev/null +++ b/installerbuilder/libinstaller/3rdparty/p7zip_9.04/unix/CPP/7zip/Crypto/ZipStrong.cpp @@ -0,0 +1,177 @@ +// Crypto/ZipStrong.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "MyAes.h" +#include "Sha1.h" +#include "ZipStrong.h" + +namespace NCrypto { +namespace NZipStrong { + +static const UInt16 kAES128 = 0x660E; + +// DeriveKey* function is similar to CryptDeriveKey() from Windows. +// But MSDN tells that we need such scheme only if +// "the required key length is longer than the hash value" +// but ZipStrong uses it always. + +static void DeriveKey2(const Byte *digest, Byte c, Byte *dest) +{ + Byte buf[64]; + memset(buf, c, 64); + for (unsigned i = 0; i < NSha1::kDigestSize; i++) + buf[i] ^= digest[i]; + NSha1::CContext sha; + sha.Init(); + sha.Update(buf, 64); + sha.Final(dest); +} + +static void DeriveKey(NSha1::CContext &sha, Byte *key) +{ + Byte digest[NSha1::kDigestSize]; + sha.Final(digest); + Byte temp[NSha1::kDigestSize * 2]; + DeriveKey2(digest, 0x36, temp); + DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); + memcpy(key, temp, 32); +} + +void CKeyInfo::SetPassword(const Byte *data, UInt32 size) +{ + NSha1::CContext sha; + sha.Init(); + sha.Update(data, size); + DeriveKey(sha, MasterKey); +} + +STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) +{ + _key.SetPassword(data, size); + return S_OK; +} + +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; + /* + SetUi32(_iv, crc); + for (int i = 0; i < 8; i++) + _iv[4 + i] = (Byte)(unpackSize >> (8 * i)); + SetUi32(_iv + 12, 0); + */ + } + else if (_ivSize == 16) + { + RINOK(ReadStream_FALSE(inStream, _iv, _ivSize)); + } + else + return E_NOTIMPL; + RINOK(ReadStream_FALSE(inStream, temp, 4)); + _remSize = GetUi32(temp); + if (_remSize > _buf.GetCapacity()) + { + _buf.Free(); + _buf.SetCapacity(_remSize); + } + return ReadStream_FALSE(inStream, _buf, _remSize); +} + +HRESULT CDecoder::CheckPassword(bool &passwOK) +{ + passwOK = false; + if (_remSize < 10) + return E_NOTIMPL; + Byte *p = _buf; + UInt16 format = GetUi16(p); + if (format != 3) + return E_NOTIMPL; + UInt16 algId = GetUi16(p + 2); + if (algId < kAES128) + return E_NOTIMPL; + algId -= kAES128; + if (algId > 2) + return E_NOTIMPL; + UInt16 bitLen = GetUi16(p + 4); + UInt16 flags = GetUi16(p + 6); + if (algId * 64 + 128 != bitLen) + return E_NOTIMPL; + _key.KeySize = 16 + algId * 8; + if ((flags & 1) == 0) + return E_NOTIMPL; + UInt32 rdSize = GetUi16(p + 8); + UInt32 pos = 10; + Byte *rd = p + pos; + pos += rdSize; + if (pos + 4 > _remSize) + return E_NOTIMPL; + UInt32 reserved = GetUi32(p + pos); + pos += 4; + if (reserved != 0) + return E_NOTIMPL; + if (pos + 2 > _remSize) + return E_NOTIMPL; + UInt32 validSize = GetUi16(p + pos); + pos += 2; + Byte *validData = p + pos; + if (pos + validSize != _remSize) + return E_NOTIMPL; + + if (!_aesFilter) + _aesFilter = new CAesCbcDecoder; + + CMyComPtr<ICryptoProperties> cp; + RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp)); + { + RINOK(cp->SetKey(_key.MasterKey, _key.KeySize)); + RINOK(cp->SetInitVector(_iv, 16)); + _aesFilter->Init(); + if (_aesFilter->Filter(rd, rdSize) != rdSize) + return E_NOTIMPL; + } + + Byte fileKey[32]; + NSha1::CContext sha; + sha.Init(); + sha.Update(_iv, 16); + sha.Update(rd, rdSize - 16); // we don't use last 16 bytes (PAD bytes) + DeriveKey(sha, fileKey); + + RINOK(cp->SetKey(fileKey, _key.KeySize)); + RINOK(cp->SetInitVector(_iv, 16)); + _aesFilter->Init(); + if (_aesFilter->Filter(validData, validSize) != validSize) + return E_NOTIMPL; + + if (validSize < 4) + return E_NOTIMPL; + validSize -= 4; + if (GetUi32(validData + validSize) != CrcCalc(validData, validSize)) + return S_OK; + passwOK = true; + _aesFilter->Init(); + return S_OK; +} + +STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) +{ + return _aesFilter->Filter(data, size); +} + +}} |