├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── google.rs └── src ├── alert.rs ├── cipher ├── chacha20_poly1305.rs ├── ecdhe.rs ├── mod.rs └── prf.rs ├── client.rs ├── crypto ├── chacha20.rs ├── mod.rs ├── p256.rs ├── poly1305.rs ├── sha2.rs └── wrapping.rs ├── handshake.rs ├── lib.rs ├── macros.rs ├── signature.rs ├── test.rs ├── tls.rs ├── tls_item.rs ├── tls_result.rs └── util.rs /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "suruga" 4 | version = "0.1.0" 5 | authors = ["klutzytheklutzy@gmail.com"] 6 | 7 | [dependencies] 8 | 9 | log = "*" 10 | rand = "*" 11 | num = "*" 12 | enum_primitive = "*" 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 klutzy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | suruga is Rust implementation of [TLS 1.2][tls-12]. 2 | 3 | It currently implements some core parts of TLS 1.2, 4 | NIST P-256 [ECDHE][tls-ecc] and [chacha20-poly1305][tls-chacha20-poly1305]. 5 | 6 | # Usage 7 | 8 | ```Rust 9 | extern crate suruga; 10 | 11 | use std::io::prelude::*; 12 | use std::net::TcpStream; 13 | 14 | fn main() { 15 | test().unwrap(); 16 | } 17 | 18 | fn test() -> suruga::tls_result::TlsResult<()> { 19 | let stream = try!(TcpStream::connect("www.google.com:443")); 20 | let mut client = try!(suruga::TlsClient::from_tcp(stream)); 21 | let _len = try!(client.write(b"GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")); 22 | 23 | let mut msg = vec![0u8; 100]; 24 | try!(client.read(&mut msg)); 25 | let msg = String::from_utf8_lossy(&msg); 26 | println!("msg: {}", msg); 27 | 28 | try!(client.close()); 29 | 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | [tls-12]: http://tools.ietf.org/html/rfc5246 35 | [tls-ecc]: http://tools.ietf.org/html/rfc4492 36 | [tls-chacha20-poly1305]: https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 37 | -------------------------------------------------------------------------------- /examples/google.rs: -------------------------------------------------------------------------------- 1 | extern crate suruga; 2 | 3 | use std::io::prelude::*; 4 | use std::net::TcpStream; 5 | 6 | fn main() { 7 | test().unwrap(); 8 | } 9 | 10 | fn test() -> suruga::tls_result::TlsResult<()> { 11 | let stream = try!(TcpStream::connect("www.google.com:443")); 12 | let mut client = try!(suruga::TlsClient::from_tcp(stream)); 13 | let _len = try!(client.write(b"GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")); 14 | 15 | let mut msg = vec![0u8; 100]; 16 | try!(client.read(&mut msg)); 17 | let msg = String::from_utf8_lossy(&msg); 18 | println!("msg: {}", msg); 19 | 20 | try!(client.close()); 21 | 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /src/alert.rs: -------------------------------------------------------------------------------- 1 | use util::{ReadExt, WriteExt}; 2 | use tls_result::{TlsResult, TlsError, TlsErrorKind}; 3 | use tls_item::TlsItem; 4 | 5 | // we treat every alert as fatal. 6 | tls_enum!(u8, enum AlertLevel { 7 | warning(1), 8 | fatal(2) 9 | }); 10 | 11 | // A.3. Alert Messages 12 | // http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml 13 | tls_enum!(u8, #[derive(Debug)] enum AlertDescription { 14 | close_notify(0), 15 | unexpected_message(10), 16 | bad_record_mac(20), 17 | decryption_failed_RESERVED(21), 18 | record_overflow(22), 19 | decompression_failure(30), 20 | handshake_failure(40), 21 | no_certificate_RESERVED(41), 22 | bad_certificate(42), 23 | unsupported_certificate(43), 24 | certificate_revoked(44), 25 | certificate_expired(45), 26 | certificate_unknown(46), 27 | illegal_parameter(47), 28 | unknown_ca(48), 29 | access_denied(49), 30 | decode_error(50), 31 | decrypt_error(51), 32 | export_restriction_RESERVED(60), 33 | protocol_version(70), 34 | insufficient_security(71), 35 | internal_error(80), 36 | user_canceled(90), 37 | no_renegotiation(100), 38 | unsupported_extension(110) 39 | 40 | // RFC 6066 41 | // certificate_unobtainable(111), 42 | // unrecognized_name(112), 43 | // bad_certificate_status_response(113), 44 | // bad_certificate_hash_value(114), 45 | }); 46 | 47 | impl AlertDescription { 48 | fn from_err(kind: TlsErrorKind) -> AlertDescription { 49 | match kind { 50 | TlsErrorKind::UnexpectedMessage => AlertDescription::unexpected_message, 51 | TlsErrorKind::BadRecordMac => AlertDescription::bad_record_mac, 52 | TlsErrorKind::RecordOverflow => AlertDescription::record_overflow, 53 | TlsErrorKind::IllegalParameter => AlertDescription::illegal_parameter, 54 | TlsErrorKind::DecodeError => AlertDescription::decode_error, 55 | TlsErrorKind::DecryptError => AlertDescription::decrypt_error, 56 | TlsErrorKind::InternalError => AlertDescription::internal_error, 57 | 58 | // FIXME: we probably can't even send alert? 59 | TlsErrorKind::IoFailure => AlertDescription::internal_error, 60 | TlsErrorKind::AlertReceived => AlertDescription::close_notify, 61 | } 62 | 63 | } 64 | } 65 | 66 | tls_struct!(struct Alert { 67 | level: AlertLevel, 68 | description: AlertDescription 69 | }); 70 | 71 | impl Alert { 72 | pub fn new(level: AlertLevel, desc: AlertDescription) -> TlsResult { 73 | // TODO filter out some rfc-invalid alerts 74 | Ok(Alert { 75 | level: level, 76 | description: desc, 77 | }) 78 | } 79 | 80 | pub fn from_tls_err(err: &TlsError) -> Alert { 81 | Alert { 82 | level: AlertLevel::fatal, 83 | description: AlertDescription::from_err(err.kind), 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/cipher/chacha20_poly1305.rs: -------------------------------------------------------------------------------- 1 | // Implements AEAD_CHACHA20_POLY1305 2 | // unfortunately, there is no concrete standard yet. some drafts exist: 3 | // http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-01 4 | // http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 5 | // they differ in detail, so here we follow google/boringssl implementation. 6 | // openssl 1.0.2-aead branch seems to implement draft 01. 7 | 8 | use crypto::chacha20::ChaCha20; 9 | use crypto::poly1305; 10 | use util::u64_le_array; 11 | use tls_result::TlsResult; 12 | use tls_result::TlsErrorKind::BadRecordMac; 13 | use super::{Encryptor, Decryptor, Aead}; 14 | 15 | const KEY_LEN: usize = 256 / 8; 16 | const EXPLICIT_IV_LEN: usize = 0; 17 | const MAC_LEN: usize = 16; 18 | 19 | fn compute_mac(poly_key: &[u8], encrypted: &[u8], ad: &[u8]) -> [u8; MAC_LEN] { 20 | let mut msg = Vec::new(); 21 | 22 | // follow draft-agl-tls-chacha20poly1305-04: data first, length later 23 | // note that in draft-agl-tls-chacha20poly1305-01 length is first 24 | fn push_all_with_len(vec: &mut Vec, data: &[u8]) { 25 | vec.extend(data); 26 | vec.extend(&u64_le_array(data.len() as u64)); 27 | } 28 | 29 | push_all_with_len(&mut msg, ad); 30 | push_all_with_len(&mut msg, encrypted); 31 | 32 | let mut r = [0u8; MAC_LEN]; 33 | for i in (0..MAC_LEN) { 34 | r[i] = poly_key[i]; 35 | } 36 | let mut k = [0u8; MAC_LEN]; 37 | for i in (0..MAC_LEN) { 38 | k[i] = poly_key[MAC_LEN + i]; 39 | } 40 | 41 | poly1305::authenticate(&msg, &r, &k) 42 | } 43 | 44 | struct ChaCha20Poly1305Encryptor { 45 | key: Vec, 46 | } 47 | 48 | impl Encryptor for ChaCha20Poly1305Encryptor { 49 | fn encrypt(&mut self, nonce: &[u8], data: &[u8], ad: &[u8]) -> Vec { 50 | let mut chacha20 = ChaCha20::new(&self.key, nonce); 51 | let poly1305_key = chacha20.next(); 52 | 53 | let mut encrypted = chacha20.encrypt(data); 54 | let mac = compute_mac(&poly1305_key, &encrypted, ad); 55 | encrypted.extend(&mac); 56 | 57 | encrypted 58 | } 59 | } 60 | 61 | struct ChaCha20Poly1305Decryptor { 62 | key: Vec, 63 | } 64 | 65 | impl Decryptor for ChaCha20Poly1305Decryptor { 66 | fn decrypt(&mut self, nonce: &[u8], data: &[u8], ad: &[u8]) -> TlsResult> { 67 | let enc_len = data.len(); 68 | if enc_len < MAC_LEN { 69 | return tls_err!(BadRecordMac, "message too short"); 70 | } 71 | 72 | let encrypted = &data[..(enc_len - MAC_LEN)]; 73 | let mac_expected = &data[(enc_len - MAC_LEN)..]; 74 | 75 | let mut chacha20 = ChaCha20::new(&self.key, nonce); 76 | let poly1305_key = chacha20.next(); 77 | 78 | let mac_computed = compute_mac(&poly1305_key, &encrypted, ad); 79 | 80 | // SECRET 81 | // even if `mac_computed != mac_expected`, decrypt the data to prevent timing attack. 82 | let plain = chacha20.encrypt(encrypted); 83 | 84 | let mut diff = 0u8; 85 | for i in (0..MAC_LEN) { 86 | diff |= mac_computed[i] ^ mac_expected[i]; 87 | } 88 | 89 | if diff != 0 { 90 | tls_err!(BadRecordMac, "wrong mac") 91 | } else { 92 | Ok(plain) 93 | } 94 | } 95 | 96 | #[inline(always)] 97 | fn mac_len(&self) -> usize { 98 | MAC_LEN 99 | } 100 | } 101 | 102 | pub struct ChaCha20Poly1305; 103 | 104 | impl Aead for ChaCha20Poly1305 { 105 | #[inline(always)] 106 | fn key_size(&self) -> usize { 107 | KEY_LEN 108 | } 109 | 110 | #[inline(always)] 111 | fn fixed_iv_len(&self) -> usize { 112 | EXPLICIT_IV_LEN 113 | } 114 | 115 | #[inline(always)] 116 | fn mac_len(&self) -> usize { 117 | MAC_LEN 118 | } 119 | 120 | #[inline(always)] 121 | fn new_encryptor(&self, key: Vec) -> Box { 122 | let encryptor = ChaCha20Poly1305Encryptor { 123 | key: key, 124 | }; 125 | Box::new(encryptor) as Box 126 | } 127 | 128 | #[inline(always)] 129 | fn new_decryptor(&self, key: Vec) -> Box { 130 | let decryptor = ChaCha20Poly1305Decryptor { 131 | key: key, 132 | }; 133 | Box::new(decryptor) as Box 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/cipher/ecdhe.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | use rand::{Rng, OsRng}; 3 | 4 | use crypto::wrapping::Wrapping as W; 5 | use util::{ReadExt, WriteExt}; 6 | use tls_result::TlsResult; 7 | use tls_result::TlsErrorKind::IllegalParameter; 8 | use tls_item::TlsItem; 9 | use crypto::p256; 10 | use handshake::NamedCurve; 11 | use signature::DigitallySigned; 12 | use super::KeyExchange; 13 | 14 | tls_vec!(EcData = u8(1, (1 << 8) - 1)); 15 | tls_struct!(struct EcCurve { 16 | a: EcData, 17 | b: EcData 18 | }); 19 | 20 | // usage: 21 | // struct { 22 | // Type type; 23 | // "opaque" { 24 | // select (type) { 25 | // case TypeVariant1: 26 | // ... 27 | // case TypeVariant2: 28 | // ... 29 | // } 30 | // } 31 | // } Struct; 32 | macro_rules! tls_enum_struct { 33 | ( 34 | $repr_ty:ident, 35 | $(#[$a:meta])* 36 | enum $enum_name:ident { 37 | $( 38 | $name:ident($body_ty:ident) = $num:tt // $num: integer literal 39 | ),+ 40 | } 41 | ) => ( 42 | #[allow(non_camel_case_types)] 43 | $(#[$a])* 44 | pub enum $enum_name { 45 | $( 46 | $name($body_ty), 47 | )+ 48 | } 49 | 50 | impl TlsItem for $enum_name { 51 | fn tls_write(&self, writer: &mut W) -> ::tls_result::TlsResult<()> { 52 | match *self { 53 | $( 54 | $enum_name::$name(ref body) => { 55 | try_write_num!($repr_ty, writer, tt_to_expr!($num)); 56 | try!(body.tls_write(writer)); 57 | } 58 | )+ 59 | } 60 | Ok(()) 61 | } 62 | 63 | fn tls_read(reader: &mut R) -> ::tls_result::TlsResult<$enum_name> { 64 | let num = try_read_num!($repr_ty, reader); 65 | match num { 66 | $( 67 | tt_to_pat!($num) => { 68 | let body: $body_ty = try!(TlsItem::tls_read(reader)); 69 | Ok($enum_name::$name(body)) 70 | } 71 | )+ 72 | _ => return tls_err!(::tls_result::TlsErrorKind::DecodeError, 73 | "unexpected value: {}", num), 74 | } 75 | } 76 | 77 | fn tls_size(&self) -> u64 { 78 | let prefix_size = num_size!($repr_ty); 79 | let body_size = match *self { 80 | $( 81 | $enum_name::$name(ref body) => body.tls_size(), 82 | )+ 83 | }; 84 | prefix_size + body_size 85 | } 86 | } 87 | ) 88 | } 89 | 90 | 91 | tls_enum_struct!(u8, enum EcParameters { 92 | // explicit_prime(...) = 1, 93 | // explicit_char2(...) = 2, 94 | named_curve(NamedCurve) = 3 95 | }); 96 | 97 | tls_struct!(struct ServerEcdhParams { 98 | curve_params: EcParameters, 99 | public: EcData 100 | }); 101 | 102 | tls_struct!(struct EcdheServerKeyExchange { 103 | params: ServerEcdhParams, 104 | signed_params: DigitallySigned 105 | }); 106 | 107 | pub struct EllipticDiffieHellman; 108 | 109 | impl KeyExchange for EllipticDiffieHellman { 110 | fn compute_keys(&self, data: &[u8], rng: &mut OsRng) -> TlsResult<(Vec, Vec)> { 111 | let mut reader = Cursor::new(data); 112 | let ecdh_params: EcdheServerKeyExchange = try!(TlsItem::tls_read(&mut reader)); 113 | 114 | let gy = &ecdh_params.params.public; 115 | let gy = p256::NPoint256::from_uncompressed_bytes(gy); 116 | let gy = match gy { 117 | None => { 118 | return tls_err!(IllegalParameter, "server sent strange public key"); 119 | } 120 | Some(gy) => gy, 121 | }; 122 | let gy = gy.to_point(); 123 | 124 | fn get_random_x(rng: &mut OsRng) -> p256::int256::Int256 { 125 | loop { 126 | let mut x = p256::int256::ZERO; 127 | for i in 0..8 { 128 | x.v[i] = W(rng.next_u32()); 129 | } 130 | let xx = x.reduce_once(W(0)); 131 | let x_is_okay = xx.compare(&x); 132 | if x_is_okay == W(0) { 133 | return x; 134 | } 135 | } 136 | } 137 | 138 | let x = get_random_x(rng); 139 | let gx = p256::G.mult_scalar(&x).normalize().to_uncompressed_bytes(); 140 | let gxy = gy.mult_scalar(&x).normalize(); 141 | let pre_master_secret = gxy.x.to_bytes(); 142 | 143 | // we don't support client cert. send public key explicitly. 144 | let public = try!(EcData::new(gx)); 145 | 146 | let mut data = Vec::new(); 147 | try!(public.tls_write(&mut data)); 148 | let public = data; 149 | 150 | Ok((public, pre_master_secret)) 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/cipher/mod.rs: -------------------------------------------------------------------------------- 1 | use rand::OsRng; 2 | 3 | use util::{ReadExt, WriteExt}; 4 | use tls_result::TlsResult; 5 | use tls_result::TlsErrorKind::UnexpectedMessage; 6 | use tls_item::TlsItem; 7 | use self::chacha20_poly1305::ChaCha20Poly1305; 8 | use self::ecdhe::EllipticDiffieHellman; 9 | 10 | pub mod prf; 11 | pub mod ecdhe; 12 | pub mod chacha20_poly1305; 13 | 14 | pub trait Aead { 15 | fn key_size(&self) -> usize; 16 | fn fixed_iv_len(&self) -> usize; 17 | fn mac_len(&self) -> usize; 18 | fn new_encryptor(&self, key: Vec) -> Box; 19 | fn new_decryptor(&self, key: Vec) -> Box; 20 | } 21 | 22 | pub trait Encryptor { 23 | fn encrypt(&mut self, nonce: &[u8], plain: &[u8], ad: &[u8]) -> Vec; 24 | } 25 | 26 | // Note: Enctryptor and Decryptor should be separated because there exists a state that 27 | // client encrypts data but server does not. 28 | pub trait Decryptor { 29 | fn decrypt(&mut self, nonce: &[u8], encrypted: &[u8], ad: &[u8]) -> TlsResult>; 30 | // FIXME: copied from Aead since record::RecordReader wants this 31 | fn mac_len(&self) -> usize; 32 | } 33 | 34 | pub trait KeyExchange { 35 | // return (client_key_exchange_data, pre_master_secret) 36 | fn compute_keys(&self, data: &[u8], rng: &mut OsRng) -> TlsResult<(Vec, Vec)>; 37 | } 38 | 39 | macro_rules! cipher_suite { 40 | ($( 41 | $id:ident = $kex:ident, $cipher:ident, $mac:ident, $v1:expr, $v2:expr; 42 | )+) => ( 43 | #[allow(non_camel_case_types)] 44 | #[derive(Copy, Clone, PartialEq, Debug)] 45 | pub enum CipherSuite { 46 | $( 47 | $id, 48 | )+ 49 | UnknownCipherSuite, 50 | } 51 | 52 | impl CipherSuite { 53 | pub fn new_aead(&self) -> Box { 54 | match *self { 55 | $( 56 | CipherSuite::$id => Box::new($cipher) as Box, 57 | )+ 58 | CipherSuite::UnknownCipherSuite => unreachable!(), 59 | } 60 | } 61 | 62 | pub fn new_kex(&self) -> Box { 63 | match *self { 64 | $( 65 | CipherSuite::$id => Box::new($kex) as Box, 66 | )+ 67 | CipherSuite::UnknownCipherSuite => unreachable!(), 68 | } 69 | } 70 | 71 | // this can be different for some cipher suites 72 | pub fn verify_data_len(&self) -> usize { 12 } 73 | } 74 | 75 | impl TlsItem for CipherSuite { 76 | fn tls_write(&self, writer: &mut W) -> TlsResult<()> { 77 | $( 78 | if *self == CipherSuite::$id { 79 | try!(writer.write_u8($v1)); 80 | try!(writer.write_u8($v2)); 81 | return Ok(()); 82 | } 83 | )+ 84 | 85 | return tls_err!(UnexpectedMessage, "unexpected CipherSuite: {:?}", self); 86 | } 87 | 88 | fn tls_read(reader: &mut R) -> TlsResult { 89 | let id1 = try!(reader.read_u8()); 90 | let id2 = try!(reader.read_u8()); 91 | $( 92 | if id1 == $v1 && id2 == $v2 { 93 | return Ok(CipherSuite::$id); 94 | } 95 | )+ 96 | // client may send cipher suites we don't know 97 | return Ok(CipherSuite::UnknownCipherSuite); 98 | } 99 | 100 | fn tls_size(&self) -> u64 { 101 | 2 102 | } 103 | } 104 | ) 105 | } 106 | 107 | // TODO RSA/ECDSA signs 108 | cipher_suite!( 109 | // http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 110 | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 111 | EllipticDiffieHellman, ChaCha20Poly1305, MAC_SHA256, 0xcc, 0x13; 112 | // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 113 | // EllipticDiffieHellman ChaCha20Poly1305 MAC_SHA256 0xcc 0x14; 114 | ); 115 | -------------------------------------------------------------------------------- /src/cipher/prf.rs: -------------------------------------------------------------------------------- 1 | // In AEAD setting, PRF is only used for key calculation. 2 | // SHA-256 only for now. 3 | 4 | use std::mem; 5 | use crypto::sha2::sha256; 6 | 7 | // key is SECRET, but the length is publicly known. 8 | pub fn hmac_sha256(key: &[u8], msg: &[u8]) -> [u8; 32] { 9 | const B: usize = 64; 10 | 11 | if key.len() > B { 12 | // FIXME 13 | unimplemented!(); 14 | } 15 | 16 | let mut i_msg = [0x36u8; B].to_vec(); 17 | let mut o_msg = [0x5cu8; B].to_vec(); 18 | for i in (0..key.len()) { 19 | i_msg[i] ^= key[i]; 20 | o_msg[i] ^= key[i]; 21 | } 22 | 23 | i_msg.extend(msg); 24 | let h_i = sha256(&i_msg); 25 | o_msg.extend(&h_i); 26 | let h_o = sha256(&o_msg); 27 | 28 | h_o 29 | } 30 | 31 | pub struct Prf { 32 | secret: Vec, // SECRET 33 | seed: Vec, 34 | a: [u8; 32], 35 | buf: Vec, 36 | } 37 | 38 | impl Prf { 39 | pub fn new(secret: Vec, seed: Vec) -> Prf { 40 | let a1 = hmac_sha256(&secret, &seed); 41 | 42 | Prf { 43 | secret: secret, 44 | seed: seed, 45 | a: a1, 46 | buf: Vec::new(), 47 | } 48 | } 49 | 50 | // get 32-byte pseudorandom number. 51 | fn next_block(&mut self) -> [u8; 32] { 52 | let mut input = self.a.to_vec(); 53 | input.extend(&self.seed); 54 | let next = hmac_sha256(&self.secret, &input); 55 | self.a = hmac_sha256(&self.secret, &self.a); 56 | 57 | next 58 | } 59 | 60 | pub fn get_bytes(&mut self, size: usize) -> Vec { 61 | let mut ret = { 62 | let buflen = self.buf.len(); 63 | if buflen > 0 { 64 | if buflen <= size { 65 | mem::replace(&mut self.buf, Vec::new()) 66 | } else { 67 | let rest = self.buf[size..].to_vec(); 68 | let mut buf = mem::replace(&mut self.buf, rest); 69 | buf.truncate(size); 70 | buf 71 | } 72 | } else { 73 | Vec::new() 74 | } 75 | }; 76 | 77 | while ret.len() < size { 78 | let next_block = self.next_block(); 79 | let slice_len = size - ret.len(); 80 | if slice_len > 32 { 81 | ret.extend(&next_block); 82 | } else { 83 | ret.extend(&next_block[..slice_len]); 84 | self.buf = next_block[slice_len..].to_vec(); 85 | break; 86 | }; 87 | } 88 | 89 | ret 90 | } 91 | } 92 | 93 | #[cfg(test)] 94 | mod test { 95 | use super::{hmac_sha256, Prf}; 96 | 97 | #[test] 98 | fn test_hmac_sha256() { 99 | // some test vectors from RFC 4231 100 | static VALUES: &'static [(&'static [u8], &'static [u8], &'static [u8])] = &[ 101 | (b"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\ 102 | \x0b\x0b\x0b\x0b", 103 | b"\x48\x69\x20\x54\x68\x65\x72\x65", 104 | b"\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\ 105 | \x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7"), 106 | (b"\x4a\x65\x66\x65", 107 | b"\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\ 108 | \x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", 109 | b"\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7\ 110 | \x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43"), 111 | (b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\ 112 | \xaa\xaa\xaa\xaa", 113 | b"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\ 114 | \xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\ 115 | \xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\ 116 | \xdd\xdd", 117 | b"\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7\ 118 | \x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe"), 119 | (b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\ 120 | \x11\x12\x13\x14\x15\x16\x17\x18\x19", 121 | b"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\ 122 | \xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\ 123 | \xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\ 124 | \xcd\xcd", 125 | b"\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08\x3a\ 126 | \x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b"), 127 | ]; 128 | 129 | for &(key, input, expected) in VALUES.iter() { 130 | let actual = hmac_sha256(key, input); 131 | assert_eq!(&actual, expected); 132 | } 133 | } 134 | 135 | #[test] 136 | fn test_get_bytes() { 137 | let ret1 = { 138 | let mut prf = Prf::new(Vec::new(), Vec::new()); 139 | let mut ret: Vec = Vec::new(); 140 | for _ in 0..100 { 141 | ret.extend(&prf.get_bytes(1)); 142 | } 143 | ret 144 | }; 145 | 146 | let ret2 = { 147 | let mut prf = Prf::new(Vec::new(), Vec::new()); 148 | prf.get_bytes(100) 149 | }; 150 | 151 | assert_eq!(ret1, ret2); 152 | 153 | let ret3 = { 154 | let mut prf = Prf::new(Vec::new(), Vec::new()); 155 | let mut b = prf.get_bytes(33); 156 | b.extend(&prf.get_bytes(33)); 157 | b.extend(&prf.get_bytes(100 - 33 * 2)); 158 | b 159 | }; 160 | 161 | assert_eq!(ret1, ret3); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::prelude::*; 3 | use std::net::TcpStream; 4 | use std::cmp; 5 | use rand::{Rng, OsRng}; 6 | 7 | use alert; 8 | use tls_result::{TlsResult, TlsError, TlsErrorKind}; 9 | use tls_result::TlsErrorKind::{UnexpectedMessage, InternalError, DecryptError, IllegalParameter}; 10 | use util::{SurugaError, crypto_compare}; 11 | use cipher::{self, Aead}; 12 | use cipher::prf::Prf; 13 | use crypto::sha2::sha256; 14 | use tls_item::{TlsItem, DummyItem}; 15 | use handshake::{self, Handshake}; 16 | use tls::{TlsReader, TlsWriter, TLS_VERSION}; 17 | 18 | // handshake is done during construction. 19 | pub struct TlsClient { 20 | pub reader: TlsReader, 21 | pub writer: TlsWriter, 22 | pub rng: OsRng, 23 | buf: Vec, 24 | } 25 | 26 | impl TlsClient { 27 | pub fn new(reader: R, writer: W, rng: OsRng) -> TlsResult> { 28 | let mut client = TlsClient { 29 | reader: TlsReader::new(reader), 30 | writer: TlsWriter::new(writer), 31 | rng: rng, 32 | buf: Vec::new(), 33 | }; 34 | 35 | // handshake failed. send alert if necessary 36 | match client.handshake() { 37 | Ok(()) => {} 38 | Err(err) => return Err(client.send_tls_alert(err)), 39 | } 40 | Ok(client) 41 | } 42 | 43 | #[inline] 44 | pub fn reader(&mut self) -> &mut R { 45 | self.reader.get_mut() 46 | } 47 | 48 | #[inline] 49 | pub fn writer(&mut self) -> &mut W { 50 | self.writer.get_mut() 51 | } 52 | 53 | // this does not send alert when error occurs 54 | fn handshake(&mut self) -> TlsResult<()> { 55 | // expect specific HandshakeMessage. otherwise return Err 56 | macro_rules! expect { 57 | ($var:ident) => ({ 58 | match try!(self.reader.read_handshake()) { 59 | handshake::Handshake::$var(data) => data, 60 | _ => return tls_err!(UnexpectedMessage, "unexpected handshake message found"), 61 | } 62 | }) 63 | } 64 | 65 | let cli_random = { 66 | let mut random_bytes = [0u8; 32]; 67 | self.rng.fill_bytes(&mut random_bytes); 68 | random_bytes.to_vec() 69 | }; 70 | let random = try!(handshake::Random::new(cli_random.clone())); 71 | 72 | // the only cipher we currently support 73 | let cipher_suite = cipher::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; 74 | 75 | let curve_list = vec!(handshake::NamedCurve::secp256r1); 76 | let curve_list = try!(handshake::Extension::new_elliptic_curve_list(curve_list)); 77 | 78 | let format_list = vec!(handshake::ECPointFormat::uncompressed); 79 | let format_list = try!(handshake::Extension::new_ec_point_formats(format_list)); 80 | 81 | let extensions = vec!(curve_list, format_list); 82 | 83 | let client_hello = try!(Handshake::new_client_hello(random, cipher_suite, extensions)); 84 | try!(self.writer.write_handshake(&client_hello)); 85 | 86 | let server_hello_data = expect!(server_hello); 87 | { 88 | let server_major = server_hello_data.server_version.major; 89 | let server_minor = server_hello_data.server_version.minor; 90 | if (server_major, server_minor) != TLS_VERSION { 91 | return tls_err!(IllegalParameter, 92 | "wrong server version: {} {}", 93 | server_major, 94 | server_minor); 95 | } 96 | 97 | if server_hello_data.cipher_suite != cipher_suite { 98 | return tls_err!(IllegalParameter, 99 | "cipher suite mismatch: found {:?}", 100 | server_hello_data.cipher_suite); 101 | } 102 | 103 | if server_hello_data.compression_method != handshake::CompressionMethod::null { 104 | return tls_err!(IllegalParameter, "compression method mismatch"); 105 | } 106 | 107 | // FIXME: check if server sent unknown extension 108 | // it is currently done by just not understanding any extensions 109 | // other than we used. 110 | } 111 | 112 | // we always expect certificate. 113 | let certificate_list = expect!(certificate); 114 | // TODO: cert validation not implemented yet 115 | 116 | // we always use server key exchange 117 | let server_key_ex_data = expect!(server_key_exchange); 118 | let kex = cipher_suite.new_kex(); 119 | let (key_data, pre_master_secret) = try!(kex.compute_keys(&server_key_ex_data, 120 | &mut self.rng)); 121 | 122 | expect!(server_hello_done); 123 | 124 | let client_key_exchange = try!(Handshake::new_client_key_exchange(key_data)); 125 | try!(self.writer.write_handshake(&client_key_exchange)); 126 | 127 | try!(self.writer.write_change_cipher_spec()); 128 | 129 | // SECRET 130 | let master_secret = { 131 | let mut label_seed = b"master secret".to_vec(); 132 | label_seed.extend(&cli_random); 133 | label_seed.extend(&server_hello_data.random[..]); 134 | 135 | let mut prf = Prf::new(pre_master_secret, label_seed); 136 | prf.get_bytes(48) 137 | }; 138 | 139 | let aead = cipher_suite.new_aead(); 140 | 141 | // SECRET 142 | let read_key = { 143 | let mut label_seed = b"key expansion".to_vec(); 144 | label_seed.extend(&server_hello_data.random[..]); 145 | label_seed.extend(&cli_random); 146 | 147 | let mut prf = Prf::new(master_secret.clone(), label_seed); 148 | 149 | // mac_key is not used in AEAD configuration. 150 | 151 | let enc_key_length = aead.key_size(); 152 | 153 | let write_key = prf.get_bytes(enc_key_length); 154 | let encryptor = aead.new_encryptor(write_key); 155 | self.writer.set_encryptor(encryptor); 156 | 157 | // this will be set after receiving ChangeCipherSpec. 158 | let read_key = prf.get_bytes(enc_key_length); 159 | 160 | // chacha20-poly1305 does not use iv. 161 | 162 | read_key 163 | }; 164 | 165 | // FIXME we should get "raw" packet data and hash them incrementally 166 | let msgs = { 167 | let mut msgs = Vec::new(); 168 | try!(client_hello.tls_write(&mut msgs)); 169 | try!(Handshake::server_hello(server_hello_data).tls_write(&mut msgs)); 170 | try!(Handshake::certificate(certificate_list).tls_write(&mut msgs)); 171 | try!(Handshake::server_key_exchange(server_key_ex_data).tls_write(&mut msgs)); 172 | try!(Handshake::server_hello_done(DummyItem).tls_write(&mut msgs)); 173 | try!(client_key_exchange.tls_write(&mut msgs)); 174 | msgs 175 | }; 176 | 177 | // this only verifies Handshake messages! what about others? 178 | // ApplicationData messages are not permitted until now. 179 | // ChangeCipherSpec messages are only permitted after ClinetKeyExchange. 180 | // Alert messages can be problematic - they are not verified and 181 | // can be broken into several records. This leads to alert attack. 182 | // since we don't accept strange alerts, all "normal" alert messages are 183 | // treated as error, so now we can assert that we haven't received alerts. 184 | let verify_hash = sha256(&msgs); 185 | 186 | let client_verify_data = { 187 | let finished_label = b"client finished"; 188 | 189 | let mut label_seed = finished_label.to_vec(); 190 | label_seed.extend(&verify_hash); 191 | let mut prf = Prf::new(master_secret.clone(), label_seed); 192 | prf.get_bytes(cipher_suite.verify_data_len()) 193 | }; 194 | let finished = try!(Handshake::new_finished(client_verify_data)); 195 | try!(self.writer.write_handshake(&finished)); 196 | 197 | // Although client->server is encrypted, server->client isn't yet. 198 | // server may send either ChangeCipherSpec or Alert. 199 | try!(self.reader.read_change_cipher_spec()); 200 | 201 | // from now server starts encryption. 202 | self.reader.set_decryptor(aead.new_decryptor(read_key)); 203 | 204 | let server_finished = expect!(finished); 205 | { 206 | let verify_hash = { 207 | // ideally we may save "raw" packet data.. 208 | let mut serv_msgs = Vec::new(); 209 | // FIXME: this should not throw "io error".. should throw "internal error" 210 | try!(Write::write_all(&mut serv_msgs, &msgs)); 211 | try!(finished.tls_write(&mut serv_msgs)); 212 | 213 | let verify_hash = sha256(&serv_msgs); 214 | verify_hash 215 | }; 216 | 217 | let server_verify_data = { 218 | let finished_label = b"server finished"; 219 | 220 | let mut label_seed = finished_label.to_vec(); 221 | label_seed.extend(&verify_hash); 222 | let mut prf = Prf::new(master_secret, label_seed); 223 | prf.get_bytes(cipher_suite.verify_data_len()) 224 | }; 225 | 226 | let verify_ok = crypto_compare(&server_finished, 227 | &server_verify_data); 228 | if !verify_ok { 229 | return tls_err!(DecryptError, "server sent wrong verify data"); 230 | } 231 | } 232 | 233 | Ok(()) 234 | } 235 | 236 | pub fn close(&mut self) -> TlsResult<()> { 237 | let alert_data = alert::Alert { 238 | level: alert::AlertLevel::fatal, 239 | description: alert::AlertDescription::close_notify, 240 | }; 241 | try!(self.writer.write_alert(&alert_data)); 242 | Ok(()) 243 | } 244 | 245 | // send fatal alert and return error 246 | // (it may be different to `err`, because writing alert can fail) 247 | pub fn send_tls_alert(&mut self, err: TlsError) -> TlsError { 248 | match err.kind { 249 | TlsErrorKind::IoFailure => return err, 250 | _ => { 251 | let alert = alert::Alert::from_tls_err(&err); 252 | let result = self.writer.write_alert(&alert); 253 | match result { 254 | Ok(()) => return err, 255 | Err(err) => return err, 256 | } 257 | } 258 | } 259 | } 260 | } 261 | 262 | impl TlsClient { 263 | pub fn from_tcp(stream: TcpStream) -> TlsResult> { 264 | let rng = match OsRng::new() { 265 | Ok(rng) => rng, 266 | Err(..) => return tls_err!(InternalError, "failed to create OsRng"), 267 | }; 268 | 269 | let reader = try!(stream.try_clone()); 270 | let writer = stream; 271 | TlsClient::new(reader, writer, rng) 272 | } 273 | } 274 | 275 | impl Write for TlsClient { 276 | // this either writes all or fails. 277 | fn write(&mut self, buf: &[u8]) -> io::Result { 278 | try!(self.write_all(buf)); 279 | Ok(buf.len()) 280 | } 281 | 282 | fn flush(&mut self) -> io::Result<()> { 283 | Ok(()) 284 | } 285 | 286 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 287 | let result = self.writer.write_application_data(buf); 288 | match result { 289 | Ok(()) => Ok(()), 290 | Err(err) => { 291 | let err = self.send_tls_alert(err); 292 | // FIXME more verbose io error 293 | Err(io::Error::new(io::ErrorKind::Other, SurugaError { 294 | desc: "TLS write error", 295 | cause: Some(Box::new(err)), 296 | })) 297 | } 298 | } 299 | } 300 | } 301 | 302 | // A replacement for the deprecated std::slice::bytes::copy_memory 303 | fn copy_memory(from: &[u8], mut to: &mut [u8]) -> usize { 304 | to.write(from).unwrap() 305 | } 306 | 307 | impl Read for TlsClient { 308 | // if ssl connection is failed, return `EndOfFile`. 309 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 310 | let mut pos: usize = 0; 311 | let len = buf.len(); 312 | while pos < len { 313 | let remaining = len - pos; 314 | if self.buf.len() == 0 { 315 | let data = match self.reader.read_application_data() { 316 | Ok(data) => data, 317 | Err(_err) => { 318 | break; // FIXME: stop if EOF. otherwise raise error? 319 | } 320 | }; 321 | self.buf.extend(&data); 322 | } 323 | 324 | let selflen = self.buf.len(); 325 | let necessary = cmp::min(remaining, selflen); 326 | copy_memory(&self.buf[.. necessary], &mut buf[pos .. pos + necessary]); 327 | pos += necessary; 328 | 329 | self.buf = self.buf[necessary..].to_vec(); 330 | } 331 | 332 | Ok(pos) 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/crypto/chacha20.rs: -------------------------------------------------------------------------------- 1 | // http://cr.yp.to/chacha/chacha-20080128.pdf 2 | // http://cr.yp.to/chacha.html 3 | 4 | use crypto::wrapping::*; 5 | 6 | // convert $e.slice($i, $i + 4) into u32 7 | macro_rules! to_le_u32 { 8 | ($e:ident[$i:expr]) => ({ 9 | let i: usize = $i; 10 | let v1 = w8($e[i + 0]).to_w32(); 11 | let v2 = w8($e[i + 1]).to_w32(); 12 | let v3 = w8($e[i + 2]).to_w32(); 13 | let v4 = w8($e[i + 3]).to_w32(); 14 | v1 | (v2 << 8) | (v3 << 16) | (v4 << 24) 15 | }) 16 | } 17 | 18 | pub struct ChaCha20 { 19 | // SECRET 20 | vals: [w32; 16], 21 | } 22 | 23 | impl ChaCha20 { 24 | // key: SECRET 25 | pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 { 26 | assert_eq!(key.len(), 32); 27 | assert_eq!(nonce.len(), 8); 28 | 29 | let mut vals = [w32(0u32); 16]; 30 | 31 | // "expand 32-byte k" 32 | vals[0] = w32(0x61707865); 33 | vals[1] = w32(0x3320646e); 34 | vals[2] = w32(0x79622d32); 35 | vals[3] = w32(0x6b206574); 36 | 37 | for i in (0..8) { 38 | vals[4 + i] = to_le_u32!(key[4 * i]); 39 | } 40 | 41 | // counter 42 | vals[12] = w32(0); 43 | vals[13] = w32(0); 44 | 45 | vals[14] = to_le_u32!(nonce[0]); 46 | vals[15] = to_le_u32!(nonce[4]); 47 | 48 | ChaCha20 { 49 | vals: vals, 50 | } 51 | } 52 | 53 | fn round20(&self) -> [w32; 16] { 54 | // $e must be > 0 and < 32 55 | macro_rules! rot { 56 | ($a:expr, $e:expr) => ({ 57 | let a: w32 = $a; 58 | let e: usize = $e; 59 | (a << e) | (a >> (32 - e)) 60 | }) 61 | } 62 | 63 | macro_rules! quarter_round { 64 | ($a:expr, $b:expr, $c:expr, $d:expr) => ({ 65 | $a = $a + $b; 66 | $d = $d ^ $a; 67 | $d = rot!($d, 16); 68 | 69 | $c = $c + $d; 70 | $b = $b ^ $c; 71 | $b = rot!($b, 12); 72 | 73 | $a = $a + $b; 74 | $d = $d ^ $a; 75 | $d = rot!($d, 8); 76 | 77 | $c = $c + $d; 78 | $b = $b ^ $c; 79 | $b = rot!($b, 7); 80 | }) 81 | } 82 | 83 | macro_rules! quarter_round_idx { 84 | ($e:expr, $a:expr, $b:expr, $c:expr, $d:expr) => ( 85 | quarter_round!($e[$a], $e[$b], $e[$c], $e[$d]) 86 | ) 87 | } 88 | 89 | let mut vals = self.vals; 90 | for _ in (0..10) { 91 | // column round 92 | quarter_round_idx!(vals, 0, 4, 8, 12); 93 | quarter_round_idx!(vals, 1, 5, 9, 13); 94 | quarter_round_idx!(vals, 2, 6, 10, 14); 95 | quarter_round_idx!(vals, 3, 7, 11, 15); 96 | 97 | // diagonal round 98 | quarter_round_idx!(vals, 0, 5, 10, 15); 99 | quarter_round_idx!(vals, 1, 6, 11, 12); 100 | quarter_round_idx!(vals, 2, 7, 8, 13); 101 | quarter_round_idx!(vals, 3, 4, 9, 14); 102 | } 103 | 104 | for i in (0..16) { 105 | vals[i] = vals[i] + self.vals[i]; 106 | } 107 | 108 | vals 109 | } 110 | 111 | pub fn next(&mut self) -> [u8; 64] { 112 | let next = self.round20(); 113 | 114 | // in TLS, vals[13] never increases 115 | { 116 | self.vals[12] = self.vals[12] + w32(1); 117 | // let mut count = (self.vals[12].to_w64()) | (self.vals[13].to_w64() << 32); 118 | // count += w64(1); 119 | // self.vals[12] = count.to_w32(); 120 | // self.vals[13] = (count >> 32).to_w32(); 121 | } 122 | 123 | let next_bytes = { 124 | let mut next_bytes = [0u8; 64]; 125 | for i in (0..16) { 126 | next_bytes[4 * i + 0] = next[i].to_w8().0; 127 | next_bytes[4 * i + 1] = (next[i] >> 8).to_w8().0; 128 | next_bytes[4 * i + 2] = (next[i] >> 16).to_w8().0; 129 | next_bytes[4 * i + 3] = (next[i] >> 24).to_w8().0; 130 | } 131 | next_bytes 132 | }; 133 | 134 | next_bytes 135 | } 136 | 137 | // Do not use same nonce for more than 2^70 bytes. 138 | // 139 | // if data is 1 byte, it still produces 64 bytes then 63 bytes are just discarded. 140 | // so this is not suitable for "byte-streaming" mode. 141 | // 142 | // data: SECRET 143 | pub fn encrypt(&mut self, data: &[u8]) -> Vec { 144 | let mut ret: Vec = Vec::new(); 145 | 146 | for chunk in data.chunks(64) { 147 | let next = self.next(); 148 | let xor_iter = next.iter().zip(chunk.iter()).map(|(&x, &y)| x ^ y); 149 | ret.extend(xor_iter); 150 | } 151 | 152 | ret 153 | } 154 | } 155 | 156 | #[cfg(test)] 157 | mod test { 158 | use std::iter::repeat; 159 | 160 | use super::ChaCha20; 161 | 162 | fn check_keystream(key: &[u8], nonce: &[u8], keystream: &[u8]) { 163 | let mut chacha = ChaCha20::new(key, nonce); 164 | let input: Vec<_> = repeat(0u8).take(keystream.len()).collect(); 165 | let output = chacha.encrypt(&input); 166 | assert_eq!(&output[..], keystream); 167 | } 168 | 169 | #[test] 170 | fn test_chacha20() { 171 | // from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 172 | 173 | let mut key = [0u8; 32]; 174 | let mut nonce = [0u8; 8]; 175 | let keystream = b"\x76\xb8\xe0\xad\xa0\xf1\x3d\x90\x40\x5d\x6a\xe5\x53\x86\xbd\x28\ 176 | \xbd\xd2\x19\xb8\xa0\x8d\xed\x1a\xa8\x36\xef\xcc\x8b\x77\x0d\xc7\ 177 | \xda\x41\x59\x7c\x51\x57\x48\x8d\x77\x24\xe0\x3f\xb8\xd8\x4a\x37\ 178 | \x6a\x43\xb8\xf4\x15\x18\xa1\x1c\xc3\x87\xb6\x69\xb2\xee\x65\x86"; 179 | check_keystream(&key, &nonce, keystream); 180 | 181 | key[31] = 1; 182 | let keystream = b"\x45\x40\xf0\x5a\x9f\x1f\xb2\x96\xd7\x73\x6e\x7b\x20\x8e\x3c\x96\ 183 | \xeb\x4f\xe1\x83\x46\x88\xd2\x60\x4f\x45\x09\x52\xed\x43\x2d\x41\ 184 | \xbb\xe2\xa0\xb6\xea\x75\x66\xd2\xa5\xd1\xe7\xe2\x0d\x42\xaf\x2c\ 185 | \x53\xd7\x92\xb1\xc4\x3f\xea\x81\x7e\x9a\xd2\x75\xae\x54\x69\x63"; 186 | check_keystream(&key, &nonce, keystream); 187 | 188 | key[31] = 0; 189 | nonce[7] = 1; 190 | let keystream = b"\xde\x9c\xba\x7b\xf3\xd6\x9e\xf5\xe7\x86\xdc\x63\x97\x3f\x65\x3a\ 191 | \x0b\x49\xe0\x15\xad\xbf\xf7\x13\x4f\xcb\x7d\xf1\x37\x82\x10\x31\ 192 | \xe8\x5a\x05\x02\x78\xa7\x08\x45\x27\x21\x4f\x73\xef\xc7\xfa\x5b\ 193 | \x52\x77\x06\x2e\xb7\xa0\x43\x3e\x44\x5f\x41\xe3"; 194 | check_keystream(&key, &nonce, keystream); 195 | 196 | key[31] = 0; 197 | nonce[7] = 0; 198 | nonce[0] = 1; 199 | let keystream = b"\xef\x3f\xdf\xd6\xc6\x15\x78\xfb\xf5\xcf\x35\xbd\x3d\xd3\x3b\x80\ 200 | \x09\x63\x16\x34\xd2\x1e\x42\xac\x33\x96\x0b\xd1\x38\xe5\x0d\x32\ 201 | \x11\x1e\x4c\xaf\x23\x7e\xe5\x3c\xa8\xad\x64\x26\x19\x4a\x88\x54\ 202 | \x5d\xdc\x49\x7a\x0b\x46\x6e\x7d\x6b\xbd\xb0\x04\x1b\x2f\x58\x6b"; 203 | check_keystream(&key, &nonce, keystream); 204 | 205 | for i in (0..0x20) { 206 | key[i] = i as u8; 207 | } 208 | for i in (0..0x08) { 209 | nonce[i] = i as u8; 210 | } 211 | let keystream = b"\xf7\x98\xa1\x89\xf1\x95\xe6\x69\x82\x10\x5f\xfb\x64\x0b\xb7\x75\ 212 | \x7f\x57\x9d\xa3\x16\x02\xfc\x93\xec\x01\xac\x56\xf8\x5a\xc3\xc1\ 213 | \x34\xa4\x54\x7b\x73\x3b\x46\x41\x30\x42\xc9\x44\x00\x49\x17\x69\ 214 | \x05\xd3\xbe\x59\xea\x1c\x53\xf1\x59\x16\x15\x5c\x2b\xe8\x24\x1a\ 215 | \x38\x00\x8b\x9a\x26\xbc\x35\x94\x1e\x24\x44\x17\x7c\x8a\xde\x66\ 216 | \x89\xde\x95\x26\x49\x86\xd9\x58\x89\xfb\x60\xe8\x46\x29\xc9\xbd\ 217 | \x9a\x5a\xcb\x1c\xc1\x18\xbe\x56\x3e\xb9\xb3\xa4\xa4\x72\xf8\x2e\ 218 | \x09\xa7\xe7\x78\x49\x2b\x56\x2e\xf7\x13\x0e\x88\xdf\xe0\x31\xc7\ 219 | \x9d\xb9\xd4\xf7\xc7\xa8\x99\x15\x1b\x9a\x47\x50\x32\xb6\x3f\xc3\ 220 | \x85\x24\x5f\xe0\x54\xe3\xdd\x5a\x97\xa5\xf5\x76\xfe\x06\x40\x25\ 221 | \xd3\xce\x04\x2c\x56\x6a\xb2\xc5\x07\xb1\x38\xdb\x85\x3e\x3d\x69\ 222 | \x59\x66\x09\x96\x54\x6c\xc9\xc4\xa6\xea\xfd\xc7\x77\xc0\x40\xd7\ 223 | \x0e\xaf\x46\xf7\x6d\xad\x39\x79\xe5\xc5\x36\x0c\x33\x17\x16\x6a\ 224 | \x1c\x89\x4c\x94\xa3\x71\x87\x6a\x94\xdf\x76\x28\xfe\x4e\xaa\xf2\ 225 | \xcc\xb2\x7d\x5a\xaa\xe0\xad\x7a\xd0\xf9\xd4\xb6\xad\x3b\x54\x09\ 226 | \x87\x46\xd4\x52\x4d\x38\x40\x7a\x6d\xeb\x3a\xb7\x8f\xab\x78\xc9"; 227 | check_keystream(&key, &nonce, keystream); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | // basic crypto primitives 2 | 3 | pub mod wrapping; 4 | 5 | pub mod sha2; 6 | pub mod p256; 7 | pub mod poly1305; 8 | pub mod chacha20; 9 | -------------------------------------------------------------------------------- /src/crypto/p256.rs: -------------------------------------------------------------------------------- 1 | // constantly slow implementation of NIST P-256 2 | // http://www.nsa.gov/ia/_files/nist-routines.pdf 3 | // http://point-at-infinity.org/ecc/nisttv 4 | 5 | use crypto::wrapping::*; 6 | use crypto::wrapping::Wrapping as W; 7 | use self::int256::{Int256, ZERO, ONE}; 8 | 9 | // Point on Y^2 = X^3 - 3 * X + B mod P256 where B is some obscure big number 10 | // (x, y, z): (X, Y) = (x/z^2, y/z^3) is point of Y^2 = X^3 - 3 * X + c 11 | // identity (INFTY) is (1, 1, 0) 12 | #[derive(Copy)] 13 | pub struct Point256 { 14 | x: Int256, 15 | y: Int256, 16 | z: Int256, 17 | } 18 | 19 | pub const G: Point256 = Point256 { 20 | x: Int256 { 21 | v: [W(0xd898c296), W(0xf4a13945), W(0x2deb33a0), W(0x77037d81), 22 | W(0x63a440f2), W(0xf8bce6e5), W(0xe12c4247), W(0x6b17d1f2)] 23 | }, 24 | y: Int256 { 25 | v: [W(0x37bf51f5), W(0xcbb64068), W(0x6b315ece), W(0x2bce3357), 26 | W(0x7c0f9e16), W(0x8ee7eb4a), W(0xfe1a7f9b), W(0x4fe342e2)] 27 | }, 28 | z: ONE, 29 | }; 30 | 31 | pub const B: Int256 = Int256 { 32 | v: [W(0x27d2604b), W(0x3bce3c3e), W(0xcc53b0f6), W(0x651d06b0), 33 | W(0x769886bc), W(0xb3ebbd55), W(0xaa3a93e7), W(0x5ac635d8)] 34 | }; 35 | 36 | const INFTY: Point256 = Point256 { 37 | x: ONE, 38 | y: ONE, 39 | z: ZERO, 40 | }; 41 | 42 | impl Clone for Point256 { 43 | fn clone(&self) -> Point256 { 44 | Point256 { 45 | x: self.x.clone(), 46 | y: self.y.clone(), 47 | z: self.z.clone(), 48 | } 49 | } 50 | } 51 | 52 | impl Point256 { 53 | pub fn normalize(&self) -> NPoint256 { 54 | let z2 = self.z.square(); 55 | let z3 = self.z.mult(&z2); 56 | let x = self.x.mult(&z2.inverse()); 57 | let y = self.y.mult(&z3.inverse()); 58 | 59 | NPoint256 { 60 | x: x, 61 | y: y, 62 | } 63 | } 64 | 65 | fn choose(flag: w32, a: &Point256, b: &Point256) -> Point256 { 66 | let x = Int256::choose(flag, &a.x, &b.x); 67 | let y = Int256::choose(flag, &a.y, &b.y); 68 | let z = Int256::choose(flag, &a.z, &b.z); 69 | 70 | Point256 { 71 | x: x, 72 | y: y, 73 | z: z, 74 | } 75 | } 76 | 77 | // compute `self + self` 78 | // self.z must not zero. 79 | fn double(&self) -> Point256 { 80 | let z2 = self.z.square(); 81 | let y2 = self.y.square(); 82 | 83 | // a = 3 * (x - z^2) * (x + z^2) 84 | let a = { 85 | let x_sub_z2 = self.x.sub(&z2); 86 | let x_add_z2 = self.x.add(&z2); 87 | let mult = x_add_z2.mult(&x_sub_z2); // (x - z^2) (x + z^2) 88 | mult.add(&mult).add(&mult) 89 | }; 90 | 91 | // b = x * y^2 92 | let b = self.x.mult(&y2); 93 | let b2 = b.add(&b); 94 | let b4 = b2.add(&b2); 95 | let b8 = b4.add(&b4); 96 | 97 | // x_new = a^2 - 8 * x * y^2 98 | let x_new = a.square().sub(&b8); 99 | 100 | // y_new = (4 * b - x_new) * a - 8 * y^4 101 | let y_new = { 102 | let y4 = y2.square(); 103 | let y4_2 = y4.add(&y4); 104 | let y4_4 = y4_2.add(&y4_2); 105 | let y4_8 = y4_4.add(&y4_4); 106 | 107 | a.mult(&b4.sub(&x_new)).sub(&y4_8) 108 | }; 109 | 110 | // z_new = 2 * z * y = (z + y)^2 - (z^2 + y^2) 111 | let z_new = self.y.add(&self.z).square().sub(&z2.add(&y2)); 112 | 113 | let ret = Point256 { 114 | x: x_new, 115 | y: y_new, 116 | z: z_new, 117 | }; 118 | 119 | // if z is zero, ret is (nonzero, nonzero, zero). 120 | // return normalized INFTY for easy comparison 121 | let self_not_infty = self.z.compare(&ZERO); 122 | let ret = Point256::choose(self_not_infty, &INFTY, &ret); 123 | 124 | ret 125 | } 126 | 127 | fn add(&self, b: &Point256) -> Point256 { 128 | let self_is_zero = self.z.compare(&ZERO); 129 | let b_is_zero = b.z.compare(&ZERO); 130 | 131 | let z2 = self.z.square(); // z^2 132 | let z3 = self.z.mult(&z2); // z^3 133 | let bz2 = b.z.square(); 134 | let bz3 = b.z.mult(&bz2); 135 | 136 | let x = self.x.mult(&bz2); 137 | let y = self.y.mult(&bz3); 138 | let bx = b.x.mult(&z2); 139 | let by = b.y.mult(&z3); 140 | 141 | let xdiff = x.sub(&bx); 142 | let xdiff2 = xdiff.square(); 143 | let xdiff3 = xdiff.mult(&xdiff2); 144 | 145 | let ydiff = y.sub(&by); 146 | let ydiff2 = ydiff.square(); 147 | 148 | let xsum = x.add(&bx); 149 | let ysum = y.add(&by); 150 | 151 | // e = (x + x') * (x - x')^3 152 | let e = xsum.mult(&xdiff2); 153 | 154 | // x_new = (y - y')^2 - e 155 | let x_new = ydiff2.sub(&e); 156 | let x_new_2 = x_new.add(&x_new); 157 | 158 | // y_new = ((y - y') * (e - 2 * x_new) - (y + y') * (x - x')^3) / 2 159 | let y_new = { 160 | let t4 = ysum.mult(&xdiff3); 161 | let t5 = ydiff.mult(&e.sub(&x_new_2)); 162 | let y_new = t5.sub(&t4).divide_by_2(); 163 | y_new 164 | }; 165 | 166 | // z_new = z * z' * (x - x') 167 | let z_new = self.z.mult(&b.z).mult(&xdiff); 168 | 169 | let xdiff_nonzero = xdiff.compare(&ZERO); // 0 if zero 170 | let ydiff_nonzero = ydiff.compare(&ZERO); // 0 if zero 171 | 172 | // if `self == b`, unfortunately, this is `(0, 0, 0)`. 173 | let ret = Point256 { 174 | x: x_new, 175 | y: y_new, 176 | z: z_new, 177 | }; 178 | 179 | // if self == b, return self.double() since ret is (0, 0, 0) 180 | let double = self.double(); 181 | let ret = Point256::choose(xdiff_nonzero | ydiff_nonzero, &double, &ret); 182 | // if self == -b, return INFTY 183 | let ret = Point256::choose(xdiff_nonzero | (W(1) - ydiff_nonzero), &INFTY, &ret); 184 | // if self == INFTY, return b 185 | let ret = Point256::choose(self_is_zero, b, &ret); 186 | // if b == INFTY, return self 187 | let ret = Point256::choose(b_is_zero, self, &ret); 188 | 189 | ret 190 | } 191 | 192 | pub fn mult_scalar(&self, n: &Int256) -> Point256 { 193 | let mut ret = INFTY.clone(); 194 | for i in (0..7).rev() { 195 | for j in (0..8).rev() { 196 | let bit = (n.v[i] >> j) & W(1); 197 | 198 | let ret2 = ret.double(); 199 | let ret3 = ret2.add(self); 200 | 201 | ret = Point256::choose(bit, &ret2, &ret3); 202 | } 203 | } 204 | 205 | ret 206 | } 207 | } 208 | 209 | // normalized 210 | pub struct NPoint256 { 211 | pub x: Int256, 212 | pub y: Int256, 213 | } 214 | 215 | impl NPoint256 { 216 | pub fn to_point(self) -> Point256 { 217 | Point256 { 218 | x: self.x, 219 | y: self.y, 220 | z: ONE, 221 | } 222 | } 223 | 224 | pub fn from_uncompressed_bytes(data: &[u8]) -> Option { 225 | if data.len() != 1 + 32 * 2 { 226 | return None; 227 | } 228 | if data[0] != 0x04 { 229 | return None; 230 | } 231 | 232 | let x = Int256::from_bytes(&data[1..(32 + 1)]); 233 | let y = Int256::from_bytes(&data[(1 + 32)..(1 + 32 * 2)]); 234 | 235 | let (x, y) = match (x, y) { 236 | (Some(x), Some(y)) => (x, y), 237 | _ => return None, 238 | }; 239 | 240 | let p = NPoint256 { 241 | x: x, 242 | y: y, 243 | }; 244 | 245 | // wait, but is p on the curve? 246 | // check if y^2 + 3 * x == x^3 + B 247 | 248 | let y2 = y.square(); 249 | let lhs = y2.add(&x.double().add(&x)); 250 | 251 | let x3 = x.square().mult(&x); 252 | let rhs = x3.add(&B); 253 | 254 | let zero_if_same = lhs.compare(&rhs); 255 | 256 | if zero_if_same.0 != 0 { 257 | return None; 258 | } 259 | 260 | Some(p) 261 | } 262 | 263 | pub fn to_uncompressed_bytes(&self) -> Vec { 264 | // 0x04 || self.x (big endian) || self.y (big endian) 265 | let mut b = Vec::with_capacity(1 + (256 / 8) * 2); 266 | b.push(0x04); // uncompressed 267 | b.extend(&self.x.to_bytes()); 268 | b.extend(&self.y.to_bytes()); 269 | b 270 | } 271 | } 272 | 273 | pub mod int256 { 274 | use crypto::wrapping::*; 275 | use crypto::wrapping::Wrapping as W; 276 | 277 | const LIMBS: usize = 8; 278 | 279 | // 2^32-radix: value = v[0] + 2^32 v[1] + ... + 2^124 v[7] 280 | // value must be < P256 281 | #[derive(Copy)] 282 | pub struct Int256 { 283 | pub v: [W; LIMBS] 284 | } 285 | 286 | // P256 = 2^256 - 2^224 + 2^192 + 2^96 - 1 287 | pub const P256: Int256 = Int256 { 288 | v: [W(0xffffffff), W(0xffffffff), W(0xffffffff), W(0x00000000), 289 | W(0x00000000), W(0x00000000), W(0x00000001), W(0xffffffff)] 290 | }; 291 | pub const ZERO: Int256 = Int256 { v: [W(0); LIMBS] }; 292 | pub const ONE: Int256 = Int256 { v: [W(1), W(0), W(0), W(0), W(0), W(0), W(0), W(0)] }; 293 | 294 | impl Clone for Int256 { 295 | fn clone(&self) -> Int256 { 296 | Int256 { v: self.v } 297 | } 298 | } 299 | 300 | impl Int256 { 301 | // return 0 if self == b. 302 | // otherwise return 1. 303 | pub fn compare(&self, b: &Int256) -> W { 304 | let mut diff = W(0u32); 305 | for i in 0..LIMBS { 306 | diff = diff | self.v[i] ^ b.v[i]; 307 | } 308 | diff = diff | diff >> 16; 309 | diff = diff | diff >> 8; 310 | diff = diff | diff >> 4; 311 | diff = diff | diff >> 2; 312 | diff = diff | diff >> 1; 313 | diff & W(1) 314 | } 315 | 316 | // if flag == 0, returns a 317 | // if flag == 1, returns b 318 | pub fn choose(flag: W, a: &Int256, b: &Int256) -> Int256 { 319 | let mut v = [W(0); LIMBS]; 320 | for i in 0..LIMBS { 321 | v[i] = a.v[i] ^ (flag * (a.v[i] ^ b.v[i])); 322 | } 323 | Int256 { v: v } 324 | } 325 | 326 | // return (value, carry) where 327 | // value = self + b mod 2^256 328 | // carry = if self + b < P256 { 0 } else { 1 } 329 | // i.e. self + b == value + 2^256 * carry 330 | fn add_no_reduce(&self, b: &Int256) -> (Int256, W) { 331 | let mut v = ZERO; 332 | 333 | // invariant: carry <= 1 334 | let mut carry = W(0u64); 335 | for i in 0..LIMBS { 336 | // add <= 2^33 337 | let add = self.v[i].to_w64() + b.v[i].to_w64() + carry; 338 | v.v[i] = add.to_w32(); 339 | carry = add >> 32; 340 | } 341 | (v, carry.to_w32()) 342 | } 343 | 344 | // return (value, carry) where 345 | // value = self - b mod 2^256 346 | // carry = if self > b { 0 } else { 1 } 347 | // i.e. self - b == value - 2^256 * carry 348 | fn sub_no_reduce(&self, b: &Int256) -> (Int256, W) { 349 | let mut v = Int256 { v: [W(0u32); LIMBS] }; 350 | 351 | // invariant: carry_sub <= 1 352 | let mut carry_sub = W(0u64); 353 | for i in 0..LIMBS { 354 | // -2^32 <= sub <= 2^32 355 | let sub = self.v[i].to_w64() - b.v[i].to_w64() - carry_sub; 356 | // if sub < 0, set carry_sub = 1 and sub += 2^32 357 | carry_sub = sub >> 63; 358 | v.v[i] = sub.to_w32(); 359 | } 360 | 361 | (v, carry_sub.to_w32()) 362 | } 363 | 364 | // input may not be reduced 365 | // precondition: `self + carry * 2^256 < 2 * P256` 366 | // return `(self + carry * 2^256) mod P256` 367 | pub fn reduce_once(&self, carry: W) -> Int256 { 368 | let (v, carry_sub) = self.sub_no_reduce(&P256); 369 | debug_assert!(!(carry_sub.0 == 0 && carry.0 == 1)); // precondition violated 370 | let choose_new = carry ^ carry_sub; 371 | Int256::choose(choose_new, &v, self) 372 | } 373 | 374 | pub fn reduce_once_zero(&self) -> Int256 { 375 | self.reduce_once(W(0)) 376 | } 377 | 378 | pub fn add(&self, b: &Int256) -> Int256 { 379 | let (v, carry) = self.add_no_reduce(b); 380 | let v = v.reduce_once(carry); 381 | v 382 | } 383 | 384 | pub fn double(&self) -> Int256 { 385 | // FIXME can be more efficient 386 | self.add(self) 387 | } 388 | 389 | pub fn sub(&self, b: &Int256) -> Int256 { 390 | let (v, carry_sub) = self.sub_no_reduce(b); 391 | // if self - b < 0, carry_sub == 1 and v == 2^256 + self - b 392 | let (v2, _carry_add) = v.add_no_reduce(&P256); 393 | debug_assert!(!(_carry_add.0 == 0 && carry_sub.0 == 1)); 394 | Int256::choose(carry_sub, &v, &v2) 395 | } 396 | 397 | pub fn mult(&self, b: &Int256) -> Int256 { 398 | let mut w = [W(0u64); LIMBS * 2]; 399 | for i in 0..LIMBS { 400 | for j in 0..LIMBS { 401 | let ij = i + j; 402 | let v_ij = self.v[i].to_w64() * b.v[j].to_w64(); 403 | let v_ij_low = v_ij.to_w32().to_w64(); 404 | let v_ij_high = v_ij >> 32; 405 | let w_ij = w[ij] + v_ij_low; 406 | let w_ij_low = w_ij.to_w32().to_w64(); 407 | let w_ij_high = v_ij_high + (w_ij >> 32); 408 | w[ij] = w_ij_low; 409 | w[ij + 1] = w[ij + 1] + w_ij_high; 410 | } 411 | } 412 | 413 | let mut v = [W(0u32); LIMBS * 2]; 414 | let mut carry = W(0u64); 415 | for i in 0..(LIMBS * 2) { 416 | let a = w[i] + carry; 417 | v[i] = a.to_w32(); 418 | carry = a >> 32; 419 | } 420 | debug_assert_eq!(carry.0, 0); 421 | 422 | let mut buf = ZERO; 423 | for i in 0..LIMBS { 424 | buf.v[i] = v[i]; 425 | } 426 | let t = buf.reduce_once_zero(); 427 | 428 | let mut buf = ZERO; 429 | for i in (0..5) { 430 | buf.v[i + 3] = v[i + 11]; 431 | } 432 | let s1 = buf.reduce_once_zero(); 433 | 434 | let mut buf = ZERO; 435 | for i in (0..4) { 436 | buf.v[i + 3] = v[i + 12]; 437 | } 438 | let s2 = buf.reduce_once_zero(); 439 | 440 | let mut buf = ZERO; 441 | for i in (0..3) { 442 | buf.v[i] = v[i + 8]; 443 | } 444 | buf.v[6] = v[14]; 445 | buf.v[7] = v[15]; 446 | let s3 = buf.reduce_once_zero(); 447 | 448 | let mut buf = ZERO; 449 | for i in (0..3) { 450 | buf.v[i] = v[i + 9]; 451 | buf.v[i + 3] = v[i + 13]; 452 | } 453 | buf.v[6] = v[13]; 454 | buf.v[7] = v[8]; 455 | let s4 = buf.reduce_once_zero(); 456 | 457 | let mut buf = ZERO; 458 | for i in (0..3) { 459 | buf.v[i] = v[i + 11]; 460 | } 461 | buf.v[6] = v[8]; 462 | buf.v[7] = v[10]; 463 | let d1 = buf.reduce_once_zero(); 464 | 465 | let mut buf = ZERO; 466 | for i in (0..4) { 467 | buf.v[i] = v[i + 12]; 468 | } 469 | buf.v[6] = v[9]; 470 | buf.v[7] = v[11]; 471 | let d2 = buf.reduce_once_zero(); 472 | 473 | let mut buf = ZERO; 474 | for i in (0..3) { 475 | buf.v[i] = v[i + 13]; 476 | buf.v[i + 3] = v[i + 8]; 477 | } 478 | buf.v[7] = v[12]; 479 | let d3 = buf.reduce_once_zero(); 480 | 481 | let mut buf = ZERO; 482 | for i in (0..3) { 483 | buf.v[i + 3] = v[i + 9]; 484 | } 485 | buf.v[7] = v[13]; 486 | buf.v[0] = v[14]; 487 | buf.v[1] = v[15]; 488 | let d4 = buf.reduce_once_zero(); 489 | 490 | let r = t.add(&s1.double()).add(&s2.double()).add(&s3).add(&s4); 491 | let r = r.sub(&d1.add(&d2).add(&d3).add(&d4)); 492 | r 493 | } 494 | 495 | pub fn square(&self) -> Int256 { 496 | // FIXME can be more efficient 497 | self.mult(self) 498 | } 499 | 500 | // return self^-1 = self^(P256 - 2) 501 | pub fn inverse(&self) -> Int256 { 502 | // 2^256 - 2^224 + 2^192 + 2^96 - 3 503 | // 2^224 (2^32 - 1) + (2^192 - 1) + 2 (2^95 - 1) 504 | // 2^256 = (2^32)^8 505 | // 2^224 = (2^32)^7 506 | 507 | // compute a^(2^n) 508 | fn square_n(a: &Int256, n: usize) -> Int256 { 509 | let mut y = a.clone(); 510 | for _ in (0..n) { 511 | y = y.square(); 512 | } 513 | y 514 | } 515 | 516 | // compute z^(2^n + 1) 517 | // if z == self^(2^n - 1), it returns self^(2^(2n) - 1) 518 | fn z_n(z: &Int256, n: usize) -> Int256 { 519 | let y = square_n(z, n); 520 | y.mult(z) 521 | } 522 | 523 | // for given z_n = a^(2^n - 1), return z_{n+1} = a^(2^(n+1) - 1) 524 | fn z_1(z: &Int256, a: &Int256) -> Int256 { 525 | z.square().mult(a) 526 | } 527 | 528 | // FIXME this routine seems far from optimal 529 | 530 | let z2 = z_n(self, 1); 531 | let z4 = z_n(&z2, 2); 532 | let z8 = z_n(&z4, 4); 533 | let z16 = z_n(&z8, 8); 534 | let z32 = z_n(&z16, 16); 535 | 536 | let z5 = z_1(&z4, self); 537 | 538 | let z10 = z_n(&z5, 5); 539 | let z11 = z_1(&z10, self); 540 | 541 | let z22 = z_n(&z11, 11); 542 | let z23 = z_1(&z22, self); 543 | 544 | let z46 = z_n(&z23, 23); 545 | let z47 = z_1(&z46, self); 546 | 547 | let z94 = z_n(&z47, 47); 548 | let z95 = z_1(&z94, self); 549 | 550 | let y96_2 = z95.square(); 551 | let z96 = y96_2.mult(self); 552 | 553 | let z192 = z_n(&z96, 96); 554 | 555 | let y256_224 = square_n(&z32, 224); 556 | 557 | y256_224.mult(&z192).mult(&y96_2) 558 | } 559 | 560 | pub fn divide_by_2(&self) -> Int256 { 561 | let is_odd = self.v[0] & W(1); 562 | 563 | let mut half_even = ZERO; 564 | for i in 0..(LIMBS - 1) { 565 | half_even.v[i] = (self.v[i] >> 1) | ((self.v[i + 1] & W(1)) << 31); 566 | } 567 | half_even.v[LIMBS - 1] = self.v[LIMBS - 1] >> 1; 568 | 569 | let mut half_odd = ZERO; 570 | let (self_p, carry) = self.add_no_reduce(&P256); 571 | for i in 0..(LIMBS - 1) { 572 | half_odd.v[i] = (self_p.v[i] >> 1) | ((self_p.v[i + 1] & W(1)) << 31); 573 | } 574 | half_odd.v[LIMBS - 1] = (self_p.v[LIMBS - 1] >> 1) | (carry << 31); 575 | // we can assume half_odd < P256 since (self + P256) < P256 * 2 576 | 577 | Int256::choose(is_odd, &half_even, &half_odd) 578 | } 579 | 580 | // big-endian. 581 | pub fn to_bytes(&self) -> Vec { 582 | let mut b = [0u8; 256 / 8]; 583 | for i in (0..LIMBS) { 584 | let vi = self.v[LIMBS - 1 - i]; 585 | for j in (0..4) { 586 | b[i * 4 + j] = (vi >> ((3 - j) * 8)).to_w8().0; 587 | } 588 | } 589 | 590 | b.to_vec() 591 | } 592 | 593 | // big-endian. 594 | pub fn from_bytes(b: &[u8]) -> Option { 595 | if b.len() != 32 { 596 | return None; 597 | } 598 | 599 | let mut x = ZERO; 600 | for i in (0..LIMBS) { 601 | let mut vi = w32(0); 602 | for j in (0..4) { 603 | vi = vi | w8(b[i * 4 + j]).to_w32() << ((3 - j) * 8); 604 | } 605 | x.v[LIMBS - 1 - i] = vi; 606 | } 607 | 608 | Some(x) 609 | } 610 | } 611 | 612 | #[cfg(test)] 613 | mod test { 614 | use super::{Int256, P256, ZERO, ONE}; 615 | use crypto::wrapping::Wrapping as W; 616 | 617 | impl PartialEq for Int256 { 618 | fn eq(&self, b: &Int256) -> bool { 619 | self.v == b.v 620 | } 621 | } 622 | 623 | impl ::std::fmt::Debug for Int256 { 624 | fn fmt(&self, a: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 625 | self.v.iter().map(|s| s.0).collect::>().fmt(a) 626 | } 627 | } 628 | 629 | // FIXME more values 630 | static VALUES_256: &'static [Int256] = &[ 631 | ZERO, 632 | ONE, 633 | Int256 { v: [W(2), W(0), W(0), W(0), W(0), W(0), W(0), W(0)] }, 634 | Int256 { v: [W(1); 8] }, 635 | Int256 { v: [W(0), W(2), W(0), W(2), W(0), W(0), W(0), W(0)] }, 636 | Int256 { v: [W(1), W(2), W(3), W(4), W(5), W(6), W(7), W(8)] }, 637 | Int256 { v: [W(0x0), W(0x0), W(0x0), W(0x0), 638 | W(0xffffffff), W(0xffffffff), W(0), W(0xffffffff)] }, 639 | Int256 { v: [W(0xfffffffe); 8] }, 640 | ]; 641 | 642 | #[test] 643 | fn test_int256_compare() { 644 | for a in VALUES_256.iter() { 645 | for b in VALUES_256.iter() { 646 | if a == b { 647 | assert_eq!(a.compare(b).0, 0); 648 | } else { 649 | assert_eq!(a.compare(b).0, 1); 650 | } 651 | } 652 | } 653 | } 654 | 655 | #[test] 656 | fn test_int256_reduce_once() { 657 | // FIXME more tests 658 | 659 | assert_eq!(ZERO.reduce_once(W(0)), ZERO); 660 | assert_eq!(P256.reduce_once(W(0)), ZERO); 661 | 662 | static P256P1: Int256 = Int256 { 663 | v: [W(0), W(0), W(0), W(1), W(0), W(0), W(1), W(0xffffffff)] 664 | }; 665 | assert_eq!(P256P1.reduce_once(W(0)), ONE); 666 | 667 | // 2^256 == 2^224 - 2^192 - 2^96 + 1 668 | let v = Int256 { 669 | v: [W(1), W(0), W(0), W(0xffffffff), 670 | W(0xffffffff), W(0xffffffff), W(0xfffffffe), W(0)] 671 | }; 672 | assert_eq!(ZERO.reduce_once(W(1)), v); 673 | } 674 | 675 | #[test] 676 | fn test_int256_add() { 677 | for a in VALUES_256.iter() { 678 | assert_eq!(a.add(&ZERO), *a); 679 | 680 | for b in VALUES_256.iter() { 681 | let ab = a.add(b); 682 | assert_eq!(ab, b.add(a)); 683 | for c in VALUES_256.iter() { 684 | let abc = ab.add(c); 685 | let acb = a.add(c).add(b); 686 | assert_eq!(abc, acb); 687 | 688 | let bca = b.add(c).add(a); 689 | assert_eq!(abc, bca); 690 | } 691 | } 692 | } 693 | } 694 | 695 | #[test] 696 | fn test_int256_sub() { 697 | for a in VALUES_256.iter() { 698 | assert_eq!(a.sub(&ZERO), *a); 699 | assert_eq!(a.sub(a), ZERO); 700 | 701 | for b in VALUES_256.iter() { 702 | assert_eq!(a.sub(b).add(b), *a); 703 | 704 | let ab = a.sub(b); 705 | assert_eq!(ab.reduce_once(W(0)), ab); 706 | 707 | for c in VALUES_256.iter() { 708 | let abc = ab.sub(c); 709 | let ac = a.sub(c); 710 | let acb = ac.sub(b); 711 | assert_eq!(abc, acb); 712 | 713 | let bc = b.add(c); 714 | let a_bc = a.sub(&bc); 715 | assert_eq!(abc, a_bc); 716 | } 717 | } 718 | } 719 | } 720 | 721 | #[test] 722 | fn test_int256_mult() { 723 | for a in VALUES_256.iter() { 724 | assert_eq!(a.mult(&ONE), *a); 725 | assert_eq!(a.mult(&ZERO), ZERO); 726 | 727 | for b in VALUES_256.iter() { 728 | let ab = a.mult(b); 729 | assert_eq!(ab, b.mult(a)); 730 | for c in VALUES_256.iter() { 731 | let ac = a.mult(c); 732 | 733 | let abc = ab.mult(c); 734 | let acb = ac.mult(b); 735 | assert_eq!(abc, acb); 736 | 737 | let bca = b.mult(c).mult(a); 738 | assert_eq!(abc, bca); 739 | 740 | let abac = ab.add(&ac); 741 | let bc = b.add(c); 742 | let abc = a.mult(&bc); 743 | assert_eq!(abac, abc); 744 | } 745 | } 746 | } 747 | } 748 | 749 | #[test] 750 | fn test_int256_inverse() { 751 | assert_eq!(ONE.inverse(), ONE); 752 | 753 | for a in VALUES_256.iter() { 754 | if *a == ZERO { 755 | continue; 756 | } 757 | 758 | let a_inv = a.inverse(); 759 | let a_inv_a = a_inv.mult(a); 760 | assert_eq!(a_inv_a, ONE); 761 | 762 | let a_inv_inv = a_inv.inverse(); 763 | assert_eq!(a_inv_inv, *a); 764 | } 765 | } 766 | 767 | #[test] 768 | fn test_int256_divide_by_2() { 769 | for a in VALUES_256.iter() { 770 | let a_half = a.divide_by_2(); 771 | assert_eq!(a_half, a_half.reduce_once(W(0))); 772 | let a_half_2 = a_half.add(&a_half); 773 | assert_eq!(*a, a_half_2); 774 | } 775 | } 776 | 777 | #[test] 778 | fn test_from_bytes() { 779 | for a in VALUES_256.iter() { 780 | let b = a.to_bytes(); 781 | let aa = Int256::from_bytes(&b).expect("to_bytes failed"); 782 | assert_eq!(*a, aa); 783 | } 784 | } 785 | } 786 | } 787 | -------------------------------------------------------------------------------- /src/crypto/poly1305.rs: -------------------------------------------------------------------------------- 1 | // http://cr.yp.to/mac/poly1305-20050329.pdf 2 | 3 | use crypto::wrapping::*; 4 | 5 | macro_rules! choose_impl { 6 | ($s: ident, $t:ty, $($a:expr)+) => ( 7 | impl $s { 8 | fn choose(flag: $t, a: &$s, b: &$s) -> $s { 9 | $s { 10 | v: [ 11 | $( 12 | a.v[$a] ^ (flag * (a.v[$a] ^ b.v[$a])), 13 | )+ 14 | ] 15 | } 16 | } 17 | } 18 | ) 19 | } 20 | 21 | // radix-2^26 (26 == 130/5) 22 | // value = v[0] + 2^26 v[1] + 2^52 v[2] + 2^78 v[3] + 2^104 v[4] 23 | // lazy normalization: v[i] <= 2^32 - 1 24 | // http://cr.yp.to/highspeed/neoncrypto-20120320.pdf 25 | pub struct Int1305 { 26 | v: [u32; 5], 27 | } 28 | 29 | pub const ZERO: Int1305 = Int1305 { v: [0; 5] }; 30 | 31 | choose_impl! {Int1305, u32, 0 1 2 3 4} 32 | 33 | impl Int1305 { 34 | // no reduction. 35 | fn add(&self, b: &Int1305) -> Int1305 { 36 | macro_rules! add_digit { 37 | ($a:expr, $b:expr, $c:expr, $($i:expr)+) => ({ 38 | $( 39 | $c[$i] = $a[$i] + $b[$i]; 40 | )+ 41 | }) 42 | } 43 | 44 | let mut ret = [0; 5]; 45 | 46 | add_digit!(self.v, b.v, ret, 0 1 2 3 4); 47 | 48 | Int1305 { v: ret } 49 | } 50 | 51 | fn mult(&self, b: &Int1305) -> Int1305 { 52 | let b5 = [b.v[0] * 5, b.v[1] * 5, b.v[2] * 5, b.v[3] * 5, b.v[4] * 5]; 53 | 54 | macro_rules! m { 55 | ($i:expr, $j:expr) => ((self.v[$i] as u64) * (b.v[$j] as u64)) 56 | } 57 | macro_rules! m5 { 58 | ($i:expr, $j:expr) => ((self.v[$i] as u64) * (b5[$j] as u64)) 59 | } 60 | 61 | let mut v: [u64; 5] = [ 62 | m!(0, 0) + m5!(1, 4) + m5!(2, 3) + m5!(3, 2) + m5!(4, 1), 63 | m!(0, 1) + m!(1, 0) + m5!(2, 4) + m5!(3, 3) + m5!(4, 2), 64 | m!(0, 2) + m!(1, 1) + m!(2, 0) + m5!(3, 4) + m5!(4, 3), 65 | m!(0, 3) + m!(1, 2) + m!(2, 1) + m!(3, 0) + m5!(4, 4), 66 | m!(0, 4) + m!(1, 3) + m!(2, 2) + m!(3, 1) + m!(4, 0), 67 | ]; 68 | 69 | // if self and b is reduced, v[i] <= 25 * (2^26 - 1)^2 70 | 71 | let mut carry = 0; 72 | 73 | macro_rules! reduce_digit { 74 | ($i:expr) => ({ 75 | v[$i] += carry; 76 | carry = v[$i] >> 26; 77 | v[$i] &= (1 << 26) - 1; 78 | }) 79 | } 80 | 81 | reduce_digit!(0); // carry <= 25 * (2^26 - 1) 82 | reduce_digit!(1); // again, carry <= 25 * (2^26 - 1) 83 | reduce_digit!(2); 84 | reduce_digit!(3); 85 | reduce_digit!(4); 86 | 87 | debug_assert_eq!(v[0] >> 32, 0); 88 | debug_assert_eq!(v[1] >> 32, 0); 89 | debug_assert_eq!(v[2] >> 32, 0); 90 | debug_assert_eq!(v[3] >> 32, 0); 91 | debug_assert_eq!(v[4] >> 32, 0); 92 | 93 | debug_assert!(carry <= 25 * ((1 << 26) - 1)); 94 | 95 | carry *= 5; // carry <= 125 * (2^26 - 1) 96 | 97 | reduce_digit!(0); // carry <= 125 98 | reduce_digit!(1); // carry <= 1 99 | reduce_digit!(2); 100 | reduce_digit!(3); 101 | reduce_digit!(4); 102 | 103 | debug_assert_eq!(v[0] >> 32, 0); 104 | debug_assert_eq!(v[1] >> 32, 0); 105 | debug_assert_eq!(v[2] >> 32, 0); 106 | debug_assert_eq!(v[3] >> 32, 0); 107 | debug_assert_eq!(v[4] >> 32, 0); 108 | 109 | debug_assert!(carry <= 1); 110 | 111 | carry *= 5; // carry <= 5 112 | 113 | reduce_digit!(0); 114 | reduce_digit!(1); 115 | reduce_digit!(2); 116 | reduce_digit!(3); 117 | reduce_digit!(4); 118 | 119 | debug_assert_eq!(v[0] >> 32, 0); 120 | debug_assert_eq!(v[1] >> 32, 0); 121 | debug_assert_eq!(v[2] >> 32, 0); 122 | debug_assert_eq!(v[3] >> 32, 0); 123 | debug_assert_eq!(v[4] >> 32, 0); 124 | 125 | debug_assert_eq!(carry, 0); 126 | 127 | Int1305 { v: [v[0] as u32, v[1] as u32, v[2] as u32, v[3] as u32, v[4] as u32] } 128 | } 129 | 130 | fn from_bytes(msg: &[u8; 16]) -> Int1305 { 131 | macro_rules! b4 { 132 | ($i:expr, $n:expr) => ( 133 | ((msg[$i] as u32) >> $n) | 134 | ((msg[$i+1] as u32) << (8 - $n)) | 135 | ((msg[$i+2] as u32) << (16 - $n)) | 136 | (((msg[$i+3] as u32) & ((1 << (2 + $n)) - 1)) << (24 - $n)) 137 | ) 138 | } 139 | macro_rules! b3 { 140 | ($i:expr, $n:expr) => ( 141 | ((msg[$i] as u32) >> $n) | 142 | ((msg[$i+1] as u32) << (8 - $n)) | 143 | ((msg[$i+2] as u32) << (16 - $n)) 144 | ) 145 | } 146 | 147 | let v = [ 148 | b4!(0, 0), 149 | b4!(3, 26 * 1 - 8 * 3), 150 | b4!(6, 26 * 2 - 8 * 6), 151 | b4!(9, 26 * 3 - 8 * 9), 152 | b3!(13, 0), 153 | ]; 154 | 155 | debug_assert_eq!(v[0] >> 26, 0); 156 | debug_assert_eq!(v[1] >> 26, 0); 157 | debug_assert_eq!(v[2] >> 26, 0); 158 | debug_assert_eq!(v[3] >> 26, 0); 159 | debug_assert_eq!(v[4] >> 26, 0); 160 | 161 | Int1305 { v: v } 162 | } 163 | 164 | // self must be reduced 165 | fn normalize(&self) -> Int1305 { 166 | // we have two possibilities: (a) 0 <= self <= p - 1, (b) p <= self <= 2 * p - 1 167 | // we must return self - p in case of (b) 168 | // if 2^130 - 5 <= a + b <= 2^131 - 11, 2^130 <= a + b + 5 <= 2^131 - 6 169 | // therefore (a + b + 5) >> 130 == 1 and (a + b - p) == (a + b + 5) & !(1 << 130) 170 | // here we compute a + b + 5 + (0b111...111 << 130) to eliminate `& !(1 << 130)` part 171 | 172 | static P5: [u64; 5] = [5, 0, 0, 0, ((1 << 6) - 1) << 26]; 173 | 174 | let mut ret_b = Int1305 { v: [0; 5] }; 175 | let mut carry = 0; 176 | 177 | macro_rules! add_digit { 178 | ($($i:expr)+) => ({ 179 | $( 180 | let v = (self.v[$i] as u64) + P5[$i] + carry; 181 | carry = v >> 26; 182 | ret_b.v[$i] = (v & ((1 << 26) - 1)) as u32; 183 | )+ 184 | }) 185 | } 186 | add_digit! {0 1 2 3} 187 | ret_b.v[4] = ((self.v[4] as u64) + P5[4] + carry) as u32; 188 | 189 | let is_case_b = ret_b.v[4] >> 31; 190 | 191 | Int1305::choose(is_case_b, &ret_b, self) 192 | } 193 | } 194 | 195 | pub fn authenticate(msg: &[u8], r: &[u8; 16], aes: &[u8; 16]) -> [u8; 16] { 196 | let mut r = *r; 197 | r[3] &= 15; 198 | r[4] &= 252; 199 | r[7] &= 15; 200 | r[8] &= 252; 201 | r[11] &= 15; 202 | r[12] &= 252; 203 | r[15] &= 15; 204 | 205 | let r = Int1305::from_bytes(&r); 206 | 207 | // c[0] * r^q + c[1] * r^(q-1) + ... + c[q-1] * r 208 | // = (((c[0] * r + c[1]) * r) + ... + c[q-1]) * r 209 | let mut h = ZERO; 210 | 211 | let len = msg.len(); 212 | let chunks = (len + 15) / 16; 213 | for i in (0..chunks) { 214 | // c[i] = sum_i (m[16*i] * 2^8) + 2^128 215 | 216 | let mut m = [0u8; 16]; 217 | let m_len = if i < chunks - 1 { 16 } else { len - 16 * i }; 218 | for j in (0..m_len) { 219 | m[j] = msg[i * 16 + j]; 220 | } 221 | let mut c = Int1305::from_bytes(&m); 222 | 223 | // append 1 to the chunk 224 | let flag_pos = m_len * 8; 225 | c.v[flag_pos / 26] |= 1 << (flag_pos % 26); 226 | 227 | h = c.add(&h).mult(&r); 228 | } 229 | 230 | let h = h.normalize(); 231 | let h = { 232 | macro_rules! b { 233 | ($i:expr, $n:expr) => ( 234 | Wrapping(h.v[$i] >> $n).to_w8().0 235 | ); 236 | ($i:expr, $n:expr, $m:expr) => ( 237 | Wrapping((h.v[$i] >> $n) | (h.v[$i+1] & ((1 << $m) - 1)) << (8 - $m)).to_w8().0 238 | ); 239 | } 240 | 241 | [ 242 | b!(0, 0 + 0), 243 | b!(0, 0 + 8), 244 | b!(0, 0 + 16), 245 | b!(0, 0 + 24, 6), // 6 == 8 * 4 - 26 * 1 246 | 247 | b!(1, 6 + 0), 248 | b!(1, 6 + 8), 249 | b!(1, 6 + 16, 4), // 4 == 8 * 7 - 26 * 2 250 | 251 | b!(2, 4 + 0), 252 | b!(2, 4 + 8), 253 | b!(2, 4 + 16, 2), // 2 == 8 * 10 - 26 * 3 254 | 255 | b!(3, 2 + 0), 256 | b!(3, 2 + 8), 257 | b!(3, 2 + 16), 258 | 259 | b!(4, 0 + 0), 260 | b!(4, 0 + 8), 261 | b!(4, 0 + 16), 262 | //b!(4, 0 + 24), // discard 2 bits: mod 2^128 263 | ] 264 | }; 265 | 266 | // h + aes (mod 2^128) 267 | let ret = { 268 | let mut ret = [0; 16]; 269 | 270 | macro_rules! to_u32 { 271 | ($a:expr, $i:expr) => ( 272 | ($a[$i] as u32) | ($a[$i + 1] as u32) << 8 | 273 | ($a[$i + 2] as u32) << 16 | ($a[$i + 3] as u32) << 24 274 | ) 275 | } 276 | 277 | let h32 = [to_u32!(h, 0), to_u32!(h, 4), to_u32!(h, 8), to_u32!(h, 12)]; 278 | let aes32 = [to_u32!(aes, 0), to_u32!(aes, 4), to_u32!(aes, 8), to_u32!(aes, 12)]; 279 | 280 | let mut carry = 0; 281 | 282 | let sum = (h32[0] as u64) + (aes32[0] as u64) + carry; 283 | let ret0 = sum as u32; 284 | carry = sum >> 32; 285 | 286 | let sum = (h32[1] as u64) + (aes32[1] as u64) + carry; 287 | let ret1 = sum as u32; 288 | carry = sum >> 32; 289 | 290 | let sum = (h32[2] as u64) + (aes32[2] as u64) + carry; 291 | let ret2 = sum as u32; 292 | carry = sum >> 32; 293 | 294 | let sum = (h32[3] as u64) + (aes32[3] as u64) + carry; 295 | let ret3 = sum as u32; 296 | 297 | macro_rules! to_u8 { 298 | ($a:expr, $r:expr, $i:expr) => ({ 299 | $a[$i] = Wrapping($r).to_w8().0; 300 | $a[$i+1] = Wrapping($r >> 8).to_w8().0; 301 | $a[$i+2] = Wrapping($r >> 16).to_w8().0; 302 | $a[$i+3] = Wrapping($r >> 24).to_w8().0; 303 | }) 304 | } 305 | 306 | to_u8!(ret, ret0, 0); 307 | to_u8!(ret, ret1, 4); 308 | to_u8!(ret, ret2, 8); 309 | to_u8!(ret, ret3, 12); 310 | 311 | ret 312 | }; 313 | 314 | ret 315 | } 316 | 317 | #[cfg(test)] 318 | mod test { 319 | use super::Int1305; 320 | 321 | static COEFFS: &'static [Int1305] = &[ 322 | super::ZERO, 323 | Int1305 { v: [1, 0, 0, 0, 0] }, 324 | Int1305 { v: [1, 1, 1, 1, 1] }, 325 | Int1305 { v: [ 326 | (1 << 26) - 1, 327 | (1 << 26) - 1, 328 | (1 << 26) - 1, 329 | (1 << 26) - 1, 330 | (1 << 25) - 1, 331 | ] }, 332 | 333 | Int1305 { v: [0, 1, 2, 3, 4] }, 334 | Int1305 { v: [5, 6, 7, 8, 9] }, 335 | Int1305 { v: [1 << 23, 3 << 20, 0, 5 << 21, 0] }, 336 | Int1305 { v: [1 << 20; 5] }, 337 | Int1305 { v: [1 << 24; 5] }, 338 | Int1305 { v: [(1 << 25) - 1; 5] }, 339 | Int1305 { v: [0x3fffffb - 1, 0x3ffffff, 0x3ffffff, 0x3ffffff, 0x3ffffff] }, // p - 1 340 | ]; 341 | 342 | impl PartialEq for Int1305 { 343 | fn eq(&self, b: &Int1305) -> bool { 344 | self.normalize().v == b.normalize().v 345 | } 346 | } 347 | 348 | impl ::std::fmt::Debug for Int1305 { 349 | fn fmt(&self, a: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 350 | (self.v).fmt(a) 351 | } 352 | } 353 | 354 | #[test] 355 | fn test_add() { 356 | // (a + b) + c == a + (b + c) 357 | for a in COEFFS.iter() { 358 | for b in COEFFS.iter() { 359 | for c in COEFFS.iter() { 360 | let abc = a.add(b).add(c); 361 | 362 | let bca = b.add(c).add(a); 363 | assert_eq!(abc, bca); 364 | 365 | let acb = a.add(c).add(b); 366 | assert_eq!(abc, acb); 367 | } 368 | } 369 | } 370 | } 371 | 372 | #[test] 373 | fn test_normalize() { 374 | let p = Int1305 { v: [0x3fffffb, 0x3ffffff, 0x3ffffff, 0x3ffffff, 0x3ffffff] }; 375 | assert_eq!(&p.normalize().v, &super::ZERO.v); 376 | 377 | let large = Int1305 { v: [0, 10, 5, 10, 1 << 26] }; 378 | let small = Int1305 { v: [5, 10, 5, 10, 0] }; 379 | 380 | assert_eq!(&large.normalize().v, &small.v); 381 | assert_eq!(&small.normalize().v, &small.v); 382 | 383 | for a in COEFFS.iter() { 384 | assert_eq!(a.normalize(), *a); 385 | } 386 | } 387 | 388 | #[test] 389 | fn test_mult() { 390 | // (a * b) * c == a * (b * c) 391 | for a in COEFFS.iter() { 392 | for b in COEFFS.iter() { 393 | for c in COEFFS.iter() { 394 | let abc = a.mult(b).mult(c).normalize(); 395 | 396 | let bca = b.mult(c).mult(a).normalize(); 397 | assert_eq!(abc, bca); 398 | 399 | let acb = a.mult(c).mult(b).normalize(); 400 | assert_eq!(abc, acb); 401 | } 402 | } 403 | } 404 | } 405 | 406 | #[test] 407 | fn test_poly1305_examples() { 408 | // from Appendix B of reference paper 409 | static VALUES: &'static [(&'static [u8], [u8; 16], [u8; 16], [u8; 16])] = &[ 410 | // (msg, r, aes, result) 411 | (&[0xf3, 0xf6], 412 | [0x85, 0x1f, 0xc4, 0x0c, 0x34, 0x67, 0xac, 0x0b, 413 | 0xe0, 0x5c, 0xc2, 0x04, 0x04, 0xf3, 0xf7, 0x00], 414 | [0x58, 0x0b, 0x3b, 0x0f, 0x94, 0x47, 0xbb, 0x1e, 415 | 0x69, 0xd0, 0x95, 0xb5, 0x92, 0x8b, 0x6d, 0xbc], 416 | [0xf4, 0xc6, 0x33, 0xc3, 0x04, 0x4f, 0xc1, 0x45, 417 | 0xf8, 0x4f, 0x33, 0x5c, 0xb8, 0x19, 0x53, 0xde]), 418 | 419 | (&[], 420 | [0xa0, 0xf3, 0x08, 0x00, 0x00, 0xf4, 0x64, 0x00, 421 | 0xd0, 0xc7, 0xe9, 0x07, 0x6c, 0x83, 0x44, 0x03], 422 | [0xdd, 0x3f, 0xab, 0x22, 0x51, 0xf1, 0x1a, 0xc7, 423 | 0x59, 0xf0, 0x88, 0x71, 0x29, 0xcc, 0x2e, 0xe7], 424 | [0xdd, 0x3f, 0xab, 0x22, 0x51, 0xf1, 0x1a, 0xc7, 425 | 0x59, 0xf0, 0x88, 0x71, 0x29, 0xcc, 0x2e, 0xe7]), 426 | 427 | (&[0x66, 0x3c, 0xea, 0x19, 0x0f, 0xfb, 0x83, 0xd8, 428 | 0x95, 0x93, 0xf3, 0xf4, 0x76, 0xb6, 0xbc, 0x24, 429 | 0xd7, 0xe6, 0x79, 0x10, 0x7e, 0xa2, 0x6a, 0xdb, 430 | 0x8c, 0xaf, 0x66, 0x52, 0xd0, 0x65, 0x61, 0x36], 431 | [0x48, 0x44, 0x3d, 0x0b, 0xb0, 0xd2, 0x11, 0x09, 432 | 0xc8, 0x9a, 0x10, 0x0b, 0x5c, 0xe2, 0xc2, 0x08], 433 | [0x83, 0x14, 0x9c, 0x69, 0xb5, 0x61, 0xdd, 0x88, 434 | 0x29, 0x8a, 0x17, 0x98, 0xb1, 0x07, 0x16, 0xef], 435 | [0x0e, 0xe1, 0xc1, 0x6b, 0xb7, 0x3f, 0x0f, 0x4f, 436 | 0xd1, 0x98, 0x81, 0x75, 0x3c, 0x01, 0xcd, 0xbe]), 437 | 438 | (&[0xab, 0x08, 0x12, 0x72, 0x4a, 0x7f, 0x1e, 0x34, 439 | 0x27, 0x42, 0xcb, 0xed, 0x37, 0x4d, 0x94, 0xd1, 440 | 0x36, 0xc6, 0xb8, 0x79, 0x5d, 0x45, 0xb3, 0x81, 441 | 0x98, 0x30, 0xf2, 0xc0, 0x44, 0x91, 0xfa, 0xf0, 442 | 0x99, 0x0c, 0x62, 0xe4, 0x8b, 0x80, 0x18, 0xb2, 443 | 0xc3, 0xe4, 0xa0, 0xfa, 0x31, 0x34, 0xcb, 0x67, 444 | 0xfa, 0x83, 0xe1, 0x58, 0xc9, 0x94, 0xd9, 0x61, 445 | 0xc4, 0xcb, 0x21, 0x09, 0x5c, 0x1b, 0xf9], 446 | [0x12, 0x97, 0x6a, 0x08, 0xc4, 0x42, 0x6d, 0x0c, 447 | 0xe8, 0xa8, 0x24, 0x07, 0xc4, 0xf4, 0x82, 0x07], 448 | [0x80, 0xf8, 0xc2, 0x0a, 0xa7, 0x12, 0x02, 0xd1, 449 | 0xe2, 0x91, 0x79, 0xcb, 0xcb, 0x55, 0x5a, 0x57], 450 | [0x51, 0x54, 0xad, 0x0d, 0x2c, 0xb2, 0x6e, 0x01, 451 | 0x27, 0x4f, 0xc5, 0x11, 0x48, 0x49, 0x1f, 0x1b]), 452 | ]; 453 | 454 | for &(msg, ref r, ref aes, ref expected) in VALUES.iter() { 455 | let output = super::authenticate(msg, r, aes); 456 | assert_eq!(&output[..], &expected[..]); 457 | } 458 | } 459 | } 460 | -------------------------------------------------------------------------------- /src/crypto/sha2.rs: -------------------------------------------------------------------------------- 1 | // http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf 2 | // not seriously audited. 3 | // no bit-level support. sorry 4 | 5 | use crypto::wrapping::*; 6 | 7 | static K: [u32; 64] = [ 8 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 9 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 10 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 11 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 12 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 13 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 14 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 15 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 16 | ]; 17 | 18 | pub fn sha256(msg: &[u8]) -> [u8; 32] { 19 | fn rot(a: w32, b: usize) -> w32 { 20 | (a >> b) | (a << (32 - b)) 21 | } 22 | 23 | let len = msg.len(); 24 | let mut msg = msg.to_vec(); // FIXME: do not allocate 25 | 26 | msg.push(0x80); 27 | let padding_len = (w64(64 - 8 - 1) - w64(len as u64)) & w64(63); 28 | for _ in 0..(padding_len.0) { 29 | msg.push(0); 30 | } 31 | 32 | let bitlen = (len as u64) * 8; // FIXME: disallow `len >= 2^64 / 8` 33 | for i in (0..8).rev() { 34 | let b = (w64(bitlen) >> (8 * i)).to_w8().0; 35 | msg.push(b); 36 | } 37 | 38 | debug_assert_eq!(msg.len() % (512 / 8), 0); 39 | 40 | let nblk = msg.len() / (512 / 8); 41 | 42 | let mut val: [w32; 8] = [ 43 | w32(0x6a09e667), w32(0xbb67ae85), w32(0x3c6ef372), w32(0xa54ff53a), 44 | w32(0x510e527f), w32(0x9b05688c), w32(0x1f83d9ab), w32(0x5be0cd19), 45 | ]; 46 | 47 | for i in 0..nblk { 48 | let w = { 49 | let mut w = [w32(0u32); 64]; 50 | for j in 0..16 { 51 | let b0 = w8(msg[i * 64 + j * 4 + 0]).to_w32(); 52 | let b1 = w8(msg[i * 64 + j * 4 + 1]).to_w32(); 53 | let b2 = w8(msg[i * 64 + j * 4 + 2]).to_w32(); 54 | let b3 = w8(msg[i * 64 + j * 4 + 3]).to_w32(); 55 | w[j] = (b0 << 8 * 3) | (b1 << 8 * 2) | (b2 << 8 * 1) | b3; 56 | } 57 | 58 | for j in 16..64 { 59 | let wj15 = w[j - 15]; 60 | let sig0 = rot(wj15, 7) ^ rot(wj15, 18) ^ (wj15 >> 3); 61 | 62 | let wj2 = w[j - 2]; 63 | let sig1 = rot(wj2, 17) ^ rot(wj2, 19) ^ (wj2 >> 10); 64 | w[j] = sig1 + w[j - 7] + sig0 + w[j - 16]; 65 | } 66 | 67 | w 68 | }; 69 | 70 | let mut a: w32 = val[0]; 71 | let mut b: w32 = val[1]; 72 | let mut c: w32 = val[2]; 73 | let mut d: w32 = val[3]; 74 | let mut e: w32 = val[4]; 75 | let mut f: w32 = val[5]; 76 | let mut g: w32 = val[6]; 77 | let mut h: w32 = val[7]; 78 | 79 | for j in 0..64 { 80 | let ch = (e & f) ^ ((!e) & g); 81 | let maj = (a & b) ^ (a & c) ^ (b & c); 82 | 83 | let sig0 = rot(a, 2) ^ rot(a, 13) ^ rot(a, 22); 84 | let sig1 = rot(e, 6) ^ rot(e, 11) ^ rot(e, 25); 85 | 86 | let t1 = h + sig1 + ch + w32(K[j]) + w[j]; 87 | let t2 = sig0 + maj; 88 | 89 | h = g; 90 | g = f; 91 | f = e; 92 | e = d + t1; 93 | d = c; 94 | c = b; 95 | b = a; 96 | a = t1 + t2; 97 | } 98 | 99 | val[0] = val[0] + a; 100 | val[1] = val[1] + b; 101 | val[2] = val[2] + c; 102 | val[3] = val[3] + d; 103 | val[4] = val[4] + e; 104 | val[5] = val[5] + f; 105 | val[6] = val[6] + g; 106 | val[7] = val[7] + h; 107 | } 108 | 109 | let mut ret = [0u8; 32]; 110 | for i in 0..8 { 111 | ret[i * 4 + 0] = (val[i] >> 8 * 3).to_w8().0; 112 | ret[i * 4 + 1] = (val[i] >> 8 * 2).to_w8().0; 113 | ret[i * 4 + 2] = (val[i] >> 8 * 1).to_w8().0; 114 | ret[i * 4 + 3] = val[i].to_w8().0; 115 | } 116 | ret 117 | } 118 | 119 | #[cfg(test)] 120 | mod test { 121 | use super::sha256; 122 | 123 | #[test] 124 | fn test_sha256() { 125 | static ANSWERS: &'static [(&'static [u8], &'static [u8])] = &[ 126 | (b"", 127 | b"\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\ 128 | \x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55"), 129 | (b"abc", 130 | b"\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23\ 131 | \xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad"), 132 | (b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 133 | b"\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39\ 134 | \xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1"), 135 | ]; 136 | 137 | for &(input, expected) in ANSWERS.iter() { 138 | let computed = sha256(input); 139 | assert_eq!(expected, &computed); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/crypto/wrapping.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | 3 | // NOTE: since there is no const fn (yet), you can't use `w32(100)` function 4 | // for consts and statics. (workaround: use `Wrapping(100)`.) 5 | 6 | pub use std::num::Wrapping; 7 | 8 | pub trait ToWrapping { 9 | fn to_w64(self) -> w64; 10 | fn to_w32(self) -> w32; 11 | fn to_w16(self) -> w16; 12 | fn to_w8(self) -> w8; 13 | } 14 | 15 | macro_rules! to_wrapping_impl_fn { 16 | ($name:ident, $ut:ty, $wt:ty, $size:expr) => ( 17 | #[inline(always)] 18 | fn $name(self) -> $wt { 19 | // NOTE: `WrappingOps::wrapping_as_u64()` can be used when implemented 20 | let val: u64 = self.0 as u64; 21 | let val: u64 = val & ((1 << $size) - 1); 22 | let val: $ut = val as $ut; 23 | Wrapping(val) 24 | } 25 | ) 26 | } 27 | 28 | macro_rules! wrapping_type { 29 | ($wt:ident, $ut:ident) => ( 30 | pub type $wt = Wrapping<$ut>; 31 | 32 | #[inline(always)] 33 | pub fn $wt(val: $ut) -> $wt { 34 | Wrapping(val) 35 | } 36 | 37 | impl ToWrapping for Wrapping<$ut> { 38 | #[inline(always)] 39 | fn to_w64(self) -> w64 { 40 | Wrapping(self.0 as u64) 41 | } 42 | 43 | to_wrapping_impl_fn!(to_w8, u8, w8, 8); 44 | to_wrapping_impl_fn!(to_w16, u16, w16, 16); 45 | to_wrapping_impl_fn!(to_w32, u32, w32, 32); 46 | } 47 | 48 | ) 49 | } 50 | 51 | wrapping_type!(w64, u64); 52 | wrapping_type!(w32, u32); 53 | wrapping_type!(w16, u16); 54 | wrapping_type!(w8, u8); 55 | 56 | #[cfg(test)] 57 | mod test { 58 | use super::*; 59 | 60 | #[test] 61 | fn test_to_wrapping() { 62 | const V: w64 = Wrapping(0x12345678_87654321); 63 | assert_eq!(V.to_w32().0, 0x87654321); 64 | assert_eq!(V.to_w16().0, 0x4321); 65 | assert_eq!(V.to_w8().0, 0x21); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/handshake.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | 3 | use util::{ReadExt, WriteExt}; 4 | use tls::TLS_VERSION; 5 | use tls_result::TlsResult; 6 | use tls_result::TlsErrorKind::{InternalError, UnexpectedMessage, DecodeError}; 7 | use tls_item::{TlsItem, DummyItem, ObscureData}; 8 | use signature::SignatureAndHashAlgorithmVec; 9 | use cipher::CipherSuite; 10 | 11 | // This is actually `struct { gmt_unix_time: u32, random_bytes: [u8, ..28] }` 12 | // cf: http://tools.ietf.org/html/draft-mathewson-no-gmtunixtime-00 13 | tls_array!(Random = [u8, ..32]); 14 | 15 | tls_vec!(CipherSuiteVec = CipherSuite(2, (1 << 16) - 2)); 16 | 17 | tls_enum!(u8, enum CompressionMethod { 18 | null(0), 19 | DEFLATE(1) // RFC 3749 20 | }); 21 | tls_vec!(CompressionMethodVec = CompressionMethod(1, (1 << 8) - 1)); 22 | 23 | tls_struct!(struct ProtocolVersion { major: u8, minor: u8 }); 24 | 25 | tls_vec!(SessionId = u8(0, 32)); 26 | 27 | tls_vec!(Asn1Cert = u8(1, (1 << 24) - 1)); 28 | 29 | // RFC 4492 30 | 31 | tls_enum!(u16, enum NamedCurve { 32 | sect163k1 (1), sect163r1 (2), sect163r2 (3), 33 | sect193r1 (4), sect193r2 (5), sect233k1 (6), 34 | sect233r1 (7), sect239k1 (8), sect283k1 (9), 35 | sect283r1 (10), sect409k1 (11), sect409r1 (12), 36 | sect571k1 (13), sect571r1 (14), secp160k1 (15), 37 | secp160r1 (16), secp160r2 (17), secp192k1 (18), 38 | secp192r1 (19), secp224k1 (20), secp224r1 (21), 39 | secp256k1 (22), secp256r1 (23), secp384r1 (24), 40 | secp521r1 (25), 41 | arbitrary_explicit_prime_curves(0xFF01), 42 | arbitrary_explicit_char2_curves(0xFF02) 43 | }); 44 | tls_vec!(EllipticCurveList = NamedCurve(1, (1 << 16) - 1)); 45 | 46 | tls_enum!(u8, enum ECPointFormat { 47 | uncompressed (0), ansiX962_compressed_prime (1), 48 | ansiX962_compressed_char2 (2) 49 | }); 50 | tls_vec!(ECPointFormatList = ECPointFormat(1, (1 << 8) - 1)); 51 | 52 | // Hello extension (RFC 5246, 7.4.1.4.) is defined as like: 53 | // tls_vec!(ExtensionData = opaque(1, (1 << 16) - 1)); 54 | // tls_struct!(struct Extension { 55 | // extension_type: u16, 56 | // extension_data: ExtensionData, 57 | // }); 58 | // 59 | // after unrolling `ExtensionData`: 60 | // struct Extension { 61 | // extension_type: u16, 62 | // extension_data_size: u16, 63 | // // type determined by extension_type 64 | // // size determined by extension_data_size 65 | // extension_data: T, 66 | // } 67 | macro_rules! tls_hello_extension { 68 | ( 69 | enum $enum_name:ident { 70 | $( 71 | $ext_name:ident($body_ty:ident) = $ext_num:tt 72 | ),+ 73 | } 74 | ) => ( 75 | #[allow(non_camel_case_types)] 76 | pub enum $enum_name { 77 | $( 78 | $ext_name($body_ty), 79 | )+ 80 | // extension_type, extension_data 81 | Unknown(u16, Vec), 82 | } 83 | 84 | impl TlsItem for $enum_name { 85 | fn tls_write(&self, writer: &mut W) -> TlsResult<()> { 86 | match *self { 87 | $( 88 | $enum_name::$ext_name(ref body) => { 89 | try_write_num!(u16, writer, tt_to_expr!($ext_num)); 90 | try_write_num!(u16, writer, body.tls_size() as u16); 91 | try!(body.tls_write(writer)); 92 | } 93 | )+ 94 | $enum_name::Unknown(extension_type, ref extension_data) => { 95 | try_write_num!(u16, writer, extension_type); 96 | try_write_num!(u16, writer, extension_data.len() as u16); 97 | try!(writer.write(extension_data)); 98 | } 99 | } 100 | Ok(()) 101 | } 102 | 103 | fn tls_read(reader: &mut R) -> TlsResult<$enum_name> { 104 | let extension_type = try_read_num!(u16, reader); 105 | let extension_data_size = try_read_num!(u16, reader); 106 | match extension_type { 107 | $( 108 | tt_to_pat!($ext_num) => { 109 | let body: $body_ty = try!(TlsItem::tls_read(reader)); 110 | let body_size = body.tls_size(); 111 | if extension_data_size as u64 != body_size { 112 | return tls_err!(DecodeError, "Hello Extension has wrong size"); 113 | } 114 | Ok($enum_name::$ext_name(body)) 115 | } 116 | )+ 117 | _ => { 118 | let body: Vec = try!(ReadExt::read_exact(reader, extension_data_size as usize)); 119 | Ok($enum_name::Unknown(extension_type, body)) 120 | } 121 | } 122 | } 123 | 124 | fn tls_size(&self) -> u64 { 125 | let body_size = match *self { 126 | $( 127 | $enum_name::$ext_name(ref body) => body.tls_size(), 128 | )+ 129 | $enum_name::Unknown(_, ref body) => body.len() as u64, 130 | }; 131 | // extension_type, extension_data_size 132 | 4 + body_size 133 | } 134 | } 135 | ) 136 | } 137 | 138 | tls_hello_extension!(enum Extension { 139 | // RFC 6066 140 | //server_name(0), 141 | //max_fragment_length(1), 142 | //client_certificate_url(2), 143 | //trusted_ca_keys(3), 144 | //truncated_hmac(4), 145 | //status_request(5), 146 | // RFC 4492 147 | elliptic_curves(EllipticCurveList) = 10, 148 | ec_point_formats(ECPointFormatList) = 11 149 | // RFC 5246 150 | //signature_algorithms(13) 151 | }); 152 | 153 | impl Extension { 154 | pub fn new_elliptic_curve_list(list: Vec) -> TlsResult { 155 | let list = try!(EllipticCurveList::new(list)); 156 | let list = Extension::elliptic_curves(list); 157 | Ok(list) 158 | } 159 | 160 | pub fn new_ec_point_formats(list: Vec) -> TlsResult { 161 | let list = try!(ECPointFormatList::new(list)); 162 | let list = Extension::ec_point_formats(list); 163 | Ok(list) 164 | } 165 | } 166 | 167 | tls_vec!(ExtensionVec = Extension(0, (1 << 16) - 1)); 168 | tls_option!(ExtensionVec); 169 | 170 | // struct Handshake { 171 | // msg_type: u8, 172 | // len: u24, 173 | // data: 174 | // } 175 | macro_rules! tls_handshake( 176 | ( 177 | $( 178 | $name:ident($body_ty:ty) = $num:tt, // $num: integer literal 179 | )+ 180 | ) => ( 181 | #[allow(non_camel_case_types)] 182 | pub enum Handshake { 183 | $( 184 | $name($body_ty), 185 | )+ 186 | } 187 | 188 | impl TlsItem for Handshake { 189 | fn tls_write(&self, writer: &mut W) -> TlsResult<()> { 190 | match *self { 191 | $( 192 | Handshake::$name(ref body) => { 193 | try!(writer.write_u8(tt_to_expr!($num))); 194 | 195 | let len = body.tls_size(); 196 | try!(writer.write_u8(((len >> 16) & 0xff) as u8)); 197 | try!(writer.write_u8(((len >> 8) & 0xff) as u8)); 198 | try!(writer.write_u8((len & 0xff) as u8)); 199 | 200 | try!(body.tls_write(writer)); 201 | } 202 | )+ 203 | } 204 | 205 | Ok(()) 206 | } 207 | 208 | fn tls_read(reader: &mut R) -> TlsResult { 209 | let ty = try!(reader.read_u8()); 210 | 211 | // HandshakeBuffer already checked validity of length 212 | let _len = { 213 | let n1 = try!(reader.read_u8()) as u32; 214 | let n2 = try!(reader.read_u8()) as u32; 215 | let n3 = try!(reader.read_u8()) as u32; 216 | (n1 << 16) | (n2 << 8) | n3 217 | }; 218 | 219 | let ret = match ty { 220 | $( 221 | tt_to_pat!($num) => { 222 | let body: $body_ty = try!(TlsItem::tls_read(reader)); 223 | Handshake::$name(body) 224 | } 225 | )+ 226 | _ => return tls_err!(UnexpectedMessage, 227 | "unexpected Handshake message: type {}", 228 | ty), 229 | }; 230 | 231 | let should_be_err = reader.read_u8(); 232 | match should_be_err { 233 | Err(_) => {}, 234 | Ok(_) => return tls_err!(InternalError, "expected EOF but found not"), 235 | } 236 | 237 | Ok(ret) 238 | } 239 | 240 | fn tls_size(&self) -> u64 { 241 | let body_len = match *self { 242 | $( 243 | Handshake::$name(ref body) => body.tls_size(), 244 | )+ 245 | }; 246 | // msg_type 1 byte, length 3 bytes 247 | 1 + 3 + body_len 248 | } 249 | } 250 | ) 251 | ); 252 | 253 | tls_handshake!( 254 | hello_request(DummyItem) = 0, 255 | client_hello(ClientHello) = 1, 256 | server_hello(ServerHello) = 2, 257 | // hello_verify_request(..) = 3, RFC 6347: DTLS 258 | // NewSessionTicket(..) = 4, RFC 5077: session resumption w/o server-side state 259 | certificate(CertificateList) = 11, 260 | server_key_exchange(ObscureData) = 12, 261 | certificate_request(CertificateRequest) = 13, 262 | server_hello_done(DummyItem) = 14, 263 | // certificate_verify = 15, 264 | client_key_exchange(ObscureData) = 16, 265 | finished(VerifyData) = 20, 266 | ); 267 | 268 | tls_struct!(struct ClientHello { 269 | client_version: ProtocolVersion, 270 | random: Random, 271 | session_id: SessionId, 272 | cipher_suites: CipherSuiteVec, 273 | compression_methods: CompressionMethodVec, 274 | extensions: Option 275 | }); 276 | 277 | tls_struct!(struct ServerHello { 278 | server_version: ProtocolVersion, 279 | random: Random, 280 | session_id: SessionId, 281 | cipher_suite: CipherSuite, 282 | compression_method: CompressionMethod, 283 | extensions: Option 284 | }); 285 | 286 | tls_vec!(CertificateList = Asn1Cert(0, (1 << 24) - 1)); 287 | 288 | tls_enum!(u8, enum ClientCertificateType { 289 | rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), 290 | rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6), 291 | fortezza_dms_RESERVED(20) 292 | }); 293 | tls_vec!(CertificiateTypeVec = ClientCertificateType(1, (1 << 8) - 1)); 294 | 295 | tls_vec!(DistinguishedName = u8(1, (1 << 16) - 1)); 296 | tls_vec!(DistinguishedNameVec = DistinguishedName(0, (1 << 16) - 1)); 297 | 298 | tls_struct!(struct CertificateRequest { 299 | certificate_types: CertificiateTypeVec, 300 | supported_signature_algorithms: SignatureAndHashAlgorithmVec, 301 | certificate_authorities: DistinguishedNameVec 302 | }); 303 | 304 | // FIXME TLS 1.2 says the length can be longer for future ciphe suites. 305 | tls_array!(VerifyData = [u8, ..12]); 306 | 307 | // buffer for handshake protocol 308 | pub struct HandshakeBuffer { 309 | buf: Vec, 310 | } 311 | 312 | impl HandshakeBuffer { 313 | pub fn new() -> HandshakeBuffer { 314 | HandshakeBuffer { buf: Vec::new() } 315 | } 316 | 317 | pub fn add_record(&mut self, fragment: &[u8]) { 318 | self.buf.extend(fragment); 319 | } 320 | 321 | // if message is arrived but has unknown type, the message is discarded and returns error. 322 | pub fn get_message(&mut self) -> TlsResult> { 323 | let len = self.buf.len(); 324 | // we need to read at least ty and length 325 | if len < 4 { 326 | return Ok(None); 327 | } 328 | 329 | let n1 = self.buf[1] as usize; 330 | let n2 = self.buf[2] as usize; 331 | let n3 = self.buf[3] as usize; 332 | let wanted_len: usize = (n1 << 16) | (n2 << 8) | n3; 333 | let wanted_len = wanted_len + 4; 334 | 335 | if len < wanted_len { 336 | return Ok(None); 337 | } 338 | 339 | // FIXME bad clone? 340 | let (message, remaining) = { 341 | let (message, remaining) = self.buf.split_at_mut(wanted_len); 342 | let message = message.to_vec(); 343 | let remaining = remaining.to_vec(); 344 | (message, remaining) 345 | }; 346 | self.buf = remaining; 347 | 348 | let mut reader = &mut &message[..]; 349 | let message: Handshake = try!(TlsItem::tls_read(reader)); 350 | let ret = Ok(Some(message)); 351 | 352 | ret 353 | } 354 | } 355 | 356 | impl Handshake { 357 | pub fn new_client_hello(random: Random, 358 | cipher_suite: CipherSuite, 359 | extensions: Vec) -> TlsResult { 360 | let client_hello_body = { 361 | let client_version = { 362 | let (major, minor) = TLS_VERSION; 363 | 364 | ProtocolVersion { 365 | major: major, 366 | minor: minor, 367 | } 368 | }; 369 | 370 | // TODO support session resumption 371 | let session_id = { 372 | let data = Vec::new(); 373 | try!(SessionId::new(data)) 374 | }; 375 | 376 | let cipher_suites = { 377 | let data = vec!(cipher_suite); 378 | try!(CipherSuiteVec::new(data)) 379 | }; 380 | 381 | let compression_methods = { 382 | let data = vec!(CompressionMethod::null); 383 | try!(CompressionMethodVec::new(data)) 384 | }; 385 | 386 | let extensions = if extensions.len() == 0 { 387 | None 388 | } else { 389 | let ext = try!(ExtensionVec::new(extensions)); 390 | Some(ext) 391 | }; 392 | ClientHello { 393 | client_version: client_version, 394 | random: random, 395 | session_id: session_id, 396 | cipher_suites: cipher_suites, 397 | compression_methods: compression_methods, 398 | extensions: extensions, 399 | } 400 | }; 401 | 402 | Ok(Handshake::client_hello(client_hello_body)) 403 | } 404 | 405 | pub fn new_client_key_exchange(data: Vec) -> TlsResult { 406 | let data = ObscureData::new(data); 407 | Ok(Handshake::client_key_exchange(data)) 408 | } 409 | 410 | pub fn new_finished(data: Vec) -> TlsResult { 411 | let data = try!(VerifyData::new(data)); 412 | Ok(Handshake::finished(data)) 413 | } 414 | } 415 | 416 | #[cfg(test)] 417 | mod test { 418 | use std::io::Cursor; 419 | use tls_item::TlsItem; 420 | use cipher::CipherSuite; 421 | 422 | use super::{ProtocolVersion, SessionId, CipherSuiteVec, CompressionMethod, 423 | CompressionMethodVec, ClientHello, Handshake, Random}; 424 | 425 | #[test] 426 | fn test_parse_client_hello() { 427 | let client_hello_msg = { 428 | let client_hello_body = { 429 | let client_version = { 430 | let (major, minor) = (3, 3); 431 | 432 | ProtocolVersion { 433 | major: major, 434 | minor: minor, 435 | } 436 | }; 437 | 438 | let random = { 439 | let random_bytes = [0u8; 32].to_vec(); 440 | Random::new(random_bytes).unwrap() 441 | }; 442 | 443 | let session_id = { 444 | let data = Vec::new(); 445 | SessionId::new(data).unwrap() 446 | }; 447 | 448 | let cipher_suites = { 449 | let data = vec!(CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); 450 | CipherSuiteVec::new(data).unwrap() 451 | }; 452 | 453 | let compression_methods = { 454 | let data = vec!(CompressionMethod::null); 455 | CompressionMethodVec::new(data).unwrap() 456 | }; 457 | 458 | ClientHello { 459 | client_version: client_version, 460 | random: random, 461 | session_id: session_id, 462 | cipher_suites: cipher_suites, 463 | compression_methods: compression_methods, 464 | extensions: None, 465 | } 466 | }; 467 | 468 | Handshake::client_hello(client_hello_body) 469 | }; 470 | 471 | let mut packet = Vec::new(); 472 | client_hello_msg.tls_write(&mut packet).unwrap(); 473 | 474 | let mut reader = Cursor::new(&packet[..]); 475 | let client_hello_msg_2: Handshake = TlsItem::tls_read(&mut reader).unwrap(); 476 | 477 | let mut packet_2 = Vec::new(); 478 | client_hello_msg_2.tls_write(&mut packet_2).unwrap(); 479 | 480 | assert_eq!(packet, packet_2); 481 | } 482 | } 483 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "lib"] 2 | #![crate_name = "suruga"] 3 | 4 | 5 | #[macro_use] 6 | extern crate log; 7 | extern crate rand; 8 | extern crate num; 9 | 10 | #[macro_use] 11 | extern crate enum_primitive; 12 | 13 | pub use client::TlsClient; 14 | 15 | #[macro_use] 16 | pub mod macros; 17 | pub mod util; 18 | 19 | // basic crypto primitives 20 | pub mod crypto; 21 | 22 | pub mod tls_result; 23 | #[macro_use] 24 | pub mod tls_item; 25 | 26 | // TLS AEAD cipehrsuites 27 | pub mod cipher; 28 | 29 | pub mod signature; 30 | pub mod alert; 31 | pub mod handshake; 32 | 33 | pub mod tls; 34 | pub mod client; 35 | 36 | #[cfg(test)] mod test; 37 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! tls_err { 2 | ($kind:expr, $($args:tt)*) => ( 3 | $crate::tls_result::TlsError::new($kind, format!($($args)*)) 4 | ) 5 | } 6 | 7 | macro_rules! num_size { 8 | (u8) => (1); 9 | (u16) => (2); 10 | (u24) => (3); 11 | (u32) => (4); 12 | (u64) => (8); 13 | } 14 | 15 | macro_rules! try_write_num { 16 | (u8, $writer:expr, $e:expr) => ({ 17 | try!($writer.write_u8($e as u8)); 18 | }); 19 | (u16, $writer:expr, $e:expr) => ({ 20 | try!($writer.write_be_u16($e as u16)); 21 | }); 22 | (u24, $writer:expr, $e:expr) => ( 23 | { 24 | let e = $e as u32; 25 | try!($writer.write_u8((e >> 16) as u8)); 26 | try!($writer.write_u8((e >> 8) as u8)); 27 | try!($writer.write_u8(e as u8)); 28 | } 29 | ); 30 | (u32, $writer:expr, $e:expr) => ({ 31 | try!($writer.write_be_u32($e as u32)); 32 | }); 33 | (u64, $writer:expr, $e:expr) => ({ 34 | try!($writer.write_be_u64($e as u64)); 35 | }); 36 | } 37 | 38 | macro_rules! try_read_num { 39 | (u8, $reader:expr) => ({ 40 | try!($reader.read_u8()) 41 | }); 42 | (u16, $reader:expr) => ({ 43 | try!($reader.read_be_u16()) 44 | }); 45 | (u24, $reader:expr) => ({ 46 | let n1 = try!($reader.read_u8()) as u32; 47 | let n2 = try!($reader.read_u8()) as u32; 48 | let n3 = try!($reader.read_u8()) as u32; 49 | (n1 << 16) | (n2 << 8) | n3 50 | }); 51 | (u32, $reader:expr) => ({ 52 | try!($reader.read_be_u32()) 53 | }); 54 | (u64, $reader:expr) => ({ 55 | try!($reader.read_be_u64()) 56 | }); 57 | } 58 | 59 | macro_rules! tt_to_expr { 60 | ($num:expr) => ($num) 61 | } 62 | macro_rules! tt_to_pat { 63 | ($num:pat) => ($num) 64 | } 65 | -------------------------------------------------------------------------------- /src/signature.rs: -------------------------------------------------------------------------------- 1 | // 7.4.1.4.1 Signature algorithm 2 | 3 | use util::{ReadExt, WriteExt}; 4 | use tls_item::TlsItem; 5 | 6 | tls_enum!(u8, enum HashAlgorithm { 7 | none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), 8 | sha512(6) 9 | }); 10 | 11 | tls_enum!(u8, enum SignatureAlgorithm { 12 | anonymous(0), rsa(1), dsa(2), ecdsa(3) 13 | }); 14 | 15 | tls_struct!(struct SignatureAndHashAlgorithm { 16 | hash: HashAlgorithm, 17 | signature: SignatureAlgorithm 18 | }); 19 | tls_vec!(SignatureAndHashAlgorithmVec = SignatureAndHashAlgorithm(2, (1 << 16) - 2)); 20 | 21 | tls_vec!(Signature = u8(0, (1 << 16) - 1)); 22 | tls_struct!(struct DigitallySigned { 23 | algorithm: SignatureAndHashAlgorithm, 24 | signature: Signature 25 | }); 26 | -------------------------------------------------------------------------------- /src/test.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | use std::io::Cursor; 3 | use std::iter::repeat; 4 | 5 | use tls::{TlsReader, TlsWriter}; 6 | use tls_result::TlsResult; 7 | use cipher::{Encryptor, Decryptor}; 8 | use tls::Message::{ApplicationDataMessage, ChangeCipherSpecMessage}; 9 | use tls::RECORD_MAX_LEN; 10 | 11 | // ROT26 is a [Caesar cipher][1] with highly optimized diffusion table. 12 | // [1]: http://www.anagram.com/jcrap/Volume_3/caesar.pdf 13 | struct NullEncryptor; 14 | struct NullDecryptor; 15 | 16 | impl Encryptor for NullEncryptor { 17 | fn encrypt(&mut self, _nonce: &[u8], plain: &[u8], _ad: &[u8]) -> Vec { 18 | plain.to_vec() 19 | } 20 | } 21 | 22 | impl Decryptor for NullDecryptor { 23 | fn decrypt(&mut self, _nonce: &[u8], encrypted: &[u8], _ad: &[u8]) -> TlsResult> { 24 | Ok(encrypted.to_vec()) 25 | } 26 | fn mac_len(&self) -> usize { 0 } 27 | } 28 | 29 | fn null_tls(reader: R, writer: W) -> (TlsReader, TlsWriter) { 30 | let mut reader = TlsReader::new(reader); 31 | let null_decryptor = Box::new(NullDecryptor) as Box; 32 | reader.set_decryptor(null_decryptor); 33 | 34 | let mut writer = TlsWriter::new(writer); 35 | let null_encryptor = Box::new(NullEncryptor) as Box; 36 | writer.set_encryptor(null_encryptor); 37 | 38 | (reader, writer) 39 | } 40 | 41 | #[test] 42 | fn test_change_cipher_spec_message() { 43 | let mut writer = Vec::new(); 44 | { 45 | let mut reader = Cursor::new(Vec::new()); 46 | let mut tls = null_tls(&mut reader, &mut writer); 47 | tls.1.write_change_cipher_spec().unwrap(); 48 | } 49 | 50 | let data = writer; 51 | assert_eq!(data.len(), 1 + 2 + 2 + 1); // type, version, length, fragment 52 | assert_eq!(data[5], 1); 53 | 54 | let mut reader = Cursor::new(data); 55 | { 56 | let mut writer = Vec::new(); 57 | let mut tls = null_tls(&mut reader, &mut writer); 58 | let msg = tls.0.read_message().unwrap(); 59 | match msg { 60 | ChangeCipherSpecMessage => {}, 61 | _ => panic!(), 62 | } 63 | } 64 | } 65 | 66 | #[test] 67 | fn test_application_message() { 68 | let app_data_len = RECORD_MAX_LEN + 200; 69 | let app_data: Vec<_> = repeat(1u8).take(app_data_len).collect(); 70 | 71 | let mut writer = Vec::new(); 72 | { 73 | let mut reader = Cursor::new(Vec::new()); 74 | let mut tls = null_tls(&mut reader, &mut writer); 75 | tls.1.write_application_data(&app_data).unwrap(); 76 | } 77 | 78 | let data = writer; 79 | 80 | let mut reader = Cursor::new(data); 81 | { 82 | let mut writer = Vec::new(); 83 | let mut tls = null_tls(&mut reader, &mut writer); 84 | let msg = tls.0.read_message().unwrap(); 85 | match msg { 86 | ApplicationDataMessage(msg) => { 87 | assert_eq!(msg, &[1u8; RECORD_MAX_LEN][..]); 88 | }, 89 | _ => panic!(), 90 | } 91 | 92 | let msg = tls.0.read_message().unwrap(); 93 | match msg { 94 | ApplicationDataMessage(msg) => { 95 | assert_eq!(msg, &[1u8; 200][..]); 96 | }, 97 | _ => panic!(), 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/tls.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | use num::traits::FromPrimitive; 3 | 4 | use tls_result::TlsResult; 5 | use tls_result::TlsErrorKind::{UnexpectedMessage, RecordOverflow, BadRecordMac, AlertReceived}; 6 | use alert::Alert; 7 | use handshake::{Handshake, HandshakeBuffer}; 8 | use util::u64_be_array; 9 | use util::{ReadExt, WriteExt}; 10 | use cipher::{Encryptor, Decryptor}; 11 | use tls_item::TlsItem; 12 | 13 | use self::ContentType::{ChangeCipherSpecTy, AlertTy, HandshakeTy, ApplicationDataTy}; 14 | use self::Message::{HandshakeMessage, ChangeCipherSpecMessage, AlertMessage, 15 | ApplicationDataMessage}; 16 | 17 | pub static TLS_VERSION: (u8, u8) = (3, 3); 18 | 19 | enum_from_primitive! { 20 | #[repr(u8)] 21 | #[derive(Copy, Clone, PartialEq, Debug)] 22 | pub enum ContentType { 23 | ChangeCipherSpecTy = 20, 24 | AlertTy = 21, 25 | HandshakeTy = 22, 26 | ApplicationDataTy = 23, 27 | // HeartBeat = 24, RFC 6520 extension :-) 28 | } 29 | } 30 | 31 | /// maximum length of Record (excluding content_type, version, length fields) 32 | pub const RECORD_MAX_LEN: usize = 1 << 14; 33 | 34 | /// maximum length of EncryptedRecord (excluding content_type, version, length fields) 35 | pub const ENC_RECORD_MAX_LEN: usize = (1 << 14) + 2048; 36 | 37 | /// corresponds to `TLSPlaintext` in Section 6.2.1. 38 | #[derive(Debug)] 39 | pub struct Record { 40 | pub content_type: ContentType, 41 | pub ver_major: u8, 42 | pub ver_minor: u8, 43 | // fragment length < 2^14 44 | pub fragment: Vec, 45 | } 46 | 47 | impl Record { 48 | pub fn new(content_type: ContentType, 49 | ver_major: u8, 50 | ver_minor: u8, 51 | fragment: Vec) -> Record { 52 | let len = fragment.len(); 53 | if len > RECORD_MAX_LEN { 54 | panic!("record too long: {} > 2^14", len); 55 | } 56 | 57 | Record { 58 | content_type: content_type, 59 | ver_major: ver_major, 60 | ver_minor: ver_minor, 61 | fragment: fragment, 62 | } 63 | } 64 | } 65 | 66 | /// Writes `Record` or higher-layer message to a writable object. 67 | /// Record is internally encrypted before written. 68 | pub struct TlsWriter { 69 | writer: W, 70 | // if encryptor is None, handshake is not done yet. 71 | encryptor: Option>, 72 | write_count: u64, 73 | } 74 | 75 | impl TlsWriter { 76 | /// Create new `TlsWriter` with null encryption. 77 | /// Invoke `set_encryptor` to set encryptor. 78 | pub fn new(writer: W) -> TlsWriter { 79 | TlsWriter { 80 | writer: writer, 81 | encryptor: None, 82 | write_count: 0, 83 | } 84 | } 85 | 86 | #[inline] 87 | pub fn get_mut(&mut self) -> &mut W { 88 | &mut self.writer 89 | } 90 | 91 | /// Set encryptor and reset count. 92 | /// This must be called only once. 93 | pub fn set_encryptor(&mut self, encryptor: Box) { 94 | assert!(self.encryptor.is_none()); 95 | self.encryptor = Some(encryptor); 96 | self.write_count = 0; 97 | } 98 | 99 | pub fn write_record(&mut self, record: Record) -> TlsResult<()> { 100 | let encrypted_fragment = match self.encryptor { 101 | None => record.fragment, 102 | Some(ref mut encryptor) => { 103 | let seq_num = u64_be_array(self.write_count); 104 | 105 | let mut ad = Vec::new(); 106 | ad.extend(&seq_num); 107 | ad.push(record.content_type as u8); 108 | ad.push(record.ver_major); 109 | ad.push(record.ver_minor); 110 | let frag_len = record.fragment.len() as u16; 111 | ad.push((frag_len >> 8) as u8); 112 | ad.push(frag_len as u8); 113 | 114 | let encrypted_fragment = encryptor.encrypt(&seq_num, 115 | &record.fragment, 116 | &ad); 117 | encrypted_fragment 118 | } 119 | }; 120 | 121 | let fragment_len = encrypted_fragment.len(); 122 | if fragment_len > ENC_RECORD_MAX_LEN { 123 | panic!("record too long: {} > 2^14 + 2048", fragment_len); 124 | } 125 | 126 | try!(self.writer.write_u8(record.content_type as u8)); 127 | try!(self.writer.write_u8(record.ver_major)); 128 | try!(self.writer.write_u8(record.ver_minor)); 129 | try!(self.writer.write_be_u16(fragment_len as u16)); 130 | try!(self.writer.write_all(&encrypted_fragment)); 131 | 132 | self.write_count += 1; 133 | 134 | Ok(()) 135 | } 136 | 137 | pub fn write_data(&mut self, ty: ContentType, data: &[u8]) -> TlsResult<()> { 138 | let (major, minor) = TLS_VERSION; 139 | // TODO: configurable maxlen 140 | for fragment in data.chunks(RECORD_MAX_LEN) { 141 | let fragment = fragment.to_vec(); 142 | let record = Record::new(ty, major, minor, fragment); 143 | try!(self.write_record(record)); 144 | } 145 | 146 | Ok(()) 147 | } 148 | 149 | pub fn write_handshake(&mut self, handshake: &Handshake) -> TlsResult<()> { 150 | let mut data = Vec::new(); 151 | try!(handshake.tls_write(&mut data)); 152 | self.write_data(HandshakeTy, &data) 153 | } 154 | 155 | pub fn write_alert(&mut self, alert: &Alert) -> TlsResult<()> { 156 | let mut data = Vec::new(); 157 | try!(alert.tls_write(&mut data)); 158 | self.write_data(AlertTy, &data) 159 | } 160 | 161 | pub fn write_change_cipher_spec(&mut self) -> TlsResult<()> { 162 | self.write_data(ChangeCipherSpecTy, &[1u8]) 163 | } 164 | 165 | pub fn write_application_data(&mut self, data: &[u8]) -> TlsResult<()> { 166 | if self.encryptor.is_none() { 167 | panic!("attempted to write ApplicationData before handshake"); 168 | } 169 | self.write_data(ApplicationDataTy, data) 170 | } 171 | } 172 | 173 | /// Return type of `TlsReader.read_record()`. 174 | pub enum Message { 175 | HandshakeMessage(Handshake), 176 | ChangeCipherSpecMessage, 177 | AlertMessage(Alert), 178 | ApplicationDataMessage(Vec), 179 | } 180 | 181 | pub struct TlsReader { 182 | reader: R, 183 | // if decryptor is none, handshake is not done yet. 184 | decryptor: Option>, 185 | read_count: u64, 186 | handshake_buffer: HandshakeBuffer, 187 | } 188 | 189 | /// Reads `Record` or `Message` from a readable object. 190 | /// Record is internally decrypted after read. 191 | impl TlsReader { 192 | pub fn new(reader: R) -> TlsReader { 193 | TlsReader { 194 | reader: reader, 195 | decryptor: None, 196 | read_count: 0, 197 | handshake_buffer: HandshakeBuffer::new(), 198 | } 199 | } 200 | 201 | #[inline] 202 | pub fn get_mut(&mut self) -> &mut R { 203 | &mut self.reader 204 | } 205 | 206 | /// Set decryptor and reset count. 207 | /// This must be called only once. 208 | pub fn set_decryptor(&mut self, decryptor: Box) { 209 | assert!(self.decryptor.is_none()); 210 | self.decryptor = Some(decryptor); 211 | self.read_count = 0; 212 | } 213 | 214 | /// Read a record from readable stream. 215 | /// 216 | /// Any record with unknown content type is treated as an error. 217 | fn read_record(&mut self) -> TlsResult { 218 | let content_type = { 219 | let ty = try!(self.reader.read_u8()); 220 | let ct: Option = FromPrimitive::from_u8(ty); 221 | match ct { 222 | Some(ty) => ty, 223 | None => return tls_err!(UnexpectedMessage, "unexpected ContentType: {}", ty), 224 | } 225 | }; 226 | 227 | let major = try!(self.reader.read_u8()); 228 | let minor = try!(self.reader.read_u8()); 229 | 230 | let len = { 231 | let len = try!(self.reader.read_be_u16()) as usize; 232 | if len > ENC_RECORD_MAX_LEN { 233 | return tls_err!(RecordOverflow, "TLSEncryptedText too long: {}", len); 234 | } 235 | len 236 | }; 237 | 238 | let fragment = try!(ReadExt::read_exact(&mut self.reader, len as usize)); 239 | 240 | let record = match self.decryptor { 241 | None => { 242 | if fragment.len() > RECORD_MAX_LEN { 243 | return tls_err!(RecordOverflow, 244 | "decrypted record too long: {}", 245 | fragment.len()); 246 | } 247 | Record::new(content_type, major, minor, fragment) 248 | } 249 | Some(ref mut decryptor) => { 250 | let seq_num = u64_be_array(self.read_count); 251 | 252 | let mut ad = Vec::new(); 253 | ad.extend(&seq_num); 254 | ad.push(content_type as u8); // TLSCompressed.type 255 | ad.push(major); 256 | ad.push(minor); 257 | 258 | let mac_len = decryptor.mac_len(); 259 | let total_len = fragment.len(); 260 | if total_len < mac_len { 261 | return tls_err!(BadRecordMac, "encrypted message too short: {}", total_len); 262 | } 263 | let frag_len = (total_len - mac_len) as u16; 264 | ad.push((frag_len >> 8) as u8); 265 | ad.push(frag_len as u8); 266 | 267 | // TODO: "seq_num as nonce" is chacha20poly1305-specific 268 | let data = try!(decryptor.decrypt(&seq_num, &fragment, &ad)); 269 | if data.len() > RECORD_MAX_LEN { 270 | // decryption routine went wrong. 271 | return panic!("decrypted record too long: {}", data.len()); 272 | } 273 | 274 | Record::new(content_type, major, minor, data) 275 | } 276 | }; 277 | 278 | self.read_count += 1; 279 | 280 | Ok(record) 281 | } 282 | 283 | /// Read records until a "complete" message is found, then return the message. 284 | /// 285 | /// if invalid ChangeCipherSpec/Alert/Handshake message is found, return Err. 286 | /// (application record is always considered "complete" and "valid" 287 | /// since it is opaque to TLS layer.) 288 | /// 289 | /// Note: In theory, `Alert` message can be broken into several records. 290 | /// It is not useful in practice and requires more complex routines. 291 | /// (Incorrect handling leads to [Alert attack](http://www.mitls.org/wsgi/alert-attack).) 292 | /// 293 | /// We treat partial alert message as an error and returns `UnexpectedMessage`. 294 | pub fn read_message(&mut self) -> TlsResult { 295 | match try!(self.handshake_buffer.get_message()) { 296 | Some(handshake_msg) => return Ok(HandshakeMessage(handshake_msg)), 297 | None => {} 298 | } 299 | 300 | // ok, no message found. read it from network! 301 | loop { 302 | // TODO: what if handshake record is present in buffer then 303 | // other record comes? is it legal? 304 | 305 | let record = try!(self.read_record()); 306 | match record.content_type { 307 | ChangeCipherSpecTy => { 308 | if record.fragment.len() != 1 || record.fragment[0] != 1 { 309 | return tls_err!(UnexpectedMessage, "invalid ChangeCipherSpec arrived"); 310 | } 311 | return Ok(ChangeCipherSpecMessage); 312 | } 313 | AlertTy => { 314 | let len = record.fragment.len(); 315 | if len == 0 { 316 | return tls_err!(UnexpectedMessage, "zero-length Alert record arrived"); 317 | } else if len < 2 { 318 | // alert attack 319 | return tls_err!(UnexpectedMessage, "awkward Alert record arrived"); 320 | } 321 | let level = FromPrimitive::from_u8(record.fragment[0]); 322 | let desc = FromPrimitive::from_u8(record.fragment[1]); 323 | match (level, desc) { 324 | (Some(level), Some(desc)) => { 325 | return Ok(AlertMessage(try!(Alert::new(level, desc)))); 326 | } 327 | _ => return tls_err!(UnexpectedMessage, 328 | "unknown alert: {:?}", 329 | record.fragment), 330 | } 331 | } 332 | HandshakeTy => { 333 | if record.fragment.len() == 0 { 334 | return tls_err!(UnexpectedMessage, "zero-length Handshake arrived"); 335 | } 336 | self.handshake_buffer.add_record(&record.fragment); 337 | 338 | match try!(self.handshake_buffer.get_message()) { 339 | Some(handshake_msg) => return Ok(HandshakeMessage(handshake_msg)), 340 | _ => {} 341 | } 342 | } 343 | ApplicationDataTy => { 344 | return Ok(ApplicationDataMessage(record.fragment)); 345 | } 346 | } 347 | } 348 | } 349 | 350 | pub fn read_application_data(&mut self) -> TlsResult> { 351 | if self.decryptor.is_none() { 352 | panic!("ApplicationData called before handshake"); 353 | } 354 | loop { 355 | let msg = try!(self.read_message()); 356 | match msg { 357 | ApplicationDataMessage(msg) => return Ok(msg), 358 | // TODO: handle other cases 359 | AlertMessage(..) => unimplemented!(), 360 | ChangeCipherSpecMessage(..) => unimplemented!(), // this should not come here 361 | HandshakeMessage(..) => unimplemented!(), // TODO: re-handshake 362 | } 363 | } 364 | } 365 | 366 | pub fn read_handshake(&mut self) -> TlsResult { 367 | match try!(self.read_message()) { 368 | HandshakeMessage(handshake) => Ok(handshake), 369 | AlertMessage(alert) => tls_err!(AlertReceived, "alert: {:?}", alert.description), 370 | _ => tls_err!(UnexpectedMessage, "expected Handshake"), 371 | } 372 | } 373 | 374 | pub fn read_change_cipher_spec(&mut self) -> TlsResult<()> { 375 | match try!(self.read_message()) { 376 | ChangeCipherSpecMessage => Ok(()), 377 | _ => tls_err!(UnexpectedMessage, "expected ChangeCipherSpec"), 378 | } 379 | } 380 | } 381 | 382 | #[cfg(test)] 383 | mod test { 384 | use std::io::Cursor; 385 | use cipher::Encryptor; 386 | use super::*; 387 | 388 | macro_rules! assert_record { 389 | ($a:expr, $b:expr) => ( 390 | assert_eq!($a.content_type, $b.content_type); 391 | assert_eq!($a.ver_major, $b.ver_major); 392 | assert_eq!($a.ver_minor, $b.ver_minor); 393 | assert_eq!($a.fragment, $b.fragment); 394 | ) 395 | } 396 | 397 | fn new_reader(data: &[u8]) -> TlsReader> { 398 | TlsReader::new(Cursor::new(data)) 399 | } 400 | 401 | macro_rules! assert_err { 402 | ($e:expr, $kind:ident) => ( 403 | if let Err(e) = $e { 404 | assert_eq!(e.kind, ::tls_result::TlsErrorKind::$kind); 405 | } else { 406 | panic!("expected `Err`, found `Ok(..)`"); 407 | } 408 | ) 409 | } 410 | 411 | #[test] 412 | fn test_reader() { 413 | let tests: &[(&[u8], Record)] = &[ 414 | // ChangeCipherSpec(1) 415 | (&[0x14, 0x03, 0x03, 0x00, 0x01, 0x01], 416 | Record::new(ContentType::ChangeCipherSpecTy, 3, 3, vec![1])), 417 | ]; 418 | for &(input, ref output) in tests { 419 | let mut rr = new_reader(input); 420 | let record = rr.read_record().unwrap(); 421 | assert_record!(record, *output); 422 | let eof = rr.read_record(); 423 | assert_err!(eof, IoFailure); 424 | } 425 | } 426 | 427 | #[test] 428 | fn test_reader_unknown() { 429 | // Heartbeat request 430 | let data = [0x18, 0x03, 0x03, 0x00, 0x03, 0x01, 0x00, 0x20]; 431 | let mut rr = new_reader(&data); 432 | let record = rr.read_record(); 433 | assert_err!(record, UnexpectedMessage); 434 | } 435 | 436 | #[test] 437 | fn test_reader_too_long() { 438 | let len = RECORD_MAX_LEN + 1; 439 | let mut data = vec![0x17, 0x03, 0x03, (len >> 8) as u8, len as u8]; 440 | for _ in 0..len { 441 | data.push(0xFF); 442 | } 443 | 444 | let mut rr = new_reader(&data); 445 | let record = rr.read_record(); 446 | assert_err!(record, RecordOverflow); 447 | } 448 | 449 | #[test] 450 | fn test_reader_zero_length() { 451 | for content_type in vec![20, 21, 22] { 452 | let buf = [content_type, 0x03, 0x03, 0x00, 0x00]; 453 | let mut rr = new_reader(&buf); 454 | let record = rr.read_message(); 455 | assert_err!(record, UnexpectedMessage); 456 | } 457 | } 458 | 459 | #[test] 460 | #[should_panic] 461 | fn test_writer_too_long() { 462 | // convert normal record into overlong encrypted record 463 | struct Enc; 464 | impl Encryptor for Enc { 465 | fn encrypt(&mut self, _nonce: &[u8], _fragment: &[u8], _ad: &[u8]) -> Vec { 466 | vec![0; ENC_RECORD_MAX_LEN + 1] 467 | } 468 | } 469 | 470 | let record = Record::new(ContentType::ApplicationDataTy, 3, 3, vec![1]); 471 | 472 | let mut rw = TlsWriter::new(Vec::new()); 473 | rw.set_encryptor(Box::new(Enc) as Box); 474 | let _unreachable = rw.write_record(record); 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /src/tls_item.rs: -------------------------------------------------------------------------------- 1 | //! `TlsItem` represents item types that are serialized into TLS stream. 2 | //! 3 | //! There are several macros implementing common patterns: 4 | //! 5 | //! - `tls_array` for fixed-length vector 6 | //! - `tls_vec` for variable-length vector 7 | //! - `tls_enum` for TLS enum type 8 | //! - `tls_struct` for TLS constructed type 9 | //! - `tls_option` for `Option` 10 | 11 | use std::io::prelude::*; 12 | 13 | use util::{ReadExt, WriteExt}; 14 | use tls_result::TlsResult; 15 | 16 | /// A trait for items that can be serialized at TLS stream. 17 | pub trait TlsItem { 18 | /// Write an item into TLS stream. 19 | fn tls_write(&self, writer: &mut W) -> TlsResult<()>; 20 | /// Read an item from TLS stream. 21 | fn tls_read(reader: &mut R) -> TlsResult where Self: Sized; 22 | /// Returns the length of serialized bytes. 23 | fn tls_size(&self) -> u64; 24 | } 25 | 26 | // implementation of `TlsItem` for primitive integer types like `u8` 27 | macro_rules! tls_primitive { 28 | ($t:ident) => ( 29 | impl TlsItem for $t { 30 | fn tls_write(&self, writer: &mut W) -> ::tls_result::TlsResult<()> { 31 | try_write_num!($t, writer, *self); 32 | Ok(()) 33 | } 34 | 35 | fn tls_read(reader: &mut R) -> ::tls_result::TlsResult<$t> { 36 | let u = try_read_num!($t, reader); 37 | Ok(u) 38 | } 39 | 40 | fn tls_size(&self) -> u64 { num_size!($t) } 41 | } 42 | ) 43 | } 44 | 45 | tls_primitive!(u8); 46 | tls_primitive!(u16); 47 | tls_primitive!(u32); 48 | tls_primitive!(u64); 49 | 50 | macro_rules! tls_struct { 51 | ( 52 | struct $name:ident { 53 | $( 54 | $item:ident: $t:ty 55 | ),+ 56 | } 57 | ) => ( 58 | pub struct $name { 59 | $( 60 | pub $item: $t, 61 | )+ 62 | } 63 | 64 | impl TlsItem for $name { 65 | fn tls_write(&self, writer: &mut W) -> ::tls_result::TlsResult<()> { 66 | $( 67 | try!(self.$item.tls_write(writer)); 68 | )+ 69 | 70 | Ok(()) 71 | } 72 | 73 | fn tls_read(reader: &mut R) -> ::tls_result::TlsResult<$name> { 74 | $( 75 | let $item: $t = try!(TlsItem::tls_read(reader)); 76 | )+ 77 | 78 | let result = $name { 79 | $( 80 | $item: $item, 81 | )+ 82 | }; 83 | Ok(result) 84 | } 85 | 86 | fn tls_size(&self) -> u64 { 87 | let mut size = 0; 88 | $( 89 | size += self.$item.tls_size(); 90 | )+ 91 | 92 | size 93 | } 94 | } 95 | ) 96 | } 97 | 98 | macro_rules! tls_enum { 99 | ( 100 | $repr_ty:ident, 101 | $(#[$a:meta])* 102 | enum $name:ident { 103 | $( 104 | $item:ident($n:expr) 105 | ),+ 106 | } 107 | ) => ( 108 | enum_from_primitive! { 109 | #[allow(non_camel_case_types)] 110 | #[derive(Copy, Clone, PartialEq)] 111 | $(#[$a])* 112 | pub enum $name { 113 | $( 114 | $item = $n, 115 | )+ 116 | } 117 | } 118 | 119 | impl TlsItem for $name { 120 | fn tls_write(&self, writer: &mut W) -> ::tls_result::TlsResult<()> { 121 | try_write_num!($repr_ty, writer, *self); 122 | Ok(()) 123 | } 124 | 125 | fn tls_read(reader: &mut R) -> ::tls_result::TlsResult<$name> { 126 | let num = try_read_num!($repr_ty, reader) as u64; 127 | let n: Option<$name> = ::num::traits::FromPrimitive::from_u64(num); 128 | match n { 129 | Some(n) => Ok(n), 130 | None => tls_err!(::tls_result::TlsErrorKind::DecodeError, 131 | "unexpected number: {}", num), 132 | } 133 | } 134 | 135 | fn tls_size(&self) -> u64 { 136 | num_size!($repr_ty) 137 | } 138 | } 139 | ) 140 | } 141 | 142 | // fixed-sized u8/opaque array 143 | macro_rules! tls_array { 144 | ($name:ident = [u8, ..$n:expr]) => ( 145 | pub struct $name(Vec); 146 | 147 | impl $name { 148 | pub fn new(v: Vec) -> $crate::tls_result::TlsResult<$name> { 149 | let n: usize = $n; 150 | let len = v.len(); 151 | if len != n { 152 | return tls_err!($crate::tls_result::TlsErrorKind::InternalError, 153 | "bad size: {} != {}", len, n); 154 | } else { 155 | Ok($name(v)) 156 | } 157 | } 158 | } 159 | 160 | impl TlsItem for $name { 161 | fn tls_write(&self, writer: &mut W) -> $crate::tls_result::TlsResult<()> { 162 | try!(writer.write(&self.0)); 163 | Ok(()) 164 | } 165 | 166 | fn tls_read(reader: &mut R) -> $crate::tls_result::TlsResult<$name> { 167 | let data = try!(ReadExt::read_exact(reader, $n)); 168 | Ok($name(data)) 169 | } 170 | 171 | fn tls_size(&self) -> u64 { 172 | $n 173 | } 174 | } 175 | 176 | impl ::std::ops::Deref for $name { 177 | type Target = [u8]; 178 | fn deref<'a>(&'a self) -> &'a [u8] { 179 | &self.0 180 | } 181 | } 182 | ) 183 | } 184 | 185 | macro_rules! tls_vec { 186 | // $item_ty must implement TlsItem 187 | ($name:ident = $item_ty:ident($size_min:expr, $size_max:expr)) => ( 188 | pub struct $name(Vec<$item_ty>); 189 | impl $name { 190 | pub fn new(v: Vec<$item_ty>) -> $crate::tls_result::TlsResult<$name> { 191 | #![allow(unused_comparisons)] // disable warnings for e.g. `size < 0` 192 | 193 | let size_min: u64 = $size_min; 194 | let size_max: u64 = $size_max; 195 | 196 | let ret = $name(v); 197 | let size: u64 = ret.data_size(); 198 | if size < size_min { 199 | return tls_err!($crate::tls_result::TlsErrorKind::DecodeError, 200 | "bad size: {} < {}", 201 | size, 202 | size_min); 203 | } else if size > size_max { 204 | return tls_err!($crate::tls_result::TlsErrorKind::DecodeError, 205 | "bad size: {} > {}", 206 | size, 207 | size_max); 208 | } else { 209 | Ok(ret) 210 | } 211 | } 212 | 213 | pub fn unwrap(self) -> Vec<$item_ty> { 214 | let $name(data) = self; 215 | data 216 | } 217 | 218 | fn data_size(&self) -> u64 { 219 | let mut size = 0u64; 220 | for item in (**self).iter() { 221 | size += item.tls_size(); 222 | } 223 | size 224 | } 225 | } 226 | 227 | impl TlsItem for $name { 228 | fn tls_write(&self, writer: &mut W) -> ::tls_result::TlsResult<()> { 229 | let len = self.data_size(); 230 | 231 | let size_max: u64 = $size_max; 232 | 233 | if size_max < 1 << 8 { 234 | try_write_num!(u8, writer, len); 235 | } else if size_max < 1 << 16 { 236 | try_write_num!(u16, writer, len); 237 | } else if size_max < 1 << 24 { 238 | try_write_num!(u24, writer, len); 239 | } else if size_max < 1 << 32 { 240 | try_write_num!(u32, writer, len); 241 | } else { 242 | try_write_num!(u64, writer, len); 243 | } 244 | 245 | for item in (**self).iter() { 246 | try!(item.tls_write(writer)); 247 | } 248 | 249 | Ok(()) 250 | } 251 | 252 | fn tls_read(reader: &mut R) -> ::tls_result::TlsResult<$name> { 253 | let size_max: u64 = $size_max; 254 | 255 | let self_size = if size_max < 1 << 8 { 256 | (try_read_num!(u8, reader)) as u64 257 | } else if size_max < 1 << 16 { 258 | (try_read_num!(u16, reader)) as u64 259 | } else if size_max < 1 << 24 { 260 | (try_read_num!(u24, reader)) as u64 261 | } else if size_max < 1 << 32 { 262 | (try_read_num!(u32, reader)) as u64 263 | } else { 264 | (try_read_num!(u64, reader)) as u64 265 | }; 266 | 267 | let mut items_size = 0u64; 268 | let mut items = Vec::new(); 269 | while items_size < self_size { 270 | let item: $item_ty = try!(TlsItem::tls_read(reader)); 271 | items_size += item.tls_size(); 272 | items.push(item); 273 | } 274 | if items_size != self_size { 275 | return tls_err!(::tls_result::TlsErrorKind::DecodeError, 276 | "wrong size: {} expected, {} found", 277 | self_size, 278 | items_size); 279 | } 280 | 281 | $name::new(items) 282 | } 283 | 284 | fn tls_size(&self) -> u64 { 285 | let mut size = 0; 286 | 287 | let size_max: u64 = $size_max; 288 | 289 | if size_max < 1 << 8 { 290 | size += 1; 291 | } else if size_max < 1 << 16 { 292 | size += 2; 293 | } else if size_max < 1 << 24 { 294 | size += 3; 295 | } else if size_max < 1 << 32 { 296 | size += 4; 297 | } else { 298 | size += 8; 299 | } 300 | 301 | size += self.data_size(); 302 | size 303 | } 304 | } 305 | 306 | impl ::std::ops::Deref for $name { 307 | type Target = [$item_ty]; 308 | fn deref<'a>(&'a self) -> &'a [$item_ty] { 309 | &self.0 310 | } 311 | } 312 | ) 313 | } 314 | 315 | // this only works when the item is at the last of stream 316 | macro_rules! tls_option { 317 | ($t:ty) => ( 318 | impl TlsItem for Option<$t> { 319 | fn tls_write(&self, writer: &mut W) -> ::tls_result::TlsResult<()> { 320 | match *self { 321 | Some(ref data) => { 322 | try!(data.tls_write(writer)); 323 | } 324 | None => {} 325 | } 326 | Ok(()) 327 | } 328 | 329 | fn tls_read(reader: &mut R) -> ::tls_result::TlsResult> { 330 | let mut rest = vec![]; 331 | let len = try!(reader.read_to_end(&mut rest)); 332 | if len == 0 { 333 | return Ok(None); 334 | } 335 | 336 | let mut rest_reader = ::std::io::Cursor::new(rest); 337 | let extensions: $t = try!(TlsItem::tls_read(&mut rest_reader)); 338 | Ok(Some(extensions)) 339 | } 340 | 341 | fn tls_size(&self) -> u64 { 342 | match *self { 343 | Some(ref data) => data.tls_size(), 344 | None => 0, 345 | } 346 | } 347 | } 348 | ) 349 | } 350 | 351 | // for macros 352 | pub struct DummyItem; 353 | 354 | impl TlsItem for DummyItem { 355 | fn tls_write(&self, _writer: &mut W) -> TlsResult<()> { Ok(()) } 356 | fn tls_read(_reader: &mut R) -> TlsResult { Ok(DummyItem) } 357 | fn tls_size(&self) -> u64 { 0 } 358 | } 359 | 360 | // obsucre data received from TLS stream. 361 | // since the semantic is unknown, it is only meaningful to read until end of stream is reached. 362 | pub struct ObscureData(Vec); 363 | 364 | impl TlsItem for ObscureData { 365 | fn tls_write(&self, writer: &mut W) -> TlsResult<()> { 366 | try!(writer.write_all(&self.0)); 367 | Ok(()) 368 | } 369 | 370 | fn tls_read(reader: &mut R) -> TlsResult { 371 | let mut data = vec![]; 372 | let _len = try!(reader.read_to_end(&mut data)); 373 | Ok(ObscureData(data)) 374 | } 375 | 376 | fn tls_size(&self) -> u64 { self.0.len() as u64 } 377 | } 378 | 379 | impl ObscureData { 380 | pub fn new(data: Vec) -> ObscureData { 381 | ObscureData(data) 382 | } 383 | 384 | pub fn unwrap(self) -> Vec { 385 | let ObscureData(data) = self; 386 | data 387 | } 388 | } 389 | 390 | impl ::std::ops::Deref for ObscureData { 391 | type Target = [u8]; 392 | fn deref<'a>(&'a self) -> &'a [u8] { 393 | &self.0 394 | } 395 | } 396 | -------------------------------------------------------------------------------- /src/tls_result.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::io; 3 | use std::fmt; 4 | 5 | #[derive(Copy, Clone, PartialEq, Debug)] 6 | pub enum TlsErrorKind { 7 | // corresponds to alert messages 8 | 9 | UnexpectedMessage, 10 | BadRecordMac, 11 | RecordOverflow, 12 | IllegalParameter, 13 | DecodeError, 14 | DecryptError, 15 | InternalError, 16 | 17 | // we probably can't even send alert? 18 | IoFailure, 19 | AlertReceived, 20 | } 21 | 22 | #[derive(Debug)] 23 | pub struct TlsError { 24 | pub kind: TlsErrorKind, 25 | pub desc: String, 26 | } 27 | 28 | impl TlsError { 29 | pub fn new(kind: TlsErrorKind, desc: String) -> TlsResult { 30 | Err(TlsError { 31 | kind: kind, 32 | desc: desc, 33 | }) 34 | } 35 | } 36 | 37 | impl Error for TlsError { 38 | fn description(&self) -> &str { 39 | match self.kind { 40 | TlsErrorKind::UnexpectedMessage => "unexpected message", 41 | TlsErrorKind::BadRecordMac => "record has bad mac and/or encryption", 42 | TlsErrorKind::RecordOverflow => "record too long", 43 | TlsErrorKind::IllegalParameter => "illegal parameter during handshake", 44 | TlsErrorKind::DecodeError => "cannot decode message", 45 | TlsErrorKind::DecryptError => "failed to verify signature/message", 46 | TlsErrorKind::InternalError => "internal error", 47 | 48 | // UnsupportedExtension, 49 | 50 | // we probably can't even send alert? 51 | TlsErrorKind::IoFailure => "i/o error", 52 | TlsErrorKind::AlertReceived => "received an alert", 53 | } 54 | } 55 | } 56 | 57 | impl From for TlsError { 58 | fn from(err: io::Error) -> TlsError { 59 | TlsError { 60 | kind: TlsErrorKind::IoFailure, 61 | desc: format!("io error: {}", err), 62 | } 63 | } 64 | } 65 | 66 | impl fmt::Display for TlsError { 67 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 68 | ::fmt(self, f) 69 | } 70 | } 71 | 72 | pub type TlsResult = Result; 73 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use std::{mem, fmt}; 2 | use std::error::Error; 3 | use std::io::{self, Read, Write}; 4 | 5 | #[derive(Debug)] 6 | pub struct SurugaError { 7 | pub desc: &'static str, 8 | pub cause: Option>, 9 | } 10 | 11 | impl fmt::Display for SurugaError { 12 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 13 | ::fmt(self, fmt) 14 | } 15 | } 16 | 17 | impl Error for SurugaError { 18 | fn description(&self) -> &str { 19 | self.desc 20 | } 21 | 22 | // FIXME: implement fn cause(&self) -> Option<&Error> 23 | // This runs into difficulties with differing trait bounds. 24 | } 25 | 26 | /// constant-time compare function. 27 | /// `a` and `b` may be SECRET, but the length is known. 28 | /// precondition: `a.len() == b.len()` 29 | pub fn crypto_compare(a: &[u8], b: &[u8]) -> bool { 30 | debug_assert_eq!(a.len(), b.len()); 31 | 32 | let mut diff = 0u8; 33 | for i in (0..a.len()) { 34 | diff |= a[i] ^ b[i]; 35 | } 36 | diff = diff | (diff >> 4); 37 | diff = diff | (diff >> 2); 38 | diff = diff | (diff >> 1); 39 | diff = diff & 1; 40 | return diff == 0; 41 | } 42 | 43 | pub fn u64_be_array(x: u64) -> [u8; 8] { 44 | unsafe { mem::transmute(x.to_be()) } 45 | } 46 | 47 | pub fn u64_le_array(x: u64) -> [u8; 8] { 48 | unsafe { mem::transmute(x.to_le()) } 49 | } 50 | 51 | // native endians. 52 | macro_rules! read_write_prim { 53 | ($read_name:ident, $write_name:ident, $t:ty, $len:expr) => ( 54 | #[inline(always)] 55 | fn $read_name(mut reader: &mut R) -> io::Result<$t> { 56 | let mut buf = [0u8; $len]; 57 | try!(reader.fill_exact(&mut buf)); 58 | let value: $t = unsafe { mem::transmute(buf) }; 59 | Ok(value) 60 | } 61 | #[inline(always)] 62 | fn $write_name(mut writer: &mut R, value: $t) -> io::Result<()> { 63 | let buf: [u8; $len] = unsafe { mem::transmute(value) }; 64 | try!(writer.write_all(&buf)); 65 | Ok(()) 66 | } 67 | ) 68 | } 69 | 70 | read_write_prim!(read_u8, write_u8, u8, 1); 71 | read_write_prim!(read_u16, write_u16, u16, 2); 72 | read_write_prim!(read_u32, write_u32, u32, 4); 73 | read_write_prim!(read_u64, write_u64, u64, 8); 74 | 75 | pub trait ReadExt: Read { 76 | /// Fill buf completely or return `Err`. 77 | /// NOTE: the default implementation returns `Err(io::ErrorKind::Other)` if EOF is found. 78 | /// this may be not desired if the source is non-blocking. 79 | #[inline(always)] 80 | fn fill_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { 81 | let len = buf.len(); 82 | let mut pos = 0; 83 | while pos < len { 84 | let num_bytes = try!(self.read(&mut buf[pos..])); 85 | if num_bytes == 0 { 86 | return Err(io::Error::new(io::ErrorKind::Other, SurugaError { 87 | desc: "EOF during `fill_exact`", 88 | cause: None 89 | })); 90 | } 91 | pos += num_bytes; 92 | } 93 | Ok(()) 94 | } 95 | 96 | #[inline(always)] 97 | fn read_exact(&mut self, len: usize) -> io::Result> { 98 | // FIXME this can be more efficient using unsafe methods 99 | let mut vec = vec![0u8; len]; 100 | try!(self.fill_exact(&mut vec)); 101 | Ok(vec) 102 | } 103 | 104 | #[inline(always)] 105 | fn read_u8(&mut self) -> io::Result { 106 | read_u8(self) 107 | } 108 | #[inline(always)] 109 | fn read_be_u16(&mut self) -> io::Result { 110 | let value: u16 = try!(read_u16(self)); 111 | Ok(value.to_be()) 112 | } 113 | #[inline(always)] 114 | fn read_le_u16(&mut self) -> io::Result { 115 | let value: u16 = try!(read_u16(self)); 116 | Ok(value.to_le()) 117 | } 118 | #[inline(always)] 119 | fn read_be_u32(&mut self) -> io::Result { 120 | let value: u32 = try!(read_u32(self)); 121 | Ok(value.to_be()) 122 | } 123 | #[inline(always)] 124 | fn read_le_u32(&mut self) -> io::Result { 125 | let value: u32 = try!(read_u32(self)); 126 | Ok(value.to_le()) 127 | } 128 | #[inline(always)] 129 | fn read_be_u64(&mut self) -> io::Result { 130 | let value: u64 = try!(read_u64(self)); 131 | Ok(value.to_be()) 132 | } 133 | #[inline(always)] 134 | fn read_le_u64(&mut self) -> io::Result { 135 | let value: u64 = try!(read_u64(self)); 136 | Ok(value.to_le()) 137 | } 138 | } 139 | 140 | impl ReadExt for R {} 141 | 142 | pub trait WriteExt: Write { 143 | #[inline(always)] 144 | fn write_u8(&mut self, value: u8) -> io::Result<()> { 145 | write_u8(self, value) 146 | } 147 | 148 | #[inline(always)] 149 | fn write_be_u16(&mut self, value: u16) -> io::Result<()> { 150 | write_u16(self, value.to_be()) 151 | } 152 | #[inline(always)] 153 | fn write_le_u16(&mut self, value: u16) -> io::Result<()> { 154 | write_u16(self, value.to_le()) 155 | } 156 | 157 | #[inline(always)] 158 | fn write_be_u32(&mut self, value: u32) -> io::Result<()> { 159 | write_u32(self, value.to_be()) 160 | } 161 | #[inline(always)] 162 | fn write_le_u32(&mut self, value: u32) -> io::Result<()> { 163 | write_u32(self, value.to_le()) 164 | } 165 | 166 | #[inline(always)] 167 | fn write_be_u64(&mut self, value: u64) -> io::Result<()> { 168 | write_u64(self, value.to_be()) 169 | } 170 | #[inline(always)] 171 | fn write_le_u64(&mut self, value: u64) -> io::Result<()> { 172 | write_u64(self, value.to_le()) 173 | } 174 | } 175 | 176 | impl WriteExt for W {} 177 | --------------------------------------------------------------------------------