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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use super::{Key, PrivateParts, PublicParts};
use crate::error::{Error, ErrorKind, OsshResult};
use crate::format::ossh_pubkey::*;
#[rustfmt::skip]
use ed25519_dalek::{
Keypair as DalekKeypair,
PublicKey as DalekPublicKey,
SecretKey as DalekSecretKey,
Signature,
Signer,
Verifier,
PUBLIC_KEY_LENGTH,
SECRET_KEY_LENGTH,
KEYPAIR_LENGTH,
};
use rand::rngs::OsRng;
use std::{convert::TryFrom, fmt};
pub const ED25519_NAME: &str = "ssh-ed25519";
#[derive(Debug, Clone)]
pub struct Ed25519PublicKey {
key: Box<DalekPublicKey>,
}
impl Ed25519PublicKey {
pub fn new(key: &[u8; PUBLIC_KEY_LENGTH]) -> Result<Self, ed25519_dalek::SignatureError> {
Ok(Self {
key: Box::new(DalekPublicKey::from_bytes(key)?),
})
}
}
impl Key for Ed25519PublicKey {
fn size(&self) -> usize {
256
}
fn keyname(&self) -> &'static str {
ED25519_NAME
}
}
impl PublicParts for Ed25519PublicKey {
fn blob(&self) -> Result<Vec<u8>, Error> {
encode_ed25519_pubkey(&self.key)
}
fn verify(&self, data: &[u8], sig: &[u8]) -> Result<bool, Error> {
let ed25519_sig = Signature::try_from(sig)?;
Ok(self.key.verify(data, &ed25519_sig).is_ok())
}
}
impl PartialEq for Ed25519PublicKey {
fn eq(&self, other: &Self) -> bool {
self.key == other.key
}
}
impl fmt::Display for Ed25519PublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&serialize_ossh_pubkey(self, "").unwrap())
}
}
pub struct Ed25519KeyPair {
pub(crate) key: Box<DalekKeypair>,
}
impl Key for Ed25519KeyPair {
fn size(&self) -> usize {
256
}
fn keyname(&self) -> &'static str {
ED25519_NAME
}
}
impl Ed25519KeyPair {
pub fn generate(bits: usize) -> OsshResult<Self> {
if bits != 0 && bits != 256 {
return Err(Error::from_kind(ErrorKind::InvalidKeySize));
}
Ok(Ed25519KeyPair {
key: Box::new(DalekKeypair::generate(&mut OsRng)),
})
}
pub(crate) fn from_bytes(pk: &[u8], sk: &[u8]) -> OsshResult<Self> {
if pk.len() != PUBLIC_KEY_LENGTH {
return Err(ErrorKind::InvalidKeySize.into());
}
if sk.len() != KEYPAIR_LENGTH {
return Err(ErrorKind::InvalidKeySize.into());
}
if pk != &sk[SECRET_KEY_LENGTH..] {
return Err(ErrorKind::InvalidKey.into());
}
Ok(Ed25519KeyPair {
key: Box::new(DalekKeypair {
public: DalekPublicKey::from_bytes(pk)?,
secret: DalekSecretKey::from_bytes(&sk[..SECRET_KEY_LENGTH])?,
}),
})
}
pub fn clone_public_key(&self) -> Result<Ed25519PublicKey, Error> {
Ok(Ed25519PublicKey {
key: Box::new(self.key.public),
})
}
}
impl PublicParts for Ed25519KeyPair {
fn blob(&self) -> Result<Vec<u8>, Error> {
encode_ed25519_pubkey(&self.key.public)
}
fn verify(&self, data: &[u8], sig: &[u8]) -> Result<bool, Error> {
let ed25519_sig = Signature::try_from(sig)?;
Ok(self.key.verify(data, &ed25519_sig).is_ok())
}
}
impl PrivateParts for Ed25519KeyPair {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
Ok(self.key.sign(data).to_bytes().to_vec())
}
}
#[allow(non_upper_case_globals)]
#[cfg(test)]
mod test {
use super::*;
const pub_str: &str =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMoWBluPErgKhNja3lHEf7ie6AVzR24mPRd742xEYodC";
const pub_key: [u8; 0x20] = [
0xca, 0x16, 0x06, 0x5b, 0x8f, 0x12, 0xb8, 0x0a, 0x84, 0xd8, 0xda, 0xde, 0x51, 0xc4, 0x7f,
0xb8, 0x9e, 0xe8, 0x05, 0x73, 0x47, 0x6e, 0x26, 0x3d, 0x17, 0x7b, 0xe3, 0x6c, 0x44, 0x62,
0x87, 0x42,
];
fn get_test_pubkey() -> Result<Ed25519PublicKey, Error> {
Ok(Ed25519PublicKey::new(&pub_key)?)
}
#[test]
fn ed25519_publickey_serialize() {
let key = get_test_pubkey().unwrap();
assert_eq!(key.to_string(), String::from(pub_str));
}
#[test]
fn ed25519_publickey_size() {
let key = get_test_pubkey().unwrap();
assert_eq!(key.size(), 256);
}
}