rlm@1: // Crypto/RarAes.cpp rlm@1: // Note: you must include MyAes.cpp to project to initialize AES tables rlm@1: rlm@1: #include "StdAfx.h" rlm@1: rlm@1: #include "RarAes.h" rlm@1: #include "Sha1.h" rlm@1: rlm@1: namespace NCrypto { rlm@1: namespace NRar29 { rlm@1: rlm@1: CDecoder::CDecoder(): rlm@1: _thereIsSalt(false), rlm@1: _needCalculate(true), rlm@1: _rar350Mode(false) rlm@1: { rlm@1: for (int i = 0; i < sizeof(_salt); i++) rlm@1: _salt[i] = 0; rlm@1: } rlm@1: rlm@1: STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) rlm@1: { rlm@1: bool thereIsSaltPrev = _thereIsSalt; rlm@1: _thereIsSalt = false; rlm@1: if (size == 0) rlm@1: return S_OK; rlm@1: if (size < 8) rlm@1: return E_INVALIDARG; rlm@1: _thereIsSalt = true; rlm@1: bool same = false; rlm@1: if (_thereIsSalt == thereIsSaltPrev) rlm@1: { rlm@1: same = true; rlm@1: if (_thereIsSalt) rlm@1: { rlm@1: for (int i = 0; i < sizeof(_salt); i++) rlm@1: if (_salt[i] != data[i]) rlm@1: { rlm@1: same = false; rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: for (int i = 0; i < sizeof(_salt); i++) rlm@1: _salt[i] = data[i]; rlm@1: if (!_needCalculate && !same) rlm@1: _needCalculate = true; rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: static const int kMaxPasswordLength = 127 * 2; rlm@1: rlm@1: STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size) rlm@1: { rlm@1: if (size > kMaxPasswordLength) rlm@1: size = kMaxPasswordLength; rlm@1: bool same = false; rlm@1: if (size == buffer.GetCapacity()) rlm@1: { rlm@1: same = true; rlm@1: for (UInt32 i = 0; i < size; i++) rlm@1: if (data[i] != buffer[i]) rlm@1: { rlm@1: same = false; rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (!_needCalculate && !same) rlm@1: _needCalculate = true; rlm@1: buffer.SetCapacity(size); rlm@1: memcpy(buffer, data, size); rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP CDecoder::Init() rlm@1: { rlm@1: Calculate(); rlm@1: Aes_SetKeyDecode(&Aes.aes, aesKey, kRarAesKeySize); rlm@1: AesCbc_Init(&Aes, aesInit); rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size) rlm@1: { rlm@1: return (UInt32)AesCbc_Decode(&Aes, data, size); rlm@1: } rlm@1: rlm@1: void CDecoder::Calculate() rlm@1: { rlm@1: if (_needCalculate) rlm@1: { rlm@1: const int kSaltSize = 8; rlm@1: rlm@1: Byte rawPassword[kMaxPasswordLength + kSaltSize]; rlm@1: rlm@1: memcpy(rawPassword, buffer, buffer.GetCapacity()); rlm@1: rlm@1: size_t rawLength = buffer.GetCapacity(); rlm@1: rlm@1: if (_thereIsSalt) rlm@1: { rlm@1: memcpy(rawPassword + rawLength, _salt, kSaltSize); rlm@1: rawLength += kSaltSize; rlm@1: } rlm@1: rlm@1: NSha1::CContext sha; rlm@1: sha.Init(); rlm@1: rlm@1: // seems rar reverts hash for sha. rlm@1: const int hashRounds = 0x40000; rlm@1: int i; rlm@1: for (i = 0; i < hashRounds; i++) rlm@1: { rlm@1: sha.Update(rawPassword, rawLength, _rar350Mode); rlm@1: Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) }; rlm@1: sha.Update(pswNum, 3, _rar350Mode); rlm@1: if (i % (hashRounds / 16) == 0) rlm@1: { rlm@1: NSha1::CContext shaTemp = sha; rlm@1: Byte digest[NSha1::kDigestSize]; rlm@1: shaTemp.Final(digest); rlm@1: aesInit[i / (hashRounds / 16)] = (Byte)digest[4 * 4 + 3]; rlm@1: } rlm@1: } rlm@1: /* rlm@1: // it's test message for sha rlm@1: const char *message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; rlm@1: sha.Update((const Byte *)message, strlen(message)); rlm@1: */ rlm@1: Byte digest[20]; rlm@1: sha.Final(digest); rlm@1: for (i = 0; i < 4; i++) rlm@1: for (int j = 0; j < 4; j++) rlm@1: aesKey[i * 4 + j] = (digest[i * 4 + 3 - j]); rlm@1: } rlm@1: _needCalculate = false; rlm@1: } rlm@1: rlm@1: }}