rlm@1
|
1 // Crypto/RarAes.cpp
|
rlm@1
|
2 // Note: you must include MyAes.cpp to project to initialize AES tables
|
rlm@1
|
3
|
rlm@1
|
4 #include "StdAfx.h"
|
rlm@1
|
5
|
rlm@1
|
6 #include "RarAes.h"
|
rlm@1
|
7 #include "Sha1.h"
|
rlm@1
|
8
|
rlm@1
|
9 namespace NCrypto {
|
rlm@1
|
10 namespace NRar29 {
|
rlm@1
|
11
|
rlm@1
|
12 CDecoder::CDecoder():
|
rlm@1
|
13 _thereIsSalt(false),
|
rlm@1
|
14 _needCalculate(true),
|
rlm@1
|
15 _rar350Mode(false)
|
rlm@1
|
16 {
|
rlm@1
|
17 for (int i = 0; i < sizeof(_salt); i++)
|
rlm@1
|
18 _salt[i] = 0;
|
rlm@1
|
19 }
|
rlm@1
|
20
|
rlm@1
|
21 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
rlm@1
|
22 {
|
rlm@1
|
23 bool thereIsSaltPrev = _thereIsSalt;
|
rlm@1
|
24 _thereIsSalt = false;
|
rlm@1
|
25 if (size == 0)
|
rlm@1
|
26 return S_OK;
|
rlm@1
|
27 if (size < 8)
|
rlm@1
|
28 return E_INVALIDARG;
|
rlm@1
|
29 _thereIsSalt = true;
|
rlm@1
|
30 bool same = false;
|
rlm@1
|
31 if (_thereIsSalt == thereIsSaltPrev)
|
rlm@1
|
32 {
|
rlm@1
|
33 same = true;
|
rlm@1
|
34 if (_thereIsSalt)
|
rlm@1
|
35 {
|
rlm@1
|
36 for (int i = 0; i < sizeof(_salt); i++)
|
rlm@1
|
37 if (_salt[i] != data[i])
|
rlm@1
|
38 {
|
rlm@1
|
39 same = false;
|
rlm@1
|
40 break;
|
rlm@1
|
41 }
|
rlm@1
|
42 }
|
rlm@1
|
43 }
|
rlm@1
|
44 for (int i = 0; i < sizeof(_salt); i++)
|
rlm@1
|
45 _salt[i] = data[i];
|
rlm@1
|
46 if (!_needCalculate && !same)
|
rlm@1
|
47 _needCalculate = true;
|
rlm@1
|
48 return S_OK;
|
rlm@1
|
49 }
|
rlm@1
|
50
|
rlm@1
|
51 static const int kMaxPasswordLength = 127 * 2;
|
rlm@1
|
52
|
rlm@1
|
53 STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
|
rlm@1
|
54 {
|
rlm@1
|
55 if (size > kMaxPasswordLength)
|
rlm@1
|
56 size = kMaxPasswordLength;
|
rlm@1
|
57 bool same = false;
|
rlm@1
|
58 if (size == buffer.GetCapacity())
|
rlm@1
|
59 {
|
rlm@1
|
60 same = true;
|
rlm@1
|
61 for (UInt32 i = 0; i < size; i++)
|
rlm@1
|
62 if (data[i] != buffer[i])
|
rlm@1
|
63 {
|
rlm@1
|
64 same = false;
|
rlm@1
|
65 break;
|
rlm@1
|
66 }
|
rlm@1
|
67 }
|
rlm@1
|
68 if (!_needCalculate && !same)
|
rlm@1
|
69 _needCalculate = true;
|
rlm@1
|
70 buffer.SetCapacity(size);
|
rlm@1
|
71 memcpy(buffer, data, size);
|
rlm@1
|
72 return S_OK;
|
rlm@1
|
73 }
|
rlm@1
|
74
|
rlm@1
|
75 STDMETHODIMP CDecoder::Init()
|
rlm@1
|
76 {
|
rlm@1
|
77 Calculate();
|
rlm@1
|
78 Aes_SetKeyDecode(&Aes.aes, aesKey, kRarAesKeySize);
|
rlm@1
|
79 AesCbc_Init(&Aes, aesInit);
|
rlm@1
|
80 return S_OK;
|
rlm@1
|
81 }
|
rlm@1
|
82
|
rlm@1
|
83 STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
|
rlm@1
|
84 {
|
rlm@1
|
85 return (UInt32)AesCbc_Decode(&Aes, data, size);
|
rlm@1
|
86 }
|
rlm@1
|
87
|
rlm@1
|
88 void CDecoder::Calculate()
|
rlm@1
|
89 {
|
rlm@1
|
90 if (_needCalculate)
|
rlm@1
|
91 {
|
rlm@1
|
92 const int kSaltSize = 8;
|
rlm@1
|
93
|
rlm@1
|
94 Byte rawPassword[kMaxPasswordLength + kSaltSize];
|
rlm@1
|
95
|
rlm@1
|
96 memcpy(rawPassword, buffer, buffer.GetCapacity());
|
rlm@1
|
97
|
rlm@1
|
98 size_t rawLength = buffer.GetCapacity();
|
rlm@1
|
99
|
rlm@1
|
100 if (_thereIsSalt)
|
rlm@1
|
101 {
|
rlm@1
|
102 memcpy(rawPassword + rawLength, _salt, kSaltSize);
|
rlm@1
|
103 rawLength += kSaltSize;
|
rlm@1
|
104 }
|
rlm@1
|
105
|
rlm@1
|
106 NSha1::CContext sha;
|
rlm@1
|
107 sha.Init();
|
rlm@1
|
108
|
rlm@1
|
109 // seems rar reverts hash for sha.
|
rlm@1
|
110 const int hashRounds = 0x40000;
|
rlm@1
|
111 int i;
|
rlm@1
|
112 for (i = 0; i < hashRounds; i++)
|
rlm@1
|
113 {
|
rlm@1
|
114 sha.Update(rawPassword, rawLength, _rar350Mode);
|
rlm@1
|
115 Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
|
rlm@1
|
116 sha.Update(pswNum, 3, _rar350Mode);
|
rlm@1
|
117 if (i % (hashRounds / 16) == 0)
|
rlm@1
|
118 {
|
rlm@1
|
119 NSha1::CContext shaTemp = sha;
|
rlm@1
|
120 Byte digest[NSha1::kDigestSize];
|
rlm@1
|
121 shaTemp.Final(digest);
|
rlm@1
|
122 aesInit[i / (hashRounds / 16)] = (Byte)digest[4 * 4 + 3];
|
rlm@1
|
123 }
|
rlm@1
|
124 }
|
rlm@1
|
125 /*
|
rlm@1
|
126 // it's test message for sha
|
rlm@1
|
127 const char *message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
rlm@1
|
128 sha.Update((const Byte *)message, strlen(message));
|
rlm@1
|
129 */
|
rlm@1
|
130 Byte digest[20];
|
rlm@1
|
131 sha.Final(digest);
|
rlm@1
|
132 for (i = 0; i < 4; i++)
|
rlm@1
|
133 for (int j = 0; j < 4; j++)
|
rlm@1
|
134 aesKey[i * 4 + j] = (digest[i * 4 + 3 - j]);
|
rlm@1
|
135 }
|
rlm@1
|
136 _needCalculate = false;
|
rlm@1
|
137 }
|
rlm@1
|
138
|
rlm@1
|
139 }}
|