Search code examples
c++webassemblyemscriptencrypto++

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.


Solution

  • 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)