summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/CPP/7zip/Crypto/7zAes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'other-licenses/7zstub/src/CPP/7zip/Crypto/7zAes.cpp')
-rw-r--r--other-licenses/7zstub/src/CPP/7zip/Crypto/7zAes.cpp280
1 files changed, 280 insertions, 0 deletions
diff --git a/other-licenses/7zstub/src/CPP/7zip/Crypto/7zAes.cpp b/other-licenses/7zstub/src/CPP/7zip/Crypto/7zAes.cpp
new file mode 100644
index 000000000..f412bf9d1
--- /dev/null
+++ b/other-licenses/7zstub/src/CPP/7zip/Crypto/7zAes.cpp
@@ -0,0 +1,280 @@
+// 7zAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Sha256.h"
+
+#include "../../Common/ComTry.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/Synchronization.h"
+#endif
+
+#include "../Common/StreamUtils.h"
+
+#include "7zAes.h"
+#include "MyAes.h"
+
+#ifndef EXTRACT_ONLY
+#include "RandGen.h"
+#endif
+
+namespace NCrypto {
+namespace N7z {
+
+static const unsigned k_NumCyclesPower_Supported_MAX = 24;
+
+bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
+{
+ if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
+ return false;
+ for (unsigned i = 0; i < SaltSize; i++)
+ if (Salt[i] != a.Salt[i])
+ return false;
+ return (Password == a.Password);
+}
+
+void CKeyInfo::CalcKey()
+{
+ if (NumCyclesPower == 0x3F)
+ {
+ unsigned pos;
+ for (pos = 0; pos < SaltSize; pos++)
+ Key[pos] = Salt[pos];
+ for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++)
+ Key[pos++] = Password[i];
+ for (; pos < kKeySize; pos++)
+ Key[pos] = 0;
+ }
+ else
+ {
+ 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);
+
+ 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, buf, bufSize);
+ for (unsigned i = 0; i < 8; i++)
+ if (++(ctr[i]) != 0)
+ break;
+ }
+ while (--numRounds != 0);
+
+ Sha256_Final(&sha, Key);
+ }
+}
+
+bool CKeyInfoCache::GetKey(CKeyInfo &key)
+{
+ FOR_VECTOR (i, Keys)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ for (unsigned j = 0; j < kKeySize; j++)
+ key.Key[j] = cached.Key[j];
+ if (i != 0)
+ Keys.MoveToFront(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyInfoCache::FindAndAdd(const CKeyInfo &key)
+{
+ FOR_VECTOR (i, Keys)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ if (i != 0)
+ Keys.MoveToFront(i);
+ return;
+ }
+ }
+ Add(key);
+}
+
+void CKeyInfoCache::Add(const CKeyInfo &key)
+{
+ if (Keys.Size() >= Size)
+ Keys.DeleteBack();
+ Keys.Insert(0, key);
+}
+
+static CKeyInfoCache g_GlobalKeyCache(32);
+
+#ifndef _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 (unsigned i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+}
+
+void CBase::PrepareKey()
+{
+ // BCJ2 threads use same password. So we use long lock.
+ MT_LOCK
+
+ bool finded = false;
+ if (!_cachedKeys.GetKey(_key))
+ {
+ finded = g_GlobalKeyCache.GetKey(_key);
+ if (!finded)
+ _key.CalcKey();
+ _cachedKeys.Add(_key);
+ }
+ if (!finded)
+ g_GlobalKeyCache.FindAndAdd(_key);
+}
+
+#ifndef EXTRACT_ONLY
+
+/*
+STDMETHODIMP CEncoder::ResetSalt()
+{
+ _key.SaltSize = 4;
+ g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CEncoder::ResetInitVector()
+{
+ for (unsigned i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+ _ivSize = 8;
+ g_RandomGenerator.Generate(_iv, _ivSize);
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
+ unsigned propsSize = 1;
+
+ props[0] = (Byte)(_key.NumCyclesPower
+ | (_key.SaltSize == 0 ? 0 : (1 << 7))
+ | (_ivSize == 0 ? 0 : (1 << 6)));
+
+ if (_key.SaltSize != 0 || _ivSize != 0)
+ {
+ props[1] = (Byte)(
+ ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4)
+ | (_ivSize == 0 ? 0 : _ivSize - 1));
+ memcpy(props + 2, _key.Salt, _key.SaltSize);
+ propsSize = 2 + _key.SaltSize;
+ memcpy(props + propsSize, _iv, _ivSize);
+ propsSize += _ivSize;
+ }
+
+ return WriteStream(outStream, props, propsSize);
+}
+
+CEncoder::CEncoder()
+{
+ // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ // _key.NumCyclesPower = 0x3F;
+ _key.NumCyclesPower = 19;
+ _aesFilter = new CAesCbcEncoder(kKeySize);
+}
+
+#endif
+
+CDecoder::CDecoder()
+{
+ _aesFilter = new CAesCbcDecoder(kKeySize);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ _key.ClearProps();
+
+ _ivSize = 0;
+ unsigned i;
+ for (i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+
+ if (size == 0)
+ return S_OK;
+
+ 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;
+
+ 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++;
+ 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()
+{
+ COM_TRY_BEGIN
+
+ PrepareKey();
+ CMyComPtr<ICryptoProperties> cp;
+ RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
+ if (!cp)
+ return E_FAIL;
+ RINOK(cp->SetKey(_key.Key, kKeySize));
+ RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
+ return _aesFilter->Init();
+
+ COM_TRY_END
+}
+
+STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
+{
+ return _aesFilter->Filter(data, size);
+}
+
+}}