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
use std::cell::RefCell;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::rc::Rc;
use rsa::pkcs1::FromRsaPrivateKey;
use rsa::PublicKeyParts;
use crate::data::Data;
use crate::{SshError, SshResult};
use crate::algorithm::hash;
use crate::algorithm::hash::HashType;
use crate::h::H;

pub struct KeyPair {
    pub(crate) private_key: String,
    pub(crate) key_type: String,
    pub(crate) blob: Vec<u8>,
}



impl KeyPair {

    pub fn new() -> Self {
        KeyPair {
            private_key: "".to_string(),
            key_type: "".to_string(),
            blob: vec![]
        }
    }


    pub fn from_path<P: AsRef<Path>>(key_path: P, key_type: KeyPairType) -> SshResult<Self> {
        let mut file = File::open(key_path).unwrap();
        let mut prks = String::new();
        file.read_to_string(&mut prks)?;
        KeyPair::from_str(&prks, key_type)
    }


    pub fn from_str(key_str: &str, key_type: KeyPairType) -> SshResult<Self> {
        let key_type_str = KeyPairType::get_string(key_type);
        let rprk = match rsa::RsaPrivateKey::from_pkcs1_pem(key_str) {
            Ok(e) => e,
            Err(e) => {
                return Err(SshError::from(e.to_string()))
            }
        };
        let rpuk = rprk.to_public_key();
        let es = rpuk.e().to_bytes_be();
        let ns = rpuk.n().to_bytes_be();
        let mut blob = Data::new();
        blob.put_str(key_type_str);
        blob.put_mpint(&es);
        blob.put_mpint(&ns);
        let blob = blob.to_vec();
        let pair = KeyPair {
            private_key: key_str.to_string(),
            key_type: key_type_str.to_string(),
            blob
        };
        Ok(pair)
    }

    pub fn get_blob(&self) -> Vec<u8> {
        self.blob.to_vec()
    }

    pub(crate) fn signature(&self, buf: &[u8], h: Rc<RefCell<H>>, hash_type: HashType) -> Vec<u8> {
        let session_id = hash::digest(h.borrow().as_bytes().as_slice(), hash_type);
        let mut sd = Data::new();
        sd.put_u8s(session_id.as_slice());
        sd.extend_from_slice(buf);
        let scheme = rsa::PaddingScheme::PKCS1v15Sign {
            hash: Some(rsa::Hash::SHA1)
        };
        let digest = ring::digest::digest(&ring::digest::SHA1_FOR_LEGACY_USE_ONLY, sd.as_slice());
        let msg = digest.as_ref();


        let rprk = rsa::RsaPrivateKey::from_pkcs1_pem(self.private_key.as_str()).unwrap();

        let sign = rprk.sign(scheme, msg).unwrap();
        let mut ss = Data::new();
        ss.put_str(self.key_type.as_str());
        ss.put_u8s(sign.as_slice());
        ss.to_vec()
    }
}



pub enum KeyPairType {
    SshRsa
}

impl KeyPairType {
    pub(crate) fn get_string<'a>(key_type: KeyPairType) -> &'a str {
        match key_type {
            KeyPairType::SshRsa => "ssh-rsa"
        }
    }
}