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

[refactor] #3422: Ursa replacement #4047

Merged
merged 14 commits into from
Nov 20, 2023
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
913 changes: 443 additions & 470 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,6 @@ strum = { version = "0.25.0", default-features = false }
getset = "0.1.2"
hex-literal = "0.4.1"

ursa = "0.3.7"
aead = "0.3.2"

rand = "0.8.5"
warp = { version = "0.3.6", default-features = false }
wasmtime = "13.0.0"
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=/x86_64-linux-musl-native/bin/
# builder stage
WORKDIR /iroha
COPY . .
RUN cargo build --target x86_64-unknown-linux-musl --features vendored --profile deploy
RUN cargo build --target x86_64-unknown-linux-musl --profile deploy


# final image
Expand Down
22 changes: 20 additions & 2 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ is-it-maintained-issue-resolution = { repository = "https://github.com/hyperledg
is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/iroha" }
maintenance = { status = "actively-developed" }

[features]
tls-native = [
"attohttpc/tls-native",
"tokio-tungstenite/native-tls",
]
tls-native-vendored = [
"attohttpc/tls-native-vendored",
"tokio-tungstenite/native-tls-vendored",
]
tls-rustls-native-roots = [
"attohttpc/tls-rustls-native-roots",
"tokio-tungstenite/rustls-tls-native-roots",
]
tls-rustls-webpki-roots = [
"attohttpc/tls-rustls-webpki-roots",
"tokio-tungstenite/rustls-tls-webpki-roots",
]

[dependencies]
iroha_config = { workspace = true }
iroha_crypto = { workspace = true }
Expand All @@ -31,7 +49,7 @@ iroha_logger = { workspace = true }
iroha_telemetry = { workspace = true }
iroha_version = { workspace = true, features = ["http"] }

attohttpc = "0.26.1"
attohttpc = { version = "0.26.1", default-features = false }
eyre = { workspace = true }
http = "0.2.9"
url = { workspace = true }
Expand All @@ -44,7 +62,7 @@ displaydoc = { workspace = true }
derive_more = { workspace = true }
parity-scale-codec = { workspace = true, default-features = false, features = ["derive"] }
tokio = { workspace = true, features = ["rt"] }
tokio-tungstenite = { workspace = true, features = ["native-tls"] }
tokio-tungstenite = { workspace = true }
futures-util = "0.3.28"

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1702,7 +1702,7 @@ mod tests {
),
private_key: Some(iroha_crypto::PrivateKey::from_hex(
iroha_crypto::Algorithm::Ed25519,
"9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0".as_ref()
"9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0"
).expect("Private key not hex encoded")),
account_id: Some(
"alice@wonderland"
Expand Down
2 changes: 1 addition & 1 deletion client_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ is-it-maintained-open-issues = { repository = "https://github.com/hyperledger/ir
maintenance = { status = "actively-developed" }

[dependencies]
iroha_client = { workspace = true }
iroha_client = { workspace = true, features = ["tls-rustls-native-roots"] }
iroha_data_model = { workspace = true }
iroha_primitives = { workspace = true }
iroha_crypto = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion config/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub mod tests {
.expect("Public key not in multihash format");
let private_key = PrivateKey::from_hex(
iroha_crypto::Algorithm::Ed25519,
"D748E18CE60CB30DEA3E73C9019B7AF45A8D465E3D71BCC9A5EF99A008205E534CFFD0EE429B1BDD36B3910EC570852B8BB63F18750341772FB46BC856C5CAAF".as_ref()
"D748E18CE60CB30DEA3E73C9019B7AF45A8D465E3D71BCC9A5EF99A008205E534CFFD0EE429B1BDD36B3910EC570852B8BB63F18750341772FB46BC856C5CAAF"
).expect("Private key not hex encoded");

KeyPair::new(public_key, private_key).expect("Key pair mismatch")
Expand Down
2 changes: 1 addition & 1 deletion config/src/iroha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ mod tests {
pub fn placeholder_keypair() -> KeyPair {
let private_key = PrivateKey::from_hex(
Algorithm::Ed25519,
"282ED9F3CF92811C3818DBC4AE594ED59DC1A2F78E4241E31924E101D6B1FB831C61FAF8FE94E253B93114240394F79A607B7FA55F9E5A41EBEC74B88055768B".as_ref()
"282ED9F3CF92811C3818DBC4AE594ED59DC1A2F78E4241E31924E101D6B1FB831C61FAF8FE94E253B93114240394F79A607B7FA55F9E5A41EBEC74B88055768B"
).expect("Private key not hex encoded");

KeyPair::new(
Expand Down
2 changes: 1 addition & 1 deletion core/test_network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn get_key_pair() -> KeyPair {
.expect("Public key not in mulithash format"),
PrivateKey::from_hex(
Algorithm::Ed25519,
"9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0".as_ref()
"9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0"
).expect("Private key not hex encoded")
).expect("Key pair mismatch")
}
Expand Down
61 changes: 56 additions & 5 deletions crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,28 @@ workspace = true
default = ["std"]
# Enable static linkage of the rust standard library.
# Please refer to https://docs.rust-embedded.org/book/intro/no-std.html
std = ["ursa"]
# Force static linking
vendored = ["openssl-sys"]
std = [
"dep:blake2",
"dep:digest",
"dep:sha2",
"dep:hkdf",
"dep:amcl",
"dep:amcl_wrapper",
"dep:signature",
"dep:ed25519-dalek",
"dep:curve25519-dalek",
"dep:x25519-dalek",
"dep:rand",
"dep:rand_chacha",
"dep:zeroize",
"dep:arrayref",
"dep:aead",
"dep:chacha20poly1305",
"dep:elliptic-curve",
"dep:k256",
"dep:thiserror",
"displaydoc/std",
]
# Replace structures and methods with FFI equivalents to facilitate dynamic linkage (mainly used in smartcontracts)
#ffi_import = ["iroha_ffi", "iroha_primitives/ffi_import"]

Expand All @@ -34,10 +53,42 @@ parity-scale-codec = { workspace = true, features = ["derive", "full"] }
serde = { workspace = true, features = ["derive"] }
serde_with = { workspace = true, features = ["macros"] }
hex = { workspace = true, features = ["alloc", "serde"] }
openssl-sys = { version = "0.9.93", features = ["vendored"], optional = true }
ursa = { workspace = true, optional = true }
getset = { workspace = true }

thiserror = { version = "1.0.50", optional = true }
displaydoc = { version = "0.2.4", default-features = false }

digest = { version = "0.10.7", optional = true }
blake2 = { version = "0.10.6", optional = true }
sha2 = { version = "0.10.8", optional = true }
hkdf = { version = "0.12.3", optional = true }
amcl = { version = "0.2.0", optional = true, default-features = false, features = ["secp256k1"] }
amcl_wrapper = { version = "0.4.0", optional = true }

signature = { version = "2.1.0", optional = true }
ed25519-dalek = { version = "2.0.0", optional = true, features = ["rand_core"] }
curve25519-dalek = { version = "4.1.1", optional = true }
x25519-dalek = { version = "2.0.0", optional = true, features = ["static_secrets"] }

rand = { workspace = true, optional = true }
rand_chacha = { version = "0.3.1", optional = true }


zeroize = { version = "1.6.0", optional = true }
arrayref = { version = "0.3.7", optional = true }

aead = { version = "0.5.2", optional = true }
chacha20poly1305 = { version = "0.10.1", optional = true }

elliptic-curve = { version = "0.13.6", optional = true }
k256 = { version = "0.13.1", optional = true, features = ["ecdsa", "sha256"]}

[dev-dependencies]
hex-literal = { workspace = true }
serde_json = { workspace = true }

# these crypto libraries are not used to implement actual crypto algorithms
# but to test some of the primitives against them
secp256k1 = { version = "0.28.0", features = ["rand", "serde"] }
libsodium-sys-stable = "1.20.3"
openssl = { version = "0.10.59", features = ["vendored"] }
125 changes: 125 additions & 0 deletions crypto/src/encryption/chacha20poly1305.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use aead::{
generic_array::{
typenum::{U0, U12, U16, U32, U36},
GenericArray,
},
Aead, AeadCore, Error, KeyInit, KeySizeUser, Payload,
};
use chacha20poly1305::ChaCha20Poly1305 as SysChaCha20Poly1305;

use super::Encryptor;

/// `ChaCha20Poly1305` is a symmetric encryption algorithm that uses the `ChaCha20` stream cipher
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ChaCha20Poly1305 {
key: GenericArray<u8, U32>,
}

impl Encryptor for ChaCha20Poly1305 {
type MinSize = U36;
}

impl KeySizeUser for ChaCha20Poly1305 {
type KeySize = U32;
}

impl KeyInit for ChaCha20Poly1305 {
fn new(key: &GenericArray<u8, Self::KeySize>) -> Self {
Self { key: *key }
}
}

impl AeadCore for ChaCha20Poly1305 {
type NonceSize = U12;
type TagSize = U16;
type CiphertextOverhead = U0;
}

// false positives: eliding lifetimes here requires an unstable feature `anonymous_lifetime_in_impl_trait`
#[allow(single_use_lifetimes)]
impl Aead for ChaCha20Poly1305 {
fn encrypt<'msg, 'aad>(
&self,
nonce: &GenericArray<u8, Self::NonceSize>,
plaintext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>, Error> {
let aead = SysChaCha20Poly1305::new(&self.key);
let ciphertext = aead.encrypt(nonce, plaintext)?;
Ok(ciphertext)
}

fn decrypt<'msg, 'aad>(
&self,
nonce: &GenericArray<u8, Self::NonceSize>,
ciphertext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>, Error> {
let aead = SysChaCha20Poly1305::new(&self.key);
let plaintext = aead.decrypt(nonce, ciphertext)?;
Ok(plaintext)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn encrypt_easy_works() {
let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap());
let aad = Vec::new();
let message = b"Hello and Goodbye!".to_vec();
let ciphertext = cipher.encrypt_easy(&aad, &message).unwrap();
let decrypted_message = cipher.decrypt_easy(&aad, &ciphertext).unwrap();
assert_eq!(message, decrypted_message);
}

#[test]
fn encrypt_works() {
let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap());
let nonce = ChaCha20Poly1305::nonce_gen().unwrap();
let aad = b"encrypt test".to_vec();
let message = b"Hello and Goodbye!".to_vec();
let payload = Payload {
msg: message.as_slice(),
aad: aad.as_slice(),
};
let ciphertext = cipher.encrypt(&nonce, payload).unwrap();
let payload = Payload {
msg: ciphertext.as_slice(),
aad: aad.as_slice(),
};
let decrypted_message = cipher.decrypt(&nonce, payload).unwrap();
assert_eq!(message, decrypted_message);
}

#[test]
fn decrypt_should_fail() {
let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap());
let aad = b"decrypt should fail".to_vec();
let message = b"Hello and Goodbye!".to_vec();
let res = cipher.encrypt_easy(&aad, &message);
let mut ciphertext = res.unwrap();

let aad = b"decrypt should succeed".to_vec();
cipher.decrypt_easy(&aad, &ciphertext).unwrap_err();

let aad = b"decrypt should fail".to_vec();
ciphertext[0] ^= ciphertext[1];
cipher.decrypt_easy(&aad, &ciphertext).unwrap_err();
}

// TODO: this should be tested for, but only after we integrate with secrecy/zeroize
// #[test]
// fn zeroed_on_drop() {
// let mut aes = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap());
// aes.zeroize();
//
// fn as_bytes<T>(x: &T) -> &[u8] {
// use std::{mem, slice};
//
// unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) }
// }
//
// assert!(as_bytes(&aes.key).iter().all(|b| *b == 0u8));
// }
}
Loading
Loading