Mercurial > vba-clojure
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/win32/7zip/7z/CPP/7zip/Crypto/ZipStrong.cpp Sat Mar 03 10:31:27 2012 -0600 1.3 @@ -0,0 +1,180 @@ 1.4 +// Crypto/ZipStrong.cpp 1.5 + 1.6 +#include "StdAfx.h" 1.7 + 1.8 +extern "C" 1.9 +{ 1.10 +#include "../../../C/7zCrc.h" 1.11 +#include "../../../C/CpuArch.h" 1.12 +} 1.13 + 1.14 +#include "../Common/StreamUtils.h" 1.15 + 1.16 +#include "MyAES.h" 1.17 +#include "Sha1.h" 1.18 +#include "ZipStrong.h" 1.19 + 1.20 +namespace NCrypto { 1.21 +namespace NZipStrong { 1.22 + 1.23 +static const UInt16 kAES128 = 0x660E; 1.24 + 1.25 +// DeriveKey* function is similar to CryptDeriveKey() from Windows. 1.26 +// But MSDN tells that we need such scheme only if 1.27 +// "the required key length is longer than the hash value" 1.28 +// but ZipStrong uses it always. 1.29 + 1.30 +static void DeriveKey2(const Byte *digest, Byte c, Byte *dest) 1.31 +{ 1.32 + Byte buf[64]; 1.33 + memset(buf, c, 64); 1.34 + for (unsigned i = 0; i < NSha1::kDigestSize; i++) 1.35 + buf[i] ^= digest[i]; 1.36 + NSha1::CContext sha; 1.37 + sha.Init(); 1.38 + sha.Update(buf, 64); 1.39 + sha.Final(dest); 1.40 +} 1.41 + 1.42 +static void DeriveKey(NSha1::CContext &sha, Byte *key) 1.43 +{ 1.44 + Byte digest[NSha1::kDigestSize]; 1.45 + sha.Final(digest); 1.46 + Byte temp[NSha1::kDigestSize * 2]; 1.47 + DeriveKey2(digest, 0x36, temp); 1.48 + DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); 1.49 + memcpy(key, temp, 32); 1.50 +} 1.51 + 1.52 +void CKeyInfo::SetPassword(const Byte *data, UInt32 size) 1.53 +{ 1.54 + NSha1::CContext sha; 1.55 + sha.Init(); 1.56 + sha.Update(data, size); 1.57 + DeriveKey(sha, MasterKey); 1.58 +} 1.59 + 1.60 +STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) 1.61 +{ 1.62 + _key.SetPassword(data, size); 1.63 + return S_OK; 1.64 +} 1.65 + 1.66 +STDMETHODIMP CBaseCoder::Init() 1.67 +{ 1.68 + return S_OK; 1.69 +} 1.70 + 1.71 +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 /* crc */, UInt64 /* unpackSize */) 1.72 +{ 1.73 + Byte temp[4]; 1.74 + RINOK(ReadStream_FALSE(inStream, temp, 2)); 1.75 + _ivSize = GetUi16(temp); 1.76 + if (_ivSize == 0) 1.77 + { 1.78 + return E_NOTIMPL; 1.79 + /* 1.80 + SetUi32(_iv, crc); 1.81 + for (int i = 0; i < 8; i++) 1.82 + _iv[4 + i] = (Byte)(unpackSize >> (8 * i)); 1.83 + SetUi32(_iv + 12, 0); 1.84 + */ 1.85 + } 1.86 + else if (_ivSize == 16) 1.87 + { 1.88 + RINOK(ReadStream_FALSE(inStream, _iv, _ivSize)); 1.89 + } 1.90 + else 1.91 + return E_NOTIMPL; 1.92 + RINOK(ReadStream_FALSE(inStream, temp, 4)); 1.93 + _remSize = GetUi32(temp); 1.94 + if (_remSize > _buf.GetCapacity()) 1.95 + { 1.96 + _buf.Free(); 1.97 + _buf.SetCapacity(_remSize); 1.98 + } 1.99 + return ReadStream_FALSE(inStream, _buf, _remSize); 1.100 +} 1.101 + 1.102 +HRESULT CDecoder::CheckPassword(bool &passwOK) 1.103 +{ 1.104 + passwOK = false; 1.105 + if (_remSize < 10) 1.106 + return E_NOTIMPL; 1.107 + Byte *p = _buf; 1.108 + UInt16 format = GetUi16(p); 1.109 + if (format != 3) 1.110 + return E_NOTIMPL; 1.111 + UInt16 algId = GetUi16(p + 2); 1.112 + if (algId < kAES128) 1.113 + return E_NOTIMPL; 1.114 + algId -= kAES128; 1.115 + if (algId > 2) 1.116 + return E_NOTIMPL; 1.117 + UInt16 bitLen = GetUi16(p + 4); 1.118 + UInt16 flags = GetUi16(p + 6); 1.119 + if (algId * 64 + 128 != bitLen) 1.120 + return E_NOTIMPL; 1.121 + _key.KeySize = 16 + algId * 8; 1.122 + if ((flags & 1) == 0) 1.123 + return E_NOTIMPL; 1.124 + UInt32 rdSize = GetUi16(p + 8); 1.125 + UInt32 pos = 10; 1.126 + Byte *rd = p + pos; 1.127 + pos += rdSize; 1.128 + if (pos + 4 > _remSize) 1.129 + return E_NOTIMPL; 1.130 + UInt32 reserved = GetUi32(p + pos); 1.131 + pos += 4; 1.132 + if (reserved != 0) 1.133 + return E_NOTIMPL; 1.134 + if (pos + 2 > _remSize) 1.135 + return E_NOTIMPL; 1.136 + UInt32 validSize = GetUi16(p + pos); 1.137 + pos += 2; 1.138 + Byte *validData = p + pos; 1.139 + if (pos + validSize != _remSize) 1.140 + return E_NOTIMPL; 1.141 + 1.142 + if (!_aesFilter) 1.143 + _aesFilter = new CAesCbcDecoder; 1.144 + 1.145 + CMyComPtr<ICryptoProperties> cp; 1.146 + RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp)); 1.147 + { 1.148 + RINOK(cp->SetKey(_key.MasterKey, _key.KeySize)); 1.149 + RINOK(cp->SetInitVector(_iv, 16)); 1.150 + _aesFilter->Init(); 1.151 + if (_aesFilter->Filter(rd, rdSize) != rdSize) 1.152 + return E_NOTIMPL; 1.153 + } 1.154 + 1.155 + Byte fileKey[32]; 1.156 + NSha1::CContext sha; 1.157 + sha.Init(); 1.158 + sha.Update(_iv, 16); 1.159 + sha.Update(rd, rdSize - 16); // we don't use last 16 bytes (PAD bytes) 1.160 + DeriveKey(sha, fileKey); 1.161 + 1.162 + RINOK(cp->SetKey(fileKey, _key.KeySize)); 1.163 + RINOK(cp->SetInitVector(_iv, 16)); 1.164 + _aesFilter->Init(); 1.165 + if (_aesFilter->Filter(validData, validSize) != validSize) 1.166 + return E_NOTIMPL; 1.167 + 1.168 + if (validSize < 4) 1.169 + return E_NOTIMPL; 1.170 + validSize -= 4; 1.171 + if (GetUi32(validData + validSize) != CrcCalc(validData, validSize)) 1.172 + return S_OK; 1.173 + passwOK = true; 1.174 + _aesFilter->Init(); 1.175 + return S_OK; 1.176 +} 1.177 + 1.178 +STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) 1.179 +{ 1.180 + return _aesFilter->Filter(data, size); 1.181 +} 1.182 + 1.183 +}}