File: Rar20Crypto.cpp

package info (click to toggle)
p7zip 16.02%2Bdfsg-8
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 14,148 kB
  • sloc: cpp: 167,145; ansic: 14,992; python: 1,911; asm: 1,688; sh: 1,132; makefile: 703
file content (130 lines) | stat: -rw-r--r-- 3,519 bytes parent folder | download | duplicates (5)
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
// Crypto/Rar20Crypto.cpp

#include "StdAfx.h"

#include "../../../C/7zCrc.h"
#include "../../../C/CpuArch.h"
#include "../../../C/RotateDefs.h"

#include "Rar20Crypto.h"

namespace NCrypto {
namespace NRar2 {

static const unsigned kNumRounds = 32;

static const Byte g_InitSubstTable[256] = {
  215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221,  2, 42,
  232,  1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
  255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86,  6,
   71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
  107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
  158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
   97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
  164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
  207,120,189,210,  8,226, 41, 72,183,203,135,165,166, 60, 98,  7,
  122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
  131,  3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
  224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
  118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45,  4,148,108,
  161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
    0, 46,169,186, 68, 95,237, 65, 53,208,253,168,  9, 18,100, 52,
  116,184,160, 96,109, 37, 30,106,140,104,150,  5,204,117,112, 84
};

void CData::UpdateKeys(const Byte *data)
{
  for (unsigned i = 0; i < 16; i += 4)
    for (unsigned j = 0; j < 4; j++)
      Keys[j] ^= g_CrcTable[data[i + j]];
}

static inline void Swap(Byte &b1, Byte &b2)
{
  Byte b = b1;
  b1 = b2;
  b2 = b;
}

void CData::SetPassword(const Byte *data, unsigned size)
{
  Keys[0] = 0xD3A3B879L;
  Keys[1] = 0x3F6D12F7L;
  Keys[2] = 0x7515A235L;
  Keys[3] = 0xA4E7F123L;
  
  Byte psw[128];
  memset(psw, 0, sizeof(psw));
  if (size != 0)
  {
    if (size >= sizeof(psw))
      size = sizeof(psw) - 1;
    memcpy(psw, data, size);
  }

  memcpy(SubstTable, g_InitSubstTable, sizeof(SubstTable));

  for (unsigned j = 0; j < 256; j++)
    for (unsigned i = 0; i < size; i += 2)
    {
      unsigned n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF];
      unsigned n2 = (Byte)g_CrcTable[(psw[i + 1] + j) & 0xFF];
      for (unsigned k = 1; (n1 & 0xFF) != n2; n1++, k++)
        Swap(SubstTable[n1 & 0xFF], SubstTable[(n1 + i + k) & 0xFF]);
    }
  
  for (unsigned i = 0; i < size; i += 16)
    EncryptBlock(psw + i);
}

void CData::CryptBlock(Byte *buf, bool encrypt)
{
  Byte inBuf[16];
  UInt32 A, B, C, D;

  A = GetUi32(buf +  0) ^ Keys[0];
  B = GetUi32(buf +  4) ^ Keys[1];
  C = GetUi32(buf +  8) ^ Keys[2];
  D = GetUi32(buf + 12) ^ Keys[3];

  if (!encrypt)
    memcpy(inBuf, buf, sizeof(inBuf));
  
  for (unsigned i = 0; i < kNumRounds; i++)
  {
    UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
    UInt32 TA = A ^ SubstLong((C + rotlFixed(D, 11)) ^ key);
    UInt32 TB = B ^ SubstLong((D ^ rotlFixed(C, 17)) + key);
    A = C; C = TA;
    B = D; D = TB;
  }

  SetUi32(buf +  0, C ^ Keys[0]);
  SetUi32(buf +  4, D ^ Keys[1]);
  SetUi32(buf +  8, A ^ Keys[2]);
  SetUi32(buf + 12, B ^ Keys[3]);

  UpdateKeys(encrypt ? buf : inBuf);
}

STDMETHODIMP CDecoder::Init()
{
  return S_OK;
}

static const UInt32 kBlockSize = 16;

STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
{
  if (size == 0)
    return 0;
  if (size < kBlockSize)
    return kBlockSize;
  size -= kBlockSize;
  UInt32 i;
  for (i = 0; i <= size; i += kBlockSize)
    DecryptBlock(data + i);
  return i;
}

}}