-
Notifications
You must be signed in to change notification settings - Fork 22
/
crypt.cpp
130 lines (110 loc) · 2.78 KB
/
crypt.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "rar.hpp"
#ifndef SFX_MODULE
#include "crypt1.cpp"
#include "crypt2.cpp"
#endif
#include "crypt3.cpp"
#include "crypt5.cpp"
CryptData::CryptData()
{
Method=CRYPT_NONE;
KDF3CachePos=0;
KDF5CachePos=0;
memset(CRCTab,0,sizeof(CRCTab));
}
void CryptData::DecryptBlock(byte *Buf,size_t Size)
{
switch(Method)
{
#ifndef SFX_MODULE
case CRYPT_RAR13:
Decrypt13(Buf,Size);
break;
case CRYPT_RAR15:
Crypt15(Buf,Size);
break;
case CRYPT_RAR20:
for (size_t I=0;I<Size;I+=CRYPT_BLOCK_SIZE)
DecryptBlock20(Buf+I);
break;
#endif
case CRYPT_RAR30:
case CRYPT_RAR50:
rin.blockDecrypt(Buf,Size,Buf);
break;
}
}
bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
SecPassword *Password,const byte *Salt,
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
{
if (Method==CRYPT_NONE || !Password->IsSet())
return false;
CryptData::Method=Method;
wchar PwdW[MAXPASSWORD];
Password->Get(PwdW,ASIZE(PwdW));
PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
char PwdA[MAXPASSWORD];
WideToChar(PwdW,PwdA,ASIZE(PwdA));
PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
bool Success=true;
switch(Method)
{
#ifndef SFX_MODULE
case CRYPT_RAR13:
SetKey13(PwdA);
break;
case CRYPT_RAR15:
SetKey15(PwdA);
break;
case CRYPT_RAR20:
SetKey20(PwdA);
break;
#endif
case CRYPT_RAR30:
SetKey30(Encrypt,Password,PwdW,Salt);
break;
case CRYPT_RAR50:
Success=SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
break;
}
cleandata(PwdA,sizeof(PwdA));
cleandata(PwdW,sizeof(PwdW));
return Success;
}
// Use the current system time to additionally randomize data.
static void TimeRandomize(byte *RndBuf,size_t BufSize)
{
static uint Count=0;
RarTime CurTime;
CurTime.SetCurrentTime();
uint64 Random=CurTime.GetWin()+clock();
for (size_t I=0;I<BufSize;I++)
{
byte RndByte = byte (Random >> ( (I & 7) * 8 ));
RndBuf[I]=byte( (RndByte ^ I) + Count++);
}
}
// Fill buffer with random data.
void GetRnd(byte *RndBuf,size_t BufSize)
{
bool Success=false;
#if defined(_WIN_ALL)
HCRYPTPROV hProvider = 0;
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) != FALSE;
CryptReleaseContext(hProvider, 0);
}
#elif defined(_UNIX)
FILE *rndf = fopen("/dev/urandom", "r");
if (rndf!=NULL)
{
Success=fread(RndBuf, BufSize, 1, rndf) == BufSize;
fclose(rndf);
}
#endif
// We use this code only as the last resort if code above failed.
if (!Success)
TimeRandomize(RndBuf,BufSize);
}