I would like to use webassembly directly from my embedded v8 without the detour via JavaScript. I used the provided hello-world example and the WasmModuleObjectBuilderStreaming class from v8.h. However, I am stuck at how to extract the add function. Help would be appreciated.
#include <include/v8.h>
#include <include/libplatform/libplatform.h>
#include <stdlib.h>
#include <unistd.h>
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Promise;
using v8::WasmModuleObjectBuilderStreaming;
int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
Isolate* isolate = Isolate::New(create_params);
Isolate::Scope isolate_scope(isolate);
HandleScope scope(isolate);
WasmModuleObjectBuilderStreaming stream(isolate);
// Use the v8 API to generate a WebAssembly module.
//
// |bytes| contains the binary format for the following module:
//
// (func (export "add") (param i32 i32) (result i32)
// get_local 0
// get_local 1
// i32.add)
//
// taken from: https://github.com/v8/v8/blob/master/samples/hello-world.cc#L66
std::vector<uint8_t> wasmbin {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
};
// write bytes and finish
stream.OnBytesReceived(wasmbin.data(), wasmbin.size());
stream.Finish();
Local<Promise> promise = stream.GetPromise();
// TODO: Get exports, extract `add` & call `add`
}
Build setup:
Follow the instruction in Run the example from the official Getting started with embedding V8. Save the code to sample/wasm.cc and execute following commands:
$ g++ -I. -O2 -Iinclude samples/wasm.cc -o wasm -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++17`
$ ./wasm`
Solution:
Thanks #liliscent, I adapted my example accordingly. Because we all like, working code:
#include <include/v8.h>
#include <include/libplatform/libplatform.h>
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Promise;
using v8::WasmModuleObjectBuilderStreaming;
using v8::WasmCompiledModule;
using v8::Context;
using v8::Local;
using v8::Value;
using v8::String;
using v8::Object;
using v8::Function;
using v8::Int32;
using args_type = Local<Value>[];
int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
Isolate* isolate = Isolate::New(create_params);
Isolate::Scope isolate_scope(isolate);
HandleScope scope(isolate);
Local<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
WasmModuleObjectBuilderStreaming stream(isolate);
// Use the v8 API to generate a WebAssembly module.
//
// |bytes| contains the binary format for the following module: //
// (func (export "add") (param i32 i32) (result i32)
// get_local 0
// get_local 1
// i32.add)
//
// taken from: https://github.com/v8/v8/blob/master/samples/hello-world.cc#L66
std::vector<uint8_t> wasmbin {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
};
// same as calling:
// let module = new WebAssembly.Module(bytes);
Local<WasmCompiledModule> module = WasmCompiledModule::DeserializeOrCompile(isolate,
WasmCompiledModule::BufferReference(0, 0),
WasmCompiledModule::BufferReference(wasmbin.data(), wasmbin.size())
).ToLocalChecked();
// same as calling:
// let module_instance_exports = new WebAssembly.Instance(module).exports;
args_type instance_args{module};
Local<Object> module_instance_exports = context->Global()
->Get(context, String::NewFromUtf8(isolate, "WebAssembly"))
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "Instance"))
.ToLocalChecked().As<Object>()
->CallAsConstructor(context, 1, instance_args)
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "exports"))
.ToLocalChecked().As<Object>()
;
// same as calling:
// module_instance_exports.add(77, 88)
args_type add_args{Int32::New(isolate, 77), Int32::New(isolate, 88)};
Local<Int32> adder_res = module_instance_exports
->Get(context, String::NewFromUtf8(isolate, "add"))
.ToLocalChecked().As<Function>()
->Call(context, context->Global(), 2, add_args)
.ToLocalChecked().As<Int32>();
printf("77 + 88 = %d\n", adder_res->Value());
return 0;
}
You can construct a WebAssembly module directly from C++ via v8::WasmCompiledModule class (it will be renamed to v8::WasmModuleObject in next version):
Local<WasmCompiledModule> module = WasmCompiledModule::DeserializeOrCompile(isolate,
WasmCompiledModule::BufferReference(0, 0),
WasmCompiledModule::BufferReference(wasmbin.data(), wasmbin.size())
).ToLocalChecked();
But AFAIK, v8 doesn't expose its webassembly api directly, you have to get them from JS global context. The following code creates a module instance, and gets the exports of the instance:
using args_type = Local<Value>[];
Local<Object> module_instance_exports = context->Global()
->Get(context, String::NewFromUtf8(isolate, "WebAssembly"))
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "Instance"))
.ToLocalChecked().As<Object>()
->CallAsConstructor(context, 1, args_type{module})
.ToLocalChecked().As<Object>()
->Get(context, String::NewFromUtf8(isolate, "exports"))
.ToLocalChecked().As<Object>()
;
Then you can get the add function from exports object and call it:
Local<Int32> adder_res = module_instance_exports
->Get(context, String::NewFromUtf8(isolate, "add"))
.ToLocalChecked().As<Function>()
->Call(context, context->Global(), 2, args_type{Int32::New(isolate, 77), Int32::New(isolate, 88)})
.ToLocalChecked().As<Int32>();
std::cout << "77 + 88 = " << adder_res->Value() << "\n";
You might be interested in the Wasm C/C++ API proposal, which allows using a Wasm engine directly from C/C++. The design of this API is independent of any particular engine, but the proposal contains a more or less complete prototype implementation on top of V8.
Sample snippet (see e.g. hello.cc):
// ...
auto engine = wasm::Engine::make();
auto store = wasm::Store::make(engine.get());
auto module = wasm::Module::make(store.get(), binary);
auto instance = wasm::Instance::make(store.get(), module.get(), imports);
auto exports = instance->exports();
exports[0]->func()->call();
Related
#include <iostream>
#include<Windows.h>
#include<bcrypt.h>
#include <ntstatus.h>
#include<string>
#include<vector>
#pragma comment(lib, "bcrypt.lib")
void test_status(NTSTATUS return_val)
{
switch (return_val)
{
case(STATUS_SUCCESS):
{
std::cout << "STATUS_SUCCESS\n";
break;
}
case(STATUS_BUFFER_TOO_SMALL):
{
std::cout << "STATUS_BUFFER_TOO_SMALL\n";
break;
}
case(STATUS_INVALID_HANDLE):
{
std::cout << "STATUS_INVALID_HANDLE\n";
break;
}
case(STATUS_INVALID_PARAMETER):
{
std::cout << "STATUS_INVALID_PARAMETER\n";
break;
}
case(STATUS_NOT_SUPPORTED):
{
std::cout << "STATUS_NOT_SUPPORTED\n";
break;
}
};
}
int main()
{
BCRYPT_ALG_HANDLE phAlgorithm = nullptr;
BCRYPT_HASH_HANDLE phHash = nullptr;
LPCWSTR pszAlgId = TEXT("XTS-AES");
LPCWSTR pszImplementation = TEXT("Advanced Encryption Standard");
PUCHAR pbHashObject = nullptr;
std::vector<BYTE> pbSalt = { 0x77, 0x1f, 0x5b, 0x30, 0x2c, 0xf7, 0xc5, 0x31,
0xa9, 0x86, 0x46, 0x52, 0xe2, 0xff, 0x4a, 0x17,
0xab, 0xd0, 0x02, 0xdd, 0x4f, 0xb0, 0x2f, 0x71,
0x0f, 0xe5, 0xa8, 0x1a, 0xfe, 0xe7, 0x9c, 0x6b }; // 771f5b302cf7c531a9864652e2ff4a17abd002dd4fb02f710fe5a81afee79c6b
NTSTATUS status = BCryptOpenAlgorithmProvider(
&phAlgorithm,
BCRYPT_PBKDF2_ALGORITHM,
NULL,
NULL
);
test_status(status);
PUCHAR pbOutput = nullptr;
ULONG pcbResult = NULL;
status = BCryptGetProperty(
phAlgorithm,
BCRYPT_OBJECT_LENGTH,
pbOutput,
sizeof(DWORD),
&pcbResult,
NULL
);
test_status(status);
PUCHAR DerivedKey = nullptr;
DWORD cbDerivedKey = NULL;
std::string pbPassword = "MySecretPass";
std::string DerivedKeyString;
status = BCryptDeriveKeyPBKDF2(
phAlgorithm,
(BYTE*)pbPassword.data(),
pbPassword.length(),
(BYTE*)pbSalt.data(),
sizeof(BYTE),
10000,
(PUCHAR)DerivedKeyString.c_str(),
64,
0);
test_status(status);
status = BCryptCloseAlgorithmProvider(
phAlgorithm,
NULL
);
test_status(status);
}
This code should get the key from the password, but at this stage of generating this key, I get an error STATUS_INVALID_PARAMETER. Why is this happening and how to fix it
-I tried to change the encryption algorithm and pass the parameters in a different way, but all this did not lead to success or gave the error STATUS_INVALID_PARAMETER.
There are two errors:
Firstly, you are performing hash computation, the BCryptOpenAlgorithmProvider function must use flags and identifiers for the hash function's behavior.
In the function BCryptOpenAlgorithmProvider, replace BCRYPT_PBKDF2_ALGORITHM with BCRYPT_SHA256_ALGORITHM, use BCRYPT_ALG_HANDLE_HMAC_FLAG in the fourth dwFlags parameter.
The documentation for these two parameters is as follows:
https://learn.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers
https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider
Secondly, do not use string type of the parameter pbDerivedKey, or it will crash the memory.
Replace std::string DerivedKeyString with BYTE DerivedKeyString[64].
In the function BCryptDeriveKeyPBKDF2, replace (PUCHAR)DerivedKeyString.c_str() with DerivedKeyString.
I have recently been setting up various testing environments and in this cas I nneed to read and decode a gzip response from a HTTP server. I know what I have so far works as I have tested it with wireshark and hardcoded data as outlined below, my question is what is wrong with how I am handling the gizzped data from a HTTP server?
Here is what Im using:
From this thread http://www.qtcentre.org/threads/30031-qUncompress-data-from-gzip I am using the gzipDecopress function with the data provided and seeing that it works.
QByteArray gzipDecompress( QByteArray compressData )
{
//Hardcode sample data
const char dat[40] = {
0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xAA, 0x2E, 0x2E, 0x49, 0x2C, 0x29,
0x2D, 0xB6, 0x4A, 0x4B, 0xCC, 0x29, 0x4E, 0xAD, 0x05, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00,
0x2A, 0x63, 0x18, 0xC5, 0x0E, 0x00, 0x00, 0x00};
compressData = QByteArray::fromRawData( dat, 40);
//decompress GZIP data
//strip header and trailer
compressData.remove(0, 10);
compressData.chop(12);
const int buffersize = 16384;
quint8 buffer[buffersize];
z_stream cmpr_stream;
cmpr_stream.next_in = (unsigned char *)compressData.data();
cmpr_stream.avail_in = compressData.size();
cmpr_stream.total_in = 0;
cmpr_stream.next_out = buffer;
cmpr_stream.avail_out = buffersize;
cmpr_stream.total_out = 0;
cmpr_stream.zalloc = Z_NULL;
cmpr_stream.zalloc = Z_NULL;
if( inflateInit2(&cmpr_stream, -8 ) != Z_OK) {
qDebug() << "cmpr_stream error!";
}
QByteArray uncompressed;
do {
int status = inflate( &cmpr_stream, Z_SYNC_FLUSH );
if(status == Z_OK || status == Z_STREAM_END) {
uncompressed.append(QByteArray::fromRawData((char *)buffer, buffersize - cmpr_stream.avail_out));
cmpr_stream.next_out = buffer;
cmpr_stream.avail_out = buffersize;
} else {
inflateEnd(&cmpr_stream);
}
if(status == Z_STREAM_END) {
inflateEnd(&cmpr_stream);
break;
}
}while(cmpr_stream.avail_out == 0);
return uncompressed;
}
When the data is hardcoded as in that example, the string is decompressed. However, when I read the response from a HTTP server and store it in a QByteArray, it cannot be uncompressed. I am reading the response as follows and I can see it works when comparing the results on wireshark
//Read that length of encoded data
char EncodedData[ LengthToRead ];
memset( EncodedData, 0, LengthToRead );
recv( socketDesc, EncodedData, LengthToRead, 0 );
EndOfData = true;
//EncodedDataBytes = QByteArray((char*)EncodedData);
EncodedDataBytes = QByteArray::fromRawData(EncodedData, LengthToRead );
I assume i am missing some header or byte order when reading the response, but at the moment have no idea what. Any help very welcome!!
EDIT: So I have been looking at this a little more over the weekend and at the moment im trying to test the encode and decode of the given hex string, which is "{status:false}" in plain text. I have tried to use online gzip encoders such as http://www.txtwizard.net/compression but it returns some ascii text that does not match the hex string in the above code. When I use PHPs gzcompress( "{status:false}", 1) function it gives me non-ascii values, that I cannot copy/paste to test since they are ascii. So I am wondering if there is any standard reference for gzip encode/decode? It is definitely not in some special encoding since both firefox and wireshark can decode the packets, but my software cannot.
So the issue was with my gzip function, the correct function I found on this link: uncompress error when using zlib
As mentioned above by Cornstalks the infalteInit2 function needs to take MAX_WBITS+16 as its max bit size, I think that was the issue. If anybody knows any libraries or plugins to handle this please post them here! I am surprised that this had to be coded manually when it is so commonly used by HTTP clients/servers.
I want to control(On/Off) the adaptive brightness like the Power Options
Enable adaptive brightness:
by API in Win 10. I guess the API is included in the Power Management Functions: https://msdn.microsoft.com/en-us/library/windows/desktop/aa373163(v=vs.85).aspx
But I cannot find the function... May someone provide me some suggestions or directions. Thanks a lot!
I found the solution by myself, and I share the way to everyone who needs!
GUID *guidScheme;
bool bResult = false;
byte enableFunction= 0x1; //Set 0x0 to disable
bResult = PowerGetActiveScheme(NULL, &guidScheme);
if (bResult != ERROR_SUCCESS){
//error message
}
GUID guidSubVideo = { 0x7516b95f, 0xf776, 0x4464, 0x8c, 0x53, 0x06, 0x16, 0x7f, 0x40, 0xcc, 0x99 };
GUID guidAdaptBright = { 0xfbd9aa66, 0x9553, 0x4097, 0xba, 0x44, 0xed, 0x6e, 0x9d, 0x65, 0xea, 0xb8 };
bResult = PowerWriteDCValueIndex(NULL, guidScheme, &guidSubVideo, &guidAdaptBright, enableFunction);
if (bResult != ERROR_SUCCESS){
//error message
}
I'm trying to make a small archive program using 7zip dll, but I can't figure out how to use it. I don't know where the CLSID and IID are defined, what IID to use in order to be able to compress multimple files into an archive.
My code looks something like this:
typedef int (_CreateObject)(const GUID clsid, const GUID iid, void *outObject);
HMODULE hMod = LoadLibrary("7zra.dll");
_CreateObject pfnCreate = (_CreateObject)GetProcAddress(hMod, "CreateObject");
GUID CLSID_CFormat7z = {0x23170F69, 0x40C1, 0x2790, {0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00}};
GUID IID_Coder = {0x23170F69, 0x40C1, 0x278A, {0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00}};
ICompressCoder2 pCoder = NULL;
int i = pfnCreate(&CLSID_CFormat7z, &IID_Coder, (void*)&pCoder);
I always get a NULL pointer, even if i've tried different GUIDs.
Can anyone help me with a simple example please?
I am trying to decrypt something using 128BIT AES Decryption. When i attempt to calling CryptDecrypt i get an Error stating "Invalid Algorithm Specified". I get the same problem when using the library posted here: http://www.codeproject.com/KB/security/WinAES.aspx
What can cause this error?
I am using CryptoAPI along on vista64bit with visual studio 2008. I checked in the registry and the AES library is there...
EDIT
BYTE*& encryptedData /* get data length */
HCRYPTPROV cryptoHandle = NULL;
HCRYPTKEY aesKeyHandle = NULL;
hr = InitWinCrypt(cryptoHandle);
if(FAILED(hr))
{
return hr;
}
AesKeyOffering aesKey = { {PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128}, 16, { 0xFF, 0x00, 0xFF, 0x1C, 0x1D, 0x1E, 0x03, 0x04, 0x05, 0x0F, 0x20, 0x21, 0xAD, 0xAF, 0xA4, 0x04 }};
if(CryptImportKey(cryptoHandle, (CONST BYTE*)&aesKey, sizeof(AesKeyOffering), NULL, 0, &aesKeyHandle) == FALSE)
{
// DO error
return HRESULT_FROM_WIN32(GetLastError());
}
if(CryptSetKeyParam(aesKeyHandle, KP_IV, { 0xFF, 0x00, 0xFF, 0x1C, 0x1D, 0x1E, 0x03, 0x04, 0x05, 0x0F, 0x20, 0x21, 0xAD, 0xAF, 0xA4, 0x04 } , 0) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
BYTE blah2 = CRYPT_MODE_CBC;
// set block mode
if(CryptSetKeyParam(aesKeyHandle, KP_MODE, &blah2, 0) == FALSE)
{
//
return HRESULT_FROM_WIN32(GetLastError());
}
DWORD lol = dataLength / 16 + 1;
DWORD lol2 = lol * 16;
if(CryptDecrypt(aesKeyHandle, 0, TRUE, 0, encryptedData, &lol2) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
InitWinCrypt function
if(!CryptAcquireContextW(&cryptoHandle, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
if(!CryptAcquireContextW(&cryptoHandle, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, 0))
{
return HRESULT_FROM_WIN32(GetLastError());
}
else
{
return S_OK;
}
}
return S_OK;
AesOffering struct:
struct AesKeyOffering
{
BLOBHEADER m_Header;
DWORD m_KeyLength;
BYTE Key[16];
};
EDIT2
After rebooting my computer, and remvoing the CBC chunk. I am now getting Bad Data Errors. The data decrypts fine in C#. But i need to do this using wincrypt.
Are you passing cryptoHandle by reference to InitWithCrypt? If not, your code
if(!CryptAcquireContextW(&cryptoHandle, ...
would only modify InitWinCrypt's copy of cryptoHandle.
EDIT: Given that it does, try getting rid of the CryptSetKeyParam call which sets CRYPT_MODE_CBC