5 #include "../../../C/Sha256.h"
\r
7 #include "Windows/Synchronization.h"
\r
9 #include "../Common/StreamObjects.h"
\r
10 #include "../Common/StreamUtils.h"
\r
15 #ifndef EXTRACT_ONLY
\r
16 #include "RandGen.h"
\r
19 using namespace NWindows;
\r
24 bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
\r
26 if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
\r
28 for (UInt32 i = 0; i < SaltSize; i++)
\r
29 if (Salt[i] != a.Salt[i])
\r
31 return (Password == a.Password);
\r
34 void CKeyInfo::CalculateDigest()
\r
36 if (NumCyclesPower == 0x3F)
\r
39 for (pos = 0; pos < SaltSize; pos++)
\r
40 Key[pos] = Salt[pos];
\r
41 for (UInt32 i = 0; i < Password.GetCapacity() && pos < kKeySize; i++)
\r
42 Key[pos++] = Password[i];
\r
43 for (; pos < kKeySize; pos++)
\r
50 const UInt64 numRounds = (UInt64)1 << NumCyclesPower;
\r
51 Byte temp[8] = { 0,0,0,0,0,0,0,0 };
\r
52 for (UInt64 round = 0; round < numRounds; round++)
\r
54 Sha256_Update(&sha, Salt, (size_t)SaltSize);
\r
55 Sha256_Update(&sha, Password, Password.GetCapacity());
\r
56 Sha256_Update(&sha, temp, 8);
\r
57 for (int i = 0; i < 8; i++)
\r
58 if (++(temp[i]) != 0)
\r
61 Sha256_Final(&sha, Key);
\r
65 bool CKeyInfoCache::Find(CKeyInfo &key)
\r
67 for (int i = 0; i < Keys.Size(); i++)
\r
69 const CKeyInfo &cached = Keys[i];
\r
70 if (key.IsEqualTo(cached))
\r
72 for (int j = 0; j < kKeySize; j++)
\r
73 key.Key[j] = cached.Key[j];
\r
76 Keys.Insert(0, cached);
\r
85 void CKeyInfoCache::Add(CKeyInfo &key)
\r
89 if (Keys.Size() >= Size)
\r
91 Keys.Insert(0, key);
\r
94 static CKeyInfoCache g_GlobalKeyCache(32);
\r
95 static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
\r
101 for (int i = 0; i < sizeof(_iv); i++)
\r
105 void CBase::CalculateDigest()
\r
107 NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
\r
108 if (_cachedKeys.Find(_key))
\r
109 g_GlobalKeyCache.Add(_key);
\r
112 if (!g_GlobalKeyCache.Find(_key))
\r
114 _key.CalculateDigest();
\r
115 g_GlobalKeyCache.Add(_key);
\r
117 _cachedKeys.Add(_key);
\r
121 #ifndef EXTRACT_ONLY
\r
124 STDMETHODIMP CEncoder::ResetSalt()
\r
127 g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
\r
132 STDMETHODIMP CEncoder::ResetInitVector()
\r
135 g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
\r
139 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
\r
142 for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
\r
145 UInt32 ivSize = _ivSize;
\r
147 // _key.NumCyclesPower = 0x3F;
\r
148 _key.NumCyclesPower = 19;
\r
150 Byte firstByte = (Byte)(_key.NumCyclesPower |
\r
151 (((_key.SaltSize == 0) ? 0 : 1) << 7) |
\r
152 (((ivSize == 0) ? 0 : 1) << 6));
\r
153 RINOK(outStream->Write(&firstByte, 1, NULL));
\r
154 if (_key.SaltSize == 0 && ivSize == 0)
\r
156 Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
\r
157 Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
\r
158 Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
\r
159 RINOK(outStream->Write(&secondByte, 1, NULL));
\r
160 if (_key.SaltSize > 0)
\r
162 RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
\r
166 RINOK(WriteStream(outStream, _iv, ivSize));
\r
171 HRESULT CEncoder::CreateFilter()
\r
173 _aesFilter = new CAesCbcEncoder;
\r
179 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
\r
183 for (i = 0; i < sizeof(_iv); i++)
\r
188 Byte firstByte = data[pos++];
\r
190 _key.NumCyclesPower = firstByte & 0x3F;
\r
191 if ((firstByte & 0xC0) == 0)
\r
193 _key.SaltSize = (firstByte >> 7) & 1;
\r
194 UInt32 ivSize = (firstByte >> 6) & 1;
\r
197 return E_INVALIDARG;
\r
198 Byte secondByte = data[pos++];
\r
200 _key.SaltSize += (secondByte >> 4);
\r
201 ivSize += (secondByte & 0x0F);
\r
203 if (pos + _key.SaltSize + ivSize > size)
\r
204 return E_INVALIDARG;
\r
205 for (i = 0; i < _key.SaltSize; i++)
\r
206 _key.Salt[i] = data[pos++];
\r
207 for (i = 0; i < ivSize; i++)
\r
208 _iv[i] = data[pos++];
\r
209 return (_key.NumCyclesPower <= 24) ? S_OK : E_NOTIMPL;
\r
212 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
\r
214 _key.Password.SetCapacity((size_t)size);
\r
215 memcpy(_key.Password, data, (size_t)size);
\r
219 STDMETHODIMP CBaseCoder::Init()
\r
222 if (_aesFilter == 0)
\r
224 RINOK(CreateFilter());
\r
226 CMyComPtr<ICryptoProperties> cp;
\r
227 RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
\r
228 RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
\r
229 RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
\r
233 STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
\r
235 return _aesFilter->Filter(data, size);
\r
238 HRESULT CDecoder::CreateFilter()
\r
240 _aesFilter = new CAesCbcDecoder;
\r