-
Notifications
You must be signed in to change notification settings - Fork 9
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
[PM-15096] Implement xchacha20-poly1305 cipher functions #150
Conversation
Great job, no security vulnerabilities found in this Pull Request |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #150 +/- ##
==========================================
+ Coverage 66.08% 66.31% +0.22%
==========================================
Files 198 199 +1
Lines 15505 15609 +104
==========================================
+ Hits 10247 10351 +104
Misses 5258 5258 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c259ab8
to
03dccda
Compare
7f33323
to
34f25de
Compare
bff507b
to
72bcf39
Compare
crates/bitwarden-crypto/Cargo.toml
Outdated
generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] } | ||
hkdf = ">=0.12.3, <0.13" | ||
hmac = ">=0.12.1, <0.13" | ||
num-bigint = ">=0.4, <0.5" | ||
num-traits = ">=0.2.15, <0.3" | ||
pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false } | ||
poly1305 = { version = "0.8.0", features = ["zeroize"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This crate doesn't seem to be used at the moment, I assume it's used in your other PR with the key-commiting implementation? If so we can probably remove it for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird, for chacha the CI pipeline complained about an unused dependency, for poly1305 it did not.
use crate::CryptoError; | ||
|
||
#[allow(unused)] | ||
pub(crate) fn generate_nonce() -> GenericArray<u8, U24> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this function only meant to be used for tests? If so, it should be moved inside mod tests {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, initially I thought we needed the IV to be included in the authenticated data, but I checked the spec of the format we want to follow for the new keys (COSE https://datatracker.ietf.org/doc/html/rfc8152), and the IV/nonce does not need to be authenticated, so it could just be generated during encrypt. We do however need to serialize it onto the encstring. So What would the recommendation here be, return a tuple / struct of Nonce + Ciphertext, and generate the nonce in the encrypt function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's more or less what we do for aes now yeah, so it seems reasonable to do the same for chacha
pub(crate) fn encrypt_aes256_hmac(
data_dec: &[u8],
mac_key: &GenericArray<u8, U32>,
key: &GenericArray<u8, U32>,
) -> Result<([u8; 16], [u8; 32], Vec<u8>)> {
/// IV is generated and returned with the encrypted data and the MAC as a tuple
Ok((iv, mac, data))
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated!
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, XChaCha20Poly1305}; | ||
use generic_array::{typenum::U24, GenericArray}; | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit, but I would move this comment to the top of the file and use //!
like on the other one. As it is right now, we're technically adding a doc comment to use crate::CryptoError
@@ -91,6 +91,7 @@ pub use wordlist::EFF_LONG_WORD_LIST; | |||
mod store; | |||
pub use store::{KeyStore, KeyStoreContext}; | |||
mod traits; | |||
mod xchacha20; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more of an idea for the future, but it would be nice to think about moving the aes
, rsa
and the new xchacha20
modules into their own separate low level algorithms module so they're not all exposed in the root.
|
||
#[allow(unused)] | ||
pub(crate) fn encrypt_xchacha20_poly1305( | ||
nonce: &[u8; 24], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the aes
module we generate the IV
internally to ensure we always generate a random one each time for encryption, assuming that the nonce
works the same in chacha20
, have you considered not exposing this as a parameter for encryption and just generating it internally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned for the nonce generating function, initially I thought the IV needed to be authenticated, but this is not the case, so I'll move this to generate during encrypt.
associated_data: &[u8], | ||
) -> Result<Vec<u8>, CryptoError> { | ||
// This buffer contains the plaintext, that will be encrypted in-place | ||
let mut buffer = Vec::from(plaintext_secret_data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit: In decrypt_xchacha20_poly1305
we're using slice.to_vec()
, while here we're using Vec::from(slice)
. We should try to be consistent and use one or the other.
associated_data, | ||
&mut buffer, | ||
) | ||
.map_err(|_| CryptoError::InvalidKey)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for aes and rsa we use the CryptoError::KeyDecrypt
error when decrypting. If so we should do the same here as well
associated_data, | ||
&mut buffer, | ||
) | ||
.map_err(|_| CryptoError::InvalidKey)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the error case for chacha20 encryption? Key and nonce sizes are checked at compile time, and as far as I know, chacha20 doesn't have any specific key format requirements.
If the only error case is the buffer not having enough space, I think we should be fine calling .expect("")
and not returning a Result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My only note is that I kind of want to see the interface one level up, as well.
I say this because we could design certain aspects of the AAD set into this level. I'm not set definitively in either direction, but there's an elegance to tying the cipherText to a key and cipher type at this level, rather than in the Encryptable
@MGibson1 Let's revisit this on the cose PR. I do at this point believe that COSE is better suited though, if we want a structured format to add our own additional data. |
|
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-15096
📔 Objective
Implements xchacha20-poly1305 (https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction) as a new encryption type.
Further, this introduces a dependency patch override (to https://github.com/bitwarden/rustcrypto-formats.git at revision 2b27c63034217dd126bbf5ed874da51b84f8c705) for rustcrypto formats, until this gets updated upstream to fix a type incompatibility when building on WASM and with chacha as a dependency.
These functions are unused until a follow-up PR (soon).
⏰ Reminders before review
team
🦮 Reviewer guidelines
:+1:
) or similar for great changes:memo:
) or ℹ️ (:information_source:
) for notes or general info:question:
) for questions:thinking:
) or 💭 (:thought_balloon:
) for more open inquiry that's not quite a confirmedissue and could potentially benefit from discussion
:art:
) for suggestions / improvements:x:
) or:warning:
) for more significant problems or concerns needing attention:seedling:
) or ♻️ (:recycle:
) for future improvements or indications of technical debt:pick:
) for minor or nitpick changes