use crate::core::libtx::secp_ser;
use crate::libwallet::dalek_ser;
use crate::libwallet::{Error, ErrorKind};
use crate::util::secp::key::{PublicKey, SecretKey};
use crate::util::{from_hex, to_hex};
use failure::ResultExt;
use base64;
use ed25519_dalek::PublicKey as DalekPublicKey;
use rand::{thread_rng, Rng};
use ring::aead;
use serde_json::{self, Value};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum JsonId {
IntId(u32),
StrId(String),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(transparent)]
pub struct Token {
#[serde(with = "secp_ser::option_seckey_serde")]
pub keychain_mask: Option<SecretKey>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(transparent)]
pub struct PubAddress {
#[serde(with = "dalek_ser::dalek_pubkey_serde")]
pub address: DalekPublicKey,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(transparent)]
pub struct ECDHPubkey {
#[serde(with = "secp_ser::pubkey_serde")]
pub ecdh_pubkey: PublicKey,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EncryptedBody {
pub nonce: String,
pub body_enc: String,
}
impl EncryptedBody {
pub fn from_json(json_in: &Value, enc_key: &SecretKey) -> Result<Self, Error> {
let mut to_encrypt = serde_json::to_string(&json_in)
.context(ErrorKind::APIEncryption(
"EncryptedBody Enc: Unable to encode JSON".to_owned(),
))?
.as_bytes()
.to_vec();
let nonce: [u8; 12] = thread_rng().gen();
let unbound_key = aead::UnboundKey::new(&aead::AES_256_GCM, &enc_key.0).unwrap();
let sealing_key: aead::LessSafeKey = aead::LessSafeKey::new(unbound_key);
let aad = aead::Aad::from(&[]);
let res = sealing_key.seal_in_place_append_tag(
aead::Nonce::assume_unique_for_key(nonce),
aad,
&mut to_encrypt,
);
if let Err(_) = res {
return Err(
ErrorKind::APIEncryption("EncryptedBody: encryption failed".to_owned()).into(),
);
}
Ok(EncryptedBody {
nonce: to_hex(nonce.to_vec()),
body_enc: base64::encode(&to_encrypt),
})
}
pub fn as_json_value(&self) -> Result<Value, Error> {
let res = serde_json::to_value(self).context(ErrorKind::APIEncryption(
"EncryptedBody: JSON serialization failed".to_owned(),
))?;
Ok(res)
}
pub fn as_json_str(&self) -> Result<String, Error> {
let res = self.as_json_value()?;
let res = serde_json::to_string(&res).context(ErrorKind::APIEncryption(
"EncryptedBody: JSON String serialization failed".to_owned(),
))?;
Ok(res)
}
pub fn decrypt(&self, dec_key: &SecretKey) -> Result<Value, Error> {
let mut to_decrypt = base64::decode(&self.body_enc).context(ErrorKind::APIEncryption(
"EncryptedBody Dec: Encrypted request contains invalid Base64".to_string(),
))?;
let nonce = from_hex(self.nonce.clone()).context(ErrorKind::APIEncryption(
"EncryptedBody Dec: Invalid Nonce".to_string(),
))?;
if nonce.len() < 12 {
return Err(ErrorKind::APIEncryption(
"EncryptedBody Dec: Invalid Nonce length".to_string(),
)
.into());
}
let mut n = [0u8; 12];
n.copy_from_slice(&nonce[0..12]);
let unbound_key = aead::UnboundKey::new(&aead::AES_256_GCM, &dec_key.0).unwrap();
let opening_key: aead::LessSafeKey = aead::LessSafeKey::new(unbound_key);
let aad = aead::Aad::from(&[]);
let res =
opening_key.open_in_place(aead::Nonce::assume_unique_for_key(n), aad, &mut to_decrypt);
if let Err(_) = res {
return Err(
ErrorKind::APIEncryption("EncryptedBody: decryption failed".to_owned()).into(),
);
}
for _ in 0..aead::AES_256_GCM.tag_len() {
to_decrypt.pop();
}
let decrypted = String::from_utf8(to_decrypt).context(ErrorKind::APIEncryption(
"EncryptedBody Dec: Invalid UTF-8".to_string(),
))?;
Ok(
serde_json::from_str(&decrypted).context(ErrorKind::APIEncryption(
"EncryptedBody Dec: Invalid JSON".to_string(),
))?,
)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EncryptedRequest {
pub jsonrpc: String,
pub method: String,
pub id: JsonId,
pub params: EncryptedBody,
}
impl EncryptedRequest {
pub fn from_json(id: &JsonId, json_in: &Value, enc_key: &SecretKey) -> Result<Self, Error> {
Ok(EncryptedRequest {
jsonrpc: "2.0".to_owned(),
method: "encrypted_request_v3".to_owned(),
id: id.clone(),
params: EncryptedBody::from_json(json_in, enc_key)?,
})
}
pub fn as_json_value(&self) -> Result<Value, Error> {
let res = serde_json::to_value(self).context(ErrorKind::APIEncryption(
"EncryptedRequest: JSON serialization failed".to_owned(),
))?;
Ok(res)
}
pub fn as_json_str(&self) -> Result<String, Error> {
let res = self.as_json_value()?;
let res = serde_json::to_string(&res).context(ErrorKind::APIEncryption(
"EncryptedRequest: JSON String serialization failed".to_owned(),
))?;
Ok(res)
}
pub fn decrypt(&self, dec_key: &SecretKey) -> Result<Value, Error> {
self.params.decrypt(dec_key)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EncryptedResponse {
pub jsonrpc: String,
pub id: JsonId,
pub result: HashMap<String, EncryptedBody>,
}
impl EncryptedResponse {
pub fn from_json(id: &JsonId, json_in: &Value, enc_key: &SecretKey) -> Result<Self, Error> {
let mut result_set = HashMap::new();
result_set.insert(
"Ok".to_string(),
EncryptedBody::from_json(json_in, enc_key)?,
);
Ok(EncryptedResponse {
jsonrpc: "2.0".to_owned(),
id: id.clone(),
result: result_set,
})
}
pub fn as_json_value(&self) -> Result<Value, Error> {
let res = serde_json::to_value(self).context(ErrorKind::APIEncryption(
"EncryptedResponse: JSON serialization failed".to_owned(),
))?;
Ok(res)
}
pub fn as_json_str(&self) -> Result<String, Error> {
let res = self.as_json_value()?;
let res = serde_json::to_string(&res).context(ErrorKind::APIEncryption(
"EncryptedResponse: JSON String serialization failed".to_owned(),
))?;
Ok(res)
}
pub fn decrypt(&self, dec_key: &SecretKey) -> Result<Value, Error> {
self.result.get("Ok").unwrap().decrypt(dec_key)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EncryptionError {
pub code: i32,
pub message: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EncryptionErrorResponse {
pub jsonrpc: String,
#[serde(with = "secp_ser::string_or_u64")]
pub id: u64,
pub error: EncryptionError,
}
impl EncryptionErrorResponse {
pub fn new(id: u64, code: i32, message: &str) -> Self {
EncryptionErrorResponse {
jsonrpc: "2.0".to_owned(),
id: id,
error: EncryptionError {
code: code,
message: message.to_owned(),
},
}
}
pub fn as_json_value(&self) -> Value {
let res = serde_json::to_value(self).context(ErrorKind::APIEncryption(
"EncryptedResponse: JSON serialization failed".to_owned(),
));
match res {
Ok(r) => r,
Err(r) => serde_json::json!({
"json_rpc" : "2.0",
"id" : "1",
"error" : {
"message": format!("internal error serialising json error response {}", r),
"code": -32000
}
}
),
}
}
}
#[test]
fn encrypted_request() -> Result<(), Error> {
use crate::util::{from_hex, static_secp_instance};
let sec_key_str = "e00dcc4a009e3427c6b1e1a550c538179d46f3827a13ed74c759c860761caf1e";
let shared_key = {
let secp_inst = static_secp_instance();
let secp = secp_inst.lock();
let sec_key_bytes = from_hex(sec_key_str.to_owned()).unwrap();
SecretKey::from_slice(&secp, &sec_key_bytes)?
};
let req = serde_json::json!({
"jsonrpc": "2.0",
"method": "accounts",
"id": 1,
"params": {
"token": "d202964900000000d302964900000000d402964900000000d502964900000000"
}
});
let enc_req =
EncryptedRequest::from_json(&JsonId::StrId(String::from("1")), &req, &shared_key)?;
println!("{:?}", enc_req);
let dec_req = enc_req.decrypt(&shared_key)?;
println!("{:?}", dec_req);
assert_eq!(req, dec_req);
let enc_res = EncryptedResponse::from_json(&JsonId::IntId(1), &req, &shared_key)?;
println!("{:?}", enc_res);
println!("{:?}", enc_res.as_json_str()?);
let dec_res = enc_res.decrypt(&shared_key)?;
println!("{:?}", dec_res);
assert_eq!(req, dec_res);
Ok(())
}