1 // 7zAes.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/Sha256.h"
6 
7 #include "../../Windows/Synchronization.h"
8 
9 #include "../Common/StreamObjects.h"
10 #include "../Common/StreamUtils.h"
11 
12 #include "7zAes.h"
13 #include "MyAes.h"
14 
15 #ifndef EXTRACT_ONLY
16 #include "RandGen.h"
17 #endif
18 
19 using namespace NWindows;
20 
21 namespace NCrypto {
22 namespace NSevenZ {
23 
IsEqualTo(const CKeyInfo & a) const24 bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
25 {
26   if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
27     return false;
28   for (UInt32 i = 0; i < SaltSize; i++)
29     if (Salt[i] != a.Salt[i])
30       return false;
31   return (Password == a.Password);
32 }
33 
CalculateDigest()34 void CKeyInfo::CalculateDigest()
35 {
36   if (NumCyclesPower == 0x3F)
37   {
38     UInt32 pos;
39     for (pos = 0; pos < SaltSize; pos++)
40       Key[pos] = Salt[pos];
41     for (UInt32 i = 0; i < Password.Size() && pos < kKeySize; i++)
42       Key[pos++] = Password[i];
43     for (; pos < kKeySize; pos++)
44       Key[pos] = 0;
45   }
46   else
47   {
48     CSha256 sha;
49     Sha256_Init(&sha);
50     const UInt64 numRounds = (UInt64)1 << NumCyclesPower;
51     Byte temp[8] = { 0,0,0,0,0,0,0,0 };
52     for (UInt64 round = 0; round < numRounds; round++)
53     {
54       Sha256_Update(&sha, Salt, (size_t)SaltSize);
55       Sha256_Update(&sha, Password, Password.Size());
56       Sha256_Update(&sha, temp, 8);
57       for (int i = 0; i < 8; i++)
58         if (++(temp[i]) != 0)
59           break;
60     }
61     Sha256_Final(&sha, Key);
62   }
63 }
64 
Find(CKeyInfo & key)65 bool CKeyInfoCache::Find(CKeyInfo &key)
66 {
67   FOR_VECTOR (i, Keys)
68   {
69     const CKeyInfo &cached = Keys[i];
70     if (key.IsEqualTo(cached))
71     {
72       for (int j = 0; j < kKeySize; j++)
73         key.Key[j] = cached.Key[j];
74       if (i != 0)
75         Keys.MoveToFront(i);
76       return true;
77     }
78   }
79   return false;
80 }
81 
Add(CKeyInfo & key)82 void CKeyInfoCache::Add(CKeyInfo &key)
83 {
84   if (Find(key))
85     return;
86   if (Keys.Size() >= Size)
87     Keys.DeleteBack();
88   Keys.Insert(0, key);
89 }
90 
91 static CKeyInfoCache g_GlobalKeyCache(32);
92 static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
93 
CBase()94 CBase::CBase():
95   _cachedKeys(16),
96   _ivSize(0)
97 {
98   for (int i = 0; i < sizeof(_iv); i++)
99     _iv[i] = 0;
100 }
101 
CalculateDigest()102 void CBase::CalculateDigest()
103 {
104   NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
105   if (_cachedKeys.Find(_key))
106     g_GlobalKeyCache.Add(_key);
107   else
108   {
109     if (!g_GlobalKeyCache.Find(_key))
110     {
111       _key.CalculateDigest();
112       g_GlobalKeyCache.Add(_key);
113     }
114     _cachedKeys.Add(_key);
115   }
116 }
117 
118 #ifndef EXTRACT_ONLY
119 
120 /*
121 STDMETHODIMP CEncoder::ResetSalt()
122 {
123   _key.SaltSize = 4;
124   g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
125   return S_OK;
126 }
127 */
128 
ResetInitVector()129 STDMETHODIMP CEncoder::ResetInitVector()
130 {
131   _ivSize = 8;
132   g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
133   return S_OK;
134 }
135 
WriteCoderProperties(ISequentialOutStream * outStream)136 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
137 {
138    // _key.Init();
139    for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
140     _iv[i] = 0;
141 
142   UInt32 ivSize = _ivSize;
143 
144   // _key.NumCyclesPower = 0x3F;
145   _key.NumCyclesPower = 19;
146 
147   Byte firstByte = (Byte)(_key.NumCyclesPower |
148     (((_key.SaltSize == 0) ? 0 : 1) << 7) |
149     (((ivSize == 0) ? 0 : 1) << 6));
150   RINOK(outStream->Write(&firstByte, 1, NULL));
151   if (_key.SaltSize == 0 && ivSize == 0)
152     return S_OK;
153   Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
154   Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
155   Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
156   RINOK(outStream->Write(&secondByte, 1, NULL));
157   if (_key.SaltSize > 0)
158   {
159     RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
160   }
161   if (ivSize > 0)
162   {
163     RINOK(WriteStream(outStream, _iv, ivSize));
164   }
165   return S_OK;
166 }
167 
CreateFilter()168 HRESULT CEncoder::CreateFilter()
169 {
170   _aesFilter = new CAesCbcEncoder(kKeySize);
171   return S_OK;
172 }
173 
174 #endif
175 
SetDecoderProperties2(const Byte * data,UInt32 size)176 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
177 {
178   _key.Init();
179   UInt32 i;
180   for (i = 0; i < sizeof(_iv); i++)
181     _iv[i] = 0;
182   if (size == 0)
183     return S_OK;
184   UInt32 pos = 0;
185   Byte firstByte = data[pos++];
186 
187   _key.NumCyclesPower = firstByte & 0x3F;
188   if ((firstByte & 0xC0) == 0)
189     return S_OK;
190   _key.SaltSize = (firstByte >> 7) & 1;
191   UInt32 ivSize = (firstByte >> 6) & 1;
192 
193   if (pos >= size)
194     return E_INVALIDARG;
195   Byte secondByte = data[pos++];
196 
197   _key.SaltSize += (secondByte >> 4);
198   ivSize += (secondByte & 0x0F);
199 
200   if (pos + _key.SaltSize + ivSize > size)
201     return E_INVALIDARG;
202   for (i = 0; i < _key.SaltSize; i++)
203     _key.Salt[i] = data[pos++];
204   for (i = 0; i < ivSize; i++)
205     _iv[i] = data[pos++];
206   return (_key.NumCyclesPower <= 24) ? S_OK :  E_NOTIMPL;
207 }
208 
CryptoSetPassword(const Byte * data,UInt32 size)209 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
210 {
211   _key.Password.CopyFrom(data, (size_t)size);
212   return S_OK;
213 }
214 
Init()215 STDMETHODIMP CBaseCoder::Init()
216 {
217   CalculateDigest();
218   if (_aesFilter == 0)
219   {
220     RINOK(CreateFilter());
221   }
222   CMyComPtr<ICryptoProperties> cp;
223   RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
224   RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
225   RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
226   return _aesFilter->Init();
227 }
228 
STDMETHODIMP_(UInt32)229 STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
230 {
231   return _aesFilter->Filter(data, size);
232 }
233 
CreateFilter()234 HRESULT CDecoder::CreateFilter()
235 {
236   _aesFilter = new CAesCbcDecoder(kKeySize);
237   return S_OK;
238 }
239 
240 }}
241