fix(encryption): do not log encrypted binary data (#1352)

This commit is contained in:
Kartikeya Hegde
2023-06-21 14:38:46 +05:30
committed by GitHub
parent 21f2ccd47c
commit b0c103a193
5 changed files with 54 additions and 35 deletions

View File

@ -2,6 +2,7 @@
use std::ops::Deref; use std::ops::Deref;
use error_stack::{IntoReport, ResultExt}; use error_stack::{IntoReport, ResultExt};
use masking::{ExposeInterface, Secret};
use md5; use md5;
use ring::{ use ring::{
aead::{self, BoundKey, OpeningKey, SealingKey, UnboundKey}, aead::{self, BoundKey, OpeningKey, SealingKey, UnboundKey},
@ -10,7 +11,7 @@ use ring::{
use crate::{ use crate::{
errors::{self, CustomResult}, errors::{self, CustomResult},
pii, pii::{self, EncryptionStratergy},
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -103,7 +104,7 @@ pub trait DecodeMessage {
fn decode_message( fn decode_message(
&self, &self,
_secret: &[u8], _secret: &[u8],
_msg: Vec<u8>, _msg: Secret<Vec<u8>, EncryptionStratergy>,
) -> CustomResult<Vec<u8>, errors::CryptoError>; ) -> CustomResult<Vec<u8>, errors::CryptoError>;
} }
@ -147,9 +148,9 @@ impl DecodeMessage for NoAlgorithm {
fn decode_message( fn decode_message(
&self, &self,
_secret: &[u8], _secret: &[u8],
msg: Vec<u8>, msg: Secret<Vec<u8>, EncryptionStratergy>,
) -> CustomResult<Vec<u8>, errors::CryptoError> { ) -> CustomResult<Vec<u8>, errors::CryptoError> {
Ok(msg.to_vec()) Ok(msg.expose())
} }
} }
@ -242,8 +243,9 @@ impl DecodeMessage for GcmAes256 {
fn decode_message( fn decode_message(
&self, &self,
secret: &[u8], secret: &[u8],
msg: Vec<u8>, msg: Secret<Vec<u8>, EncryptionStratergy>,
) -> CustomResult<Vec<u8>, errors::CryptoError> { ) -> CustomResult<Vec<u8>, errors::CryptoError> {
let msg = msg.expose();
let key = UnboundKey::new(&aead::AES_256_GCM, secret) let key = UnboundKey::new(&aead::AES_256_GCM, secret)
.into_report() .into_report()
.change_context(errors::CryptoError::DecodingFailed)?; .change_context(errors::CryptoError::DecodingFailed)?;
@ -264,7 +266,7 @@ impl DecodeMessage for GcmAes256 {
.into_report() .into_report()
.change_context(errors::CryptoError::DecodingFailed)?; .change_context(errors::CryptoError::DecodingFailed)?;
Ok(result.into()) Ok(result.to_vec())
} }
} }
@ -380,14 +382,17 @@ pub fn generate_cryptographically_secure_random_bytes<const N: usize>() -> [u8;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Encryptable<T: Clone> { pub struct Encryptable<T: Clone> {
inner: T, inner: T,
encrypted: Vec<u8>, encrypted: Secret<Vec<u8>, EncryptionStratergy>,
} }
impl<T: Clone, S: masking::Strategy<T>> Encryptable<masking::Secret<T, S>> { impl<T: Clone, S: masking::Strategy<T>> Encryptable<Secret<T, S>> {
/// ///
/// constructor function to be used by the encryptor and decryptor to generate the data type /// constructor function to be used by the encryptor and decryptor to generate the data type
/// ///
pub fn new(masked_data: masking::Secret<T, S>, encrypted_data: Vec<u8>) -> Self { pub fn new(
masked_data: Secret<T, S>,
encrypted_data: Secret<Vec<u8>, EncryptionStratergy>,
) -> Self {
Self { Self {
inner: masked_data, inner: masked_data,
encrypted: encrypted_data, encrypted: encrypted_data,
@ -405,13 +410,13 @@ impl<T: Clone> Encryptable<T> {
/// ///
/// Get the inner encrypted data while consuming self /// Get the inner encrypted data while consuming self
/// ///
pub fn into_encrypted(self) -> Vec<u8> { pub fn into_encrypted(self) -> Secret<Vec<u8>, EncryptionStratergy> {
self.encrypted self.encrypted
} }
} }
impl<T: Clone> Deref for Encryptable<masking::Secret<T>> { impl<T: Clone> Deref for Encryptable<Secret<T>> {
type Target = masking::Secret<T>; type Target = Secret<T>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.inner &self.inner
} }
@ -439,18 +444,17 @@ where
} }
/// Type alias for `Option<Encryptable<Secret<String>>>` /// Type alias for `Option<Encryptable<Secret<String>>>`
pub type OptionalEncryptableSecretString = Option<Encryptable<masking::Secret<String>>>; pub type OptionalEncryptableSecretString = Option<Encryptable<Secret<String>>>;
/// Type alias for `Option<Encryptable<Secret<String>>>` used for `name` field /// Type alias for `Option<Encryptable<Secret<String>>>` used for `name` field
pub type OptionalEncryptableName = Option<Encryptable<masking::Secret<String>>>; pub type OptionalEncryptableName = Option<Encryptable<Secret<String>>>;
/// Type alias for `Option<Encryptable<Secret<String>>>` used for `email` field /// Type alias for `Option<Encryptable<Secret<String>>>` used for `email` field
pub type OptionalEncryptableEmail = pub type OptionalEncryptableEmail = Option<Encryptable<Secret<String, pii::EmailStrategy>>>;
Option<Encryptable<masking::Secret<String, pii::EmailStrategy>>>;
/// Type alias for `Option<Encryptable<Secret<String>>>` used for `phone` field /// Type alias for `Option<Encryptable<Secret<String>>>` used for `phone` field
pub type OptionalEncryptablePhone = Option<Encryptable<masking::Secret<String>>>; pub type OptionalEncryptablePhone = Option<Encryptable<Secret<String>>>;
/// Type alias for `Option<Encryptable<Secret<serde_json::Value>>>` used for `phone` field /// Type alias for `Option<Encryptable<Secret<serde_json::Value>>>` used for `phone` field
pub type OptionalEncryptableValue = Option<Encryptable<masking::Secret<serde_json::Value>>>; pub type OptionalEncryptableValue = Option<Encryptable<Secret<serde_json::Value>>>;
/// Type alias for `Option<Secret<serde_json::Value>>` used for `phone` field /// Type alias for `Option<Secret<serde_json::Value>>` used for `phone` field
pub type OptionalSecretValue = Option<masking::Secret<serde_json::Value>>; pub type OptionalSecretValue = Option<Secret<serde_json::Value>>;
#[cfg(test)] #[cfg(test)]
mod crypto_tests { mod crypto_tests {
@ -572,7 +576,7 @@ mod crypto_tests {
assert_eq!( assert_eq!(
algorithm algorithm
.decode_message(&secret, encoded_message) .decode_message(&secret, encoded_message.into())
.expect("Decode Failed"), .expect("Decode Failed"),
message message
); );
@ -594,12 +598,12 @@ mod crypto_tests {
}; };
let decoded = algorithm let decoded = algorithm
.decode_message(&right_secret, message.clone()) .decode_message(&right_secret, message.clone().into())
.expect("Decoded message"); .expect("Decoded message");
assert_eq!(decoded, r#"{"type":"PAYMENT"}"#.as_bytes()); assert_eq!(decoded, r#"{"type":"PAYMENT"}"#.as_bytes());
let err_decoded = algorithm.decode_message(&wrong_secret, message); let err_decoded = algorithm.decode_message(&wrong_secret, message.into());
assert!(err_decoded.is_err()); assert!(err_decoded.is_err());
} }

View File

@ -142,6 +142,19 @@ where
} }
*/ */
/// Strategy for Encryption
#[derive(Debug)]
pub struct EncryptionStratergy;
impl<T> Strategy<T> for EncryptionStratergy
where
T: AsRef<[u8]>,
{
fn fmt(value: &T, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(fmt, "*** Encrypted {} of bytes ***", value.as_ref().len())
}
}
/// Client secret /// Client secret
#[derive(Debug)] #[derive(Debug)]
pub struct ClientSecret; pub struct ClientSecret;

View File

@ -60,7 +60,7 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
algorithm algorithm
.decode_message(&secret, message) .decode_message(&secret, message.into())
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
} }

View File

@ -45,7 +45,7 @@ impl<
) -> CustomResult<Self, errors::CryptoError> { ) -> CustomResult<Self, errors::CryptoError> {
let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?; let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?;
Ok(Self::new(masked_data, encrypted_data)) Ok(Self::new(masked_data, encrypted_data.into()))
} }
#[instrument(skip_all)] #[instrument(skip_all)]
@ -84,7 +84,7 @@ impl<
.change_context(errors::CryptoError::DecodingFailed)?; .change_context(errors::CryptoError::DecodingFailed)?;
let encrypted_data = crypt_algo.encode_message(key, &data)?; let encrypted_data = crypt_algo.encode_message(key, &data)?;
Ok(Self::new(masked_data, encrypted_data)) Ok(Self::new(masked_data, encrypted_data.into()))
} }
#[instrument(skip_all)] #[instrument(skip_all)]
@ -118,7 +118,7 @@ impl<
) -> CustomResult<Self, errors::CryptoError> { ) -> CustomResult<Self, errors::CryptoError> {
let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?; let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?;
Ok(Self::new(masked_data, encrypted_data)) Ok(Self::new(masked_data, encrypted_data.into()))
} }
#[instrument(skip_all)] #[instrument(skip_all)]

View File

@ -1,15 +1,17 @@
use common_utils::pii::EncryptionStratergy;
use diesel::{ use diesel::{
backend::Backend, backend::Backend,
deserialize::{self, FromSql, Queryable}, deserialize::{self, FromSql, Queryable},
serialize::ToSql, serialize::ToSql,
sql_types, AsExpression, sql_types, AsExpression,
}; };
use masking::Secret;
#[derive(Debug, AsExpression, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, AsExpression, Clone, serde::Serialize, serde::Deserialize)]
#[diesel(sql_type = diesel::sql_types::Binary)] #[diesel(sql_type = diesel::sql_types::Binary)]
#[repr(transparent)] #[repr(transparent)]
pub struct Encryption { pub struct Encryption {
inner: Vec<u8>, inner: Secret<Vec<u8>, EncryptionStratergy>,
} }
impl<T: Clone> From<common_utils::crypto::Encryptable<T>> for Encryption { impl<T: Clone> From<common_utils::crypto::Encryptable<T>> for Encryption {
@ -19,17 +21,17 @@ impl<T: Clone> From<common_utils::crypto::Encryptable<T>> for Encryption {
} }
impl Encryption { impl Encryption {
pub fn new(item: Vec<u8>) -> Self { pub fn new(item: Secret<Vec<u8>, EncryptionStratergy>) -> Self {
Self { inner: item } Self { inner: item }
} }
#[inline] #[inline]
pub fn into_inner(self) -> Vec<u8> { pub fn into_inner(self) -> Secret<Vec<u8>, EncryptionStratergy> {
self.inner self.inner
} }
#[inline] #[inline]
pub fn get_inner(&self) -> &Vec<u8> { pub fn get_inner(&self) -> &Secret<Vec<u8>, EncryptionStratergy> {
&self.inner &self.inner
} }
} }
@ -37,17 +39,17 @@ impl Encryption {
impl<DB> FromSql<sql_types::Binary, DB> for Encryption impl<DB> FromSql<sql_types::Binary, DB> for Encryption
where where
DB: Backend, DB: Backend,
Vec<u8>: FromSql<sql_types::Binary, DB>, Secret<Vec<u8>, EncryptionStratergy>: FromSql<sql_types::Binary, DB>,
{ {
fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> { fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
<Vec<u8>>::from_sql(bytes).map(Self::new) <Secret<Vec<u8>, EncryptionStratergy>>::from_sql(bytes).map(Self::new)
} }
} }
impl<DB> ToSql<sql_types::Binary, DB> for Encryption impl<DB> ToSql<sql_types::Binary, DB> for Encryption
where where
DB: Backend, DB: Backend,
Vec<u8>: ToSql<sql_types::Binary, DB>, Secret<Vec<u8>, EncryptionStratergy>: ToSql<sql_types::Binary, DB>,
{ {
fn to_sql<'b>( fn to_sql<'b>(
&'b self, &'b self,
@ -60,9 +62,9 @@ where
impl<DB> Queryable<sql_types::Binary, DB> for Encryption impl<DB> Queryable<sql_types::Binary, DB> for Encryption
where where
DB: Backend, DB: Backend,
Vec<u8>: FromSql<sql_types::Binary, DB>, Secret<Vec<u8>, EncryptionStratergy>: FromSql<sql_types::Binary, DB>,
{ {
type Row = Vec<u8>; type Row = Secret<Vec<u8>, EncryptionStratergy>;
fn build(row: Self::Row) -> deserialize::Result<Self> { fn build(row: Self::Row) -> deserialize::Result<Self> {
Ok(Self { inner: row }) Ok(Self { inner: row })
} }