Read an Ed25519 key from a directory or create a new key if not found in the directory.
(key_dir: impl AsRef<Path>)
| 200 | |
| 201 | /// Read an Ed25519 key from a directory or create a new key if not found in the directory. |
| 202 | pub async fn try_from_dir(key_dir: impl AsRef<Path>) -> Result<NodeKey> { |
| 203 | let key_path = key_dir.as_ref().join("id_ed25519_0"); |
| 204 | let private_key = match tokio::fs::read_to_string(&key_path).await { |
| 205 | Ok(content) => ssh_key::private::PrivateKey::from_str(&content) |
| 206 | .map_err(|e| anyhow::anyhow!("failed to parse private key: {}", e))?, |
| 207 | Err(_) => { |
| 208 | let key = ssh_key::private::PrivateKey::random( |
| 209 | &mut rand::rngs::OsRng, |
| 210 | ssh_key::Algorithm::Ed25519, |
| 211 | )?; |
| 212 | // Write out contents to file for next time |
| 213 | let content = key.to_openssh(ssh_key::LineEnding::default())?; |
| 214 | tokio::fs::write(&key_path, content).await?; |
| 215 | key |
| 216 | } |
| 217 | }; |
| 218 | let seed = private_key |
| 219 | .key_data() |
| 220 | .ed25519() |
| 221 | .map_or(Err(anyhow::anyhow!("failed to parse ed25519 key")), |key| { |
| 222 | Ok(key.private.to_bytes()) |
| 223 | })?; |
| 224 | let key_pair = Ed25519KeyPair::from_seed_unchecked(seed.as_ref()) |
| 225 | .map_err(|e| anyhow::anyhow!("failed to create key pair: {}", e))?; |
| 226 | let public_ed25519_key_bytes = key_pair.public_key().as_ref().try_into()?; |
| 227 | Ok(Self::new( |
| 228 | NodeId { |
| 229 | public_ed25519_key_bytes, |
| 230 | }, |
| 231 | seed, |
| 232 | )) |
| 233 | } |
| 234 | /// Create an Ed25519 key pair from a secret. The secret can be formatted in two ways: |
| 235 | /// - Multibase of Secret:Multibase of Public Key |
| 236 | /// (e.g. z3u2WLX8jeyN6sfbDowLGudoZHudxgVkNJfrw2TDTVx4tijd:z6MkueF19qChpGQJBJXcXjfoM1MYCwC167RMwUiNWXXvEm1M) |