Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ChaCha20/Poly1305 #26

Merged
merged 2 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: rustc, cargo
- run: cargo test --no-default-features --features openssl
- run: cargo test --no-default-features --features openssl,rustcrypto

fmt:
name: Rustfmt
Expand Down
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ exclude = [
default = ["std", "openssl"]
std = ["serde/std", "ciborium/std", "serde_bytes/std", "erased-serde/std", "derive_builder/std"]
rustcrypto = ["rustcrypto-aes-gcm", "rustcrypto-aes-kw", "rustcrypto-ecdsa", "rustcrypto-hmac"]
rustcrypto-encrypt = ["rustcrypto-aes-gcm", "rustcrypto-aes-ccm"]
rustcrypto-encrypt = ["rustcrypto-aes-gcm", "rustcrypto-aes-ccm", "rustcrypto-chacha20-poly1305"]
rustcrypto-sign = ["rustcrypto-ecdsa"]
rustcrypto-key-distribution = ["rustcrypto-aes-kw"]
rustcrypto-mac = ["rustcrypto-hmac"]
rustcrypto-aes-gcm = ["dep:aes-gcm", "dep:typenum", "dep:aead", "dep:aes"]
rustcrypto-aes-ccm = ["dep:ccm", "dep:typenum", "dep:aead", "dep:aes"]
rustcrypto-chacha20-poly1305 = ["dep:chacha20poly1305", "dep:typenum", "dep:aead"]
rustcrypto-aes-kw = ["dep:aes-kw", "dep:aes", "dep:typenum", "dep:crypto-common"]
rustcrypto-ecdsa = ["dep:ecdsa", "dep:p256", "dep:p384", "dep:digest", "dep:sha2", "dep:elliptic-curve"]
rustcrypto-hmac = ["dep:hmac", "dep:digest", "dep:sha2"]
Expand All @@ -43,6 +44,7 @@ openssl = { version = "^0.10", optional = true }
lazy_static = "1.4.0"
aes-gcm = { version = "0.10.3", optional = true, default-features = false, features = ["alloc", "aes"] }
ccm = { version = "0.5.0", optional = true, default-features = false, features = ["alloc"] }
chacha20poly1305 = { version = "0.10.1", optional = true, default-features = false, features = ["alloc"] }
typenum = { version = "1.17.0", optional = true, default-features = false, features = ["const-generics"] }
crypto-common = { version = "0.1.6", optional = true, default-features = false }
aead = { version = "0.5.2", optional = true, default-features = false }
Expand Down
4 changes: 3 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ fn main() {
cfg_aliases! {
rustcrypto_encrypt_base: {
any(
feature = "rustcrypto-aes-gcm"
feature = "rustcrypto-aes-gcm",
feature = "rustcrypto-aes-ccm",
feature = "rustcrypto-chacha20-poly1305"
)
},
rustcrypto_sign_base: {
Expand Down
79 changes: 73 additions & 6 deletions src/token/cose/crypto_impl/openssl/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::openssl::OpensslContext;
use crate::token::cose::util::{aes_ccm_algorithm_tag_len, AES_GCM_TAG_LEN};
use crate::token::cose::util::symmetric_algorithm_tag_len;
use crate::token::cose::{crypto_impl, CoseSymmetricKey, EncryptCryptoBackend};
use alloc::vec::Vec;
use coset::iana;
Expand All @@ -27,6 +27,7 @@ impl EncryptCryptoBackend for OpensslContext {
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
let cipher = crypto_impl::openssl::algorithm_to_cipher(algorithm)?;
let tag_len = symmetric_algorithm_tag_len(algorithm)?;
let mut ctx = CipherCtx::new()?;
// So, apparently OpenSSL requires a very specific order of operations which differs
// slightly for AES-GCM and AES-CCM in order to work.
Expand All @@ -51,7 +52,7 @@ impl EncryptCryptoBackend for OpensslContext {
// 6. Then, we can finish the operation.
ctx.cipher_final_vec(&mut ciphertext)?;
let ciphertext_len = ciphertext.len();
ciphertext.resize(ciphertext_len + AES_GCM_TAG_LEN, 0u8);
ciphertext.resize(ciphertext_len + tag_len, 0u8);
ctx.tag(&mut ciphertext[ciphertext_len..])?;
Ok(ciphertext)
}
Expand All @@ -65,8 +66,9 @@ impl EncryptCryptoBackend for OpensslContext {
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
let cipher = crypto_impl::openssl::algorithm_to_cipher(algorithm)?;
let auth_tag = &ciphertext_with_tag[(ciphertext_with_tag.len() - AES_GCM_TAG_LEN)..];
let ciphertext = &ciphertext_with_tag[..(ciphertext_with_tag.len() - AES_GCM_TAG_LEN)];
let tag_len = symmetric_algorithm_tag_len(algorithm)?;
let auth_tag = &ciphertext_with_tag[(ciphertext_with_tag.len() - tag_len)..];
let ciphertext = &ciphertext_with_tag[..(ciphertext_with_tag.len() - tag_len)];

let mut ctx = CipherCtx::new()?;
// Refer to https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Decryption_using_GCM_mode
Expand Down Expand Up @@ -103,7 +105,7 @@ impl EncryptCryptoBackend for OpensslContext {
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
let cipher = crypto_impl::openssl::algorithm_to_cipher(algorithm)?;
let tag_len = aes_ccm_algorithm_tag_len(algorithm)?;
let tag_len = symmetric_algorithm_tag_len(algorithm)?;
let mut ctx = CipherCtx::new()?;
// Refer to https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_CCM_mode
// for reference.
Expand Down Expand Up @@ -140,7 +142,7 @@ impl EncryptCryptoBackend for OpensslContext {
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
let cipher = crypto_impl::openssl::algorithm_to_cipher(algorithm)?;
let tag_len = aes_ccm_algorithm_tag_len(algorithm)?;
let tag_len = symmetric_algorithm_tag_len(algorithm)?;
let auth_tag = &ciphertext_with_tag[(ciphertext_with_tag.len() - tag_len)..];
let ciphertext = &ciphertext_with_tag[..(ciphertext_with_tag.len() - tag_len)];

Expand Down Expand Up @@ -169,4 +171,69 @@ impl EncryptCryptoBackend for OpensslContext {

Ok(plaintext)
}

fn encrypt_chacha20_poly1305(
&mut self,
key: CoseSymmetricKey<'_, Self::Error>,
plaintext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
let cipher = openssl::cipher::Cipher::chacha20_poly1305();
let tag_len = symmetric_algorithm_tag_len(iana::Algorithm::ChaCha20Poly1305)?;
let mut ctx = CipherCtx::new()?;
// Refer to https://docs.openssl.org/1.1.1/man3/EVP_EncryptInit/#chacha20-poly1305 for
// reference.
// 1. First, we set the cipher.
ctx.encrypt_init(Some(cipher), None, None)?;
// 2. We *must* set the IV length _before_ setting the IV.
ctx.set_iv_length(iv.len())?;
// 3. Now we can set key and IV.
ctx.encrypt_init(None, Some(key.k), Some(iv))?;
let mut ciphertext = vec![];
// 4. Then, we set the AAD before setting the plaintext.
ctx.cipher_update(aad, None)?;
// 5. Finally, we provide the plaintext.
ctx.cipher_update_vec(plaintext, &mut ciphertext)?;
// 6. Then, we can finish the operation.
ctx.cipher_final_vec(&mut ciphertext)?;
let ciphertext_len = ciphertext.len();
ciphertext.resize(ciphertext_len + tag_len, 0u8);
ctx.tag(&mut ciphertext[ciphertext_len..])?;
Ok(ciphertext)
}

fn decrypt_chacha20_poly1305(
&mut self,
key: CoseSymmetricKey<'_, Self::Error>,
ciphertext_with_tag: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
let cipher = openssl::cipher::Cipher::chacha20_poly1305();
let tag_len = symmetric_algorithm_tag_len(iana::Algorithm::ChaCha20Poly1305)?;
let auth_tag = &ciphertext_with_tag[(ciphertext_with_tag.len() - tag_len)..];
let ciphertext = &ciphertext_with_tag[..(ciphertext_with_tag.len() - tag_len)];

let mut ctx = CipherCtx::new()?;
// Refer to https://docs.openssl.org/1.1.1/man3/EVP_EncryptInit/#chacha20-poly1305 for
// reference.
// 1. First, we set the cipher.
ctx.decrypt_init(Some(cipher), None, None)?;
// 2. We *must* set the tag and IV length _before_ setting key and IV.
ctx.set_iv_length(iv.len())?;
ctx.set_tag(auth_tag)?;
// 3. Now we can set key and IV.
ctx.decrypt_init(None, Some(key.k), Some(iv))?;
// 4. Then, we set the AAD before setting the ciphertext.
ctx.cipher_update(aad, None)?;
// 5. Finally, we provide the ciphertext for decryption.
let mut plaintext = vec![0; ciphertext.len()];
let plaintext_len = ctx.cipher_update(ciphertext, Some(&mut plaintext))?;
plaintext.truncate(plaintext_len);
// No call to cipher_final() here, I guess?
// The official examples in the OpenSSL wiki don't finalize, so we won't either.

Ok(plaintext)
}
}
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/encrypt/aead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::error::CoseCipherError;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};

use super::RustCryptoContext;
use alloc::vec::Vec;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform an AEAD encryption operation on `plaintext` and the additional authenticated
Expand Down
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/encrypt/aes_ccm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::error::CoseCipherError;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};

use super::RustCryptoContext;
use alloc::vec::Vec;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform an AES-CCM encryption operation on `plaintext` and the additional authenticated
Expand Down
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/encrypt/aes_gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::error::CoseCipherError;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};

use super::RustCryptoContext;
use alloc::vec::Vec;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform an AES-GCM encryption operation on `plaintext` and the additional authenticated
Expand Down
41 changes: 41 additions & 0 deletions src/token/cose/crypto_impl/rustcrypto/encrypt/chacha_poly.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};
use alloc::vec::Vec;
use chacha20poly1305::ChaCha20Poly1305;
use rand::CryptoRng;
use rand::RngCore;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform a ChaCha20/Poly1305 encryption operation on `plaintext` and the additional
/// authenticated data `aad` using the given `iv` and `key`.
pub(super) fn encrypt_chacha20_poly1305(
key: &CoseSymmetricKey<'_, <Self as CryptoBackend>::Error>,
plaintext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<<Self as CryptoBackend>::Error>> {
Self::encrypt_aead::<ChaCha20Poly1305>(key, plaintext, aad, iv)
}

/// Perform a ChaCha20/Poly1305 decryption operation on `ciphertext_with_tag` and the additional
/// authenticated data `aad` using the given `iv` and `key`.
pub(super) fn decrypt_chacha20_poly1305(
key: &CoseSymmetricKey<'_, <Self as CryptoBackend>::Error>,
ciphertext_with_tag: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<<Self as CryptoBackend>::Error>> {
Self::decrypt_aead::<ChaCha20Poly1305>(key, ciphertext_with_tag, aad, iv)
}
}
32 changes: 31 additions & 1 deletion src/token/cose/crypto_impl/rustcrypto/encrypt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@ use rand::{CryptoRng, RngCore};
use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::{CoseSymmetricKey, EncryptCryptoBackend};
use alloc::vec::Vec;

#[cfg(feature = "rustcrypto-aes-gcm")]
mod aes_gcm;

#[cfg(feature = "rustcrypto-aes-ccm")]
mod aes_ccm;

#[cfg(any(feature = "rustcrypto-aes-gcm", feature = "rustcrypto-aes-ccm"))]
#[cfg(feature = "rustcrypto-chacha20-poly1305")]
mod chacha_poly;

#[cfg(any(
feature = "rustcrypto-aes-gcm",
feature = "rustcrypto-aes-ccm",
feature = "rustcrypto-chacha20-poly1305"
))]
mod aead;

impl<RNG: RngCore + CryptoRng> EncryptCryptoBackend for RustCryptoContext<RNG> {
Expand Down Expand Up @@ -72,4 +80,26 @@ impl<RNG: RngCore + CryptoRng> EncryptCryptoBackend for RustCryptoContext<RNG> {
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
Self::decrypt_aes_ccm(algorithm, &key, ciphertext_with_tag, aad, iv)
}

#[cfg(feature = "rustcrypto-chacha20-poly1305")]
fn encrypt_chacha20_poly1305(
&mut self,
key: CoseSymmetricKey<'_, Self::Error>,
plaintext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
Self::encrypt_chacha20_poly1305(&key, plaintext, aad, iv)
}

#[cfg(feature = "rustcrypto-chacha20-poly1305")]
fn decrypt_chacha20_poly1305(
&mut self,
key: CoseSymmetricKey<'_, Self::Error>,
ciphertext_with_tag: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
Self::decrypt_chacha20_poly1305(&key, ciphertext_with_tag, aad, iv)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::error::CoseCipherError;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};

use super::RustCryptoContext;
use alloc::vec::Vec;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform an AES key wrap operation on the key contained in `plaintext` which is wrapped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rand::{CryptoRng, RngCore};
use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::{CoseSymmetricKey, KeyDistributionCryptoBackend};
use alloc::vec::Vec;

#[cfg(feature = "rustcrypto-aes-kw")]
mod aes_key_wrap;
Expand Down
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/mac/hmac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use sha2::{Sha256, Sha384, Sha512};
use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};
use alloc::vec::Vec;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Compute the HMAC of `payload` using the given `key` with the HMAC function
Expand Down
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/mac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::token::cose::crypto_impl::rustcrypto::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::CoseSymmetricKey;
use crate::token::cose::MacCryptoBackend;
use alloc::vec::Vec;
use coset::iana;
use rand::{CryptoRng, RngCore};

Expand Down
6 changes: 5 additions & 1 deletion src/token/cose/crypto_impl/rustcrypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ impl From<digest::MacError> for CoseCipherError<CoseRustCryptoCipherError> {
}
}

#[cfg(feature = "rustcrypto-aes-gcm")]
#[cfg(any(
feature = "rustcrypto-aes-gcm",
feature = "rustcrypto-aes-ccm",
feature = "rustcrypto-chacha20-poly1305"
))]
impl From<aead::Error> for CoseCipherError<CoseRustCryptoCipherError> {
fn from(_value: aead::Error) -> Self {
CoseCipherError::VerificationFailure
Expand Down
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/sign/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::CoseRustCryptoCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::{CoseEc2Key, CryptoBackend, EllipticCurve};
use alloc::vec::Vec;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform an ECDSA signature operation with the ECDSA variant given in `algorithm` for the
Expand Down
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/rustcrypto/sign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use rand::{CryptoRng, RngCore};

use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::SignCryptoBackend;
use alloc::vec::Vec;

#[cfg(feature = "rustcrypto-ecdsa")]
mod ecdsa;
Expand Down
Loading
Loading