-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathed25519_basic.rs
212 lines (187 loc) · 7.22 KB
/
ed25519_basic.rs
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Example implementation of polyproto's signature and key traits for ed25519-dalek.
// This example is not complete and should not be copy-pasted into a production environment without
// further scrutiny and consideration.
use std::str::FromStr;
use der::asn1::BitString;
use ed25519_dalek::{Signature as Ed25519DalekSignature, Signer, SigningKey, VerifyingKey};
use polyproto::certs::PublicKeyInfo;
use polyproto::key::{PrivateKey, PublicKey};
use polyproto::signature::Signature;
use rand::rngs::OsRng;
use spki::{AlgorithmIdentifierOwned, ObjectIdentifier, SignatureBitStringEncoding};
fn main() {
let mut csprng = rand::rngs::OsRng;
// Generate a key pair
let priv_key = Ed25519PrivateKey::gen_keypair(&mut csprng);
println!("Private Key is: {:?}", priv_key.key.to_bytes());
println!("Public Key is: {:?}", priv_key.public_key.key.to_bytes());
println!();
// Create and sign a message
let message_unsigned = "hi my name is flori".as_bytes();
let signature = priv_key.sign(message_unsigned);
println!(
"Signature of the message \"{}\": {:?}",
String::from_utf8_lossy(message_unsigned),
signature.as_signature().to_bytes()
);
// Verify the signature
println!(
"Is the signature valid? {}",
priv_key
.public_key
.verify_signature(&signature, message_unsigned)
.is_ok()
);
// Try to verify the same signature with different data, which should fail
println!(
"Trying again with different data. The result is: {}",
priv_key
.pubkey()
.verify_signature(
&signature,
format!("{} ", String::from_utf8_lossy(message_unsigned)).as_bytes()
)
.is_ok()
)
}
// As mentioned in the README, we start by implementing the signature trait.
// Here, we start by defining the signature type, which is a wrapper around the signature type from
// the ed25519-dalek crate.
#[derive(Debug, PartialEq, Eq, Clone)]
struct Ed25519Signature {
signature: Ed25519DalekSignature,
algorithm: AlgorithmIdentifierOwned,
}
impl std::fmt::Display for Ed25519Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.signature)
}
}
// We implement the Signature trait for our signature type.
impl Signature for Ed25519Signature {
// We define the signature type from the ed25519-dalek crate as the associated type.
type Signature = Ed25519DalekSignature;
// This is straightforward: we return a reference to the signature.
fn as_signature(&self) -> &Self::Signature {
&self.signature
}
// The algorithm identifier for a given signature implementation is constant. We just need
// to define it here.
fn algorithm_identifier() -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned {
// This is the OID for Ed25519. It is defined in the IANA registry.
oid: ObjectIdentifier::from_str("1.3.101.112").unwrap(),
// For this example, we don't need or want any parameters.
parameters: None,
}
}
#[cfg(not(tarpaulin_include))]
fn from_bytes(signature: &[u8]) -> Self {
let mut signature_vec = signature.to_vec();
signature_vec.resize(64, 0);
let signature_array: [u8; 64] = {
let mut array = [0; 64];
array.copy_from_slice(&signature_vec[..]);
array
};
Self {
signature: Ed25519DalekSignature::from_bytes(&signature_array),
algorithm: Self::algorithm_identifier(),
}
}
}
// The `SignatureBitStringEncoding` trait is used to convert a signature to a bit string. We implement
// it for our signature type.
impl SignatureBitStringEncoding for Ed25519Signature {
#[cfg(not(tarpaulin_include))]
fn to_bitstring(&self) -> der::Result<der::asn1::BitString> {
BitString::from_bytes(&self.as_signature().to_bytes())
}
}
// Next, we implement the key traits. We start by defining the private key type.
#[derive(Debug, Clone, PartialEq, Eq)]
struct Ed25519PrivateKey {
// Defined below
public_key: Ed25519PublicKey,
// The private key from the ed25519-dalek crate
key: SigningKey,
}
impl PrivateKey<Ed25519Signature> for Ed25519PrivateKey {
type PublicKey = Ed25519PublicKey;
// Return a reference to the public key
fn pubkey(&self) -> &Self::PublicKey {
&self.public_key
}
// Signs a message. The beauty of having to wrap the ed25519-dalek crate is that we can
// harness all of its functionality, such as the `sign` method.
fn sign(&self, data: &[u8]) -> Ed25519Signature {
let signature = self.key.sign(data);
Ed25519Signature {
signature,
algorithm: self.algorithm_identifier(),
}
}
}
impl Ed25519PrivateKey {
// Let's also define a handy method to generate a key pair.
pub fn gen_keypair(csprng: &mut OsRng) -> Self {
let key = SigningKey::generate(csprng);
let public_key = Ed25519PublicKey {
key: key.verifying_key(),
};
Self { public_key, key }
}
}
// Same thing as above for the public key type.
#[derive(Debug, Clone, PartialEq, Eq)]
struct Ed25519PublicKey {
// The public key type from the ed25519-dalek crate
key: VerifyingKey,
}
impl PublicKey<Ed25519Signature> for Ed25519PublicKey {
// Verifies a signature. We use the `verify_strict` method from the ed25519-dalek crate.
// This method is used to mitigate weak key forgery.
fn verify_signature(
&self,
signature: &Ed25519Signature,
data: &[u8],
) -> Result<(), polyproto::errors::composite::PublicKeyError> {
match self.key.verify_strict(data, signature.as_signature()) {
Ok(_) => Ok(()),
Err(_) => Err(polyproto::errors::composite::PublicKeyError::BadSignature),
}
}
// Returns the public key info. Public key info is used to encode the public key in a
// certificate or a CSR. It is named after the `SubjectPublicKeyInfo` type from the X.509
// standard, and thus includes the information needed to encode the public key in a certificate
// or a CSR.
#[cfg(not(tarpaulin_include))]
fn public_key_info(&self) -> PublicKeyInfo {
PublicKeyInfo {
algorithm: Ed25519Signature::algorithm_identifier(),
public_key_bitstring: BitString::from_bytes(&self.key.to_bytes()).unwrap(),
}
}
#[cfg(not(tarpaulin_include))]
fn try_from_public_key_info(
public_key_info: PublicKeyInfo,
) -> Result<Self, polyproto::errors::composite::ConversionError> {
let mut key_vec = public_key_info.public_key_bitstring.raw_bytes().to_vec();
key_vec.resize(32, 0);
let signature_array: [u8; 32] = {
let mut array = [0; 32];
array.copy_from_slice(&key_vec[..]);
array
};
Ok(Self {
key: VerifyingKey::from_bytes(&signature_array).unwrap(),
})
}
}
#[test]
fn test_example() {
main()
}