Skip to content

Commit

Permalink
WIP AesCbcCryptoAlgorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
budgetpreneur committed Sep 12, 2023
1 parent 411fc9d commit 20547b1
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 69 deletions.
9 changes: 9 additions & 0 deletions src/Api/PubnubApi/Security/Crypto/Common/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ internal static string GetLegacyEncryptionKey(string input)
//convert to lower case
return strKeySHA256Hash.ToLowerInvariant();
}
internal static string GetEncryptionKey(string input)
{
//Compute Hash using the SHA256
string strKeySHA256HashRaw = ComputeHashRaw(input);
//delete the "-" that appear after every 2 chars
string strKeySHA256Hash = strKeySHA256HashRaw.Replace("-", "");
//convert to lower case
return strKeySHA256Hash.ToLowerInvariant();
}

private static string ComputeHashRaw(string input)
{
Expand Down
328 changes: 259 additions & 69 deletions src/Api/PubnubApi/Security/Crypto/Cryptors/AesCbcCryptoAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,106 +14,296 @@ public class AesCbcCryptoAlgorithm : ICryptoAlgorithm
/// AES cipher block size.
private const int AES_BLOCK_SIZE = 16;

private static readonly byte[] _identifier = Encoding.ASCII.GetBytes("CRIV");

private readonly byte[] _cipherKey;
private readonly string _cipherKey;
private readonly bool _useRandomIV = true;
private readonly IPubnubLog _log;
public AesCbcCryptoAlgorithm(string cipherKey, IPubnubLog log)
private readonly IPubnubUnitTest _unitTest;
public AesCbcCryptoAlgorithm(string cipherKey, IPubnubLog log, IPubnubUnitTest unitTest)
{
_cipherKey = Util.ComputeSha256(cipherKey);
_cipherKey = cipherKey;
_log = log;
_unitTest = unitTest;
}
public AesCbcCryptoAlgorithm(string cipherKey): this(cipherKey, null)
public AesCbcCryptoAlgorithm(string cipherKey): this(cipherKey, null, null)
{
}
public byte[] Identifier => _identifier;
public byte[] Identifier { get; } = Encoding.ASCII.GetBytes("CRIV");

private static string EncodeNonAsciiCharacters(string value)
{
StringBuilder sb = new StringBuilder();
foreach (char c in value)
{
if (c > 127)
{
// This character is too big for ASCII
string encodedValue = "\\u" + ((int)c).ToString("x4", CultureInfo.InvariantCulture);
sb.Append(encodedValue);
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
public EncryptedData Encrypt(string data)
{
try
if (data == null)
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
using (Aes aesAlg = Aes.Create())
return new EncryptedData
{
aesAlg.Key = _cipherKey;
aesAlg.IV = Util.InitializationVector(true, AES_BLOCK_SIZE);
Metadata = null,
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Input is null", new Exception("Input is null")), StatusCode = 400 }
};
}
string input = EncodeNonAsciiCharacters(data);
byte[] dataBytes = Encoding.UTF8.GetBytes(input);

byte[] ivBytes = Util.InitializationVector(_useRandomIV, AES_BLOCK_SIZE);
if (_unitTest != null && _unitTest.IV != null)
{
ivBytes = _unitTest.IV;
}

byte[] encryptedData;
using (MemoryStream ms = new MemoryStream())
string keyString = Util.GetEncryptionKey(_cipherKey);
try
{
EncryptedBytes encryptedBytes = InternalEncrypt(dataBytes, ivBytes, keyString);
if (encryptedBytes.Data != null)
{
return new EncryptedData
{
using (CryptoStream csEncrypt = new CryptoStream(ms, aesAlg.CreateEncryptor(), CryptoStreamMode.Write))
{
csEncrypt.Write(dataBytes, 0, data.Length);
csEncrypt.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
return new EncryptedData()
Metadata = Convert.ToBase64String(ivBytes),
Data = Convert.ToBase64String(encryptedBytes.Data)
};
}
else
{
return new EncryptedData
{
Data = Convert.ToBase64String(encryptedData),
Metadata = Convert.ToBase64String(aesAlg.IV),
Status = new PNStatus { Error = false, ErrorData = null, StatusCode = 200 }
Metadata = null,
Data = null,
Status = encryptedBytes.Status
};
}
}
catch (Exception ex)
catch(Exception ex)
{
_log?.WriteToLog(string.Format(CultureInfo.InvariantCulture, "DateTime {0} Encrypt Error. {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.ToString()));
return new EncryptedData()
return new EncryptedData
{
Data = null,
Metadata = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData(ex.Message, ex), StatusCode = 400 }
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Encryption error", ex), StatusCode = 400 }
};
}
}

public DecryptedData Decrypt(DataEnvelope encryptedData)
public EncryptedBytes Encrypt(byte[] data)
{
return null;
//try
//{
// using (Aes aesAlg = Aes.Create())
// {
// aesAlg.Key = _cipherKey;
// aesAlg.IV = encryptedData.Metadata.Take(AES_BLOCK_SIZE).ToArray(); // Extract IV
if (data == null)
{
return new EncryptedBytes
{
Metadata = null,
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Input is null", new Exception("Input is null")), StatusCode = 400 }
};
}

// byte[] decryptedData;
// using (MemoryStream ms = new MemoryStream())
// {
// using (CryptoStream csDecrypt = new CryptoStream(ms, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
// {
// csDecrypt.Write(encryptedData.Data, AES_BLOCK_SIZE, encryptedData.Metadata.Length - AES_BLOCK_SIZE);
// csDecrypt.FlushFinalBlock();
// }
// decryptedData = ms.ToArray();
// }
// return new DecryptedData
// {
// Data = decryptedData,
// Status = new PNStatus() { Error = false, ErrorData = null, StatusCode = 200 }
// };
// }
//}
//catch(Exception ex)
//{
// _log?.WriteToLog(string.Format(CultureInfo.InvariantCulture, "DateTime {0} Decrypt Error. {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.ToString()));
// return new DecryptedData
// {
// Data = null,
// Status = new PNStatus() { Error = true, ErrorData = new PNErrorData(ex.Message, ex), StatusCode = 400 }
// };
//}
}
int dataOffset = _useRandomIV ? AES_BLOCK_SIZE : 0;
byte[] ivBytes = Util.InitializationVector(_useRandomIV, dataOffset);
if (_unitTest != null && _unitTest.IV != null && _unitTest.IV.Length == 16)
{
ivBytes = _unitTest.IV;
}

public EncryptedBytes Encrypt(byte[] data)
string keyString = Util.GetEncryptionKey(_cipherKey);
try
{
return InternalEncrypt(data, ivBytes, keyString);
}
catch(Exception ex)
{
return new EncryptedBytes
{
Metadata = null,
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Encryption error", ex), StatusCode = 400 }
};
}
}
private EncryptedBytes InternalEncrypt(byte[] dataBytes, byte[] ivBytes, string keyString)
{
throw new NotImplementedException();
try
{

using (Aes aesAlg = Aes.Create())
{
aesAlg.KeySize = 256;
aesAlg.BlockSize = AES_BLOCK_SIZE;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.IV = ivBytes;
aesAlg.Key = Encoding.UTF8.GetBytes(keyString);

using (ICryptoTransform crypto = aesAlg.CreateEncryptor())
{
byte[] buffer = crypto.TransformFinalBlock(dataBytes, 0, dataBytes.Length);
return new EncryptedBytes
{
Metadata = _useRandomIV ? ivBytes : null,
Data = buffer,
Status = null
};
}
}
}
catch(Exception ex)
{
return new EncryptedBytes
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Encryption error", ex), StatusCode = 400 }
};
}
}
public DecryptedData Decrypt(DataEnvelope encryptedData)
{
if (encryptedData == null)
{
return new DecryptedData
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Input is null", new Exception("Input is null")), StatusCode = 400 }
};
}

if (!(encryptedData is EncryptedData encData))
{
return new DecryptedData
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Input is not EncryptedData", new Exception("Input is not EncryptedData")), StatusCode = 400 }
};
}

byte[] dataBytes;
byte[] ivBytes;
try
{
dataBytes = Convert.FromBase64String(encData.Data);
ivBytes = Convert.FromBase64String(encData.Metadata);
}
catch(Exception ex)
{
return new DecryptedData
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Base64 conversion error", ex), StatusCode = 400 }
};
}
string keyString = Util.GetEncryptionKey(_cipherKey);

try
{
DecryptedBytes decryptedBytes = InternalDecrypt(dataBytes, ivBytes, keyString);
if (decryptedBytes.Data != null)
{
return new DecryptedData
{
Data = Encoding.UTF8.GetString(decryptedBytes.Data),
Status = null
};
}
else
{
return new DecryptedData
{
Data = null,
Status = decryptedBytes.Status
};
}

}
catch(Exception ex)
{
return new DecryptedData
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Decryption error", ex), StatusCode = 400 }
};
}
}
public DecryptedBytes Decrypt(BytesEnvelope encryptedBytes)
{
throw new NotImplementedException();
if (encryptedBytes == null || encryptedBytes.Data == null)
{
return new DecryptedBytes
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Input is null", new Exception("Input is null")), StatusCode = 400 }
};
}

if (!(encryptedBytes is EncryptedBytes))
{
return new DecryptedBytes
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Input is not EncryptedData", new Exception("Input is not EncryptedData")), StatusCode = 400 }
};
}

byte[] ivBytes = encryptedBytes.Metadata;
byte[] dataBytes = encryptedBytes.Data;
string keyString = Util.GetEncryptionKey(_cipherKey);
try
{
return InternalDecrypt(dataBytes, ivBytes, keyString);
}
catch(Exception ex)
{
return new DecryptedBytes
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Decryption error", ex), StatusCode = 400 }
};
}
}
private DecryptedBytes InternalDecrypt(byte[] dataBytes, byte[] ivBytes, string keyString)
{
try
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.KeySize = 256;
aesAlg.BlockSize = AES_BLOCK_SIZE;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.IV = ivBytes;
aesAlg.Key = Encoding.UTF8.GetBytes(keyString);

using(ICryptoTransform decrypto = aesAlg.CreateDecryptor())
{
byte[] buffer = decrypto.TransformFinalBlock(dataBytes, 0, dataBytes.Length);
return new DecryptedBytes
{
Data = buffer,
Status = null
};
}
}

}
catch(Exception ex)
{
return new DecryptedBytes
{
Data = null,
Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Decryption error", ex), StatusCode = 400 }
};
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public LegacyCryptoAlgorithm(string cipherKey, bool useRandomIV, IPubnubLog log)
public LegacyCryptoAlgorithm(string cipherKey, bool useRandomIV): this(cipherKey, useRandomIV, null, null)
{
}
public LegacyCryptoAlgorithm(string cipherKey): this(cipherKey, true, null, null)
{
}
public byte[] Identifier => _identifier;
private static string EncodeNonAsciiCharacters(string value)
{
Expand Down

0 comments on commit 20547b1

Please sign in to comment.