#symmetric-encryption #dracoon #openssl #crypto-api

dco3_crypto

Symmetric and asymmetric encryption for DRACOON in Rust

8 releases (breaking)

0.7.0 Apr 23, 2024
0.6.0 Mar 22, 2024
0.5.1 Aug 27, 2023
0.5.0 May 4, 2023
0.1.0 Dec 20, 2022

#510 in Cryptography

21 downloads per month
Used in 2 crates (via dco3)

MIT license

55KB
837 lines

dco3-crypto

DRACOON Crypto utils in Rust
Documentation »
Report Bug

dco3-crypto

What is this?

Work in progress Crypto library for DRACOON based on openssl crate.

Breaking changes are most likely at this early stage - the library is under heavy development and depends on requirements from dco3 (currently private API wrapper for DRACOON). Changes will be documented in the release notes.

What does work?

  • Asymmetric encryption / decryption of file keys (RSA)
  • Keypair generation (RSA)
  • Keypair encryption / decryption (RSA)
  • Symmetric encryption / decryption of messages (AES256 GCM)
    • on the fly encryption / decryption
    • chunked encryption / decryption

What is planned?

  • Refactor asymmetric encryption (split keypair generation from other operations)
  • Use other libraries like ring as alternative to openssl bindings
  • Add feature flags to cargo build
  • Add e2e tests using encryption data from other SDKs / libs and ensure compatibility in pipeline

What is shipped?

Using the crate currently binds to the latest openssl version and is compiled in vendored mode (see openssl for details).

How to use?

See crates.io TL;DR Add the following line to your Cargo.toml file (dependencies):

dco3_crypto = "0.4.1"

Documentation

Documentation All detailed documentation is provided via docs on docs.rs

TL; DR usage

Required imports

The lib consists of several traits that are all (currently only) implemented by the DracoonCrypto struct. Therefore, the minimum required import is always DracoonCrypto and the relevant required trait (DracoonRSACrypto, Encrypt, Decrypt, ChunkedEncryption, Encrypter, Decrypter).

Asymmetric encryption

In order to

  • generate a (plain) user keypair
  • en/decrypt a user keypair
  • decrypt a private only
  • encrypt a file key with a public key (user keypair)
  • decrypt a file key with a private key (user keypair)

Generate a plain user keypair:

use dco3_crypto::{DracoonCrypto, DracoonRSACrypto, UserKeypairVersion};

// RSA2048 is only supported for legacy compatibility 
// always use UserKeypairVersion::RSA4096
let new_keypair = DracoonCrypto::create_plain_user_keypair(UserKeyPairVersion::RSA4096).unwrap();

Encrypt a plain user keypair:

use dco3_crypto::{DracoonCrypto, DracoonRSACrypto, UserKeypairVersion};

let new_keypair = DracoonCrypto::create_plain_user_keypair(UserKeyPairVersion::RSA4096).unwrap();
let secret ="VerySecret123!";
let enc_keypair = DracoonCrypto::encrypt_private_key(secret, new_keypair).unwrap();

Decrypt a private key only (for public share use):

use dco3_crypto::{DracoonCrypto, DracoonRSACrypto, UserKeypairVersion};

let new_keypair = DracoonCrypto::create_plain_user_keypair(UserKeyPairVersion::RSA4096).unwrap();
let secret ="VerySecret123!";
let enc_keypair = DracoonCrypto::encrypt_private_key(secret, new_keypair).unwrap();
let plain_private_key = DracoonCrypto::decrypt_private_key_only(secret, enc_keypair.private_key_container).unwrap();

Decrypt a protected user keypair:

use dco3_crypto::{DracoonCrypto, DracoonRSACrypto, UserKeypairVersion};

let new_keypair = DracoonCrypto::create_plain_user_keypair(UserKeyPairVersion::RSA4096).unwrap();
let secret ="VerySecret123!";
let enc_keypair = DracoonCrypto::encrypt_private_key(secret, new_keypair).unwrap();
let plain_keypair = DracoonCrypto::decrypt_private_key(secret, enc_keypair).unwrap();

Encrypt a file key using either a plain user keypair or a public key container:

use dco3_crypto::{DracoonCrypto, DracoonRSACrypto, UserKeypairVersion, Encrypt};
let new_keypair = DracoonCrypto::create_plain_user_keypair(UserKeyPairVersion::RSA4096).unwrap();

// encrypt a message to get a plain file key for demo purposes
let message = b"Secret message";
let (enc_message, plain_file_key) = DracoonCrypto::encrypt(message.to_vec()).unwrap();

// the function also accepts a public key container as argument
let enc_file_key = DracoonCrypto::encrypt_file_key(plain_file_key, plain_keypair).unwrap();

Decrypt the file key using a plain user keypair:

use dco3_crypto::{DracoonCrypto, DracoonRSACrypto, UserKeypairVersion, Encrypt};
let new_keypair = DracoonCrypto::create_plain_user_keypair(UserKeyPairVersion::RSA4096).unwrap();

// encrypt a message to get a plain file key for demo purposes
let message = b"Secret message";
let (enc_message, plain_file_key) = DracoonCrypto::encrypt(message.to_vec()).unwrap();

// the function also accepts a public key container as argument
let enc_file_key = DracoonCrypto::encrypt_file_key(plain_file_key, plain_keypair).unwrap();

// this code is for demo purposes - plain_keypair is consumed above and needs to be 
// instantiated again
let plain_file_key = DracoonCrypto::decrypt_file_key(enc_file_key, plain_keypair).unwrap();

Symmetric encryption

Symmetric encryption is represented by the following traits:

  • Encrypt: needed for in-memory encryption
  • Decrypt: needed for in-memory decryption
  • Decrypter: needed to build a decrypter capable of chunked decryption
  • Encrypter: needed to build an encrypter capable of chunked encryption
  • ChunkedEncryption: needed for both en- and decryption when using a decrypter / encrypter

Encrypt a message on the fly:

use dco3_crypto::{DracoonCrypto, Encrypt};

// encrypt a message to get a plain file key for demo purposes
let message = b"Secret message";
let (enc_message, plain_file_key) = DracoonCrypto::encrypt(message.to_vec()).unwrap();

// to encrypt the file key, see asymmetric encryption above

Decrypt a message on the fly:

use dco3_crypto::{DracoonCrypto, Encrypt, Decrypt};

// encrypt a message to get a plain file key for demo purposes
let message = b"Secret message";
let (enc_message, plain_file_key) = DracoonCrypto::encrypt(message.to_vec()).unwrap();

// to decrypt / encrypt the file key, see asymmetric encryption above
let plain_message = DracoonCrypto::decrypt(&enc_message, plain_file_key);

Encrypt in chunks:

use dco3_crypto::{DracoonCrypto, Encrypter, ChunkedEncryption};
let mut message = b"Encrypt this very long message in chunks and decrypt it";
let buff_len = message.len() + 1;
let mut buf = vec![0u8; buff_len];
let mut encrypter = DracoonCrypto::encrypter(&mut buf).unwrap();
let mut count: usize = 0;

// chunks of 8 bytes
const CHUNKSIZE: usize = 8;
let mut chunks = message.chunks(CHUNKSIZE);
while let Some(chunk) = chunks.next() {
  count += encrypter.update(&chunk).unwrap();
  };

count += encrypter.finalize().unwrap();
let enc_message = encrypter.get_message();
let plain_file_key = encrypter.get_plain_file_key();

Decrypt in chunks:

// importing Encrypt is only necessary for the inital message encryption
use dco3_crypto::{DracoonCrypto, Encrypt, Decrypter, ChunkedEncryption};
use openssl::symm::Cipher;
let message = b"Encrypt this very long message in chunks and decrypt it";
    
let (message, plain_file_key) = DracoonCrypto::encrypt(message.to_vec()).unwrap();
let buff_len = message.len() + 1;
    
let mut chunks = message.chunks(5);
let mut buf = vec![0u8; buff_len];
let mut decrypter = DracoonCrypto::decrypter(plain_file_key, &mut buf).unwrap();
let mut count: usize = 0;
while let Some(chunk) = chunks.next() {
  count += decrypter.update(&chunk).unwrap();
  }

count += decrypter.finalize().unwrap();
    
let plain_message = std::str::from_utf8(decrypter.get_message()).unwrap();
  

Dependencies

~2.5–7MB
~162K SLoC