Crate crypter

Source
Expand description

The crypter crate provides Rust and FFI for encryption and decryption using AES-GCM-SIV 256-bits.

To enable the C api, the feature ffi must be enabled. To enable the WASM api, the feature wasm must be enabled. See the examples for working FFI applications.

§Examples

let key = get_key();
let payload = "mega ultra safe payload";

let encrypted = crypter::encrypt(key, payload).expect("Failed to encrypt");
let decrypted = crypter::decrypt(key, encrypted).expect("Failed to decrypt");
println!("{}", String::from_utf8(decrypted).expect("Invalid decrypted string"));

§FFI examples

§C example: example.c

#include <stdio.h>
#include <string.h>

#include <crypter.h>

const char * get_key();

int main() {
  const char *key = get_key();
  const char *payload = "mega ultra safe payload";

  CrypterCSlice key_slice = {.ptr = (const unsigned char *)key, .len = strlen(key)};

  CrypterRustSlice encrypted = crypter_encrypt(
      key_slice, (CrypterCSlice){.ptr = (const unsigned char *)payload,
                                 .len = strlen(payload)});

  CrypterCSlice encrypted_slice = {.ptr = encrypted.ptr, .len = encrypted.len};

  CrypterRustSlice decrypted = crypter_decrypt(key_slice, encrypted_slice);

  if (decrypted.ptr) {
    for (int i = 0; i < decrypted.len; i++) {
      if (decrypted.ptr[i] == 0) {
        putchar('0');
      } else {
        putchar(decrypted.ptr[i]);
      }
    }
    putchar('\n');
  } else {
    puts("Null return");
  }

  crypter_free_slice(encrypted);
  crypter_free_slice(decrypted);
}

§Lua example: example.lua

local ffi = require('ffi')

ffi.cdef[[
  typedef struct Slice { uint8_t * ptr; size_t len; } Slice;
  typedef struct RustSlice { uint8_t * ptr; size_t len; size_t capacity; } RustSlice;

  RustSlice crypter_encrypt(struct Slice key, struct Slice payload);
  RustSlice crypter_decrypt(struct Slice key, struct Slice payload);
]]

local function slice_from_str(text)
  local slice = ffi.new('Slice')

  slice.ptr = ffi.cast('uint8_t *', text)
  slice.len = string.len(text)
  return slice
end

local function relax_rust_slice(rust_slice)
  local slice = ffi.new('Slice')

  slice.ptr = rust_slice.ptr
  slice.len = rust_slice.len
  return slice
end

crypter = ffi.load('crypter')

local key = require('my_key_getter').get_key()
local encrypted = crypter.crypter_encrypt(key, slice_from_str('mega ultra safe payload'))
local decrypted = crypter.crypter_decrypt(key, relax_rust_slice(encrypted))

if decrypted.ptr ~= nil then
  print(ffi.string(decrypted.ptr, decrypted.len))
else
  print('Failed roud trip')
end

§WASM example: index.html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
    <title>crypter</title>
  </head>
  <body>
    <script type="module">
      import init from "./crypter.js";

      init("./crypter_bg.wasm").then(() => {
        const crypter = import('./crypter.js');
        crypter.then(c => {
          const encoder = new TextEncoder();
          const key = encoder.encode('supersecret'); // Bad key. Just as an example
          const encrypted = c.encrypt(key, encoder.encode('mega ultra safe payload'));
          const decrypted = c.decrypt(key, encrypted);
          console.log('Encrypted: ', new TextDecoder().decode(decrypted));
        });
      });
    </script>
  </body>
</html>

Modules§

ffiffi
FFI bindings for crypter
streamstream
Stream support for AES-GCM-SIV 256-bits encrypting and decrypting in chunks.
wasmwasm
WASM bindings for crypter

Functions§

decrypt
Decrypts the payload with AES256 GCM SIV
encrypt
Encrypts the payload with AES256 GCM SIV. The iv is randomly generated for each call