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

Implement Keystore spec for BLS12-381 secret keys #777

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7a336c6
Add test to understand flow of key storage
pawanjay176 Oct 30, 2019
44e4e29
First commit
pawanjay176 Oct 31, 2019
4dd39e4
Committing to save trait stuff
pawanjay176 Nov 4, 2019
cc56ac8
Working naive design
pawanjay176 Nov 4, 2019
f668763
Add keystore struct
pawanjay176 Nov 4, 2019
dfbb40a
Move keystore files into their own module
pawanjay176 Nov 4, 2019
d6204a5
Add serde (de)serialize_with magic
pawanjay176 Nov 4, 2019
9716c41
Add keystore test
pawanjay176 Nov 5, 2019
d801316
Fix tests
pawanjay176 Nov 5, 2019
30027b1
Add comments and minor fixes
pawanjay176 Nov 5, 2019
5f4dddf
Pass optional params to `to_keystore` function
pawanjay176 Nov 5, 2019
3fe10a7
Add `path` field to keystore
pawanjay176 Nov 6, 2019
3238325
Add function to read Keystore from file
pawanjay176 Nov 6, 2019
b78c9fd
Add test vectors and fix Version serialization
pawanjay176 Nov 6, 2019
7ebe307
Checksum params is empty object
pawanjay176 Nov 7, 2019
9bb8647
Add public key to Keystore
pawanjay176 Nov 7, 2019
f8e7f57
Add function for saving keystore into file
pawanjay176 Nov 8, 2019
2777b49
Deleted account_manager main.rs
pawanjay176 Jan 7, 2020
ae631d4
Move keystore module to validator_client
pawanjay176 Nov 26, 2019
9c366eb
Add save_keystore method to validator_directory
pawanjay176 Nov 26, 2019
4e1a0d0
Add load_keystore function. Minor refactorings
pawanjay176 Nov 26, 2019
a56e5a3
Fixed dependencies
pawanjay176 Jan 7, 2020
3a93b98
Address some review comments
pawanjay176 Mar 5, 2020
1933b75
Add Password newtype; derive Zeroize
pawanjay176 Mar 6, 2020
7fbc971
Fix test
pawanjay176 Mar 6, 2020
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
34 changes: 34 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions validator_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ types = { path = "../eth2/types" }
serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
serde_repr = "0.1"
slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] }
slog-async = "2.3.0"
slog-term = "2.4.2"
Expand All @@ -41,3 +42,7 @@ bls = { path = "../eth2/utils/bls" }
remote_beacon_node = { path = "../eth2/utils/remote_beacon_node" }
tempdir = "0.3"
rayon = "1.2.0"
rand = "0.7.2"
rust-crypto = "0.2.36"
uuid = { version = "0.8", features = ["serde", "v4"] }
time = "0.1.42"
27 changes: 27 additions & 0 deletions validator_client/src/keystore/checksum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use serde::{Deserialize, Serialize};

/// Checksum module for `Keystore`.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ChecksumModule {
pub function: String,
pub params: serde_json::Value, // Empty json object
pub message: String,
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Checksum(String);

impl Checksum {
/// Generate checksum using checksum function.
pub fn gen_checksum(message: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.input(message);
hasher.result_str()
}

pub fn function() -> String {
"sha256".to_string()
}
}
97 changes: 97 additions & 0 deletions validator_client/src/keystore/cipher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use crypto::aes::{ctr, KeySize};
use rand::prelude::*;
use serde::{de, Deserialize, Serialize, Serializer};
use std::default::Default;

const IV_SIZE: usize = 16;

/// Convert slice to fixed length array.
fn from_slice(bytes: &[u8]) -> [u8; IV_SIZE] {
let mut array = [0; IV_SIZE];
let bytes = &bytes[..array.len()]; // panics if not enough data
array.copy_from_slice(bytes);
array
}

/// Cipher module representation.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct CipherModule {
pub function: String,
pub params: Cipher,
pub message: String,
}

/// Parameters for AES128 with ctr mode.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Aes128Ctr {
#[serde(serialize_with = "serialize_iv")]
#[serde(deserialize_with = "deserialize_iv")]
pub iv: [u8; 16],
}

impl Aes128Ctr {
pub fn encrypt(&self, key: &[u8], pt: &[u8]) -> Vec<u8> {
// TODO: sanity checks
let mut ct = vec![0; pt.len()];
ctr(KeySize::KeySize128, key, &self.iv).process(pt, &mut ct);
ct
}

pub fn decrypt(&self, key: &[u8], ct: &[u8]) -> Vec<u8> {
// TODO: sanity checks
let mut pt = vec![0; ct.len()];
ctr(KeySize::KeySize128, key, &self.iv).process(ct, &mut pt);
pt
}
}

/// Serialize `iv` to its hex representation.
fn serialize_iv<S>(x: &[u8], s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(&hex::encode(x))
}

/// Deserialize `iv` from its hex representation to bytes.
fn deserialize_iv<'de, D>(deserializer: D) -> Result<[u8; 16], D::Error>
where
D: de::Deserializer<'de>,
{
struct StringVisitor;
impl<'de> de::Visitor<'de> for StringVisitor {
type Value = [u8; IV_SIZE];
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("String should be hex format and 16 bytes in length")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let bytes = hex::decode(v).map_err(E::custom)?;
Ok(from_slice(&bytes))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The from_slice function will panic unless bytes.len() == IV_SIZE.

I think it would be best to check bytes.len() here and return an error if it's not 16.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I guess we can also return an Option from the from_slice function and handle the None case here.

}
}
deserializer.deserialize_any(StringVisitor)
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Cipher {
Aes128Ctr(Aes128Ctr),
}

impl Default for Cipher {
fn default() -> Self {
let iv = rand::thread_rng().gen::<[u8; IV_SIZE]>();
Cipher::Aes128Ctr(Aes128Ctr { iv })
}
}

impl Cipher {
pub fn function(&self) -> String {
match &self {
Cipher::Aes128Ctr(_) => "aes-128-ctr".to_string(),
}
}
}
Loading