Rajas Bondale
Rajas Bondale

Reputation: 39

Web assembly: Using crypto++ library with emscripten

I'm planning on using the crypto++ library for a web application and wasm seemed perfect for it.

My cpp code:

#include <string>
using std::string;


#include "cryptopp/cryptlib.h"
#include "cryptopp/rsa.h"
#include "cryptopp/files.h"
#include "cryptopp/osrng.h"

using CryptoPP::RSA;
using CryptoPP::InvertibleRSAFunction;
using CryptoPP::RSAES_OAEP_SHA_Encryptor;
using CryptoPP::RSAES_OAEP_SHA_Decryptor;
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::PK_EncryptorFilter;
using CryptoPP::PK_DecryptorFilter;
using CryptoPP::FileSink;
using CryptoPP::FileSource;
using CryptoPP::AutoSeededRandomPool;
using CryptoPP::DecodingResult;
using CryptoPP::SHA1;

using namespace CryptoPP;

extern "C" {
    char* generateKeys() {
        AutoSeededRandomPool rng;

        InvertibleRSAFunction parameters;
        parameters.GenerateRandomWithKeySize(rng, 1024);

        RSA::PrivateKey privateKey(parameters);
        RSA::PublicKey publicKey(parameters);
        string pubKey;
        publicKey.Save(StringSink(pubKey).Ref());
        privateKey.Save(FileSink("privkey.der", true).Ref());
        int n = pubKey.length();
        char* char_array = new char[n + 1];
        strcpy(char_array, pubKey.c_str());
        return char_array;
    }
}
extern "C" {
    char* encrypt(string pubKey, string plain) {
        AutoSeededRandomPool rng;
        string cipher;
        RSA::PublicKey publicKey;
        publicKey.Load(StringSource(pubKey, true, NULL).Ref());
        RSAES_OAEP_SHA_Encryptor e(publicKey);
        StringSource(plain, true,
            new PK_EncryptorFilter(rng, e,
                new StringSink(cipher)
            ) // PK_EncryptorFilter
        ); // StringSource
        int n = cipher.length();
        char* char_array = new char[n + 1];
        strcpy(char_array, cipher.c_str());
        return char_array;
    }
}

extern "C" {
    char* decrypt(const char* filename, string cipher) {
        AutoSeededRandomPool rng;
        RSA::PrivateKey privateKey;
        string recovered;
        privateKey.Load(FileSource(filename, true).Ref());

        RSAES_OAEP_SHA_Decryptor d(privateKey);

        StringSource(cipher, true,
            new PK_DecryptorFilter(rng, d,
                new StringSink(recovered)
            ) // PK_EncryptorFilter
        ); // StringSource
        int n = recovered.length();
        char* char_array = new char[n + 1];
        strcpy(char_array, recovered.c_str());
        return char_array;
    }
}

I referred emscripten documentation for using libraries in emscripten I created cryptlib.a using the cryptlib.cpp file and compiled it using emcc like so

emcc -c -o cryptlib.o cryptlib.cpp
ar rcs cryptlib.a cryptlib.o

Finally I also created Source.o like so emcc -c -o Source.o Source.cpp

I figured out that this would the command to get an html and js file emcc Source.o cryptlib.a -o source.html -sEXPORTED_FUNCTIONS=_generateKeys -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

I get wasm-ld errors like so Error screenshots

What am I doing wrong? I also want to expose other functions of my source code but I was testing with just one of the functions.

Upvotes: 1

Views: 893

Answers (3)

Riot
Riot

Reputation: 16696

As of newer versions of cryptopp-cmake, this is even more straightforward - if you're using CMake for your own project, the manual steps in the other answer are no longer necessary.

Simply include the following in your project's CMakeLists.txt, to fetch and build cryptopp as part of your emscripten emcmake / emmake build:

include(FetchContent)
FetchContent_Declare(cryptopp-cmake
  GIT_REPOSITORY https://github.com/abdes/cryptopp-cmake.git
  GIT_TAG CRYPTOPP_8_9_0
)
FetchContent_MakeAvailable(cryptopp-cmake)

Upvotes: 1

Irineu Antunes
Irineu Antunes

Reputation: 779

I was having the same issue. To turn things more easy, i recommend you use CMake to build your project and cryptopp lib for wasm.

1: in your project, create a folder named 3rdparty then:

mkdir 3rdparty
cd 3rdparty
git clone https://github.com/abdes/cryptopp-cmake.git

This is an updated project of crypto++ with cmake

2: After clone the project:

cd cryptopp-cmake
mkdir build
cd build
emcmake cmake -UIS_WASM ../
emmake make

now on your build folder, you will have a folder named: build/_deps (cryptopp include folder) and build/cryptopp/libcrypto.a (cryptopp library)

4: Edit your project CMakeLists.txt for WASM build, here is the mine: Don't forget to change the PROJ_PATH to your project path. I'm building the same version for console version for tests and when i build with emcmake instead cmake it will enter on emscripten condition and load the wasm version of cryptopp lib instead of cryptopp lib on my system for desktop.

cmake_minimum_required(VERSION 3.24)
project(RSAPlayground)

set(CMAKE_CXX_STANDARD 17)
set(PROJ_PATH /home/you/your_projects/RSAPlayground) #Change Here

include_directories(/usr/local/include)

add_executable(RSAPlayground main.cpp)

if(${EMSCRIPTEN})

    set(EMCC_COMPILER_FLAGS "-g3 -sALLOW_MEMORY_GROWTH=1 -sEXPORTED_FUNCTIONS=_main,_encdec -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --preload-file ${PROJ_PATH}/keys")
    set(EMCC_LINKER_FLAGS ${EMCC_COMPILER_FLAGS})
    set_target_properties(RSAPlayground PROPERTIES LINK_FLAGS "${EMCC_LINKER_FLAGS}")
    #important part:
    target_include_directories(RSAPlayground PRIVATE ${PROJ_PATH}/3rdparty/cryptopp-cmake/build/_deps/)
    target_link_libraries(RSAPlayground ${PROJ_PATH}/3rdparty/cryptopp-cmake/build/cryptopp/libcryptopp.a)
    target_link_libraries(RSAPlayground pthread)
else()
    target_include_directories(RSAPlayground PRIVATE /usr/local/include)
    target_link_libraries(RSAPlayground /usr/local/lib/libcryptopp.a)
endif()

5: Finally on your project base path you can run the following commands:

rm -rf build
mkdir build
cd build
emcmake cmake -UIS_WASM ../
emmake make

and on build folder on your project basepath, you will have: RSAPlayground.wasm, RSAPlayground.js and RSAPlayground.data (your keys)

Upvotes: 0

EDIT2: That one might be more along what you tried: => https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-as-module/blob/main/samples/basic/js/logic/runAesSymmetricTest.js

=> online sample: ===> https://guillaumebouchetepitech.github.io/wasm-cryptopp-as-module/samples/basic/index.html


it's easier if you map the C++ code with an IDL file: => https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-as-module/blob/main/definitions/wasm-crypto.idl

=> that's one way to make it work: ===> https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-as-module/blob/main/Makefile#L148


something you might want to consider is adding some JS custom logic in the wasm module => https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-as-module/blob/main/src/js/post.js

=> it does need some extra compile flags ===> https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-as-module/blob/main/Makefile#L109




PREVIOUS ANSWER

Looks like you try to use the native version of crypto++, and this will only work if you build the webassembly version of the library.

EDIT: sorry... you were already trying that...

I saw your question here as I was doing it myself. this is what I just published, which might help:

=> wasm online demo:

===> https://guillaumebouchetepitech.github.io/wasm-cryptopp-demo/dist/index.html

=> source code:

===> https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-demo

PS: I've added the code to set/get string values to/from the js/wasm code as well, it's not overly well done but it feels like you could also get started on that side as well thanks to it.

let me know.

Upvotes: -1

Related Questions