Files
SuperVPN/output/Libraries/BouncyCastle.Crypto/Org/BouncyCastle/Crypto/Engines/SM4Engine.cs
2025-10-09 09:57:24 +09:00

168 lines
5.2 KiB
C#

using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines;
public class SM4Engine : IBlockCipher
{
private const int BlockSize = 16;
private static readonly byte[] Sbox = new byte[256]
{
214, 144, 233, 254, 204, 225, 61, 183, 22, 182,
20, 194, 40, 251, 44, 5, 43, 103, 154, 118,
42, 190, 4, 195, 170, 68, 19, 38, 73, 134,
6, 153, 156, 66, 80, 244, 145, 239, 152, 122,
51, 84, 11, 67, 237, 207, 172, 98, 228, 179,
28, 169, 201, 8, 232, 149, 128, 223, 148, 250,
117, 143, 63, 166, 71, 7, 167, 252, 243, 115,
23, 186, 131, 89, 60, 25, 230, 133, 79, 168,
104, 107, 129, 178, 113, 100, 218, 139, 248, 235,
15, 75, 112, 86, 157, 53, 30, 36, 14, 94,
99, 88, 209, 162, 37, 34, 124, 59, 1, 33,
120, 135, 212, 0, 70, 87, 159, 211, 39, 82,
76, 54, 2, 231, 160, 196, 200, 158, 234, 191,
138, 210, 64, 199, 56, 181, 163, 247, 242, 206,
249, 97, 21, 161, 224, 174, 93, 164, 155, 52,
26, 85, 173, 147, 50, 48, 245, 140, 177, 227,
29, 246, 226, 46, 130, 102, 202, 96, 192, 41,
35, 171, 13, 83, 78, 111, 213, 219, 55, 69,
222, 253, 142, 47, 3, 255, 106, 114, 109, 108,
91, 81, 141, 27, 175, 146, 187, 221, 188, 127,
17, 217, 92, 65, 31, 16, 90, 216, 10, 193,
49, 136, 165, 205, 123, 189, 45, 116, 208, 18,
184, 229, 180, 176, 137, 105, 151, 74, 12, 150,
119, 126, 101, 185, 241, 9, 197, 110, 198, 132,
24, 240, 125, 236, 58, 220, 77, 32, 121, 238,
95, 62, 215, 203, 57, 72
};
private static readonly uint[] CK = new uint[32]
{
462357u, 472066609u, 943670861u, 1415275113u, 1886879365u, 2358483617u, 2830087869u, 3301692121u, 3773296373u, 4228057617u,
404694573u, 876298825u, 1347903077u, 1819507329u, 2291111581u, 2762715833u, 3234320085u, 3705924337u, 4177462797u, 337322537u,
808926789u, 1280531041u, 1752135293u, 2223739545u, 2695343797u, 3166948049u, 3638552301u, 4110090761u, 269950501u, 741554753u,
1213159005u, 1684763257u
};
private static readonly uint[] FK = new uint[4] { 2746333894u, 1453994832u, 1736282519u, 2993693404u };
private uint[] rk;
public virtual string AlgorithmName => "SM4";
public virtual bool IsPartialBlockOkay => false;
private static uint tau(uint A)
{
uint num = Sbox[A >> 24];
uint num2 = Sbox[(A >> 16) & 0xFF];
uint num3 = Sbox[(A >> 8) & 0xFF];
uint num4 = Sbox[A & 0xFF];
return (num << 24) | (num2 << 16) | (num3 << 8) | num4;
}
private static uint L_ap(uint B)
{
return B ^ Integers.RotateLeft(B, 13) ^ Integers.RotateLeft(B, 23);
}
private uint T_ap(uint Z)
{
return L_ap(tau(Z));
}
private void ExpandKey(bool forEncryption, byte[] key)
{
uint num = Pack.BE_To_UInt32(key, 0) ^ FK[0];
uint num2 = Pack.BE_To_UInt32(key, 4) ^ FK[1];
uint num3 = Pack.BE_To_UInt32(key, 8) ^ FK[2];
uint num4 = Pack.BE_To_UInt32(key, 12) ^ FK[3];
if (forEncryption)
{
rk[0] = num ^ T_ap(num2 ^ num3 ^ num4 ^ CK[0]);
rk[1] = num2 ^ T_ap(num3 ^ num4 ^ rk[0] ^ CK[1]);
rk[2] = num3 ^ T_ap(num4 ^ rk[0] ^ rk[1] ^ CK[2]);
rk[3] = num4 ^ T_ap(rk[0] ^ rk[1] ^ rk[2] ^ CK[3]);
for (int i = 4; i < 32; i++)
{
rk[i] = rk[i - 4] ^ T_ap(rk[i - 3] ^ rk[i - 2] ^ rk[i - 1] ^ CK[i]);
}
return;
}
rk[31] = num ^ T_ap(num2 ^ num3 ^ num4 ^ CK[0]);
rk[30] = num2 ^ T_ap(num3 ^ num4 ^ rk[31] ^ CK[1]);
rk[29] = num3 ^ T_ap(num4 ^ rk[31] ^ rk[30] ^ CK[2]);
rk[28] = num4 ^ T_ap(rk[31] ^ rk[30] ^ rk[29] ^ CK[3]);
for (int num5 = 27; num5 >= 0; num5--)
{
rk[num5] = rk[num5 + 4] ^ T_ap(rk[num5 + 3] ^ rk[num5 + 2] ^ rk[num5 + 1] ^ CK[31 - num5]);
}
}
private static uint L(uint B)
{
return B ^ Integers.RotateLeft(B, 2) ^ Integers.RotateLeft(B, 10) ^ Integers.RotateLeft(B, 18) ^ Integers.RotateLeft(B, 24);
}
private static uint T(uint Z)
{
return L(tau(Z));
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
if (!(parameters is KeyParameter keyParameter))
{
throw new ArgumentException("invalid parameter passed to SM4 init - " + Platform.GetTypeName(parameters), "parameters");
}
byte[] key = keyParameter.GetKey();
if (key.Length != 16)
{
throw new ArgumentException("SM4 requires a 128 bit key", "parameters");
}
if (rk == null)
{
rk = new uint[32];
}
ExpandKey(forEncryption, key);
}
public virtual int GetBlockSize()
{
return 16;
}
public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (rk == null)
{
throw new InvalidOperationException("SM4 not initialised");
}
Check.DataLength(input, inOff, 16, "input buffer too short");
Check.OutputLength(output, outOff, 16, "output buffer too short");
uint num = Pack.BE_To_UInt32(input, inOff);
uint num2 = Pack.BE_To_UInt32(input, inOff + 4);
uint num3 = Pack.BE_To_UInt32(input, inOff + 8);
uint num4 = Pack.BE_To_UInt32(input, inOff + 12);
for (int i = 0; i < 32; i += 4)
{
num ^= T(num2 ^ num3 ^ num4 ^ rk[i]);
num2 ^= T(num3 ^ num4 ^ num ^ rk[i + 1]);
num3 ^= T(num4 ^ num ^ num2 ^ rk[i + 2]);
num4 ^= T(num ^ num2 ^ num3 ^ rk[i + 3]);
}
Pack.UInt32_To_BE(num4, output, outOff);
Pack.UInt32_To_BE(num3, output, outOff + 4);
Pack.UInt32_To_BE(num2, output, outOff + 8);
Pack.UInt32_To_BE(num, output, outOff + 12);
return 16;
}
public virtual void Reset()
{
}
}