mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-02-06 06:54:58 +00:00
Add error handling flags for AnsiX923Padding, and PKCS5Padding
This commit is contained in:
parent
7ef4437447
commit
3ed38eec6a
|
@ -577,7 +577,7 @@ namespace WelsonJS.Cryptography
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected byte[] CreateKey(string key)
|
private byte[] CreateKey(string key)
|
||||||
{
|
{
|
||||||
SHA256 hasher = SHA256.Create();
|
SHA256 hasher = SHA256.Create();
|
||||||
byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
|
byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
|
||||||
|
@ -587,7 +587,7 @@ namespace WelsonJS.Cryptography
|
||||||
|
|
||||||
public byte[] Encrypt(byte[] data)
|
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];
|
byte[] outdata = new byte[indata.Length];
|
||||||
|
|
||||||
for (int i = 0; i < indata.Length; i += BLOCK_SIZE)
|
for (int i = 0; i < indata.Length; i += BLOCK_SIZE)
|
||||||
|
@ -607,7 +607,7 @@ namespace WelsonJS.Cryptography
|
||||||
engine.Decrypt(data, i, outdata, i);
|
engine.Decrypt(data, i, outdata, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnsiX923Padding.RemovePadding(outdata, BLOCK_SIZE);
|
return AnsiX923Padding.RemovePadding(outdata, BLOCK_SIZE, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
* references:
|
* 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
|
* - 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#" (chatgpt.com)
|
||||||
|
* - ChatGPT prompt "AnsiX923Padding with C#, Add a flag to decide how to handle possible errors when removing padding." (chatgpt.com)
|
||||||
*
|
*
|
||||||
* license:
|
* license:
|
||||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||||
|
@ -31,12 +32,12 @@ namespace WelsonJS.Cryptography
|
||||||
class AnsiX923Padding
|
class AnsiX923Padding
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The data to be padded.</param>
|
/// <param name="data">The data to be padded.</param>
|
||||||
/// <param name="blockSize">The block size to pad to.</param>
|
/// <param name="blockSize">The block size to pad to.</param>
|
||||||
/// <returns>Padded data with ANSI X.923 padding.</returns>
|
/// <returns>Padded data with ANSI X.923 padding.</returns>
|
||||||
public static byte[] ApplyPadding(byte[] data, int blockSize)
|
public static byte[] AddPadding(byte[] data, int blockSize)
|
||||||
{
|
{
|
||||||
int paddingLength = blockSize - (data.Length % blockSize);
|
int paddingLength = blockSize - (data.Length % blockSize);
|
||||||
|
|
||||||
|
@ -62,19 +63,69 @@ namespace WelsonJS.Cryptography
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes the ANSI X.923 padding from the data.
|
/// Removes ANSI X.923 padding from the given data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The padded data to remove padding from.</param>
|
/// <param name="data">The input data, including padding.</param>
|
||||||
/// <param name="blockSize">The block size used during padding.</param>
|
/// <param name="blockSize">The block size used for padding.</param>
|
||||||
/// <returns>Data without padding.</returns>
|
/// <param name="ignoreErrors">If true, ignores errors and attempts to process the input data as-is.</param>
|
||||||
public static byte[] RemovePadding(byte[] data, int blockSize)
|
/// <returns>The unpadded data as a byte array.</returns>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the input data or padding is invalid and ignoreErrors is false.</exception>
|
||||||
|
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];
|
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];
|
byte[] unpaddedData = new byte[data.Length - paddingLength];
|
||||||
Array.Copy(data, unpaddedData, unpaddedData.Length);
|
Array.Copy(data, 0, unpaddedData, 0, unpaddedData.Length);
|
||||||
|
|
||||||
return unpaddedData;
|
return unpaddedData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace WelsonJS.Cryptography
|
namespace WelsonJS.Cryptography
|
||||||
{
|
{
|
||||||
|
@ -279,5 +281,69 @@ namespace WelsonJS.Cryptography
|
||||||
ENCRYPT,
|
ENCRYPT,
|
||||||
DECRYPT
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
105
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs
Normal file
105
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs
Normal file
|
@ -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) <abuse@catswords.net>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -93,6 +93,7 @@
|
||||||
<Compile Include="Cryptography\ARIA.cs" />
|
<Compile Include="Cryptography\ARIA.cs" />
|
||||||
<Compile Include="Cryptography\HIGHT.cs" />
|
<Compile Include="Cryptography\HIGHT.cs" />
|
||||||
<Compile Include="Cryptography\LEA.cs" />
|
<Compile Include="Cryptography\LEA.cs" />
|
||||||
|
<Compile Include="Cryptography\PKCS5Padding.cs" />
|
||||||
<Compile Include="Cryptography\SEED.cs" />
|
<Compile Include="Cryptography\SEED.cs" />
|
||||||
<Compile Include="NamedSharedMemory.cs" />
|
<Compile Include="NamedSharedMemory.cs" />
|
||||||
<Compile Include="ProcessUtils.cs" />
|
<Compile Include="ProcessUtils.cs" />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user