Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Problem: (CRO-392) Outdated dependencies in client's storage encryption #588

Merged
merged 1 commit into from
Nov 14, 2019
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
6 changes: 3 additions & 3 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ steps:
pull: never
commands:
- export RUST_BACKTRACE=1
- export RUSTFLAGS=-Ctarget-feature=+aes,+ssse3
- export RUSTFLAGS=-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3
tomtau marked this conversation as resolved.
Show resolved Hide resolved
- export LD_LIBRARY_PATH=$HOME/lib
- export LIBRARY_PATH=$HOME/lib
- export PATH=$HOME/.cargo/bin:$HOME/.local/bin:$PATH
Expand Down Expand Up @@ -114,7 +114,7 @@ steps:
from_secret: dev_ias_key
commands:
- export RUST_BACKTRACE=1
- export RUSTFLAGS=-Ctarget-feature=+aes,+ssse3
- export RUSTFLAGS=-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3
- export SGX_MODE=HW
- export NETWORK_ID=ab
- export RUST_LOG=info
Expand Down Expand Up @@ -146,6 +146,6 @@ trigger:

---
kind: signature
hmac: 7cc5892757c793d3cabdbacedaf37498fb1cf65d9a05eb19218daf38e28222de
hmac: cf4d1c1fdb5895f7fa7bcf7edb0e1fe4131cf8d9d548a46cb8f4aca4e182d4ab

...
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ rust: &rust
- rm -rf $HOME/.cargo/registry/src
env:
- RUST_BACKTRACE=1
- RUSTFLAGS=-Ctarget-feature=+aes,+ssse3
- RUSTFLAGS=-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3
- PATH=$HOME/.local/bin:$PATH
- LD_LIBRARY_PATH=$HOME/lib
- PKG_CONFIG_PATH=$HOME/lib/pkgconfig
Expand Down
210 changes: 80 additions & 130 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Crypto.com chain requires the following to be installed before build.
After all dependencies are installed, add the following lines to `~/.cargo/config` to enable generating instructions for Streaming SIMD Extensions 3 and Advanced Vector Extensions on build:
```
[build]
rustflags = ["-Ctarget-feature=+aes,+ssse3"]
rustflags = ["-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"]
```

(TODO: In the future, the build tooling may be migrated to Bazel / Nix etc. for reproducible builds.)
Expand Down
2 changes: 1 addition & 1 deletion ci-scripts/drone.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ stdenv.mkDerivation {
];
shellHook = ''
export RUST_BACKTRACE=1
export RUSTFLAGS=-Ctarget-feature=+aes,+ssse3
export RUSTFLAGS=-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3
export PATH="$PWD/node_modules/.bin/:$PATH"
export OPENSSL_DIR="${openssl.dev}"
export OPENSSL_LIB_DIR="${openssl.out}/lib"
Expand Down
2 changes: 1 addition & 1 deletion client-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ chain-tx-filter = { path = "../chain-tx-filter" }
secp256k1zkp = { git = "https://github.com/crypto-com/rust-secp256k1-zkp.git", rev = "8b9a38b870a7759fcdbd4a5d435b5ba873c70afd", features = ["serde", "zeroize", "rand", "recovery", "endomorphism", "musig"] }
rand = "0.7"
log = "0.4"
miscreant = "0.4"
aes-gcm-siv = "0.2"
blake2 = "0.8"
hex = "0.4"
base64 = "0.11"
Expand Down
3 changes: 3 additions & 0 deletions client-common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ pub enum ErrorKind {
StorageError,
/// Random number generation error
RngError,
/// Encryption error
EncryptionError,
/// Decryption error
DecryptionError,
/// Serialization error
Expand Down Expand Up @@ -120,6 +122,7 @@ impl fmt::Display for ErrorKind {
ErrorKind::ConnectionError => write!(f, "Connection error"),
ErrorKind::StorageError => write!(f, "Storage error"),
ErrorKind::RngError => write!(f, "Random number generation error"),
ErrorKind::EncryptionError => write!(f, "Encryption error"),
ErrorKind::DecryptionError => write!(f, "Decryption error"),
ErrorKind::SerializationError => write!(f, "Serialization error"),
ErrorKind::DeserializationError => write!(f, "Deserialization error"),
Expand Down
110 changes: 49 additions & 61 deletions client-common/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ pub use memory_storage::MemoryStorage;
pub use sled_storage::SledStorage;
pub use unauthorized_storage::UnauthorizedStorage;

use aes_gcm_siv::aead::generic_array::GenericArray;
use aes_gcm_siv::aead::{Aead, NewAead};
use aes_gcm_siv::Aes256GcmSiv;
use blake2::{Blake2s, Digest};
use miscreant::{Aead, Aes128PmacSivAead};
use rand::rngs::OsRng;
use rand::Rng;
use secstr::SecUtf8;

use crate::{ErrorKind, Result, ResultExt};
use crate::{Error, ErrorKind, Result, ResultExt};

/// Nonce size in bytes
const NONCE_SIZE: usize = 8;
const NONCE_SIZE: usize = 12;

/// Interface for a generic key-value storage
pub trait Storage: Send + Sync {
Expand Down Expand Up @@ -104,19 +106,7 @@ where
passphrase: &SecUtf8,
) -> Result<Option<Vec<u8>>> {
self.get(keyspace, &key)?
.map(|value| {
let nonce_index = value.len() - NONCE_SIZE;
let mut algo = get_algo(passphrase);

Ok(algo
.open(&value[nonce_index..], key.as_ref(), &value[..nonce_index])
.chain(|| {
(
ErrorKind::DecryptionError,
"Incorrect passphrase: Unable to unlock stored values",
)
})?)
})
.map(|value| decrypt_bytes(passphrase, &value))
.transpose()
}

Expand All @@ -129,14 +119,7 @@ where
) -> Result<Option<Vec<u8>>> {
let old_value = self.get_secure(&keyspace, &key, passphrase)?;

let mut algo = get_algo(passphrase);

let mut nonce = [0u8; NONCE_SIZE];
OsRng.fill(&mut nonce);

let mut cipher = algo.seal(&nonce, key.as_ref(), &value);
cipher.extend(&nonce[..]);

let cipher = encrypt_bytes(passphrase, &value)?;
self.set(keyspace, key, cipher)?;

Ok(old_value)
Expand All @@ -155,17 +138,8 @@ where
F: Fn(Option<&[u8]>) -> Result<Option<Vec<u8>>>,
{
self.fetch_and_update(keyspace, &key, |current| {
let mut algo = get_algo(passphrase);
let opened = current
.map(|current| {
let nonce_index = current.len() - NONCE_SIZE;

algo.open(
&current[nonce_index..],
key.as_ref(),
&current[..nonce_index],
)
})
.map(|current| decrypt_bytes(passphrase, current))
.transpose()
.chain(|| {
(
Expand All @@ -176,39 +150,53 @@ where

let next = f(opened.as_ref().map(AsRef::as_ref))?;

next.map(|next| {
let mut nonce = [0u8; NONCE_SIZE];
OsRng.fill(&mut nonce);

let mut sealed = algo.seal(&nonce, key.as_ref(), &next);
sealed.extend(&nonce[..]);

Ok(sealed)
})
.transpose()
next.as_ref()
.map(|next| encrypt_bytes(passphrase, next))
.transpose()
})
}
}

/// Decrypts bytes with given key and passphrase
pub fn decrypt_bytes<K>(key: K, passphrase: &SecUtf8, bytes: &[u8]) -> Result<Vec<u8>>
where
K: AsRef<[u8]>,
{
let mut algo = get_algo(passphrase);
let nonce_index = bytes.len() - NONCE_SIZE;

algo.open(&bytes[nonce_index..], key.as_ref(), &bytes[..nonce_index])
.chain(|| {
(
ErrorKind::DecryptionError,
"Incorrect passphrase: Unable to unlock stored values",
)
})
/// Encrypts bytes with given passphrase
pub fn encrypt_bytes(passphrase: &SecUtf8, bytes: &[u8]) -> Result<Vec<u8>> {
let mut nonce = [0; NONCE_SIZE];

OsRng.fill(&mut nonce);

let algo = get_algo(passphrase)?;

let mut cipher = Vec::new();
cipher.extend_from_slice(&nonce[..]);

cipher.append(
&mut algo
.encrypt(GenericArray::from_slice(&nonce), bytes)
.map_err(|_| Error::new(ErrorKind::EncryptionError, "Unable to encrypt bytes"))?,
);

Ok(cipher)
}

fn get_algo(passphrase: &SecUtf8) -> Aes128PmacSivAead {
/// Decrypts bytes with given passphrase
pub fn decrypt_bytes(passphrase: &SecUtf8, bytes: &[u8]) -> Result<Vec<u8>> {
let algo = get_algo(passphrase)?;

algo.decrypt(
GenericArray::from_slice(&bytes[..NONCE_SIZE]),
&bytes[NONCE_SIZE..],
)
.map_err(|_| {
Error::new(
ErrorKind::DecryptionError,
"Incorrect passphrase: Unable to unlock stored values",
)
})
}

fn get_algo(passphrase: &SecUtf8) -> Result<Aes256GcmSiv> {
let mut hasher = Blake2s::new();
hasher.input(passphrase.unsecure());
Aes128PmacSivAead::new(&hasher.result_reset())

let key = GenericArray::clone_from_slice(&hasher.result_reset());
Ok(Aes256GcmSiv::new(key))
}
2 changes: 1 addition & 1 deletion client-core/src/service/hd_key_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ where
)
})?;

let hd_key_bytes = decrypt_bytes(name, passphrase, &bytes)?;
let hd_key_bytes = decrypt_bytes(passphrase, &bytes)?;

let hd_key = HdKey::decode(&mut hd_key_bytes.as_slice()).chain(|| {
(
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM rust:1.38.0 AS builder
LABEL maintainer="calvin@crypto.com"

ENV RUSTFLAGS "-Ctarget-feature=+aes,+ssse3"
ENV RUSTFLAGS "-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"

RUN apt-get update -y && \
apt-get install cmake libgflags-dev libzmq3-dev pkg-config -y
Expand Down