diff --git a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs
index c96b364..af65692 100644
--- a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs
@@ -577,7 +577,7 @@ namespace WelsonJS.Cryptography
///
///
///
- protected byte[] CreateKey(string key)
+ private byte[] CreateKey(string key)
{
SHA256 hasher = SHA256.Create();
byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
@@ -587,7 +587,7 @@ namespace WelsonJS.Cryptography
public byte[] Encrypt(byte[] data)
{
- byte[] indata = AnsiX923Padding.ApplyPadding(data, BLOCK_SIZE);
+ byte[] indata = AnsiX923Padding.AddPadding(data, BLOCK_SIZE);
byte[] outdata = new byte[indata.Length];
for (int i = 0; i < indata.Length; i += BLOCK_SIZE)
@@ -607,7 +607,7 @@ namespace WelsonJS.Cryptography
engine.Decrypt(data, i, outdata, i);
}
- return AnsiX923Padding.RemovePadding(outdata, BLOCK_SIZE);
+ return AnsiX923Padding.RemovePadding(outdata, BLOCK_SIZE, true);
}
}
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/AnsiX923Padding.cs b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/AnsiX923Padding.cs
index 063fc7c..86690d9 100644
--- a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/AnsiX923Padding.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/AnsiX923Padding.cs
@@ -19,6 +19,7 @@
* references:
* - https://github.com/eGovFrame/egovframework.rte.root/blob/master/Foundation/egovframework.rte.fdl.crypto/src/main/java/egovframework/rte/fdl/cryptography/impl/aria/AnsiX923Padding.java
* - ChatGPT prompt "AnsiX923Padding with C#" (chatgpt.com)
+ * - ChatGPT prompt "AnsiX923Padding with C#, Add a flag to decide how to handle possible errors when removing padding." (chatgpt.com)
*
* license:
* GPLv3 or MS-RL(Microsoft Reciprocal License)
@@ -31,12 +32,12 @@ namespace WelsonJS.Cryptography
class AnsiX923Padding
{
///
- /// Applies ANSI X.923 padding to the input data to make it a multiple of the block size.
+ /// Add ANSI X.923 padding to the input data to make it a multiple of the block size.
///
/// The data to be padded.
/// The block size to pad to.
/// Padded data with ANSI X.923 padding.
- public static byte[] ApplyPadding(byte[] data, int blockSize)
+ public static byte[] AddPadding(byte[] data, int blockSize)
{
int paddingLength = blockSize - (data.Length % blockSize);
@@ -62,19 +63,69 @@ namespace WelsonJS.Cryptography
}
///
- /// Removes the ANSI X.923 padding from the data.
+ /// Removes ANSI X.923 padding from the given data.
///
- /// The padded data to remove padding from.
- /// The block size used during padding.
- /// Data without padding.
- public static byte[] RemovePadding(byte[] data, int blockSize)
+ /// The input data, including padding.
+ /// The block size used for padding.
+ /// If true, ignores errors and attempts to process the input data as-is.
+ /// The unpadded data as a byte array.
+ /// Thrown if the input data or padding is invalid and ignoreErrors is false.
+ public static byte[] RemovePadding(byte[] data, int blockSize, bool ignoreErrors = false)
{
- // The last byte is the padding length
+ // Check for null or empty data
+ if (data == null || data.Length == 0)
+ {
+ if (ignoreErrors)
+ {
+ return new byte[] { };
+ }
+ throw new ArgumentException("Input data cannot be null or empty.");
+ }
+
+ // Ensure the data length is a multiple of the block size
+ if (data.Length % blockSize != 0)
+ {
+ if (ignoreErrors)
+ {
+ // Return the original data if errors are ignored
+ return data;
+ }
+ throw new ArgumentException("Input data length must be a multiple of the block size.");
+ }
+
+ // Retrieve the padding length from the last byte
int paddingLength = data[data.Length - 1];
- // Remove the padding
+ // Validate padding length
+ if (paddingLength <= 0 || paddingLength > blockSize)
+ {
+ if (ignoreErrors)
+ {
+ // Treat padding length as 0 and return the full data
+ return data;
+ }
+ throw new ArgumentException($"Invalid padding length: {paddingLength}. Must be between 1 and {blockSize}.");
+ }
+
+ // Validate the padding region (last paddingLength - 1 bytes must be 0x00)
+ for (int i = data.Length - paddingLength; i < data.Length - 1; i++)
+ {
+ if (data[i] != 0x00)
+ {
+ if (ignoreErrors)
+ {
+ // Ignore invalid padding and return data up to the detected length
+ byte[] fallbackData = new byte[data.Length - paddingLength];
+ Array.Copy(data, 0, fallbackData, 0, fallbackData.Length);
+ return fallbackData;
+ }
+ throw new ArgumentException("Invalid padding detected. Expected padding bytes to be 0x00.");
+ }
+ }
+
+ // Extract unpadded data
byte[] unpaddedData = new byte[data.Length - paddingLength];
- Array.Copy(data, unpaddedData, unpaddedData.Length);
+ Array.Copy(data, 0, unpaddedData, 0, unpaddedData.Length);
return unpaddedData;
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/LEA.cs b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/LEA.cs
index 2e5f0da..0492bb0 100644
--- a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/LEA.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/LEA.cs
@@ -30,6 +30,8 @@
*
*/
using System;
+using System.Security.Cryptography;
+using System.Text;
namespace WelsonJS.Cryptography
{
@@ -279,5 +281,69 @@ namespace WelsonJS.Cryptography
ENCRYPT,
DECRYPT
}
+
+ public class ECB
+ {
+ private Mode mode;
+ private LEA engine;
+ private int blockSize;
+
+ ECB(Mode mode, string key)
+ {
+ engine = new LEA();
+ Init(mode, CreateKey(key));
+ blockSize = engine.GetBlockSize();
+ }
+
+ public string GetAlgorithmName()
+ {
+ return engine.GetAlgorithmName() + "/ECB";
+ }
+
+ public void Init(Mode mode, byte[] mk)
+ {
+ this.mode = mode;
+ engine.Init(mode, mk);
+ }
+
+ private byte[] CreateKey(string key)
+ {
+ SHA256 hasher = SHA256.Create();
+ byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
+
+ return hashData;
+ }
+
+ public byte[] Encrypt(byte[] data)
+ {
+ if (this.mode != Mode.ENCRYPT)
+ throw new InvalidOperationException("Not initialized for encryption mode.");
+
+ byte[] inputData = PKCS5Padding.AddPadding(data, blockSize);
+ byte[] outputData = new byte[inputData.Length];
+
+ for (int i = 0; i < inputData.Length; i += blockSize)
+ {
+ engine.ProcessBlock(inputData, i, outputData, i);
+ }
+
+ return outputData;
+ }
+
+ public byte[] Decrypt(byte[] data)
+ {
+ if (this.mode != Mode.DECRYPT)
+ throw new InvalidOperationException("Not initialized for decryption mode.");
+
+ byte[] outputData = new byte[data.Length];
+
+ for (int i = 0; i < data.Length; i += blockSize)
+ {
+ engine.ProcessBlock(data, i, outputData, i);
+ }
+
+ return PKCS5Padding.RemovePadding(outputData, blockSize, true);
+ }
+ }
}
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs
new file mode 100644
index 0000000..cb16f8c
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs
@@ -0,0 +1,105 @@
+/*
+ * WelsonJS.Toolkit: WelsonJS native component
+ *
+ * filename:
+ * PKCS5Padding.cs
+ *
+ * description:
+ * PKCS5Padding implementation
+ *
+ * website:
+ * - https://github.com/gnh1201/welsonjs
+ * - https://catswords.social/@catswords_oss
+ * - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
+ * - https://discord.gg/XKG5CjtXEj
+ *
+ * authors:
+ * - Namhyeon Go (@gnh1201)
+ *
+ * references:
+ * - ChatGPT prompt "PKCS5Padding with C#" (chatgpt.com)
+ * - ChatGPT prompt "PKCS5Padding with C#, Add a flag to decide how to handle possible errors when removing padding." (chatgpt.com)
+ *
+ * license:
+ * GPLv3 or MS-RL(Microsoft Reciprocal License)
+ *
+ */
+using System;
+
+namespace WelsonJS.Cryptography
+{
+ public class PKCS5Padding
+ {
+ // Add padding to the data based on the block size.
+ public static byte[] AddPadding(byte[] data, int blockSize)
+ {
+ int paddingLength = blockSize - (data.Length % blockSize);
+ byte[] paddedData = new byte[data.Length + paddingLength];
+
+ // Copy original data into the padded array
+ Array.Copy(data, paddedData, data.Length);
+
+ // Fill padding with the padding length (PKCS5)
+ for (int i = data.Length; i < paddedData.Length; i++)
+ {
+ paddedData[i] = (byte)paddingLength;
+ }
+
+ return paddedData;
+ }
+
+ // Remove padding based on the block size.
+ public static byte[] RemovePadding(byte[] data, int blockSize, bool ignoreErrors = false)
+ {
+ // If data length is 0, return empty array
+ if (data.Length == 0)
+ {
+ return new byte[] { };
+ }
+
+ // If data length is smaller than block size, treat it as unpadded
+ if (data.Length < blockSize)
+ {
+ return data;
+ }
+
+ // Check if the last byte is valid padding (PKCS5)
+ int paddingLength = data[data.Length - 1];
+
+ // Validate padding length
+ if (paddingLength < 1 || paddingLength > blockSize)
+ {
+ if (!ignoreErrors)
+ {
+ throw new ArgumentException("Invalid padding length.");
+ }
+ else
+ {
+ return data; // Return data as is if error is ignored
+ }
+ }
+
+ // Check if the padding is correct (i.e., all padding bytes must be equal to paddingLength)
+ for (int i = data.Length - paddingLength; i < data.Length; i++)
+ {
+ if (data[i] != paddingLength)
+ {
+ if (!ignoreErrors)
+ {
+ throw new ArgumentException("Invalid padding detected.");
+ }
+ else
+ {
+ return data; // Return data as is if error is ignored
+ }
+ }
+ }
+
+ // Remove the padding
+ byte[] unpaddedData = new byte[data.Length - paddingLength];
+ Array.Copy(data, unpaddedData, unpaddedData.Length);
+
+ return unpaddedData;
+ }
+ }
+}
diff --git a/WelsonJS.Toolkit/WelsonJS.Toolkit/WelsonJS.Toolkit.csproj b/WelsonJS.Toolkit/WelsonJS.Toolkit/WelsonJS.Toolkit.csproj
index 6f914f9..3dda594 100644
--- a/WelsonJS.Toolkit/WelsonJS.Toolkit/WelsonJS.Toolkit.csproj
+++ b/WelsonJS.Toolkit/WelsonJS.Toolkit/WelsonJS.Toolkit.csproj
@@ -93,6 +93,7 @@
+