-
Notifications
You must be signed in to change notification settings - Fork 0
/
dpapi_win.cpp
106 lines (90 loc) · 2.82 KB
/
dpapi_win.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
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
// Implementation referenced from https://github.com/bradhugh/node-dpapi
#include <napi.h>
#include <uv.h>
#include <Windows.h>
#include <functional>
#include <iostream>
#include <string>
#include "dpapi_addon.h"
Napi::Value ProtectDataCommon(bool protect, const Napi::CallbackInfo& info)
{
Napi::Env env = info.Env();
if (info.Length() != 3) {
throw Napi::RangeError::New(env, "3 arguments are required");
}
if (info[0].IsNull() ||
info[0].IsUndefined() ||
!info[0].IsTypedArray() ||
info[0].As<Napi::TypedArray>().TypedArrayType() != napi_uint8_array)
{
throw Napi::TypeError::New(env, "First argument, data, must be a valid Uint8Array");
}
if (!info[1].IsNull() &&
(!info[1].IsTypedArray() || info[1].As<Napi::TypedArray>().TypedArrayType() != napi_uint8_array))
{
throw Napi::TypeError::New(env, "Second argument, optionalEntropy, must be null or an ArrayBuffer");
}
if (info[2].IsNull() || info[2].IsUndefined() || !info[2].IsString())
{
throw Napi::TypeError::New(env, "Third argument, scope, must be a string");
}
DWORD flags = 0;
Napi::String strData = info[2].As<Napi::String>();
std::string scope = strData.Utf8Value();
if (stricmp(scope.c_str(), "LocalMachine") == 0)
{
flags = CRYPTPROTECT_LOCAL_MACHINE;
}
auto buffer = info[0].As<Napi::Buffer<char>>().Data();
auto len = info[0].As<Napi::Buffer<char>>().ElementLength();
DATA_BLOB entropyBlob;
entropyBlob.pbData = nullptr;
if (!info[1].IsNull())
{
entropyBlob.pbData = reinterpret_cast<BYTE*>(info[1].As<Napi::Buffer<char>>().Data());
entropyBlob.cbData = info[1].As<Napi::Buffer<char>>().ElementLength();
}
DATA_BLOB dataIn;
DATA_BLOB dataOut;
// initialize input data
dataIn.pbData = reinterpret_cast<BYTE*>(buffer);
dataIn.cbData = len;
bool success = false;
// Call either Protect or Unprotect based on the flag
if (protect)
{
success = CryptProtectData(
&dataIn,
nullptr, // Description string
entropyBlob.pbData ? &entropyBlob : nullptr,
nullptr, // reserved
nullptr, // pass null for the prompt structure
flags, // dwFlags
&dataOut);
}
else
{
success = CryptUnprotectData(
&dataIn,
nullptr, // Description string
entropyBlob.pbData ? &entropyBlob : nullptr,
nullptr, // reserved
nullptr, // pass null for the prompt structure
flags, // dwFlags
&dataOut);
}
if (!success)
{
DWORD errorCode = GetLastError();
std::string errorMessage = std::string("Encryption/Decryption failed. Error code: ") + std::to_string(errorCode);
throw Napi::Error::New(env, &errorMessage[0]);
}
// Copy and free the buffer
Napi::Buffer<char> returnBuffer = Napi::Buffer<char>::Copy(env, reinterpret_cast<char*>(dataOut.pbData), dataOut.cbData);
LocalFree(dataOut.pbData);
return returnBuffer;
}