Skip to content

Commit

Permalink
avoid using node API in decryption
Browse files Browse the repository at this point in the history
  • Loading branch information
toyobayashi committed Jan 4, 2022
1 parent e395136 commit 8ab61d1
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 43 deletions.
2 changes: 2 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
'target_name': 'main',
'sources': [
'src/main.cpp',
'src/base64.c',
'src/aes/aes.c'
],
'includes': [
Expand All @@ -23,6 +24,7 @@
'target_name': 'renderer',
'sources': [
'src/main.cpp',
'src/base64.c',
'src/aes/aes.c'
],
'includes': [
Expand Down
184 changes: 184 additions & 0 deletions src/base64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#include "string.h"
#include "base64.h"

static const char table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// supports regular and URL-safe base64
static const int8_t unbase64_table[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 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, -1, -1, -1, -1, 63,
-1, 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, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};

size_t base64_encode(const uint8_t* src, size_t len, char* dst) {
size_t slen, dlen;
unsigned i, k, n, a, b, c;
if (src == NULL) {
return 0;
}

if (len == -1) {
slen = strlen((const char*)src);
} else {
slen = len;
}

dlen = ((slen + 2 - ((slen + 2) % 3)) / 3 * 4);

if (dst == NULL) {
return dlen;
}

i = 0;
k = 0;
n = slen / 3 * 3;

while (i < n) {
a = src[i + 0] & 0xff;
b = src[i + 1] & 0xff;
c = src[i + 2] & 0xff;

dst[k + 0] = table[a >> 2];
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
dst[k + 3] = table[c & 0x3f];

i += 3;
k += 4;
}

if (n != slen) {
switch (slen - n) {
case 1:
a = src[i + 0] & 0xff;
dst[k + 0] = table[a >> 2];
dst[k + 1] = table[(a & 3) << 4];
dst[k + 2] = '=';
dst[k + 3] = '=';
break;

case 2:
a = src[i + 0] & 0xff;
b = src[i + 1] & 0xff;
dst[k + 0] = table[a >> 2];
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
dst[k + 2] = table[(b & 0x0f) << 2];
dst[k + 3] = '=';
break;
}
}

return dlen;
}

static int base64_decode_group_slow(char* const dst, const size_t dstlen,
const char* const src, const size_t srclen,
size_t* const i, size_t* const k) {
uint8_t hi;
uint8_t lo;
uint8_t c;
#define V(expr) \
for (;;) { \
c = src[*i]; \
lo = unbase64_table[c]; \
*i += 1; \
if (lo < 64) \
break; /* Legal character. */ \
if (c == '=' || *i >= srclen) \
return 0; /* Stop decoding. */ \
} \
expr; \
if (*i >= srclen) \
return 0; \
if (*k >= dstlen) \
return 0; \
hi = lo;
V((void)0);
V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
#undef V
return 1; // Continue decoding.
}

size_t base64_decode(const char* src, size_t len, uint8_t* dst) {
size_t slen, dlen, remainder, size;
size_t available, max_k, max_i, i, k, v;

if (src == NULL) {
return 0;
}

if (len == -1) {
slen = strlen(src);
} else {
slen = len;
}

if (slen == 0) {
dlen = 0;
} else {
if (src[slen - 1] == '=') slen--;
if (slen > 0 && src[slen - 1] == '=') slen--;

size = slen;
remainder = size % 4;

size = (size / 4) * 3;
if (remainder) {
if (size == 0 && remainder == 1) {
size = 0;
} else {
size += 1 + (remainder == 3);
}
}

dlen = size;
}

if (dst == NULL) {
return dlen;
}

available = dlen;
max_k = available / 3 * 3;
max_i = slen / 4 * 4;
i = 0;
k = 0;
while (i < max_i && k < max_k) {
v = unbase64_table[src[i + 0]] << 24 |
unbase64_table[src[i + 1]] << 16 |
unbase64_table[src[i + 2]] << 8 |
unbase64_table[src[i + 3]];
// If MSB is set, input contains whitespace or is not valid base64.
if (v & 0x80808080) {
if (!base64_decode_group_slow((char*)dst, dlen, src, slen, &i, &k))
return k;
max_i = i + (slen - i) / 4 * 4; // Align max_i again.
} else {
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
i += 4;
k += 3;
}
}
if (i < slen && k < dlen) {
base64_decode_group_slow((char*)dst, dlen, src, slen, &i, &k);
}
return k;
}
18 changes: 18 additions & 0 deletions src/base64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef SRC_BASE64_H_
#define SRC_BASE64_H_

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

size_t base64_encode(const uint8_t* src, size_t len, char* dst);
size_t base64_decode(const char* src, size_t len, uint8_t* dst);

#ifdef __cplusplus
}
#endif

#endif // SRC_BASE64_H_
71 changes: 28 additions & 43 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ try {
#include <unordered_map>
#include "napi.h"
#include "script.h"
#include "base64.h"

#include "aes/aes.hpp"

Expand All @@ -77,12 +78,12 @@ struct AddonData {

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

void ConsoleLog(const Napi::Env& env, Napi::Value value) {
/* void ConsoleLog(const Napi::Env& env, Napi::Value value) {
Napi::Object console = env.Global().As<Napi::Object>()
.Get("console").As<Napi::Object>();
Napi::Function log = console.Get("log").As<Napi::Function>();
log.Call(console, { value });
}
} */

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

std::vector<uint8_t> GetKeyVector() {
const uint8_t key[KEY_LENGTH] = {
const uint8_t* GetKey() {
static const uint8_t key[KEY_LENGTH] = {
#include "key.txt"
};

return std::vector<uint8_t>(key, key + KEY_LENGTH);
return key;
}

Napi::Array GetKey(const Napi::Env& env) {
std::vector<uint8_t> key = GetKeyVector();
Napi::Array arrkey = Napi::Array::New(env, key.size());
for (uint32_t i = 0; i < key.size(); i++) {
Napi::Array GetKeyArray(const Napi::Env& env) {
const uint8_t* key = GetKey();
Napi::Array arrkey = Napi::Array::New(env, KEY_LENGTH);
for (uint32_t i = 0; i < KEY_LENGTH; i++) {
arrkey.Set(i, key[i]);
}
return arrkey;
Expand All @@ -123,14 +124,14 @@ int Pkcs7cut(uint8_t *p, int plen) {
}

std::string Aesdec(const std::vector<uint8_t>& data,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv) {
const uint8_t* key,
const uint8_t* iv) {
size_t l = data.size();
uint8_t* encrypt = new uint8_t[l];
memcpy(encrypt, data.data(), l);

struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key.data(), iv.data());
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_decrypt_buffer(&ctx, encrypt, l);

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

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

Napi::String Base64toCode(const Napi::Env& env,
const Napi::String& base64) {
Napi::Object buffer_constructor = env.Global().Get("Buffer")
.As<Napi::Object>();
Napi::Buffer<uint8_t> body = buffer_constructor.Get("from")
.As<Napi::Function>()
.Call(buffer_constructor, { base64, Napi::String::New(env, "base64") })
.As<Napi::Buffer<uint8_t>>();

Napi::Buffer<uint8_t> iv = body.Get("slice").As<Napi::Function>()
.Call(body, { Napi::Number::New(env, 0), Napi::Number::New(env, 16) })
.As<Napi::Buffer<uint8_t>>();
Napi::Buffer<uint8_t> data = body.Get("slice").As<Napi::Function>()
.Call(body, { Napi::Number::New(env, 16) })
.As<Napi::Buffer<uint8_t>>();

std::string plain_content = Aesdec(BufferToVector(data),
GetKeyVector(), BufferToVector(iv));

return Napi::String::New(env, plain_content);
std::vector<uint8_t> iv(buf.begin(), buf.begin() + 16);
std::vector<uint8_t> data(buf.begin() + 16, buf.end());

return Aesdec(data, GetKey(), iv.data());
}

Napi::Value ModulePrototypeCompile(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
AddonData* addon_data = static_cast<AddonData*>(info.Data());
Napi::Object content = info[0].As<Napi::Object>();
Napi::Object filename = info[1].As<Napi::Object>();
Napi::String content = info[0].As<Napi::String>();
Napi::String filename = info[1].As<Napi::String>();
std::string filename_str = filename.Utf8Value();
Napi::Function old_compile =
addon_data->functions[FN_MODULE_PROTOTYPE__COMPILE].Value();

if (-1 != filename.Get("indexOf").As<Napi::Function>()
.Call(filename, { Napi::String::New(env, "app.asar") })
.As<Napi::Number>().Int32Value()) {
if (filename_str.find("app.asar") != std::string::npos) {
return old_compile.Call(info.This(),
{ Base64toCode(env, content.As<Napi::String>()), filename });
{ Napi::String::New(env, Decrypt(content.Utf8Value())), filename });
}
return old_compile.Call(info.This(), { content, filename });
}
Expand Down Expand Up @@ -337,7 +322,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {

try {
require({ Napi::String::New(env, "./main.js") })
.As<Napi::Function>().Call({ GetKey(env) });
.As<Napi::Function>().Call({ GetKeyArray(env) });
} catch (const Napi::Error& e) {
ShowErrorAndQuit(env, electron, e.Get("stack").As<Napi::String>());
}
Expand Down

0 comments on commit 8ab61d1

Please sign in to comment.