diff options
Diffstat (limited to '7zip/Crypto/WzAES/WzAES.cpp')
-rwxr-xr-x | 7zip/Crypto/WzAES/WzAES.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/7zip/Crypto/WzAES/WzAES.cpp b/7zip/Crypto/WzAES/WzAES.cpp new file mode 100755 index 00000000..8bf53b43 --- /dev/null +++ b/7zip/Crypto/WzAES/WzAES.cpp @@ -0,0 +1,246 @@ +// WzAES.cpp +/* +This code implements Brian Gladman's scheme +specified in password Based File Encryption Utility. +*/ + +#include "StdAfx.h" + +#include "Windows/Defs.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" +#include "../Hash/Pbkdf2HmacSha1.h" +#include "../Hash/RandGen.h" + +#include "WzAES.h" + +#ifdef CRYPTO_AES +#include "../AES/MyAES.h" +#else +extern void GetCryptoFolderPrefix(TCHAR *path); +#endif + +// define it if you don't want to use speed-optimized version of Pbkdf2HmacSha1 +// #define _NO_WZAES_OPTIMIZATIONS + +namespace NCrypto { +namespace NWzAES { + +const unsigned int kAesKeySizeMax = 32; + +static const UInt32 kNumKeyGenIterations = 1000; + +STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size) +{ + if(size > kPasswordSizeMax) + return E_INVALIDARG; + _key.Password.SetCapacity(size); + memcpy(_key.Password, data, size); + return S_OK; +} + +void CBaseCoder::EncryptData(Byte *data, UInt32 size) +{ + unsigned int pos = _blockPos; + for (; size > 0; size--) + { + if (pos == kAesBlockSize) + { + int j; + for (j = 0; j < 8 && ++_counter[j] == 0; j++); + for (j = 0; j < 8; j++) + _buffer[j] = _counter[j]; + for (; j < kAesBlockSize; j++) + _buffer[j] = 0; + _aesFilter->Filter(_buffer, kAesBlockSize); + pos = 0; + } + *data++ ^= _buffer[pos++]; + } + _blockPos = pos; +} + +#ifndef _NO_WZAES_OPTIMIZATIONS + +static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, int destSize) +{ + for (int i = 0 ; i < destSize; i++) + dest[i] = + ((UInt32)(src[i * 4 + 0]) << 24) | + ((UInt32)(src[i * 4 + 1]) << 16) | + ((UInt32)(src[i * 4 + 2]) << 8) | + ((UInt32)(src[i * 4 + 3])); +} + +#endif + +STDMETHODIMP CBaseCoder::Init() +{ + UInt32 keySize = _key.GetKeySize(); + UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize; + Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize]; + + // for (int ii = 0; ii < 1000; ii++) + { + #ifdef _NO_WZAES_OPTIMIZATIONS + + NSha1::Pbkdf2Hmac( + _key.Password, _key.Password.GetCapacity(), + _key.Salt, _key.GetSaltSize(), + kNumKeyGenIterations, + buf, keysTotalSize); + + #else + + UInt32 buf32[(2 * kAesKeySizeMax + kPwdVerifCodeSize + 3) / 4]; + UInt32 key32SizeTotal = (keysTotalSize + 3) / 4; + UInt32 salt[kSaltSizeMax * 4]; + UInt32 saltSizeInWords = _key.GetSaltSize() / 4; + BytesToBeUInt32s(_key.Salt, salt, saltSizeInWords); + NSha1::Pbkdf2Hmac32( + _key.Password, _key.Password.GetCapacity(), + salt, saltSizeInWords, + kNumKeyGenIterations, + buf32, key32SizeTotal); + for (UInt32 j = 0; j < keysTotalSize; j++) + buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3))); + + #endif + } + + _hmac.SetKey(buf + keySize, keySize); + memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize); + + _blockPos = kAesBlockSize; + for (int i = 0; i < 8; i++) + _counter[i] = 0; + + RINOK(CreateFilters()); + CMyComPtr<ICryptoProperties> cp; + RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp)); + return cp->SetKey(buf, keySize); +} + +static HRESULT SafeWrite(ISequentialOutStream *outStream, const Byte *data, UInt32 size) +{ + UInt32 processedSize; + RINOK(WriteStream(outStream, data, size, &processedSize)); + return ((processedSize == size) ? S_OK : E_FAIL); +} + +/* +STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream) +{ + Byte keySizeMode = 3; + return outStream->Write(&keySizeMode, 1, NULL); +} +*/ + +HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream) +{ + UInt32 saltSize = _key.GetSaltSize(); + g_RandomGenerator.Generate(_key.Salt, saltSize); + Init(); + RINOK(SafeWrite(outStream, _key.Salt, saltSize)); + return SafeWrite(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize); +} + +HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream) +{ + Byte mac[kMacSize]; + _hmac.Final(mac, kMacSize); + return SafeWrite(outStream, mac, kMacSize); +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size != 1) + return E_INVALIDARG; + _key.Init(); + Byte keySizeMode = data[0]; + if (keySizeMode < 1 || keySizeMode > 3) + return E_INVALIDARG; + _key.KeySizeMode = keySizeMode; + return S_OK; +} + +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) +{ + UInt32 saltSize = _key.GetSaltSize(); + UInt32 extraSize = saltSize + kPwdVerifCodeSize; + Byte temp[kSaltSizeMax + kPwdVerifCodeSize]; + UInt32 processedSize; + RINOK(ReadStream(inStream, temp, extraSize, &processedSize)); + if (processedSize != extraSize) + return E_FAIL; + UInt32 i; + for (i = 0; i < saltSize; i++) + _key.Salt[i] = temp[i]; + for (i = 0; i < kPwdVerifCodeSize; i++) + _pwdVerifFromArchive[i] = temp[saltSize + i]; + return S_OK; +} + +static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + if (p1[i] != p2[i]) + return false; + return true; +} + +bool CDecoder::CheckPasswordVerifyCode() +{ + return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize); +} + +HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK) +{ + isOK = false; + UInt32 processedSize; + Byte mac1[kMacSize]; + RINOK(ReadStream(inStream, mac1, kMacSize, &processedSize)); + if (processedSize != kMacSize) + return E_FAIL; + Byte mac2[kMacSize]; + _hmac.Final(mac2, kMacSize); + isOK = CompareArrays(mac1, mac2, kMacSize); + return S_OK; +} + +STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size) +{ + EncryptData(data, size); + _hmac.Update(data, size); + return size; +} + +STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) +{ + _hmac.Update(data, size); + EncryptData(data, size); + return size; +} + + +HRESULT CBaseCoder::CreateFilters() +{ + if (!_aesFilter) + { + #ifdef CRYPTO_AES + + _aesFilter = new CAES_ECB_Encoder; + + #else + + TCHAR aesLibPath[MAX_PATH + 64]; + GetCryptoFolderPrefix(aesLibPath); + lstrcat(aesLibPath, TEXT("AES.dll")); + RINOK(_aesLibrary.LoadAndCreateFilter(aesLibPath, CLSID_CCrypto_AES_ECB_Encoder, &_aesFilter)); + + #endif + } + return S_OK; +} + +}} |