5 releases

0.2.0 Nov 14, 2023
0.1.3 Nov 13, 2023
0.1.2 Sep 10, 2023
0.1.1 Jun 7, 2022
0.1.0 Sep 21, 2021

#936 in Cryptography

25 downloads per month

MIT license

39KB
545 lines

crypter

Github MIT licensed Cargo Documentation

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>

Dependencies

~1–1.6MB
~31K SLoC