forked from pmachapman/unrar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
crypt.cpp
128 lines (109 loc) · 2.74 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
#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 (!Password->IsSet() || Method==CRYPT_NONE)
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.
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:
SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
break;
}
cleandata(PwdA,sizeof(PwdA));
cleandata(PwdW,sizeof(PwdW));
return true;
}
// 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) == TRUE;
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);
}