mirror of
https://gitlab.redox-os.org/CoffeeCode/redox-ssh.git
synced 2025-12-28 20:22:18 +01:00
Add ED25519 crypto system
This commit is contained in:
parent
6380617655
commit
4dcfe63ab5
8 changed files with 158 additions and 36 deletions
|
|
@ -3,7 +3,7 @@ use std::io::prelude::*;
|
|||
use std::fs::File;
|
||||
|
||||
pub fn main() {
|
||||
let keys = (ssh::key::RSA.generate_key_pair)(1024);
|
||||
let keypair = (ssh::key::ED25519.generate_key_pair)(None);
|
||||
let mut buffer = File::create("key.pub").unwrap();
|
||||
keys.0.write(&mut buffer);
|
||||
keypair.export(&mut buffer);
|
||||
}
|
||||
|
|
|
|||
106
src/key/ed25519.rs
Normal file
106
src/key/ed25519.rs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
use key::{KeyPair, CryptoSystem};
|
||||
use std::io::{self, Read, Write};
|
||||
use rand::{self, Rng};
|
||||
use crypto::ed25519;
|
||||
|
||||
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<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: public
|
||||
})
|
||||
}
|
||||
|
||||
fn import(mut r: &mut Read) -> io::Result<Box<KeyPair>> {
|
||||
use packet::ReadPacketExt;
|
||||
let id = r.read_utf8()?;
|
||||
assert_eq!(id, "ssh-ed25519");
|
||||
|
||||
let pub_len = r.read_uint32()?;
|
||||
assert_eq!(pub_len, 32);
|
||||
|
||||
let mut public = [0u8;32];
|
||||
r.read_exact(&mut public)?;
|
||||
|
||||
let priv_len = r.read_uint32()?;
|
||||
assert_eq!(priv_len, 64);
|
||||
|
||||
let mut private = [0u8;64];
|
||||
r.read_exact(&mut private)?;
|
||||
|
||||
Ok(Box::new(Ed25519KeyPair {
|
||||
public: public,
|
||||
private: Some(private)
|
||||
}))
|
||||
}
|
||||
|
||||
fn read_public(mut r: &mut Read) -> io::Result<Box<KeyPair>> {
|
||||
use packet::ReadPacketExt;
|
||||
|
||||
let len = r.read_uint32()?;
|
||||
assert_eq!(len, 32);
|
||||
|
||||
let mut public = [0u8;32];
|
||||
r.read_exact(&mut public)?;
|
||||
|
||||
Ok(Box::new(Ed25519KeyPair {
|
||||
private: None,
|
||||
public: 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, ()> {
|
||||
Ok(ed25519::verify(data, &self.public, signature))
|
||||
}
|
||||
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
|
||||
if let Some(private_key) = self.private {
|
||||
let signature = ed25519::signature(data, &private_key);
|
||||
Ok(signature.to_vec())
|
||||
}
|
||||
else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_public(&self, w: &mut Write) -> io::Result<()> {
|
||||
use packet::WritePacketExt;
|
||||
w.write_string("ssh-ed25519")?;
|
||||
w.write_bytes(&self.public)
|
||||
}
|
||||
|
||||
fn export(&self, w: &mut Write) -> io::Result<()> {
|
||||
use 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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,26 @@
|
|||
use std::io::{Result, Read, Write};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
mod rsa;
|
||||
//mod rsa;
|
||||
mod ed25519;
|
||||
|
||||
pub use self::rsa::RSA;
|
||||
//pub use self::rsa::RSA;
|
||||
pub use self::ed25519::ED25519;
|
||||
|
||||
pub trait Key {
|
||||
pub trait KeyPair {
|
||||
fn system(&self) -> &'static CryptoSystem;
|
||||
|
||||
fn read(&self, r: &mut Read) -> Result<Box<Self>>
|
||||
where
|
||||
Self: Sized;
|
||||
fn has_private(&self) -> bool;
|
||||
|
||||
fn import(&self, r: &mut Read) -> Result<Box<Self>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.read(r)
|
||||
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, ()>;
|
||||
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()>;
|
||||
|
||||
fn write_public(&self, w: &mut Write) -> io::Result<()>;
|
||||
fn export(&self, w: &mut Write) -> io::Result<()>;
|
||||
}
|
||||
|
||||
fn write(&self, w: &mut Write) -> Result<()>;
|
||||
|
||||
fn export(&self, w: &mut Write) -> Result<()> {
|
||||
self.write(w)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PublicKey: Key {
|
||||
fn encrypt(&self, data: &[u8]) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub trait PrivateKey: Key {
|
||||
fn sign(&self, data: &[u8]) -> Vec<u8>;
|
||||
}
|
||||
|
||||
type KeyPair = (Box<PublicKey>, Box<PrivateKey>);
|
||||
|
||||
pub struct CryptoSystem {
|
||||
pub id: &'static str,
|
||||
pub generate_key_pair: fn(bits: u32) -> KeyPair
|
||||
pub generate_key_pair: fn(bits: Option<u32>) -> Box<KeyPair>,
|
||||
pub import: fn(r: &mut Read) -> io::Result<Box<KeyPair>>,
|
||||
pub read_public: fn(r: &mut Read) -> io::Result<Box<KeyPair>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use key::{Key, PublicKey, PrivateKey, KeyPair, CryptoSystem};
|
|||
use std::io::{Read, Write, Result};
|
||||
|
||||
pub static RSA: CryptoSystem = CryptoSystem {
|
||||
id: "ssh-rsa",
|
||||
id: "rsa",
|
||||
generate_key_pair: generate_key_pair,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
extern crate byteorder;
|
||||
extern crate rand;
|
||||
extern crate ring;
|
||||
extern crate crypto;
|
||||
extern crate num_bigint;
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -126,11 +126,15 @@ pub trait WritePacketExt: WriteBytesExt {
|
|||
|
||||
fn write_string(&mut self, s: &str) -> Result<()> {
|
||||
let bytes = s.as_bytes();
|
||||
self.write_bytes(bytes)
|
||||
}
|
||||
|
||||
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
|
||||
self.write_u32::<BigEndian>(bytes.len() as u32)?;
|
||||
self.write_all(bytes)
|
||||
}
|
||||
|
||||
fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
|
||||
fn write_raw_bytes(&mut self, bytes: &[u8]) -> Result<()> {
|
||||
self.write_all(bytes)
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +144,6 @@ pub trait WritePacketExt: WriteBytesExt {
|
|||
|
||||
fn write_mpint(&mut self, value: BigInt) -> Result<()> {
|
||||
let bytes = value.to_signed_bytes_be();
|
||||
self.write_u32::<BigEndian>(bytes.len() as u32)?;
|
||||
self.write_bytes(bytes.as_slice())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl<W: Write> Session<W> {
|
|||
|
||||
let mut packet = Packet::new(MessageType::KexInit);
|
||||
packet.with_writer(&|w| {
|
||||
w.write_bytes(cookie.as_slice());
|
||||
w.write_raw_bytes(cookie.as_slice());
|
||||
w.write_list(KEY_EXCHANGE);
|
||||
w.write_list(HOST_KEY);
|
||||
w.write_list(ENCRYPTION);
|
||||
|
|
|
|||
29
tests/crypto_systems.rs
Normal file
29
tests/crypto_systems.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
extern crate ssh;
|
||||
extern crate rand;
|
||||
|
||||
use rand::Rng;
|
||||
use std::io::Cursor;
|
||||
use ssh::key::{self, CryptoSystem, KeyPair};
|
||||
|
||||
fn test_export_import(keypair: &Box<KeyPair>) -> Box<KeyPair> {
|
||||
let mut buffer = Vec::new();
|
||||
keypair.export(&mut buffer).unwrap();
|
||||
|
||||
(keypair.system().import)(&mut Cursor::new(buffer)).unwrap()
|
||||
}
|
||||
|
||||
fn test_crypto_system(system: &CryptoSystem, key_size: Option<u32>) {
|
||||
let keypair = (system.generate_key_pair)(key_size);
|
||||
let keypair2 = test_export_import(&keypair);
|
||||
|
||||
let mut buffer = [0;4096];
|
||||
let mut rng = rand::thread_rng();
|
||||
rng.fill_bytes(&mut buffer);
|
||||
|
||||
let signature = keypair.sign(&buffer).unwrap();
|
||||
let verified = keypair2.verify(&buffer, signature.as_slice()).unwrap();
|
||||
assert!(verified)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ed25519() { test_crypto_system(&key::ED25519, None); }
|
||||
Loading…
Reference in a new issue