Commit 4dcfe63a authored by Thomas Gatzweiler's avatar Thomas Gatzweiler
Browse files

Add ED25519 crypto system

parent 63806176
......@@ -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);
}
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(())
}
}
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(&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>;
fn write_public(&self, w: &mut Write) -> io::Result<()>;
fn export(&self, w: &mut Write) -> io::Result<()>;
}
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,
};
......
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);
......
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); }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment