2019-09-06 11:20:40 +00:00
|
|
|
use std::fmt;
|
|
|
|
use std::ops::Deref;
|
2019-09-15 17:09:48 +00:00
|
|
|
use std::str::FromStr;
|
2019-09-13 14:06:52 +00:00
|
|
|
|
|
|
|
use crate::Error;
|
2019-09-06 11:20:40 +00:00
|
|
|
|
|
|
|
/// Initialization vector.
|
|
|
|
///
|
|
|
|
/// See: [4.3.2.4. EXT-X-KEY]
|
|
|
|
///
|
|
|
|
/// [4.3.2.4. EXT-X-KEY]: https://tools.ietf.org/html/rfc8216#section-4.3.2.4
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2019-09-17 12:45:10 +00:00
|
|
|
pub struct InitializationVector(pub [u8; 16]);
|
2019-09-15 14:45:43 +00:00
|
|
|
|
|
|
|
impl InitializationVector {
|
2019-09-22 18:33:40 +00:00
|
|
|
/// Converts the [InitializationVector] to a slice.
|
2019-10-03 15:01:15 +00:00
|
|
|
pub const fn to_slice(&self) -> [u8; 16] { self.0 }
|
2019-09-15 14:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<[u8; 16]> for InitializationVector {
|
2019-10-03 15:01:15 +00:00
|
|
|
fn from(value: [u8; 16]) -> Self { Self(value) }
|
2019-09-15 14:45:43 +00:00
|
|
|
}
|
2019-09-06 11:20:40 +00:00
|
|
|
|
|
|
|
impl Deref for InitializationVector {
|
|
|
|
type Target = [u8];
|
2019-10-03 15:01:15 +00:00
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target { &self.0 }
|
2019-09-06 11:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<[u8]> for InitializationVector {
|
2019-10-03 15:01:15 +00:00
|
|
|
fn as_ref(&self) -> &[u8] { &self.0 }
|
2019-09-06 11:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for InitializationVector {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "0x")?;
|
|
|
|
for b in &self.0 {
|
|
|
|
write!(f, "{:02x}", b)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for InitializationVector {
|
|
|
|
type Err = Error;
|
2019-09-13 14:06:52 +00:00
|
|
|
|
2019-09-22 18:33:40 +00:00
|
|
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
|
|
|
if !(input.starts_with("0x") || input.starts_with("0X")) {
|
2019-09-13 14:06:52 +00:00
|
|
|
return Err(Error::invalid_input());
|
|
|
|
}
|
2019-09-22 18:33:40 +00:00
|
|
|
if input.len() - 2 != 32 {
|
2019-09-13 14:06:52 +00:00
|
|
|
return Err(Error::invalid_input());
|
|
|
|
}
|
2019-09-06 11:20:40 +00:00
|
|
|
|
2019-09-22 18:33:40 +00:00
|
|
|
let mut result = [0; 16];
|
|
|
|
for (i, c) in input.as_bytes().chunks(2).skip(1).enumerate() {
|
|
|
|
let d = std::str::from_utf8(c).map_err(Error::custom)?;
|
|
|
|
let b = u8::from_str_radix(d, 16).map_err(Error::custom)?;
|
|
|
|
result[i] = b;
|
2019-09-06 11:20:40 +00:00
|
|
|
}
|
2019-09-13 14:06:52 +00:00
|
|
|
|
2019-09-22 18:33:40 +00:00
|
|
|
Ok(Self(result))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2019-10-08 13:42:33 +00:00
|
|
|
use pretty_assertions::assert_eq;
|
2019-09-22 18:33:40 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_display() {
|
|
|
|
assert_eq!(
|
|
|
|
"0x10ef8f758ca555115584bb5b3c687f52".to_string(),
|
|
|
|
InitializationVector([
|
|
|
|
16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82
|
|
|
|
])
|
|
|
|
.to_string()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parser() {
|
|
|
|
assert_eq!(
|
|
|
|
"0x10ef8f758ca555115584bb5b3c687f52"
|
|
|
|
.parse::<InitializationVector>()
|
|
|
|
.unwrap(),
|
|
|
|
InitializationVector([
|
|
|
|
16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82
|
|
|
|
])
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
"0X10ef8f758ca555115584bb5b3c687f52"
|
|
|
|
.parse::<InitializationVector>()
|
|
|
|
.unwrap(),
|
|
|
|
InitializationVector([
|
|
|
|
16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82
|
|
|
|
])
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
"0X10EF8F758CA555115584BB5B3C687F52"
|
|
|
|
.parse::<InitializationVector>()
|
|
|
|
.unwrap(),
|
|
|
|
InitializationVector([
|
|
|
|
16, 239, 143, 117, 140, 165, 85, 17, 85, 132, 187, 91, 60, 104, 127, 82
|
|
|
|
])
|
|
|
|
);
|
|
|
|
|
|
|
|
assert!("garbage".parse::<InitializationVector>().is_err());
|
|
|
|
assert!("0xgarbage".parse::<InitializationVector>().is_err());
|
|
|
|
assert!("0x12".parse::<InitializationVector>().is_err());
|
|
|
|
assert!("0X10EF8F758CA555115584BB5B3C687F5Z"
|
|
|
|
.parse::<InitializationVector>()
|
|
|
|
.is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_ref() {
|
|
|
|
assert_eq!(
|
|
|
|
InitializationVector([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).as_ref(),
|
|
|
|
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deref() {
|
|
|
|
assert_eq!(
|
|
|
|
InitializationVector([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).deref(),
|
|
|
|
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from() {
|
|
|
|
assert_eq!(
|
|
|
|
InitializationVector::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
|
|
|
|
InitializationVector([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_to_slice() {
|
|
|
|
assert_eq!(
|
|
|
|
InitializationVector([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).to_slice(),
|
|
|
|
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
|
|
);
|
2019-09-06 11:20:40 +00:00
|
|
|
}
|
|
|
|
}
|