cfxstore/json/
crypto.rs

1// Copyright 2015-2019 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3
4// Parity Ethereum is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Ethereum is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17use super::{
18    Bytes, Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256,
19};
20use serde::{
21    de::{Error, MapAccess, Visitor},
22    ser::SerializeStruct,
23    Deserialize, Deserializer, Serialize, Serializer,
24};
25use serde_json;
26use std::{fmt, str};
27
28pub type CipherText = Bytes;
29
30#[derive(Debug, PartialEq)]
31pub struct Crypto {
32    pub cipher: Cipher,
33    pub ciphertext: CipherText,
34    pub kdf: Kdf,
35    pub mac: H256,
36}
37
38impl str::FromStr for Crypto {
39    type Err = serde_json::error::Error;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> { serde_json::from_str(s) }
42}
43
44impl From<Crypto> for String {
45    fn from(c: Crypto) -> Self {
46        serde_json::to_string(&c).expect(
47            "Serialization cannot fail, because all crypto keys are strings",
48        )
49    }
50}
51
52enum CryptoField {
53    Cipher,
54    CipherParams,
55    CipherText,
56    Kdf,
57    KdfParams,
58    Mac,
59    Version,
60}
61
62impl<'a> Deserialize<'a> for CryptoField {
63    fn deserialize<D>(deserializer: D) -> Result<CryptoField, D::Error>
64    where D: Deserializer<'a> {
65        deserializer.deserialize_any(CryptoFieldVisitor)
66    }
67}
68
69struct CryptoFieldVisitor;
70
71impl<'a> Visitor<'a> for CryptoFieldVisitor {
72    type Value = CryptoField;
73
74    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
75        write!(formatter, "a valid crypto struct description")
76    }
77
78    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
79    where E: Error {
80        match value {
81            "cipher" => Ok(CryptoField::Cipher),
82            "cipherparams" => Ok(CryptoField::CipherParams),
83            "ciphertext" => Ok(CryptoField::CipherText),
84            "kdf" => Ok(CryptoField::Kdf),
85            "kdfparams" => Ok(CryptoField::KdfParams),
86            "mac" => Ok(CryptoField::Mac),
87            "version" => Ok(CryptoField::Version),
88            _ => Err(Error::custom(format!("Unknown field: '{}'", value))),
89        }
90    }
91}
92
93impl<'a> Deserialize<'a> for Crypto {
94    fn deserialize<D>(deserializer: D) -> Result<Crypto, D::Error>
95    where D: Deserializer<'a> {
96        static FIELDS: &[&str] =
97            &["id", "version", "crypto", "Crypto", "address"];
98        deserializer.deserialize_struct("Crypto", FIELDS, CryptoVisitor)
99    }
100}
101
102struct CryptoVisitor;
103
104impl<'a> Visitor<'a> for CryptoVisitor {
105    type Value = Crypto;
106
107    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
108        write!(formatter, "a valid vault crypto object")
109    }
110
111    fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
112    where V: MapAccess<'a> {
113        let mut cipher = None;
114        let mut cipherparams = None;
115        let mut ciphertext = None;
116        let mut kdf = None;
117        let mut kdfparams = None;
118        let mut mac = None;
119
120        loop {
121            match visitor.next_key()? {
122                Some(CryptoField::Cipher) => {
123                    cipher = Some(visitor.next_value()?);
124                }
125                Some(CryptoField::CipherParams) => {
126                    cipherparams = Some(visitor.next_value()?);
127                }
128                Some(CryptoField::CipherText) => {
129                    ciphertext = Some(visitor.next_value()?);
130                }
131                Some(CryptoField::Kdf) => {
132                    kdf = Some(visitor.next_value()?);
133                }
134                Some(CryptoField::KdfParams) => {
135                    kdfparams = Some(visitor.next_value()?);
136                }
137                Some(CryptoField::Mac) => {
138                    mac = Some(visitor.next_value()?);
139                }
140                // skip not required version field (it appears in pyethereum
141                // generated keystores)
142                Some(CryptoField::Version) => {
143                    visitor.next_value().unwrap_or(())
144                }
145                None => {
146                    break;
147                }
148            }
149        }
150
151        let cipher = match (cipher, cipherparams) {
152            (
153                Some(CipherSer::Aes128Ctr),
154                Some(CipherSerParams::Aes128Ctr(params)),
155            ) => Cipher::Aes128Ctr(params),
156            (None, _) => return Err(V::Error::missing_field("cipher")),
157            (Some(_), None) => {
158                return Err(V::Error::missing_field("cipherparams"))
159            }
160        };
161
162        let ciphertext = match ciphertext {
163            Some(ciphertext) => ciphertext,
164            None => return Err(V::Error::missing_field("ciphertext")),
165        };
166
167        let kdf = match (kdf, kdfparams) {
168            (Some(KdfSer::Pbkdf2), Some(KdfSerParams::Pbkdf2(params))) => {
169                Kdf::Pbkdf2(params)
170            }
171            (Some(KdfSer::Scrypt), Some(KdfSerParams::Scrypt(params))) => {
172                Kdf::Scrypt(params)
173            }
174            (Some(_), Some(_)) => {
175                return Err(V::Error::custom("Invalid cipherparams"))
176            }
177            (None, _) => return Err(V::Error::missing_field("kdf")),
178            (Some(_), None) => {
179                return Err(V::Error::missing_field("kdfparams"))
180            }
181        };
182
183        let mac = match mac {
184            Some(mac) => mac,
185            None => return Err(V::Error::missing_field("mac")),
186        };
187
188        let result = Crypto {
189            cipher,
190            ciphertext,
191            kdf,
192            mac,
193        };
194
195        Ok(result)
196    }
197}
198
199impl Serialize for Crypto {
200    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
201    where S: Serializer {
202        let mut crypto = serializer.serialize_struct("Crypto", 6)?;
203        match self.cipher {
204            Cipher::Aes128Ctr(ref params) => {
205                crypto.serialize_field("cipher", &CipherSer::Aes128Ctr)?;
206                crypto.serialize_field("cipherparams", params)?;
207            }
208        }
209        crypto.serialize_field("ciphertext", &self.ciphertext)?;
210        match self.kdf {
211            Kdf::Pbkdf2(ref params) => {
212                crypto.serialize_field("kdf", &KdfSer::Pbkdf2)?;
213                crypto.serialize_field("kdfparams", params)?;
214            }
215            Kdf::Scrypt(ref params) => {
216                crypto.serialize_field("kdf", &KdfSer::Scrypt)?;
217                crypto.serialize_field("kdfparams", params)?;
218            }
219        }
220
221        crypto.serialize_field("mac", &self.mac)?;
222        crypto.end()
223    }
224}