Skip to content

Commit 8ab61d1

Browse files
committed
avoid using node API in decryption
1 parent e395136 commit 8ab61d1

4 files changed

Lines changed: 232 additions & 43 deletions

File tree

binding.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
'target_name': 'main',
1414
'sources': [
1515
'src/main.cpp',
16+
'src/base64.c',
1617
'src/aes/aes.c'
1718
],
1819
'includes': [
@@ -23,6 +24,7 @@
2324
'target_name': 'renderer',
2425
'sources': [
2526
'src/main.cpp',
27+
'src/base64.c',
2628
'src/aes/aes.c'
2729
],
2830
'includes': [

src/base64.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include "string.h"
2+
#include "base64.h"
3+
4+
static const char table[] =
5+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6+
7+
// supports regular and URL-safe base64
8+
static const int8_t unbase64_table[256] = {
9+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
10+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
11+
-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
12+
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
13+
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
14+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
15+
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
16+
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
17+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
19+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
24+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
25+
};
26+
27+
size_t base64_encode(const uint8_t* src, size_t len, char* dst) {
28+
size_t slen, dlen;
29+
unsigned i, k, n, a, b, c;
30+
if (src == NULL) {
31+
return 0;
32+
}
33+
34+
if (len == -1) {
35+
slen = strlen((const char*)src);
36+
} else {
37+
slen = len;
38+
}
39+
40+
dlen = ((slen + 2 - ((slen + 2) % 3)) / 3 * 4);
41+
42+
if (dst == NULL) {
43+
return dlen;
44+
}
45+
46+
i = 0;
47+
k = 0;
48+
n = slen / 3 * 3;
49+
50+
while (i < n) {
51+
a = src[i + 0] & 0xff;
52+
b = src[i + 1] & 0xff;
53+
c = src[i + 2] & 0xff;
54+
55+
dst[k + 0] = table[a >> 2];
56+
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
57+
dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
58+
dst[k + 3] = table[c & 0x3f];
59+
60+
i += 3;
61+
k += 4;
62+
}
63+
64+
if (n != slen) {
65+
switch (slen - n) {
66+
case 1:
67+
a = src[i + 0] & 0xff;
68+
dst[k + 0] = table[a >> 2];
69+
dst[k + 1] = table[(a & 3) << 4];
70+
dst[k + 2] = '=';
71+
dst[k + 3] = '=';
72+
break;
73+
74+
case 2:
75+
a = src[i + 0] & 0xff;
76+
b = src[i + 1] & 0xff;
77+
dst[k + 0] = table[a >> 2];
78+
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
79+
dst[k + 2] = table[(b & 0x0f) << 2];
80+
dst[k + 3] = '=';
81+
break;
82+
}
83+
}
84+
85+
return dlen;
86+
}
87+
88+
static int base64_decode_group_slow(char* const dst, const size_t dstlen,
89+
const char* const src, const size_t srclen,
90+
size_t* const i, size_t* const k) {
91+
uint8_t hi;
92+
uint8_t lo;
93+
uint8_t c;
94+
#define V(expr) \
95+
for (;;) { \
96+
c = src[*i]; \
97+
lo = unbase64_table[c]; \
98+
*i += 1; \
99+
if (lo < 64) \
100+
break; /* Legal character. */ \
101+
if (c == '=' || *i >= srclen) \
102+
return 0; /* Stop decoding. */ \
103+
} \
104+
expr; \
105+
if (*i >= srclen) \
106+
return 0; \
107+
if (*k >= dstlen) \
108+
return 0; \
109+
hi = lo;
110+
V((void)0);
111+
V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
112+
V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
113+
V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
114+
#undef V
115+
return 1; // Continue decoding.
116+
}
117+
118+
size_t base64_decode(const char* src, size_t len, uint8_t* dst) {
119+
size_t slen, dlen, remainder, size;
120+
size_t available, max_k, max_i, i, k, v;
121+
122+
if (src == NULL) {
123+
return 0;
124+
}
125+
126+
if (len == -1) {
127+
slen = strlen(src);
128+
} else {
129+
slen = len;
130+
}
131+
132+
if (slen == 0) {
133+
dlen = 0;
134+
} else {
135+
if (src[slen - 1] == '=') slen--;
136+
if (slen > 0 && src[slen - 1] == '=') slen--;
137+
138+
size = slen;
139+
remainder = size % 4;
140+
141+
size = (size / 4) * 3;
142+
if (remainder) {
143+
if (size == 0 && remainder == 1) {
144+
size = 0;
145+
} else {
146+
size += 1 + (remainder == 3);
147+
}
148+
}
149+
150+
dlen = size;
151+
}
152+
153+
if (dst == NULL) {
154+
return dlen;
155+
}
156+
157+
available = dlen;
158+
max_k = available / 3 * 3;
159+
max_i = slen / 4 * 4;
160+
i = 0;
161+
k = 0;
162+
while (i < max_i && k < max_k) {
163+
v = unbase64_table[src[i + 0]] << 24 |
164+
unbase64_table[src[i + 1]] << 16 |
165+
unbase64_table[src[i + 2]] << 8 |
166+
unbase64_table[src[i + 3]];
167+
// If MSB is set, input contains whitespace or is not valid base64.
168+
if (v & 0x80808080) {
169+
if (!base64_decode_group_slow((char*)dst, dlen, src, slen, &i, &k))
170+
return k;
171+
max_i = i + (slen - i) / 4 * 4; // Align max_i again.
172+
} else {
173+
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
174+
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
175+
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
176+
i += 4;
177+
k += 3;
178+
}
179+
}
180+
if (i < slen && k < dlen) {
181+
base64_decode_group_slow((char*)dst, dlen, src, slen, &i, &k);
182+
}
183+
return k;
184+
}

src/base64.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef SRC_BASE64_H_
2+
#define SRC_BASE64_H_
3+
4+
#include <stddef.h>
5+
#include <stdint.h>
6+
7+
#ifdef __cplusplus
8+
extern "C" {
9+
#endif
10+
11+
size_t base64_encode(const uint8_t* src, size_t len, char* dst);
12+
size_t base64_decode(const char* src, size_t len, uint8_t* dst);
13+
14+
#ifdef __cplusplus
15+
}
16+
#endif
17+
18+
#endif // SRC_BASE64_H_

src/main.cpp

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ try {
6161
#include <unordered_map>
6262
#include "napi.h"
6363
#include "script.h"
64+
#include "base64.h"
6465

6566
#include "aes/aes.hpp"
6667

@@ -77,12 +78,12 @@ struct AddonData {
7778

7879
const char errmsg[] = "This program has been changed by others.";
7980

80-
void ConsoleLog(const Napi::Env& env, Napi::Value value) {
81+
/* void ConsoleLog(const Napi::Env& env, Napi::Value value) {
8182
Napi::Object console = env.Global().As<Napi::Object>()
8283
.Get("console").As<Napi::Object>();
8384
Napi::Function log = console.Get("log").As<Napi::Function>();
8485
log.Call(console, { value });
85-
}
86+
} */
8687

8788
void ConsoleError(const Napi::Env& env, Napi::Value value) {
8889
Napi::Object console = env.Global().As<Napi::Object>()
@@ -91,18 +92,18 @@ void ConsoleError(const Napi::Env& env, Napi::Value value) {
9192
error.Call(console, { value });
9293
}
9394

94-
std::vector<uint8_t> GetKeyVector() {
95-
const uint8_t key[KEY_LENGTH] = {
95+
const uint8_t* GetKey() {
96+
static const uint8_t key[KEY_LENGTH] = {
9697
#include "key.txt"
9798
};
9899

99-
return std::vector<uint8_t>(key, key + KEY_LENGTH);
100+
return key;
100101
}
101102

102-
Napi::Array GetKey(const Napi::Env& env) {
103-
std::vector<uint8_t> key = GetKeyVector();
104-
Napi::Array arrkey = Napi::Array::New(env, key.size());
105-
for (uint32_t i = 0; i < key.size(); i++) {
103+
Napi::Array GetKeyArray(const Napi::Env& env) {
104+
const uint8_t* key = GetKey();
105+
Napi::Array arrkey = Napi::Array::New(env, KEY_LENGTH);
106+
for (uint32_t i = 0; i < KEY_LENGTH; i++) {
106107
arrkey.Set(i, key[i]);
107108
}
108109
return arrkey;
@@ -123,14 +124,14 @@ int Pkcs7cut(uint8_t *p, int plen) {
123124
}
124125

125126
std::string Aesdec(const std::vector<uint8_t>& data,
126-
const std::vector<uint8_t>& key,
127-
const std::vector<uint8_t>& iv) {
127+
const uint8_t* key,
128+
const uint8_t* iv) {
128129
size_t l = data.size();
129130
uint8_t* encrypt = new uint8_t[l];
130131
memcpy(encrypt, data.data(), l);
131132

132133
struct AES_ctx ctx;
133-
AES_init_ctx_iv(&ctx, key.data(), iv.data());
134+
AES_init_ctx_iv(&ctx, key, iv);
134135
AES_CBC_decrypt_buffer(&ctx, encrypt, l);
135136

136137
uint8_t* out = new uint8_t[l + 1];
@@ -146,46 +147,30 @@ std::string Aesdec(const std::vector<uint8_t>& data,
146147
return res;
147148
}
148149

149-
std::vector<uint8_t> BufferToVector(const Napi::Buffer<uint8_t>& buf) {
150-
uint8_t* data = buf.Data();
151-
return std::vector<uint8_t>(data, data + buf.ByteLength());
152-
}
150+
std::string Decrypt(const std::string& base64) {
151+
size_t buflen = base64_decode(base64.c_str(), base64.length(), nullptr);
152+
if (buflen == 0) return "";
153+
std::vector<uint8_t> buf(buflen);
154+
base64_decode(base64.c_str(), base64.length(), &buf[0]);
153155

154-
Napi::String Base64toCode(const Napi::Env& env,
155-
const Napi::String& base64) {
156-
Napi::Object buffer_constructor = env.Global().Get("Buffer")
157-
.As<Napi::Object>();
158-
Napi::Buffer<uint8_t> body = buffer_constructor.Get("from")
159-
.As<Napi::Function>()
160-
.Call(buffer_constructor, { base64, Napi::String::New(env, "base64") })
161-
.As<Napi::Buffer<uint8_t>>();
162-
163-
Napi::Buffer<uint8_t> iv = body.Get("slice").As<Napi::Function>()
164-
.Call(body, { Napi::Number::New(env, 0), Napi::Number::New(env, 16) })
165-
.As<Napi::Buffer<uint8_t>>();
166-
Napi::Buffer<uint8_t> data = body.Get("slice").As<Napi::Function>()
167-
.Call(body, { Napi::Number::New(env, 16) })
168-
.As<Napi::Buffer<uint8_t>>();
169-
170-
std::string plain_content = Aesdec(BufferToVector(data),
171-
GetKeyVector(), BufferToVector(iv));
172-
173-
return Napi::String::New(env, plain_content);
156+
std::vector<uint8_t> iv(buf.begin(), buf.begin() + 16);
157+
std::vector<uint8_t> data(buf.begin() + 16, buf.end());
158+
159+
return Aesdec(data, GetKey(), iv.data());
174160
}
175161

176162
Napi::Value ModulePrototypeCompile(const Napi::CallbackInfo& info) {
177163
Napi::Env env = info.Env();
178164
AddonData* addon_data = static_cast<AddonData*>(info.Data());
179-
Napi::Object content = info[0].As<Napi::Object>();
180-
Napi::Object filename = info[1].As<Napi::Object>();
165+
Napi::String content = info[0].As<Napi::String>();
166+
Napi::String filename = info[1].As<Napi::String>();
167+
std::string filename_str = filename.Utf8Value();
181168
Napi::Function old_compile =
182169
addon_data->functions[FN_MODULE_PROTOTYPE__COMPILE].Value();
183170

184-
if (-1 != filename.Get("indexOf").As<Napi::Function>()
185-
.Call(filename, { Napi::String::New(env, "app.asar") })
186-
.As<Napi::Number>().Int32Value()) {
171+
if (filename_str.find("app.asar") != std::string::npos) {
187172
return old_compile.Call(info.This(),
188-
{ Base64toCode(env, content.As<Napi::String>()), filename });
173+
{ Napi::String::New(env, Decrypt(content.Utf8Value())), filename });
189174
}
190175
return old_compile.Call(info.This(), { content, filename });
191176
}
@@ -337,7 +322,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
337322

338323
try {
339324
require({ Napi::String::New(env, "./main.js") })
340-
.As<Napi::Function>().Call({ GetKey(env) });
325+
.As<Napi::Function>().Call({ GetKeyArray(env) });
341326
} catch (const Napi::Error& e) {
342327
ShowErrorAndQuit(env, electron, e.Get("stack").As<Napi::String>());
343328
}

0 commit comments

Comments
 (0)