rust-libp2p/protocols/secio/src/algo_support.rs
2018-09-05 02:15:16 +02:00

97 lines
3.6 KiB
Rust

// Copyright 2017 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//! This module contains some utilities for algorithm support exchange.
//!
//! One important part of the SECIO handshake is negotiating algorithms. This is what this module
//! helps you with.
macro_rules! supported_impl {
($mod_name:ident: $ty:ty, $($name:expr => $val:expr),*,) => (
pub mod $mod_name {
use std::cmp::Ordering;
#[allow(unused_imports)]
use stream_cipher::Cipher;
#[allow(unused_imports)]
use ring::{agreement, digest};
use error::SecioError;
/// String to advertise to the remote.
pub const PROPOSITION_STRING: &'static str = concat_comma!($($name),*);
/// Choose which algorithm to use based on the remote's advertised list.
pub fn select_best(hashes_ordering: Ordering, input: &str) -> Result<$ty, SecioError> {
match hashes_ordering {
Ordering::Less | Ordering::Equal => {
for second_elem in input.split(',') {
$(
if $name == second_elem {
return Ok($val);
}
)+
}
},
Ordering::Greater => {
$(
for second_elem in input.split(',') {
if $name == second_elem {
return Ok($val);
}
}
)+
},
};
Err(SecioError::NoSupportIntersection(PROPOSITION_STRING, input.to_owned()))
}
}
);
}
// Concatenates several strings with commas.
macro_rules! concat_comma {
($first:expr, $($rest:expr),*) => (
concat!($first $(, ',', $rest)*)
);
}
// TODO: there's no library in the Rust ecosystem that supports P-521, but the Go & JS
// implementations advertise it
supported_impl!(
exchanges: &'static agreement::Algorithm,
"P-256" => &agreement::ECDH_P256,
"P-384" => &agreement::ECDH_P384,
);
// TODO: the Go & JS implementations advertise Blowfish ; however doing so in Rust leads to
// runtime errors
supported_impl!(
ciphers: Cipher,
"AES-128" => Cipher::Aes128,
"AES-256" => Cipher::Aes256,
"TwofishCTR" => Cipher::Twofish,
);
supported_impl!(
hashes: &'static digest::Algorithm,
"SHA256" => &digest::SHA256,
"SHA512" => &digest::SHA512,
);