summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/unix/CPP/7zip/Crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Crypto')
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp244
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h117
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp109
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h39
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h38
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp83
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp107
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp133
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h50
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp134
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h47
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp229
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h68
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp221
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h125
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp88
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h56
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp164
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h47
23 files changed, 2207 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp
new file mode 100644
index 000000000..b686fb61f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp
@@ -0,0 +1,244 @@
+// 7zAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Sha256.h"
+
+#include "Windows/Synchronization.h"
+
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "7zAes.h"
+#include "MyAes.h"
+
+#ifndef EXTRACT_ONLY
+#include "RandGen.h"
+#endif
+
+using namespace NWindows;
+
+namespace NCrypto {
+namespace NSevenZ {
+
+bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
+{
+ if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
+ return false;
+ for (UInt32 i = 0; i < SaltSize; i++)
+ if (Salt[i] != a.Salt[i])
+ return false;
+ return (Password == a.Password);
+}
+
+void CKeyInfo::CalculateDigest()
+{
+ if (NumCyclesPower == 0x3F)
+ {
+ UInt32 pos;
+ for (pos = 0; pos < SaltSize; pos++)
+ Key[pos] = Salt[pos];
+ for (UInt32 i = 0; i < Password.GetCapacity() && pos < kKeySize; i++)
+ Key[pos++] = Password[i];
+ for (; pos < kKeySize; pos++)
+ Key[pos] = 0;
+ }
+ else
+ {
+ 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++)
+ {
+ Sha256_Update(&sha, Salt, (size_t)SaltSize);
+ Sha256_Update(&sha, Password, Password.GetCapacity());
+ Sha256_Update(&sha, temp, 8);
+ for (int i = 0; i < 8; i++)
+ if (++(temp[i]) != 0)
+ break;
+ }
+ Sha256_Final(&sha, Key);
+ }
+}
+
+bool CKeyInfoCache::Find(CKeyInfo &key)
+{
+ for (int i = 0; i < Keys.Size(); i++)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ for (int j = 0; j < kKeySize; j++)
+ key.Key[j] = cached.Key[j];
+ if (i != 0)
+ {
+ Keys.Insert(0, cached);
+ Keys.Delete(i+1);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyInfoCache::Add(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;
+
+CBase::CBase():
+ _cachedKeys(16),
+ _ivSize(0)
+{
+ for (int i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+}
+
+void CBase::CalculateDigest()
+{
+ NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
+ if (_cachedKeys.Find(_key))
+ g_GlobalKeyCache.Add(_key);
+ else
+ {
+ if (!g_GlobalKeyCache.Find(_key))
+ {
+ _key.CalculateDigest();
+ g_GlobalKeyCache.Add(_key);
+ }
+ _cachedKeys.Add(_key);
+ }
+}
+
+#ifndef EXTRACT_ONLY
+
+/*
+STDMETHODIMP CEncoder::ResetSalt()
+{
+ _key.SaltSize = 4;
+ g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CEncoder::ResetInitVector()
+{
+ _ivSize = 8;
+ g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ // _key.Init();
+ for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+
+ UInt32 ivSize = _ivSize;
+
+ // _key.NumCyclesPower = 0x3F;
+ _key.NumCyclesPower = 19;
+
+ 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)
+ {
+ RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
+ }
+ if (ivSize > 0)
+ {
+ RINOK(WriteStream(outStream, _iv, ivSize));
+ }
+ return S_OK;
+}
+
+HRESULT CEncoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcEncoder;
+ return S_OK;
+}
+
+#endif
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ _key.Init();
+ UInt32 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)
+ return E_INVALIDARG;
+ for (i = 0; i < _key.SaltSize; i++)
+ _key.Salt[i] = data[pos++];
+ for (i = 0; i < ivSize; i++)
+ _iv[i] = data[pos++];
+ return (_key.NumCyclesPower <= 24) ? S_OK : E_NOTIMPL;
+}
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _key.Password.SetCapacity((size_t)size);
+ memcpy(_key.Password, data, (size_t)size);
+ return S_OK;
+}
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ CalculateDigest();
+ if (_aesFilter == 0)
+ {
+ RINOK(CreateFilter());
+ }
+ CMyComPtr<ICryptoProperties> cp;
+ RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
+ RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
+ RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
+{
+ return _aesFilter->Filter(data, size);
+}
+
+HRESULT CDecoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcDecoder;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h
new file mode 100644
index 000000000..79d723fae
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h
@@ -0,0 +1,117 @@
+// 7zAes.h
+
+#ifndef __CRYPTO_7Z_AES_H
+#define __CRYPTO_7Z_AES_H
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NSevenZ {
+
+const int kKeySize = 32;
+
+class CKeyInfo
+{
+public:
+ int NumCyclesPower;
+ UInt32 SaltSize;
+ Byte Salt[16];
+ CByteBuffer Password;
+ Byte Key[kKeySize];
+
+ bool IsEqualTo(const CKeyInfo &a) const;
+ void CalculateDigest();
+
+ CKeyInfo() { Init(); }
+ void Init()
+ {
+ NumCyclesPower = 0;
+ SaltSize = 0;
+ for (int i = 0; i < sizeof(Salt); i++)
+ Salt[i] = 0;
+ }
+};
+
+class CKeyInfoCache
+{
+ int Size;
+ CObjectVector<CKeyInfo> Keys;
+public:
+ CKeyInfoCache(int size): Size(size) {}
+ bool Find(CKeyInfo &key);
+ // HRESULT Calculate(CKeyInfo &key);
+ void Add(CKeyInfo &key);
+};
+
+class CBase
+{
+ CKeyInfoCache _cachedKeys;
+protected:
+ CKeyInfo _key;
+ Byte _iv[16];
+ UInt32 _ivSize;
+ void CalculateDigest();
+ CBase();
+};
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp,
+ public CBase
+{
+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);
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public CBaseCoder,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP3(
+ ICryptoSetPassword,
+ ICompressWriteCoderProperties,
+ // ICryptoResetSalt,
+ ICryptoResetInitVector)
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+ // STDMETHOD(ResetSalt)();
+ STDMETHOD(ResetInitVector)();
+};
+#endif
+
+class CDecoder:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp
new file mode 100644
index 000000000..5e57748f5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp
@@ -0,0 +1,18 @@
+// 7zAesRegister.cpp
+
+#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)
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp
new file mode 100644
index 000000000..a66d62711
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp
@@ -0,0 +1,109 @@
+// HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+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)
+ {
+ _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);
+}
+
+void CHmac::Final(Byte *mac, size_t macSize)
+{
+ Byte digest[kDigestSize];
+ _sha.Final(digest);
+ _sha2.Update(digest, kDigestSize);
+ _sha2.Final(digest);
+ for(size_t i = 0; i < macSize; i++)
+ mac[i] = digest[i];
+}
+
+
+void CHmac32::SetKey(const Byte *key, size_t keySize)
+{
+ UInt32 keyTemp[kBlockSizeInWords];
+ size_t i;
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] = 0;
+ if(keySize > kBlockSize)
+ {
+ CContext sha;
+ sha.Init();
+ sha.Update(key, 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;
+ }
+ else
+ for (size_t i = 0; i < keySize; i++)
+ keyTemp[i / 4] |= (key[i] << (24 - 8 * (i & 3)));
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] ^= 0x36363636;
+ _sha.Init();
+ _sha.Update(keyTemp, kBlockSizeInWords);
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
+ _sha2.Init();
+ _sha2.Update(keyTemp, kBlockSizeInWords);
+}
+
+void CHmac32::Final(UInt32 *mac, size_t macSize)
+{
+ UInt32 digest[kDigestSizeInWords];
+ _sha.Final(digest);
+ _sha2.Update(digest, kDigestSizeInWords);
+ _sha2.Final(digest);
+ 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++)
+ block[s] = mac[s];
+ for(UInt32 i = 0; i < numIteration; i++)
+ {
+ _sha.GetBlockDigest(block, block2);
+ _sha2.GetBlockDigest(block2, block);
+ for (unsigned int s = 0; s < kDigestSizeInWords; s++)
+ mac[s] ^= block[s];
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h
new file mode 100644
index 000000000..d7181329c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h
@@ -0,0 +1,39 @@
+// HmacSha1.h
+// Implements HMAC-SHA-1 (RFC2104, FIPS-198)
+
+#ifndef __CRYPTO_HMAC_SHA1_H
+#define __CRYPTO_HMAC_SHA1_H
+
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+// Use: SetKey(key, keySize); for () Update(data, size); Final(mac, macSize);
+
+class CHmac
+{
+ CContext _sha;
+ CContext _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); }
+ void Final(Byte *mac, size_t macSize = kDigestSize);
+};
+
+class CHmac32
+{
+ CContext32 _sha;
+ CContext32 _sha2;
+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);
+
+ // It'sa for hmac function. in,out: mac[kDigestSizeInWords].
+ void GetLoopXorDigest(UInt32 *mac, UInt32 numIteration);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp
new file mode 100644
index 000000000..70a7dccff
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp
@@ -0,0 +1,48 @@
+// Crypto/MyAes.cpp
+
+#include "StdAfx.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+
+struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
+
+CAesCbcCoder::CAesCbcCoder()
+{
+ _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
+}
+
+STDMETHODIMP CAesCbcCoder::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CAesCbcCoder::Filter(Byte *data, UInt32 size)
+{
+ if (size == 0)
+ return 0;
+ if (size < AES_BLOCK_SIZE)
+ return AES_BLOCK_SIZE;
+ size >>= 4;
+ _codeFunc(_aes + _offset, data, size);
+ return size << 4;
+}
+
+STDMETHODIMP CAesCbcCoder::SetKey(const Byte *data, UInt32 size)
+{
+ if ((size & 0x7) != 0 || size < 16 || size > 32)
+ return E_INVALIDARG;
+ _setKeyFunc(_aes + _offset + 4, data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CAesCbcCoder::SetInitVector(const Byte *data, UInt32 size)
+{
+ if (size != AES_BLOCK_SIZE)
+ return E_INVALIDARG;
+ AesCbc_Init(_aes + _offset, data);
+ return S_OK;
+}
+
+CAesCbcEncoder::CAesCbcEncoder() { _codeFunc = g_AesCbc_Encode; _setKeyFunc = Aes_SetKey_Enc; }
+CAesCbcDecoder::CAesCbcDecoder() { _codeFunc = g_AesCbc_Decode; _setKeyFunc = Aes_SetKey_Dec; }
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h
new file mode 100644
index 000000000..60b13845f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h
@@ -0,0 +1,38 @@
+// Crypto/MyAes.h
+
+#ifndef __CRYPTO_MY_AES_H
+#define __CRYPTO_MY_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCrypto {
+
+class CAesCbcCoder:
+ public ICompressFilter,
+ public ICryptoProperties,
+ public CMyUnknownImp
+{
+protected:
+ AES_CODE_FUNC _codeFunc;
+ AES_SET_KEY_FUNC _setKeyFunc;
+ unsigned _offset;
+ UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];
+public:
+ CAesCbcCoder();
+ MY_UNKNOWN_IMP1(ICryptoProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetKey)(const Byte *data, UInt32 size);
+ STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);
+};
+
+struct CAesCbcEncoder: public CAesCbcCoder { CAesCbcEncoder(); };
+struct CAesCbcDecoder: public CAesCbcCoder { CAesCbcDecoder(); };
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
new file mode 100644
index 000000000..cbbdec89d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
@@ -0,0 +1,83 @@
+// Pbkdf2HmacSha1.cpp
+
+#include "StdAfx.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)
+{
+ CHmac baseCtx;
+ baseCtx.SetKey(pwd, pwdSize);
+ 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;
+ ctx.Update(u, 4);
+ ctx.Final(u, kDigestSize);
+
+ unsigned int s;
+ for (s = 0; s < curSize; s++)
+ key[s] = u[s];
+
+ for (UInt32 j = numIterations; j > 1; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, kDigestSize);
+ ctx.Final(u, kDigestSize);
+ for (s = 0; s < curSize; s++)
+ key[s] ^= u[s];
+ }
+
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+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++)
+ {
+ CHmac32 ctx = baseCtx;
+ ctx.Update(salt, saltSize);
+ UInt32 u[kDigestSizeInWords] = { i };
+ const unsigned int curSize = (keySize < kDigestSizeInWords) ? (unsigned int)keySize : kDigestSizeInWords;
+ ctx.Update(u, 1);
+ ctx.Final(u, kDigestSizeInWords);
+
+ // Speed-optimized code start
+ ctx = baseCtx;
+ ctx.GetLoopXorDigest(u, numIterations - 1);
+ // Speed-optimized code end
+
+ unsigned int s;
+ for (s = 0; s < curSize; s++)
+ key[s] = u[s];
+
+ /*
+ // Default code start
+ for (UInt32 j = numIterations; j > 1; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, kDigestSizeInWords);
+ ctx.Final(u, kDigestSizeInWords);
+ for (s = 0; s < curSize; s++)
+ key[s] ^= u[s];
+ }
+ // Default code end
+ */
+
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
new file mode 100644
index 000000000..bb90e1214
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
@@ -0,0 +1,21 @@
+// Pbkdf2HmacSha1.h
+// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1
+
+#ifndef __CRYPTO_PBKDF2_HMAC_SHA1_H
+#define __CRYPTO_PBKDF2_HMAC_SHA1_H
+
+#include <stddef.h>
+#include "../../Common/Types.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 Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize,
+ UInt32 numIterations, UInt32 *key, size_t keySize);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp
new file mode 100644
index 000000000..e0e2e3abd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp
@@ -0,0 +1,107 @@
+// RandGen.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+#include "Windows/Synchronization.h"
+#include "RandGen.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+// This is not very good random number generator.
+// Please use it only for salt.
+// First generated data block depends from timer and processID.
+// Other generated data blocks depend from previous state
+// Maybe it's possible to restore original timer value from generated value.
+
+void CRandomGenerator::Init()
+{
+ NCrypto::NSha1::CContext hash;
+ hash.Init();
+
+ #ifdef _WIN32
+ DWORD w = ::GetCurrentProcessId();
+ hash.Update((const Byte *)&w, sizeof(w));
+ w = ::GetCurrentThreadId();
+ hash.Update((const Byte *)&w, sizeof(w));
+ #else
+ pid_t pid = getpid();
+ hash.Update((const Byte *)&pid, sizeof(pid));
+ pid = getppid();
+ hash.Update((const Byte *)&pid, sizeof(pid));
+ #endif
+
+ for (int i = 0; i < 1000; i++)
+ {
+ #ifdef _WIN32
+ LARGE_INTEGER v;
+ if (::QueryPerformanceCounter(&v))
+ hash.Update((const Byte *)&v.QuadPart, sizeof(v.QuadPart));
+ #endif
+
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, 0) == 0)
+ {
+ hash.Update((const Byte *)&v.tv_sec, sizeof(v.tv_sec));
+ hash.Update((const Byte *)&v.tv_usec, sizeof(v.tv_usec));
+ }
+ #endif
+ time_t v2 = time(NULL);
+ hash.Update((const Byte *)&v2, sizeof(v2));
+ #endif
+
+ DWORD tickCount = ::GetTickCount();
+ hash.Update((const Byte *)&tickCount, sizeof(tickCount));
+
+ for (int j = 0; j < 100; j++)
+ {
+ hash.Final(_buff);
+ hash.Init();
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ }
+ }
+ hash.Final(_buff);
+ _needInit = false;
+}
+
+static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
+
+void CRandomGenerator::Generate(Byte *data, unsigned int size)
+{
+ g_CriticalSection.Enter();
+ if (_needInit)
+ Init();
+ while (size > 0)
+ {
+ NCrypto::NSha1::CContext hash;
+
+ hash.Init();
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ hash.Final(_buff);
+
+ hash.Init();
+ UInt32 salt = 0xF672ABD1;
+ hash.Update((const Byte *)&salt, sizeof(salt));
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ Byte buff[NCrypto::NSha1::kDigestSize];
+ hash.Final(buff);
+ for (unsigned int i = 0; i < NCrypto::NSha1::kDigestSize && size > 0; i++, size--)
+ *data++ = buff[i];
+ }
+ g_CriticalSection.Leave();
+}
+
+CRandomGenerator g_RandomGenerator;
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h
new file mode 100644
index 000000000..209445c43
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h
@@ -0,0 +1,21 @@
+// RandGen.h
+
+#ifndef __CRYPTO_RAND_GEN_H
+#define __CRYPTO_RAND_GEN_H
+
+#include "Sha1.h"
+
+class CRandomGenerator
+{
+ Byte _buff[NCrypto::NSha1::kDigestSize];
+ bool _needInit;
+
+ void Init();
+public:
+ CRandomGenerator(): _needInit(true) {};
+ void Generate(Byte *data, unsigned size);
+};
+
+extern CRandomGenerator g_RandomGenerator;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp
new file mode 100644
index 000000000..c2df0e527
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp
@@ -0,0 +1,133 @@
+// Crypto/Rar20Crypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/RotateDefs.h"
+
+#include "Rar20Crypto.h"
+
+namespace NCrypto {
+namespace NRar20 {
+
+static const int kNumRounds = 32;
+
+static const Byte InitSubstTable[256] = {
+ 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
+ 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
+ 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
+ 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
+ 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
+ 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
+ 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
+ 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
+ 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
+ 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
+ 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
+ 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
+ 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
+ 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
+ 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
+ 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
+};
+
+void CData::UpdateKeys(const Byte *data)
+{
+ for (int i = 0; i < 16; i += 4)
+ for (int j = 0; j < 4; j++)
+ Keys[j] ^= g_CrcTable[data[i + j]];
+}
+
+static void Swap(Byte *b1, Byte *b2)
+{
+ Byte b = *b1;
+ *b1 = *b2;
+ *b2 = b;
+}
+
+void CData::SetPassword(const Byte *password, UInt32 passwordLen)
+{
+ Keys[0] = 0xD3A3B879L;
+ Keys[1] = 0x3F6D12F7L;
+ Keys[2] = 0x7515A235L;
+ Keys[3] = 0xA4E7F123L;
+
+ Byte psw[256];
+ memset(psw, 0, sizeof(psw));
+ memcpy(psw, password, passwordLen);
+ memcpy(SubstTable, InitSubstTable, sizeof(SubstTable));
+
+ for (UInt32 j = 0; j < 256; j++)
+ for (UInt32 i = 0; i < passwordLen; 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)
+ EncryptBlock(&psw[i]);
+}
+
+void CData::CryptBlock(Byte *buf, bool encrypt)
+{
+ Byte inBuf[16];
+ UInt32 A, B, C, D, T, TA, TB;
+
+ A = GetUi32(buf + 0) ^ Keys[0];
+ B = GetUi32(buf + 4) ^ Keys[1];
+ C = GetUi32(buf + 8) ^ Keys[2];
+ D = GetUi32(buf + 12) ^ Keys[3];
+
+ if (!encrypt)
+ memcpy(inBuf, buf, sizeof(inBuf));
+
+ for (int i = 0; i < kNumRounds; i++)
+ {
+ UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
+ T = ((C + rotlFixed(D, 11)) ^ key);
+ TA = A ^ SubstLong(T);
+ T = ((D ^ rotlFixed(C, 17)) + key);
+ TB = B ^ SubstLong(T);
+ A = C;
+ B = D;
+ C = TA;
+ D = TB;
+ }
+
+ SetUi32(buf + 0, C ^ Keys[0]);
+ SetUi32(buf + 4, D ^ Keys[1]);
+ SetUi32(buf + 8, A ^ Keys[2]);
+ SetUi32(buf + 12, B ^ Keys[3]);
+
+ UpdateKeys(encrypt ? buf : inBuf);
+}
+
+STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _cipher.SetPassword(data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Init()
+{
+ return S_OK;
+}
+
+static const UInt32 kBlockSize = 16;
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ if (size == 0)
+ return 0;
+ if (size < kBlockSize)
+ return kBlockSize;
+ UInt32 i;
+ size -= kBlockSize;
+ for (i = 0; i <= size; i += kBlockSize)
+ _cipher.DecryptBlock(data + i);
+ return i;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h
new file mode 100644
index 000000000..b9648f59d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h
@@ -0,0 +1,50 @@
+// Crypto/Rar20Crypto.h
+
+#ifndef __CRYPTO_RAR20_CRYPTO_H
+#define __CRYPTO_RAR20_CRYPTO_H
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NRar20 {
+
+class CData
+{
+ Byte SubstTable[256];
+ UInt32 Keys[4];
+
+ UInt32 SubstLong(UInt32 t)
+ {
+ 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);
+ }
+ void UpdateKeys(const Byte *data);
+ void CryptBlock(Byte *buf, bool encrypt);
+public:
+ void EncryptBlock(Byte *buf) { CryptBlock(buf, true); }
+ void DecryptBlock(Byte *buf) { CryptBlock(buf, false); }
+ void SetPassword(const Byte *password, UInt32 passwordLen);
+};
+
+class CDecoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ CData _cipher;
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp
new file mode 100644
index 000000000..b0f00ea85
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp
@@ -0,0 +1,134 @@
+// Crypto/RarAes.cpp
+// Note: you must include MyAes.cpp to project to initialize AES tables
+
+#include "StdAfx.h"
+
+#include "RarAes.h"
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NRar29 {
+
+CDecoder::CDecoder():
+ _thereIsSalt(false),
+ _needCalculate(true),
+ _rar350Mode(false)
+{
+ for (int i = 0; i < sizeof(_salt); i++)
+ _salt[i] = 0;
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ bool thereIsSaltPrev = _thereIsSalt;
+ _thereIsSalt = false;
+ if (size == 0)
+ return S_OK;
+ if (size < 8)
+ return E_INVALIDARG;
+ _thereIsSalt = true;
+ bool same = false;
+ if (_thereIsSalt == thereIsSaltPrev)
+ {
+ same = true;
+ if (_thereIsSalt)
+ {
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ if (_salt[i] != data[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ }
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ _salt[i] = data[i];
+ if (!_needCalculate && !same)
+ _needCalculate = true;
+ return S_OK;
+}
+
+static const unsigned kMaxPasswordLength = 127 * 2;
+
+STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ if (size > kMaxPasswordLength)
+ size = kMaxPasswordLength;
+ bool same = false;
+ if (size == buffer.GetCapacity())
+ {
+ same = true;
+ for (UInt32 i = 0; i < size; i++)
+ if (data[i] != buffer[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ if (!_needCalculate && !same)
+ _needCalculate = true;
+ buffer.SetCapacity(size);
+ memcpy(buffer, data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Init()
+{
+ Calculate();
+ SetKey(aesKey, kRarAesKeySize);
+ AesCbc_Init(_aes + _offset, _aesInit);
+ return S_OK;
+}
+
+void CDecoder::Calculate()
+{
+ if (_needCalculate)
+ {
+ const unsigned kSaltSize = 8;
+
+ Byte rawPassword[kMaxPasswordLength + kSaltSize];
+
+ memcpy(rawPassword, buffer, buffer.GetCapacity());
+
+ size_t rawLength = buffer.GetCapacity();
+
+ if (_thereIsSalt)
+ {
+ memcpy(rawPassword + rawLength, _salt, kSaltSize);
+ rawLength += kSaltSize;
+ }
+
+ NSha1::CContext sha;
+ sha.Init();
+
+ // 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]);
+ }
+ _needCalculate = false;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h
new file mode 100644
index 000000000..119cc2336
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h
@@ -0,0 +1,47 @@
+// Crypto/RarAes.h
+
+#ifndef __CRYPTO_RAR_AES_H
+#define __CRYPTO_RAR_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "Common/Buffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NRar29 {
+
+const UInt32 kRarAesKeySize = 16;
+
+class CDecoder:
+ public CAesCbcDecoder,
+ public ICompressSetDecoderProperties2,
+ public ICryptoSetPassword
+{
+ Byte _salt[8];
+ bool _thereIsSalt;
+ CByteBuffer buffer;
+ Byte aesKey[kRarAesKeySize];
+ Byte _aesInit[AES_BLOCK_SIZE];
+ bool _needCalculate;
+ bool _rar350Mode;
+
+ void Calculate();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(Init)();
+ STDMETHOD(CryptoSetPassword)(const Byte *aData, UInt32 aSize);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ CDecoder();
+ void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp
new file mode 100644
index 000000000..82ca986c7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp
@@ -0,0 +1,229 @@
+// 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--)
+ {
+ int pos = (int)(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--)
+ {
+ int pos = (int)(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 (int i = 0; i < kBlockSizeInWords; i++)
+ {
+ UInt32 d = _buffer[i];
+ data[i * 4 + 0 - kBlockSize] = (Byte)(d);
+ data[i * 4 + 1 - kBlockSize] = (Byte)(d >> 8);
+ data[i * 4 + 2 - kBlockSize] = (Byte)(d >> 16);
+ data[i * 4 + 3 - kBlockSize] = (Byte)(d >> 24);
+ }
+ returnRes = rar350Mode;
+ }
+ }
+ _count2 = curBufferPos;
+}
+
+void CContext::Final(Byte *digest)
+{
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 3);
+ unsigned curBufferPos = _count2;
+ int pos = (int)(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();
+
+ int 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();
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h
new file mode 100644
index 000000000..1bad1f91f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h
@@ -0,0 +1,68 @@
+// 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/Types.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
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp
new file mode 100644
index 000000000..08a1818c0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp
@@ -0,0 +1,221 @@
+// Crypto/WzAes.cpp
+/*
+This code implements Brian Gladman's scheme
+specified in 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 "../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 _NO_WZAES_OPTIMIZATIONS
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kAesKeySizeMax = 32;
+
+static const UInt32 kNumKeyGenIterations = 1000;
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ if(size > kPasswordSizeMax)
+ return E_INVALIDARG;
+ _key.Password.SetCapacity(size);
+ memcpy(_key.Password, data, size);
+ return S_OK;
+}
+
+#ifndef _NO_WZAES_OPTIMIZATIONS
+
+static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, unsigned destSize)
+{
+ 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]));
+}
+
+#endif
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ UInt32 keySize = _key.GetKeySize();
+ UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize;
+ Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize];
+
+ // for (unsigned ii = 0; ii < 1000; ii++)
+ {
+ #ifdef _NO_WZAES_OPTIMIZATIONS
+
+ NSha1::Pbkdf2Hmac(
+ _key.Password, _key.Password.GetCapacity(),
+ _key.Salt, _key.GetSaltSize(),
+ kNumKeyGenIterations,
+ buf, keysTotalSize);
+
+ #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);
+ NSha1::Pbkdf2Hmac32(
+ _key.Password, _key.Password.GetCapacity(),
+ salt, saltSizeInWords,
+ kNumKeyGenIterations,
+ buf32, key32SizeTotal);
+ for (UInt32 j = 0; j < keysTotalSize; j++)
+ buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3)));
+
+ #endif
+ }
+
+ _hmac.SetKey(buf + keySize, keySize);
+ memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize);
+
+ AesCtr2_Init(&_aes);
+ Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, buf, keySize);
+ return S_OK;
+}
+
+HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
+{
+ UInt32 saltSize = _key.GetSaltSize();
+ g_RandomGenerator.Generate(_key.Salt, saltSize);
+ Init();
+ RINOK(WriteStream(outStream, _key.Salt, saltSize));
+ return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize);
+}
+
+HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
+{
+ Byte mac[kMacSize];
+ _hmac.Final(mac, kMacSize);
+ return WriteStream(outStream, mac, kMacSize);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _key.Init();
+ return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ UInt32 saltSize = _key.GetSaltSize();
+ UInt32 extraSize = saltSize + kPwdVerifCodeSize;
+ Byte temp[kSaltSizeMax + kPwdVerifCodeSize];
+ RINOK(ReadStream_FAIL(inStream, temp, extraSize));
+ UInt32 i;
+ for (i = 0; i < saltSize; i++)
+ _key.Salt[i] = temp[i];
+ for (i = 0; i < kPwdVerifCodeSize; i++)
+ _pwdVerifFromArchive[i] = temp[saltSize + i];
+ return S_OK;
+}
+
+static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+
+bool CDecoder::CheckPasswordVerifyCode()
+{
+ return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize);
+}
+
+HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
+{
+ isOK = false;
+ Byte mac1[kMacSize];
+ RINOK(ReadStream_FAIL(inStream, mac1, kMacSize));
+ Byte mac2[kMacSize];
+ _hmac.Final(mac2, kMacSize);
+ isOK = CompareArrays(mac1, mac2, kMacSize);
+ return S_OK;
+}
+
+CAesCtr2::CAesCtr2()
+{
+ offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
+}
+
+void AesCtr2_Init(CAesCtr2 *p)
+{
+ UInt32 *ctr = p->aes + p->offset + 4;
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ ctr[i] = 0;
+ p->pos = AES_BLOCK_SIZE;
+}
+
+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;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+ if (size >= 16)
+ {
+ SizeT size2 = size >> 4;
+ g_AesCtr_Code(buf32 + 4, data, size2);
+ size2 <<= 4;
+ data += size2;
+ size -= size2;
+ pos = AES_BLOCK_SIZE;
+ }
+ if (size != 0)
+ {
+ unsigned j;
+ const Byte *buf;
+ for (j = 0; j < 4; j++)
+ buf32[j] = 0;
+ g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
+ buf = (const Byte *)buf32;
+ pos = 0;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+ p->pos = pos;
+}
+
+STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
+{
+ AesCtr2_Code(&_aes, data, size);
+ _hmac.Update(data, size);
+ return size;
+}
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ _hmac.Update(data, size);
+ AesCtr2_Code(&_aes, data, size);
+ return size;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h
new file mode 100644
index 000000000..f37fe6440
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h
@@ -0,0 +1,125 @@
+// Crypto/WzAes.h
+/*
+This code implements Brian Gladman's scheme
+specified in password Based File Encryption Utility:
+ - AES encryption (128,192,256-bit) in Counter (CTR) mode.
+ - HMAC-SHA1 authentication for encrypted data (10 bytes)
+ - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and
+ Salt (saltSize = aesKeySize / 2).
+ - 2 bytes contain Password Verifier's Code
+*/
+
+#ifndef __CRYPTO_WZ_AES_H
+#define __CRYPTO_WZ_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kSaltSizeMax = 16;
+const unsigned kMacSize = 10;
+
+const UInt32 kPasswordSizeMax = 99; // 128;
+
+// Password Verification Code Size
+const unsigned kPwdVerifCodeSize = 2;
+
+enum EKeySizeMode
+{
+ kKeySizeMode_AES128 = 1,
+ kKeySizeMode_AES192 = 2,
+ kKeySizeMode_AES256 = 3
+};
+
+class CKeyInfo
+{
+public:
+ EKeySizeMode KeySizeMode;
+ Byte Salt[kSaltSizeMax];
+ Byte PwdVerifComputed[kPwdVerifCodeSize];
+
+ CByteBuffer Password;
+
+ UInt32 GetKeySize() const { return (8 * (KeySizeMode & 3) + 8); }
+ UInt32 GetSaltSize() const { return (4 * (KeySizeMode & 3) + 4); }
+
+ CKeyInfo() { Init(); }
+ void Init() { KeySizeMode = kKeySizeMode_AES256; }
+};
+
+struct CAesCtr2
+{
+ unsigned pos;
+ unsigned offset;
+ UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3];
+ CAesCtr2();
+};
+
+void AesCtr2_Init(CAesCtr2 *p);
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size);
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+protected:
+ CKeyInfo _key;
+ NSha1::CHmac _hmac;
+ Byte _pwdVerifFromArchive[kPwdVerifCodeSize];
+ CAesCtr2 _aes;
+
+public:
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) = 0;
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+
+ UInt32 GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifCodeSize; }
+ bool SetKeyMode(unsigned mode)
+ {
+ if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
+ return false;
+ _key.KeySizeMode = (EKeySizeMode)mode;
+ return true;
+ }
+};
+
+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:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+ bool CheckPasswordVerifyCode();
+ HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp
new file mode 100644
index 000000000..baaaf98e3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp
@@ -0,0 +1,88 @@
+// Crypto/ZipCrypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "RandGen.h"
+#include "ZipCrypto.h"
+
+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));
+}
+
+STDMETHODIMP CCipher::CryptoSetPassword(const Byte *password, UInt32 passwordLen)
+{
+ 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];
+ return S_OK;
+}
+
+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)
+{
+ Byte h[kHeaderSize];
+ g_RandomGenerator.Generate(h, kHeaderSize - 2);
+ h[kHeaderSize - 1] = (Byte)(crc >> 24);
+ h[kHeaderSize - 2] = (Byte)(crc >> 16);
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return WriteStream(outStream, h, kHeaderSize);
+}
+
+STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b ^ DecryptByteSpec());;
+ UpdateKeys(b);
+ }
+ return size;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FAIL(inStream, h, kHeaderSize));
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte c = (Byte)(data[i] ^ DecryptByteSpec());
+ UpdateKeys(c);
+ data[i] = c;
+ }
+ return size;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h
new file mode 100644
index 000000000..6f104beb4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h
@@ -0,0 +1,56 @@
+// Crypto/ZipCrypto.h
+
+#ifndef __CRYPTO_ZIP_CRYPTO_H
+#define __CRYPTO_ZIP_CRYPTO_H
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NZip {
+
+const unsigned kHeaderSize = 12;
+
+class CCipher:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ UInt32 Keys[3];
+ UInt32 Keys2[3];
+
+protected:
+ void UpdateKeys(Byte b);
+ Byte DecryptByteSpec();
+ void RestoreKeys()
+ {
+ for (int i = 0; i < 3; i++)
+ Keys[i] = Keys2[i];
+ }
+
+public:
+ STDMETHOD(Init)();
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+class CEncoder: public CCipher
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT WriteHeader(ISequentialOutStream *outStream, UInt32 crc);
+};
+
+class CDecoder: public CCipher
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp
new file mode 100644
index 000000000..1554b3489
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp
@@ -0,0 +1,164 @@
+// 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;
+}
+
+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);
+ const UInt32 kAlign = 16;
+ if (_remSize < 16 || _remSize > (1 << 18))
+ return E_NOTIMPL;
+ if (_remSize + kAlign > _buf.GetCapacity())
+ {
+ _buf.Free();
+ _buf.SetCapacity(_remSize + kAlign);
+ _bufAligned = (Byte *)((ptrdiff_t)((Byte *)_buf + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
+ }
+ return ReadStream_FALSE(inStream, _bufAligned, _remSize);
+}
+
+HRESULT CDecoder::CheckPassword(bool &passwOK)
+{
+ passwOK = false;
+ if (_remSize < 16)
+ return E_NOTIMPL;
+ Byte *p = _bufAligned;
+ 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;
+ if ((flags & 0x4000) != 0)
+ {
+ // Use 3DES
+ return E_NOTIMPL;
+ }
+
+ UInt32 rdSize = GetUi16(p + 8);
+ if ((rdSize & 0xF) != 0 || rdSize + 16 > _remSize)
+ return E_NOTIMPL;
+ memmove(p, p + 10, rdSize);
+ Byte *validData = p + rdSize + 16;
+ if (GetUi32(validData - 6) != 0) // reserved
+ return E_NOTIMPL;
+ UInt32 validSize = GetUi16(validData - 2);
+ if ((validSize & 0xF) != 0 || 16 + rdSize + validSize != _remSize)
+ return E_NOTIMPL;
+
+
+ {
+ RINOK(SetKey(_key.MasterKey, _key.KeySize));
+ RINOK(SetInitVector(_iv, 16));
+ Init();
+ Filter(p, rdSize);
+ }
+
+ Byte fileKey[32];
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(_iv, 16);
+ sha.Update(p, rdSize - 16); // we don't use last 16 bytes (PAD bytes)
+ DeriveKey(sha, fileKey);
+
+ RINOK(SetKey(fileKey, _key.KeySize));
+ RINOK(SetInitVector(_iv, 16));
+ Init();
+ Filter(validData, validSize);
+
+ if (validSize < 4)
+ return E_NOTIMPL;
+ validSize -= 4;
+ if (GetUi32(validData + validSize) != CrcCalc(validData, validSize))
+ return S_OK;
+ passwOK = true;
+ Init();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h
new file mode 100644
index 000000000..151677ea6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h
@@ -0,0 +1,47 @@
+// Crypto/ZipStrong.h
+
+#ifndef __CRYPTO_ZIP_STRONG_H
+#define __CRYPTO_ZIP_STRONG_H
+
+#include "Common/Buffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+struct CKeyInfo
+{
+ Byte MasterKey[32];
+ UInt32 KeySize;
+ void SetPassword(const Byte *data, UInt32 size);
+};
+
+class CBaseCoder:
+ public CAesCbcDecoder,
+ public ICryptoSetPassword
+{
+protected:
+ CKeyInfo _key;
+ CByteBuffer _buf;
+ Byte *_bufAligned;
+public:
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+class CDecoder: public CBaseCoder
+{
+ UInt32 _ivSize;
+ Byte _iv[16];
+ UInt32 _remSize;
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize);
+ HRESULT CheckPassword(bool &passwOK);
+};
+
+}}
+
+#endif