use std::fmt;
use data_encoding::BASE64URL_NOPAD;
use serde::de::{self, DeserializeOwned};
use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
use crate::errors::{DecodeError, Error, ValidationError};
use crate::jwa::{
self, ContentEncryptionAlgorithm, EncryptionOptions, EncryptionResult, KeyManagementAlgorithm,
};
use crate::jwk;
use crate::{CompactJson, CompactPart, Empty};
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CompressionAlgorithm {
Deflate,
Other(String),
}
impl Serialize for CompressionAlgorithm {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let string = match *self {
CompressionAlgorithm::Deflate => "DEF",
CompressionAlgorithm::Other(ref other) => other,
};
serializer.serialize_str(string)
}
}
impl<'de> Deserialize<'de> for CompressionAlgorithm {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct CompressionAlgorithmVisitor;
impl<'de> de::Visitor<'de> for CompressionAlgorithmVisitor {
type Value = CompressionAlgorithm;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(match v {
"DEF" => CompressionAlgorithm::Deflate,
other => CompressionAlgorithm::Other(other.to_string()),
})
}
}
deserializer.deserialize_string(CompressionAlgorithmVisitor)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct RegisteredHeader {
#[serde(rename = "alg")]
pub cek_algorithm: KeyManagementAlgorithm,
#[serde(rename = "enc")]
pub enc_algorithm: ContentEncryptionAlgorithm,
#[serde(rename = "zip", skip_serializing_if = "Option::is_none")]
pub compression_algorithm: Option<CompressionAlgorithm>,
#[serde(rename = "typ", skip_serializing_if = "Option::is_none")]
pub media_type: Option<String>,
#[serde(rename = "cty", skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
#[serde(rename = "jku", skip_serializing_if = "Option::is_none")]
pub web_key_url: Option<String>,
#[serde(rename = "jwk", skip_serializing_if = "Option::is_none")]
pub web_key: Option<String>,
#[serde(rename = "kid", skip_serializing_if = "Option::is_none")]
pub key_id: Option<String>,
#[serde(rename = "x5u", skip_serializing_if = "Option::is_none")]
pub x509_url: Option<String>,
#[serde(rename = "x5c", skip_serializing_if = "Option::is_none")]
pub x509_chain: Option<Vec<String>>,
#[serde(rename = "x5t", skip_serializing_if = "Option::is_none")]
pub x509_fingerprint: Option<String>,
#[serde(rename = "crit", skip_serializing_if = "Option::is_none")]
pub critical: Option<Vec<String>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct CekAlgorithmHeader {
#[serde(rename = "iv", skip_serializing_if = "Option::is_none")]
pub nonce: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<Vec<u8>>,
}
#[derive(Debug, Eq, PartialEq, Clone, Default, Serialize, Deserialize)]
pub struct Header<T> {
#[serde(flatten)]
pub registered: RegisteredHeader,
#[serde(flatten)]
pub cek_algorithm: CekAlgorithmHeader,
#[serde(flatten)]
pub private: T,
}
impl<T: Serialize + DeserializeOwned> CompactJson for Header<T> {}
impl<T: Serialize + DeserializeOwned> Header<T> {
fn update_cek_algorithm(&mut self, encrypted: &EncryptionResult) {
if !encrypted.nonce.is_empty() {
self.cek_algorithm.nonce = Some(encrypted.nonce.clone());
}
if !encrypted.tag.is_empty() {
self.cek_algorithm.tag = Some(encrypted.tag.clone());
}
}
fn extract_cek_encryption_result(&mut self, encrypted_payload: &[u8]) -> EncryptionResult {
let result = EncryptionResult {
encrypted: encrypted_payload.to_vec(),
nonce: self.cek_algorithm.nonce.clone().unwrap_or_default(),
tag: self.cek_algorithm.tag.clone().unwrap_or_default(),
..Default::default()
};
self.cek_algorithm = Default::default();
result
}
}
impl Header<Empty> {
pub fn from_registered_header(registered: RegisteredHeader) -> Self {
Self {
registered,
..Default::default()
}
}
}
impl From<RegisteredHeader> for Header<Empty> {
fn from(registered: RegisteredHeader) -> Self {
Self::from_registered_header(registered)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Compact<T, H> {
#[serde(skip_serializing)]
#[serde(skip_deserializing)]
Decrypted {
header: Header<H>,
payload: T,
},
Encrypted(crate::Compact),
}
impl<T, H> Compact<T, H>
where
T: CompactPart,
H: Serialize + DeserializeOwned + Clone,
{
pub fn new_decrypted(header: Header<H>, payload: T) -> Self {
Compact::Decrypted { header, payload }
}
pub fn new_encrypted(token: &str) -> Self {
Compact::Encrypted(crate::Compact::decode(token))
}
pub fn into_encrypted<K: Serialize + DeserializeOwned>(
self,
key: &jwk::JWK<K>,
options: &EncryptionOptions,
) -> Result<Self, Error> {
match self {
Compact::Encrypted(_) => Ok(self),
Compact::Decrypted { .. } => self.encrypt(key, options),
}
}
pub fn encrypt<K: Serialize + DeserializeOwned>(
&self,
key: &jwk::JWK<K>,
options: &EncryptionOptions,
) -> Result<Self, Error> {
match *self {
Compact::Encrypted(_) => Err(Error::UnsupportedOperation),
Compact::Decrypted {
ref header,
ref payload,
} => {
use std::borrow::Cow;
let (key_option, content_option): (_, Cow<'_, _>) =
match header.registered.cek_algorithm {
KeyManagementAlgorithm::DirectSymmetricKey => {
(jwa::NONE_ENCRYPTION_OPTIONS, Cow::Borrowed(options))
}
_ => (
options,
Cow::Owned(
header
.registered
.enc_algorithm
.random_encryption_options()?,
),
),
};
let cek = header
.registered
.cek_algorithm
.cek(header.registered.enc_algorithm, key)?;
let encrypted_cek = header.registered.cek_algorithm.wrap_key(
cek.algorithm.octet_key()?,
key,
key_option,
)?;
let mut header = header.clone();
header.update_cek_algorithm(&encrypted_cek);
let payload = payload.to_bytes()?;
if header.registered.compression_algorithm.is_some() {
Err(Error::UnsupportedOperation)?
}
let encoded_protected_header = BASE64URL_NOPAD.encode(&header.to_bytes()?);
let encrypted_payload = header.registered.enc_algorithm.encrypt(
&payload,
encoded_protected_header.as_bytes(),
&cek,
&content_option,
)?;
let mut compact = crate::Compact::with_capacity(5);
compact.push(&header)?;
compact.push(&encrypted_cek.encrypted)?;
compact.push(&encrypted_payload.nonce)?;
compact.push(&encrypted_payload.encrypted)?;
compact.push(&encrypted_payload.tag)?;
Ok(Compact::Encrypted(compact))
}
}
}
pub fn into_decrypted<K: Serialize + DeserializeOwned>(
self,
key: &jwk::JWK<K>,
cek_alg: KeyManagementAlgorithm,
enc_alg: ContentEncryptionAlgorithm,
) -> Result<Self, Error> {
match self {
Compact::Encrypted(_) => self.decrypt(key, cek_alg, enc_alg),
Compact::Decrypted { .. } => Ok(self),
}
}
pub fn decrypt<K: Serialize + DeserializeOwned>(
&self,
key: &jwk::JWK<K>,
cek_alg: KeyManagementAlgorithm,
enc_alg: ContentEncryptionAlgorithm,
) -> Result<Self, Error> {
match *self {
Compact::Encrypted(ref encrypted) => {
if encrypted.len() != 5 {
Err(DecodeError::PartsLengthError {
actual: encrypted.len(),
expected: 5,
})?
}
let mut header: Header<H> = encrypted.part(0)?;
let encrypted_cek: Vec<u8> = encrypted.part(1)?;
let nonce: Vec<u8> = encrypted.part(2)?;
let encrypted_payload: Vec<u8> = encrypted.part(3)?;
let tag: Vec<u8> = encrypted.part(4)?;
if header.registered.cek_algorithm != cek_alg
|| header.registered.enc_algorithm != enc_alg
{
Err(Error::ValidationError(
ValidationError::WrongAlgorithmHeader,
))?;
}
let cek_encryption_result = header.extract_cek_encryption_result(&encrypted_cek);
let cek = header.registered.cek_algorithm.unwrap_key(
&cek_encryption_result,
header.registered.enc_algorithm,
key,
)?;
let protected_header: Vec<u8> = encrypted.part(0)?;
let encoded_protected_header = BASE64URL_NOPAD.encode(protected_header.as_ref());
let encrypted_payload_result = EncryptionResult {
nonce,
tag,
encrypted: encrypted_payload,
additional_data: encoded_protected_header.as_bytes().to_vec(),
};
let payload = header
.registered
.enc_algorithm
.decrypt(&encrypted_payload_result, &cek)?;
if header.registered.compression_algorithm.is_some() {
Err(Error::UnsupportedOperation)?
}
let payload = T::from_bytes(&payload)?;
Ok(Compact::new_decrypted(header, payload))
}
Compact::Decrypted { .. } => Err(Error::UnsupportedOperation),
}
}
pub fn encrypted(&self) -> Result<&crate::Compact, Error> {
match *self {
Compact::Decrypted { .. } => Err(Error::UnsupportedOperation),
Compact::Encrypted(ref encoded) => Ok(encoded),
}
}
pub fn encrypted_mut(&mut self) -> Result<&mut crate::Compact, Error> {
match *self {
Compact::Decrypted { .. } => Err(Error::UnsupportedOperation),
Compact::Encrypted(ref mut encoded) => Ok(encoded),
}
}
pub fn payload(&self) -> Result<&T, Error> {
match *self {
Compact::Decrypted { ref payload, .. } => Ok(payload),
Compact::Encrypted(_) => Err(Error::UnsupportedOperation),
}
}
pub fn payload_mut(&mut self) -> Result<&mut T, Error> {
match *self {
Compact::Decrypted {
ref mut payload, ..
} => Ok(payload),
Compact::Encrypted(_) => Err(Error::UnsupportedOperation),
}
}
pub fn header(&self) -> Result<&Header<H>, Error> {
match *self {
Compact::Decrypted { ref header, .. } => Ok(header),
Compact::Encrypted(_) => Err(Error::UnsupportedOperation),
}
}
pub fn header_mut(&mut self) -> Result<&mut Header<H>, Error> {
match *self {
Compact::Decrypted { ref mut header, .. } => Ok(header),
Compact::Encrypted(_) => Err(Error::UnsupportedOperation),
}
}
pub fn unwrap_decrypted(self) -> (Header<H>, T) {
match self {
Compact::Decrypted { header, payload } => (header, payload),
Compact::Encrypted(_) => panic!("JWE is encrypted"),
}
}
pub fn unwrap_encrypted(self) -> crate::Compact {
match self {
Compact::Decrypted { .. } => panic!("JWE is decrypted"),
Compact::Encrypted(compact) => compact,
}
}
}
impl<P, H> Compact<crate::ClaimsSet<P>, H>
where
crate::ClaimsSet<P>: CompactPart,
H: Serialize + DeserializeOwned + Clone,
{
pub fn validate(&self, options: crate::ValidationOptions) -> Result<(), Error> {
self.payload()?.registered.validate(options)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use ring::rand::SecureRandom;
use serde_test::{assert_tokens, Token};
use super::*;
use crate::jwa::{self, random_aes_gcm_nonce, rng};
use crate::jws;
use crate::test::assert_serde_json;
use crate::JWE;
fn cek_oct_key(len: usize) -> jwk::JWK<Empty> {
let mut key: Vec<u8> = vec![0; len];
not_err!(rng().fill(&mut key));
jwk::JWK {
common: Default::default(),
additional: Default::default(),
algorithm: jwk::AlgorithmParameters::OctetKey(jwk::OctetKeyParameters {
key_type: Default::default(),
value: key,
}),
}
}
#[test]
fn compression_algorithm_serde_token() {
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
struct Test {
test: CompressionAlgorithm,
}
let test_value = Test {
test: CompressionAlgorithm::Deflate,
};
assert_tokens(
&test_value,
&[
Token::Struct {
name: "Test",
len: 1,
},
Token::Str("test"),
Token::Str("DEF"),
Token::StructEnd,
],
);
let test_value = Test {
test: CompressionAlgorithm::Other("xxx".to_string()),
};
assert_tokens(
&test_value,
&[
Token::Struct {
name: "Test",
len: 1,
},
Token::Str("test"),
Token::Str("xxx"),
Token::StructEnd,
],
);
}
#[test]
fn compression_algorithm_json_serde() {
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
struct Test {
test: CompressionAlgorithm,
}
let test_json = r#"{"test": "DEF"}"#;
assert_serde_json(
&Test {
test: CompressionAlgorithm::Deflate,
},
Some(test_json),
);
let test_json = r#"{"test": "xxx"}"#;
assert_serde_json(
&Test {
test: CompressionAlgorithm::Other("xxx".to_string()),
},
Some(test_json),
);
}
#[test]
fn jwe_interoperability_check() {
let external_token = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..7-eXscPDD5DI4kTT.SUQuqkzIrp6j.QaNRHGYXtKC2lj11rgKDpw";
let key_json = r#"{"k":"YKaiJrr6_-PY8DJelu3rWrxVQQ24tnE9XGIRdZTy9ys","kty":"oct"}"#;
let key: jwk::JWK<Empty> = not_err!(serde_json::from_str(key_json));
let token: Compact<Vec<u8>, Empty> = Compact::new_encrypted(external_token);
let decrypted_jwe = not_err!(token.decrypt(
&key,
KeyManagementAlgorithm::DirectSymmetricKey,
ContentEncryptionAlgorithm::A256GCM,
));
let decrypted_payload: &Vec<u8> = not_err!(decrypted_jwe.payload());
let decrypted_str = not_err!(std::str::from_utf8(decrypted_payload));
assert_eq!(decrypted_str, "Encrypted");
}
#[test]
fn jwe_header_round_trips() {
let test_value: Header<Empty> = From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::RSA_OAEP,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
});
let test_json = r#"{"alg":"RSA-OAEP","enc":"A256GCM"}"#;
assert_serde_json(&test_value, Some(test_json));
let test_value: Header<Empty> = From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::RSA1_5,
enc_algorithm: ContentEncryptionAlgorithm::A128CBC_HS256,
..Default::default()
});
let test_json = r#"{"alg":"RSA1_5","enc":"A128CBC-HS256"}"#;
assert_serde_json(&test_value, Some(test_json));
let test_value: Header<Empty> = From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A128KW,
enc_algorithm: ContentEncryptionAlgorithm::A128CBC_HS256,
..Default::default()
});
let test_json = r#"{"alg":"A128KW","enc":"A128CBC-HS256"}"#;
assert_serde_json(&test_value, Some(test_json));
}
#[test]
fn custom_jwe_header_round_trip() {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct CustomHeader {
something: String,
}
let test_value = Header {
registered: RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::RSA_OAEP,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
},
cek_algorithm: Default::default(),
private: CustomHeader {
something: "foobar".to_string(),
},
};
let test_json = r#"{"alg":"RSA-OAEP","enc":"A256GCM","something":"foobar"}"#;
assert_serde_json(&test_value, Some(test_json));
}
#[test]
fn jwe_a256gcmkw_a256gcm_string_round_trip() {
use std::str;
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
{
let compact = not_err!(encrypted_jwe.encrypted());
let header: Header<Empty> = not_err!(compact.part(0));
assert!(header.cek_algorithm.nonce.is_some());
assert!(header.cek_algorithm.tag.is_some());
let cek: Vec<u8> = not_err!(compact.part(1));
assert_eq!(256 / 8, cek.len());
}
let json = not_err!(serde_json::to_string(&encrypted_jwe));
let deserialized_json: Compact<Vec<u8>, Empty> = not_err!(serde_json::from_str(&json));
assert_eq!(deserialized_json, encrypted_jwe);
let decrypted_jwe = not_err!(encrypted_jwe.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM
));
assert_eq!(jwe, decrypted_jwe);
let decrypted_payload: &Vec<u8> = not_err!(decrypted_jwe.payload());
let decrypted_str = not_err!(str::from_utf8(decrypted_payload));
assert_eq!(decrypted_str, payload);
}
#[test]
fn jwe_a256gcmkw_a256gcm_jws_round_trip() {
let claims = crate::ClaimsSet::<Empty> {
registered: crate::RegisteredClaims {
issuer: Some(not_err!(FromStr::from_str("https://www.acme.com"))),
subject: Some(not_err!(FromStr::from_str("John Doe"))),
audience: Some(crate::SingleOrMultiple::Single(not_err!(
FromStr::from_str("htts://acme-customer.com")
))),
not_before: Some(1234.into()),
..Default::default()
},
private: Default::default(),
};
let jws = jws::Compact::new_decoded(
From::from(jws::RegisteredHeader {
algorithm: jwa::SignatureAlgorithm::HS256,
..Default::default()
}),
claims,
);
let jws =
not_err!(jws.into_encoded(&jws::Secret::Bytes("secret".to_string().into_bytes())));
let key = cek_oct_key(256 / 8);
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
media_type: Some("JOSE".to_string()),
content_type: Some("JOSE".to_string()),
..Default::default()
}),
jws.clone(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
{
let compact = not_err!(encrypted_jwe.encrypted());
let header: Header<Empty> = not_err!(compact.part(0));
assert!(header.cek_algorithm.nonce.is_some());
assert!(header.cek_algorithm.tag.is_some());
let cek: Vec<u8> = not_err!(compact.part(1));
assert_eq!(256 / 8, cek.len());
}
let json = not_err!(serde_json::to_string(&encrypted_jwe));
let deserialized_json: JWE<Empty, Empty, Empty> = not_err!(serde_json::from_str(&json));
assert_eq!(deserialized_json, encrypted_jwe);
let decrypted_jwe = not_err!(encrypted_jwe.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM
));
assert_eq!(jwe, decrypted_jwe);
let decrypted_jws = not_err!(decrypted_jwe.payload());
assert_eq!(jws, *decrypted_jws);
}
#[test]
fn jwe_dir_aes256gcm_jws_round_trip() {
let claims = crate::ClaimsSet::<Empty> {
registered: crate::RegisteredClaims {
issuer: Some(not_err!(FromStr::from_str("https://www.acme.com"))),
subject: Some(not_err!(FromStr::from_str("John Doe"))),
audience: Some(crate::SingleOrMultiple::Single(not_err!(
FromStr::from_str("htts://acme-customer.com")
))),
not_before: Some(1234.into()),
..Default::default()
},
private: Default::default(),
};
let jws = jws::Compact::new_decoded(
From::from(jws::RegisteredHeader {
algorithm: jwa::SignatureAlgorithm::HS256,
..Default::default()
}),
claims,
);
let jws =
not_err!(jws.into_encoded(&jws::Secret::Bytes("secret".to_string().into_bytes())));
let key = cek_oct_key(256 / 8);
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::DirectSymmetricKey,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
media_type: Some("JOSE".to_string()),
content_type: Some("JOSE".to_string()),
..Default::default()
}),
jws.clone(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
{
let compact = not_err!(encrypted_jwe.encrypted());
let header: Header<Empty> = not_err!(compact.part(0));
assert!(header.cek_algorithm.nonce.is_none());
assert!(header.cek_algorithm.tag.is_none());
let cek: Vec<u8> = not_err!(compact.part(1));
assert!(cek.is_empty());
}
let json = not_err!(serde_json::to_string(&encrypted_jwe));
let deserialized_json: JWE<Empty, Empty, Empty> = not_err!(serde_json::from_str(&json));
assert_eq!(deserialized_json, encrypted_jwe);
let decrypted_jwe = not_err!(encrypted_jwe.into_decrypted(
&key,
KeyManagementAlgorithm::DirectSymmetricKey,
ContentEncryptionAlgorithm::A256GCM
));
assert_eq!(jwe, decrypted_jwe);
let decrypted_jws = not_err!(decrypted_jwe.payload());
assert_eq!(jws, *decrypted_jws);
}
#[test]
#[should_panic(expected = "WrongAlgorithmHeader")]
fn decrypt_with_mismatch_cek_algorithm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A128GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "WrongAlgorithmHeader")]
fn decrypt_with_mismatch_enc_algorithm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A128GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "PartsLengthError")]
fn decrypt_with_incorrect_length() {
let key = cek_oct_key(256 / 8);
let invalid = Compact::<Empty, Empty>::new_encrypted("INVALID");
let _ = invalid
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A128GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_nonce_for_aes256gcmkw() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
let mut header: Header<Empty> = not_err!(compact.part(0));
header.cek_algorithm.nonce = Some(vec![0; 96 / 8]);
compact.parts[0] = not_err!(header.to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_tag_for_aes256gcmkw() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
let mut header: Header<Empty> = not_err!(compact.part(0));
header.cek_algorithm.tag = Some(vec![0; 96 / 8]);
compact.parts[0] = not_err!(header.to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_tag_for_aes256gcm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
compact.parts[4] = not_err!(vec![0u8; 1].to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_modified_header_for_aes256gcm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
let mut header: Header<Empty> = not_err!(compact.part(0));
header.registered.media_type = Some("JOSE+JSON".to_string());
compact.parts[0] = not_err!(header.to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_modified_encrypted_cek_for_aes256gcm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
compact.parts[1] = not_err!(vec![0u8; 256 / 8].to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_modified_encrypted_payload_for_aes256gcm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
let mut header: Header<Empty> = not_err!(compact.part(0));
header.registered.media_type = Some("JOSE+JSON".to_string());
compact.parts[3] = not_err!(vec![0u8; 32].to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
#[test]
#[should_panic(expected = "UnspecifiedCryptographicError")]
fn invalid_modified_encrypted_nonce_for_aes256gcm() {
let key = cek_oct_key(256 / 8);
let payload = "The true sign of intelligence is not knowledge but imagination.";
let jwe = Compact::new_decrypted(
From::from(RegisteredHeader {
cek_algorithm: KeyManagementAlgorithm::A256GCMKW,
enc_algorithm: ContentEncryptionAlgorithm::A256GCM,
..Default::default()
}),
payload.as_bytes().to_vec(),
);
let options = EncryptionOptions::AES_GCM {
nonce: random_aes_gcm_nonce().unwrap(),
};
let encrypted_jwe = not_err!(jwe.encrypt(&key, &options));
let mut compact = encrypted_jwe.unwrap_encrypted();
let mut header: Header<Empty> = not_err!(compact.part(0));
header.registered.media_type = Some("JOSE+JSON".to_string());
compact.parts[2] = not_err!(vec![0u8; 96 / 8].to_base64());
let encrypted_jwe = Compact::<Empty, Empty>::new_encrypted(&compact.to_string());
let _ = encrypted_jwe
.into_decrypted(
&key,
KeyManagementAlgorithm::A256GCMKW,
ContentEncryptionAlgorithm::A256GCM,
)
.unwrap();
}
}