mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 20:23:43 +08:00
fix(encryption): do not log encrypted binary data (#1352)
This commit is contained in:
@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)]
|
||||||
|
|||||||
@ -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 })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user