1
0
Fork 0
mirror of https://gitlab.redox-os.org/CoffeeCode/redox-ssh.git synced 2025-12-28 15:02:18 +01:00
redox-ssh/src/public_key/ed25519.rs

131 lines
3.5 KiB
Rust

use std::io::{self, Read, Write};
use std::io::ErrorKind::InvalidData;
use crypto::ed25519;
use rand::RngCore;
use crate::public_key::{CryptoSystem, KeyPair};
pub static ED25519: CryptoSystem = CryptoSystem {
id: "ed25519",
generate_key_pair: Ed25519KeyPair::generate,
import: Ed25519KeyPair::import,
read_public: Ed25519KeyPair::read_public,
};
struct Ed25519KeyPair {
private: Option<[u8; 64]>,
public: [u8; 32],
}
impl Ed25519KeyPair {
fn generate(_: Option<u32>) -> Box<dyn KeyPair> {
let mut seed = [0u8; 32];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut seed);
let (private, public) = ed25519::keypair(&seed);
Box::new(Ed25519KeyPair {
private: Some(private),
public,
})
}
fn import(mut r: &mut dyn Read) -> io::Result<Box<dyn KeyPair>> {
use crate::packet::ReadPacketExt;
if r.read_utf8()? != "ssh-ed25519" {
return Err(io::Error::new(InvalidData, "not a ED25519 key"));
}
if r.read_uint32()? != 32 {
return Err(io::Error::new(InvalidData, "invalid ED25519 key"));
}
let mut public = [0u8; 32];
r.read_exact(&mut public)?;
if r.read_uint32()? != 64 {
return Err(io::Error::new(InvalidData, "invalid ED25519 key"));
}
let mut private = [0u8; 64];
r.read_exact(&mut private)?;
Ok(Box::new(Ed25519KeyPair {
public,
private: Some(private),
}))
}
fn read_public(mut r: &mut dyn Read) -> io::Result<Box<dyn KeyPair>> {
use crate::packet::ReadPacketExt;
if r.read_uint32()? != 32 {
return Err(io::Error::new(InvalidData, "invalid ED25519 key"));
}
let mut public = [0u8; 32];
r.read_exact(&mut public)?;
Ok(Box::new(Ed25519KeyPair {
private: None,
public,
}))
}
}
impl KeyPair for Ed25519KeyPair {
fn system(&self) -> &'static CryptoSystem {
&ED25519
}
fn has_private(&self) -> bool {
self.private.is_some()
}
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, ()> {
use crate::packet::ReadPacketExt;
use std::io::Cursor;
let mut reader = Cursor::new(signature);
let id = reader.read_string().unwrap_or_default();
if id == b"ssh-ed25519" {
if let Ok(sig) = reader.read_string() {
return Ok(ed25519::verify(data, &self.public, sig.as_slice()));
}
}
Err(())
}
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
use crate::packet::WritePacketExt;
if let Some(private_key) = self.private {
let mut result = Vec::new();
let sig = ed25519::signature(data, &private_key);
result.write_string("ssh-ed25519").or(Err(()))?;
result.write_bytes(&sig).or(Err(()))?;
Ok(result)
}
else {
Err(())
}
}
fn write_public(&self, w: &mut dyn Write) -> io::Result<()> {
use crate::packet::WritePacketExt;
w.write_string("ssh-ed25519")?;
w.write_bytes(&self.public)
}
fn export(&self, w: &mut dyn Write) -> io::Result<()> {
use crate::packet::WritePacketExt;
w.write_string("ssh-ed25519")?;
w.write_bytes(&self.public)?;
if let Some(private_key) = self.private {
w.write_bytes(&private_key)?;
}
Ok(())
}
}