Encrypt/Decrypt a string: Why so hard?

I am looking for a crate to encrypt/decrypt a short string to/from Vec

I want:

fn encrypt(clear: &str, key: &Vec<u8>) -> Vec<u8>{...}
fn decrypt(obsf: &Vec<u8>, key:&Vec<u8>) -> String {...}

I have been hunting for a crate that presents these two functions, and astonishing ly none of them do.

I found this but not one single repository linked from there has an examples folder.

Can somebody point me in the correct direction please?

I am not protecting crown jewels, and I do not want to spend months backfilling my cryptography knowledge (I am a competent mathematician, competent enough to know my limits).

I appreciate cryptographers concern for correctness, robustness etcetera, I am grateful for it. But my needs are very simple.

I chose a crate at random from the list given at the link, and found this example on the first page of its documentation:

use chacha20poly1305::{
    aead::{Aead, AeadCore, KeyInit, OsRng},
    ChaCha20Poly1305, Nonce
};

let key = ChaCha20Poly1305::generate_key(&mut OsRng);
let cipher = ChaCha20Poly1305::new(&key);
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); // 96-bits; unique per message
let ciphertext = cipher.encrypt(&nonce, b"plaintext message".as_ref())?;
let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref())?;
assert_eq!(&plaintext, b"plaintext message");

That crate doesn't have those exact functions, but it looks like you can construct keys and nonces from regular byte slices.

1 Like

That is correct. it does not have the simplicity I was looking for. Why a nonce and a key?

I could care less about the exact signature. I care a lot about a simple interface.

(I looked at the github pages linked for an examples directory. I did not find the link to the docs.rs page. My point stands: Why so hard?)

Public libraries are written to be flexible, which is why they have some degree of complexity.

I may be new to Rust, but I have a lot of experience programming. The general rule is - if you're looking for a simple interface that fits your exact needs, then you're probably best rolling it yourself.

1 Like

One needs a key, obviously, to encrypt anything. One needs a nonce so as to ensure the same text is never encrypted to the same thing twice. which is protection against replay attacks. Cyber Security Resource Center for Threats & Tips | Kaspersky is standard procedure in the encryption world.

Give the above the ´chacha´ interface presented by DanielKeep above seems to be only as hard as it needs to be and as only hard as many others I have seen in all kind of languages.

It would only take a few minutes to wrap that in the interface you want. Be sure to cater for replay attacks mind.

4 Likes

I think these are the relevant functions — someone should feel free to publish this to a crate.

// [dependencies]
// chacha20poly1305 = "0.10"

use chacha20poly1305::aead::generic_array::typenum::Unsigned;
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::aead::{Aead, AeadCore, KeyInit, OsRng};
use chacha20poly1305::ChaCha20Poly1305;

pub fn generate_key() -> Vec<u8> {
    ChaCha20Poly1305::generate_key(&mut OsRng).to_vec()
}

pub fn encrypt(cleartext: &str, key: &[u8]) -> Vec<u8> {
    let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key));
    let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
    let mut obsf = cipher.encrypt(&nonce, cleartext.as_bytes()).unwrap();
    obsf.splice(..0, nonce.iter().copied());
    obsf
}

pub fn decrypt(obsf: &[u8], key: &[u8]) -> String {
    type NonceSize = <ChaCha20Poly1305 as AeadCore>::NonceSize;
    let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key));
    let (nonce, ciphertext) = obsf.split_at(NonceSize::to_usize());
    let nonce = GenericArray::from_slice(nonce);
    let plaintext = cipher.decrypt(nonce, ciphertext).unwrap();
    String::from_utf8(plaintext).unwrap()
}

fn main() {
    let key = generate_key();
    let ciphertext = encrypt("plaintext message", &key);
    let plaintext = decrypt(&ciphertext, &key);
    assert_eq!(plaintext, "plaintext message");
}
5 Likes

This simple_crypt has exactly what I was looking for.

1 Like

One needs a key, obviously, to encrypt anything. One needs a nonce so as to ensure the same text is never encrypted to the same thing twice

I do not care if "the same text is ...[ever] encrypted to the same thing twice"

Public libraries are written to be flexible, which is why they have some degree of complexity.

Horses for courses. Not everything has to be flexible. Sometimes simplicity is better.

I am definitely not saying that industrial grade cryptography should not be available, it should. But if it is not needed then it should not be mandatory. It is not mandatory, as it turns out. Yay!

I don't really understand your problem. These libraries are all made by people and they are generous enough to just give them away for free.

Why don't you just wrap one of them with the simple interface you need? And if you feel like giving back, publish your simple interface so that the next person needing a simple interface does not have the same struggle as you.

1 Like

You do, because not doing that opens up attacks that make it possible to break the encryption. You might as well just not care about encrypting at all.

6 Likes

That is not true "You might as well just not care about encrypting at all.". Hyperbole. For my use case it is irrelevant.

I am encrypting a token that includes a time stamp. The clear text is never the same.

Two reasons:

(1) I have no use for a nonce. What do I do then? I cannot answer that without more work than this is worth.

(2) Why would I redo the work of simple-crypt. Amusingly I found simple-crypt because I could hear myself whining, and I thought: "Just do it, implement it". So I went on crates.io, having decided I would call my package "simple-crypt". And there it was! Happy day!!

1 Like

It's all fun and games assuming your plaintext is always unique, until you expose an API and attackers start using it as an oracle.

Don't ignore best practices around encryption. Cryptography is subtle, and you markedly don't know better than several decades of industry experience.

3 Likes

I too have decades of experience.

I know not to build complex solutions to simple problems.

Hahaha😂 Nice.
Sorry, I overlooked your previous post about simple_crypt.

1 Like