use crate::error::SecioError;
#[cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))]
use ring::digest;
use std::cmp::Ordering;
use crate::stream_cipher::Cipher;
use crate::KeyAgreement;
const ECDH_P256: &str = "P-256";
const ECDH_P384: &str = "P-384";
const AES_128: &str = "AES-128";
const AES_256: &str = "AES-256";
const TWOFISH_CTR: &str = "TwofishCTR";
const NULL: &str = "NULL";
const SHA_256: &str = "SHA256";
const SHA_512: &str = "SHA512";
pub(crate) const DEFAULT_AGREEMENTS_PROPOSITION: &str = "P-256,P-384";
pub(crate) const DEFAULT_CIPHERS_PROPOSITION: &str = "AES-128,AES-256,TwofishCTR";
pub(crate) const DEFAULT_DIGESTS_PROPOSITION: &str = "SHA256,SHA512";
pub fn key_agreements_proposition<'a, I>(xchgs: I) -> String
where
I: IntoIterator<Item=&'a KeyAgreement>
{
let mut s = String::new();
for x in xchgs {
match x {
KeyAgreement::EcdhP256 => {
s.push_str(ECDH_P256);
s.push(',')
}
KeyAgreement::EcdhP384 => {
s.push_str(ECDH_P384);
s.push(',')
}
}
}
s.pop(); s
}
pub fn select_agreement(r: Ordering, ours: &str, theirs: &str) -> Result<KeyAgreement, SecioError> {
let (a, b) = match r {
Ordering::Less | Ordering::Equal => (theirs, ours),
Ordering::Greater => (ours, theirs)
};
for x in a.split(',') {
if b.split(',').any(|y| x == y) {
match x {
ECDH_P256 => return Ok(KeyAgreement::EcdhP256),
ECDH_P384 => return Ok(KeyAgreement::EcdhP384),
_ => continue
}
}
}
Err(SecioError::NoSupportIntersection)
}
pub fn ciphers_proposition<'a, I>(ciphers: I) -> String
where
I: IntoIterator<Item=&'a Cipher>
{
let mut s = String::new();
for c in ciphers {
match c {
Cipher::Aes128 => {
s.push_str(AES_128);
s.push(',')
}
Cipher::Aes256 => {
s.push_str(AES_256);
s.push(',')
}
Cipher::TwofishCtr => {
s.push_str(TWOFISH_CTR);
s.push(',')
}
Cipher::Null => {
s.push_str(NULL);
s.push(',')
}
}
}
s.pop(); s
}
pub fn select_cipher(r: Ordering, ours: &str, theirs: &str) -> Result<Cipher, SecioError> {
let (a, b) = match r {
Ordering::Less | Ordering::Equal => (theirs, ours),
Ordering::Greater => (ours, theirs)
};
for x in a.split(',') {
if b.split(',').any(|y| x == y) {
match x {
AES_128 => return Ok(Cipher::Aes128),
AES_256 => return Ok(Cipher::Aes256),
TWOFISH_CTR => return Ok(Cipher::TwofishCtr),
NULL => return Ok(Cipher::Null),
_ => continue
}
}
}
Err(SecioError::NoSupportIntersection)
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Digest {
Sha256,
Sha512
}
impl Digest {
#[inline]
pub fn num_bytes(&self) -> usize {
match *self {
Digest::Sha256 => 256 / 8,
Digest::Sha512 => 512 / 8,
}
}
}
pub fn digests_proposition<'a, I>(digests: I) -> String
where
I: IntoIterator<Item=&'a Digest>
{
let mut s = String::new();
for d in digests {
match d {
Digest::Sha256 => {
s.push_str(SHA_256);
s.push(',')
}
Digest::Sha512 => {
s.push_str(SHA_512);
s.push(',')
}
}
}
s.pop(); s
}
pub fn select_digest(r: Ordering, ours: &str, theirs: &str) -> Result<Digest, SecioError> {
let (a, b) = match r {
Ordering::Less | Ordering::Equal => (theirs, ours),
Ordering::Greater => (ours, theirs)
};
for x in a.split(',') {
if b.split(',').any(|y| x == y) {
match x {
SHA_256 => return Ok(Digest::Sha256),
SHA_512 => return Ok(Digest::Sha512),
_ => continue
}
}
}
Err(SecioError::NoSupportIntersection)
}
#[cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))]
impl Into<&'static digest::Algorithm> for Digest {
#[inline]
fn into(self) -> &'static digest::Algorithm {
match self {
Digest::Sha256 => &digest::SHA256,
Digest::Sha512 => &digest::SHA512,
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn cipher_non_null() {
assert!(!super::DEFAULT_CIPHERS_PROPOSITION.contains("NULL"));
}
}