#encryption #signature #signing #message-authentication

signcryption

Library implementing the Toorani-Beheshti signcryption scheme instantiated over Ristretto255 or Ed25519

4 releases

0.1.3 Aug 15, 2023
0.1.2 Jun 25, 2023
0.1.1 Jan 9, 2023
0.1.0 Jan 9, 2023

#914 in Cryptography

MIT/Apache

35KB
519 lines

Build Status Crates

Signcryption

Signcryption is a cryptographic technique that combines the functionality of both digital signatures and encryption. It allows a sender to both authenticate the origin of a message and protect its confidentiality, while also allowing the recipient to verify the authenticity of the message and decrypt it without requiring any separate communication channels.

This library implements the Toorani-Beheshti signcryption scheme instantiated over Ristretto255 or Ed25519.

Installation

This library currently depends on the libsodium-sys-stable crate. You will need libsodium installed first.

https://libsodium.gitbook.io/doc/installation

Or simply use the fetch-libsodium feature of this crate on first use which will download and install the current stable version.

To add to your project:

cargo add signcryption

or in Cargo.toml:

[dependencies]
signcryption = "0.1"

Usage

The higher level signcrypt and unsigncrypt functions automatically handle encryption using the AES-GCM crate.

// Default uses Ristretto255
let alice_keys = Keypair::default();
let bob_keys = Keypair::default();

let alice_public_key = alice_keys.public.clone();
let bob_public_key = bob_keys.public.clone();

let msg = "Hello".as_bytes();

// Sign and encrypt, returns a SignCrypt struct
let ciphertext = signcrypt(&alice_keys, &bob_public_key, &msg)?;

// Verify and decrypt, returns a plaintext Vec<u8>
let plaintext = unsigncrypt(ciphertext, &alice_public_key, &bob_keys)?;

assert_eq!(payload , &plaintext[..]);

To use a different AEAD or for lower level control you'll need to run through the discrete step functions themselves. To remove the aes-gcm crate dependency set default-features = false in Cargo.toml

Signcrypt

// Initialise state
let mut state = SignState::default();

// Using Ed25519 keys this time
let alice_keys = Keypair::new(Curve::Ed25519);
let bob_keys = Keypair::new(Curve::Ed25519);

// Shared secret for encryption
let mut crypt_key = [0u8; SHAREDBYTES];

let msg = "Hello".as_bytes()

// Additional Authenticated Data if desired
let sender_id = "alice".as_bytes()
let recipient_id = "bob".as_bytes()
let info = "rust-signcryption".as_bytes()

// Sign plaintext
sign_before(
  &mut state, &mut crypt_key, &sender_id, &recipient_id, &info, 
  &alice.expose_secret(), &bob.public, msg, Curve::Ed25519
)?;

/////////////////////////////////////////////////////////////
// Encrypt here with your desired AEAD using crypt_key eg. //
// let cipher = ChaCha20Poly1305::new(&crypt_key);         //
/////////////////////////////////////////////////////////////

// Sign ciphertext
let mut sig = [0u8; SIGNBYTES];
sign_after(&mut state, &mut sig, &alice.expose_secret(), &ciphertext, Curve::Ed25519);

// Send ciphertext, signature and any AAD to recipient

Unsigncrypt

let mut state = SignState::default();
let mut crypt_key = [0u8; SHAREDBYTES];

// Additional Authenticated Data used to signcrypt the message
let sender_id = "alice".as_bytes()
let recipient_id = "bob".as_bytes()
let info = "rust-signcryption".as_bytes()

// Verify and get shared secret
verify_before(
  &mut state, &mut crypt_key, &sig, &sender_id,
  &recipient_id, &info, &alice_public_key,
  &bob.expose_secret(), Curve::Ed25519
)?; 

////////////////////////////
// Decrypt with crypt_key //
////////////////////////////

// Verify after
verify_after(&mut state, &sig, &alice_public_key, &ciphertext, Curve::Ed25519)?;

Public Verification

Verify the message without learning the decryption key.

verify_public(
  &sig, &sender_id, &recipient_id, &info, 
  &alice_public_key, &ciphertext, Curve::Ed25519
)?;

Why?

Combining encryption and signing has flaws either way you order them:

  • Encrypt then Sign: An attacker can replace your signature, making it seem as though they encrypted the file.

  • Sign then Encrypt: The recipient can re-encrypt the file and impersonate you sending the file to someone else.

Signcryption performs signing before and after the encryption stage, negating these flaws.

Alternatives

This crate is based on the Libsodium-Signcryption library, written in C by Frank Denis.

Licensing

All crates licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~2.6–5MB
~54K SLoC