Mercurial > vba-linux
comparison src/win32/7zip/7z/CPP/7zip/Crypto/ZipStrong.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // Crypto/ZipStrong.cpp | |
2 | |
3 #include "StdAfx.h" | |
4 | |
5 extern "C" | |
6 { | |
7 #include "../../../C/7zCrc.h" | |
8 #include "../../../C/CpuArch.h" | |
9 } | |
10 | |
11 #include "../Common/StreamUtils.h" | |
12 | |
13 #include "MyAES.h" | |
14 #include "Sha1.h" | |
15 #include "ZipStrong.h" | |
16 | |
17 namespace NCrypto { | |
18 namespace NZipStrong { | |
19 | |
20 static const UInt16 kAES128 = 0x660E; | |
21 | |
22 // DeriveKey* function is similar to CryptDeriveKey() from Windows. | |
23 // But MSDN tells that we need such scheme only if | |
24 // "the required key length is longer than the hash value" | |
25 // but ZipStrong uses it always. | |
26 | |
27 static void DeriveKey2(const Byte *digest, Byte c, Byte *dest) | |
28 { | |
29 Byte buf[64]; | |
30 memset(buf, c, 64); | |
31 for (unsigned i = 0; i < NSha1::kDigestSize; i++) | |
32 buf[i] ^= digest[i]; | |
33 NSha1::CContext sha; | |
34 sha.Init(); | |
35 sha.Update(buf, 64); | |
36 sha.Final(dest); | |
37 } | |
38 | |
39 static void DeriveKey(NSha1::CContext &sha, Byte *key) | |
40 { | |
41 Byte digest[NSha1::kDigestSize]; | |
42 sha.Final(digest); | |
43 Byte temp[NSha1::kDigestSize * 2]; | |
44 DeriveKey2(digest, 0x36, temp); | |
45 DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); | |
46 memcpy(key, temp, 32); | |
47 } | |
48 | |
49 void CKeyInfo::SetPassword(const Byte *data, UInt32 size) | |
50 { | |
51 NSha1::CContext sha; | |
52 sha.Init(); | |
53 sha.Update(data, size); | |
54 DeriveKey(sha, MasterKey); | |
55 } | |
56 | |
57 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) | |
58 { | |
59 _key.SetPassword(data, size); | |
60 return S_OK; | |
61 } | |
62 | |
63 STDMETHODIMP CBaseCoder::Init() | |
64 { | |
65 return S_OK; | |
66 } | |
67 | |
68 HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 /* crc */, UInt64 /* unpackSize */) | |
69 { | |
70 Byte temp[4]; | |
71 RINOK(ReadStream_FALSE(inStream, temp, 2)); | |
72 _ivSize = GetUi16(temp); | |
73 if (_ivSize == 0) | |
74 { | |
75 return E_NOTIMPL; | |
76 /* | |
77 SetUi32(_iv, crc); | |
78 for (int i = 0; i < 8; i++) | |
79 _iv[4 + i] = (Byte)(unpackSize >> (8 * i)); | |
80 SetUi32(_iv + 12, 0); | |
81 */ | |
82 } | |
83 else if (_ivSize == 16) | |
84 { | |
85 RINOK(ReadStream_FALSE(inStream, _iv, _ivSize)); | |
86 } | |
87 else | |
88 return E_NOTIMPL; | |
89 RINOK(ReadStream_FALSE(inStream, temp, 4)); | |
90 _remSize = GetUi32(temp); | |
91 if (_remSize > _buf.GetCapacity()) | |
92 { | |
93 _buf.Free(); | |
94 _buf.SetCapacity(_remSize); | |
95 } | |
96 return ReadStream_FALSE(inStream, _buf, _remSize); | |
97 } | |
98 | |
99 HRESULT CDecoder::CheckPassword(bool &passwOK) | |
100 { | |
101 passwOK = false; | |
102 if (_remSize < 10) | |
103 return E_NOTIMPL; | |
104 Byte *p = _buf; | |
105 UInt16 format = GetUi16(p); | |
106 if (format != 3) | |
107 return E_NOTIMPL; | |
108 UInt16 algId = GetUi16(p + 2); | |
109 if (algId < kAES128) | |
110 return E_NOTIMPL; | |
111 algId -= kAES128; | |
112 if (algId > 2) | |
113 return E_NOTIMPL; | |
114 UInt16 bitLen = GetUi16(p + 4); | |
115 UInt16 flags = GetUi16(p + 6); | |
116 if (algId * 64 + 128 != bitLen) | |
117 return E_NOTIMPL; | |
118 _key.KeySize = 16 + algId * 8; | |
119 if ((flags & 1) == 0) | |
120 return E_NOTIMPL; | |
121 UInt32 rdSize = GetUi16(p + 8); | |
122 UInt32 pos = 10; | |
123 Byte *rd = p + pos; | |
124 pos += rdSize; | |
125 if (pos + 4 > _remSize) | |
126 return E_NOTIMPL; | |
127 UInt32 reserved = GetUi32(p + pos); | |
128 pos += 4; | |
129 if (reserved != 0) | |
130 return E_NOTIMPL; | |
131 if (pos + 2 > _remSize) | |
132 return E_NOTIMPL; | |
133 UInt32 validSize = GetUi16(p + pos); | |
134 pos += 2; | |
135 Byte *validData = p + pos; | |
136 if (pos + validSize != _remSize) | |
137 return E_NOTIMPL; | |
138 | |
139 if (!_aesFilter) | |
140 _aesFilter = new CAesCbcDecoder; | |
141 | |
142 CMyComPtr<ICryptoProperties> cp; | |
143 RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp)); | |
144 { | |
145 RINOK(cp->SetKey(_key.MasterKey, _key.KeySize)); | |
146 RINOK(cp->SetInitVector(_iv, 16)); | |
147 _aesFilter->Init(); | |
148 if (_aesFilter->Filter(rd, rdSize) != rdSize) | |
149 return E_NOTIMPL; | |
150 } | |
151 | |
152 Byte fileKey[32]; | |
153 NSha1::CContext sha; | |
154 sha.Init(); | |
155 sha.Update(_iv, 16); | |
156 sha.Update(rd, rdSize - 16); // we don't use last 16 bytes (PAD bytes) | |
157 DeriveKey(sha, fileKey); | |
158 | |
159 RINOK(cp->SetKey(fileKey, _key.KeySize)); | |
160 RINOK(cp->SetInitVector(_iv, 16)); | |
161 _aesFilter->Init(); | |
162 if (_aesFilter->Filter(validData, validSize) != validSize) | |
163 return E_NOTIMPL; | |
164 | |
165 if (validSize < 4) | |
166 return E_NOTIMPL; | |
167 validSize -= 4; | |
168 if (GetUi32(validData + validSize) != CrcCalc(validData, validSize)) | |
169 return S_OK; | |
170 passwOK = true; | |
171 _aesFilter->Init(); | |
172 return S_OK; | |
173 } | |
174 | |
175 STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) | |
176 { | |
177 return _aesFilter->Filter(data, size); | |
178 } | |
179 | |
180 }} |