1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{Address, InternalError, PublicKey, SecretKey};
use ed25519_dalek::Keypair;
use failure::*;
use std::convert::{TryFrom, TryInto};
use std::fs;
use std::path::Path;
pub struct Identity {
pub address: Address,
pub public_key: PublicKey,
pub secret_key: Option<SecretKey>,
}
impl Identity {
pub fn read<P: AsRef<Path>>(path: P) -> Fallible<Self> {
Identity::try_from(&fs::read_to_string(path)?[..])
}
pub fn read_default() -> Fallible<Self> {
Identity::read("/var/lib/zerotier-one/identity.secret")
}
}
impl TryFrom<SecretKey> for Identity {
type Error = Error;
fn try_from(secret_key: SecretKey) -> Fallible<Self> {
let public_key = PublicKey::from(&secret_key);
Ok(Self {
address: Address::try_from(&public_key)?,
public_key: PublicKey::from(&secret_key),
secret_key: Some(secret_key),
})
}
}
impl TryFrom<&str> for Identity {
type Error = Error;
fn try_from(identity: &str) -> Fallible<Self> {
let split_identity: Vec<&str> = identity.split(':').collect();
let (address, public_key, maybe_secret_key) = match &split_identity[..] {
[address, "0", public_key] => (address, public_key, None),
[address, "0", public_key, secret_key] => (address, public_key, Some(secret_key)),
_ => return Err(InternalError::MalformedIdentity.into()),
};
Ok(Identity {
address: Address::try_from(hex::decode(address)?.as_slice())?,
public_key: PublicKey::try_from(hex::decode(public_key)?.as_slice())?,
secret_key: match maybe_secret_key {
Some(secret_key) => Some(SecretKey::try_from(hex::decode(secret_key)?.as_slice())?),
None => None,
},
})
}
}
impl TryInto<Keypair> for Identity {
type Error = Error;
fn try_into(self) -> Fallible<Keypair> {
Ok(Keypair {
public: self.public_key.ed,
secret: self.secret_key.unwrap().ed,
})
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn test_identity() -> Fallible<()> {
let identity_str = "538c34e03c:0:070288330a72d2aa3cb7935dfe6028d9fb83bdb42240aaa05e33529121babd183ff775351742a47487454195c08c0e83c520e7466fcdde3396a0c4cd40557737:f20542ab6955fe140fb3a5be9557666b9c89a3e2b73432de46d827d11736773aca15c3e03b89a1d09436ae45bc02f84b8d5a0a2f6c0d42b3856c2b22f5ab2b27";
let identity = Identity::try_from(identity_str)?;
assert_eq!(identity.address, Address::try_from(&identity.public_key)?);
let secret_key = identity.secret_key.unwrap();
let public_key = PublicKey::from(&secret_key);
assert_eq!(identity.public_key.ed, public_key.ed);
assert_eq!(identity.public_key.dh.as_bytes(), public_key.dh.as_bytes());
let keypair = ed25519_dalek::Keypair {
public: public_key.ed,
secret: secret_key.ed,
};
let message = b"7VbLpreCRY738Sw4OGecCw";
let signature = keypair.sign(message);
identity.public_key.ed.verify(message, &signature)?;
Ok(())
}
}