Mercurial > vba-linux
view 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 source
1 // Crypto/ZipStrong.cpp3 #include "StdAfx.h"5 extern "C"6 {7 #include "../../../C/7zCrc.h"8 #include "../../../C/CpuArch.h"9 }11 #include "../Common/StreamUtils.h"13 #include "MyAES.h"14 #include "Sha1.h"15 #include "ZipStrong.h"17 namespace NCrypto {18 namespace NZipStrong {20 static const UInt16 kAES128 = 0x660E;22 // DeriveKey* function is similar to CryptDeriveKey() from Windows.23 // But MSDN tells that we need such scheme only if24 // "the required key length is longer than the hash value"25 // but ZipStrong uses it always.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 }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 }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 }57 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)58 {59 _key.SetPassword(data, size);60 return S_OK;61 }63 STDMETHODIMP CBaseCoder::Init()64 {65 return S_OK;66 }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 else88 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 }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;139 if (!_aesFilter)140 _aesFilter = new CAesCbcDecoder;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 }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);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;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 }175 STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)176 {177 return _aesFilter->Filter(data, size);178 }180 }}