welsonjs/WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs

606 lines
23 KiB
C#

// ARIA.cs
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
// https://github.com/gnh1201/welsonjs
//
// ARIA(KS X 1213-1, RFC5794, RFC6209) cryptography algorithm implementation (Experimental)
//
using System.Security.Cryptography;
using System.Text;
namespace WelsonJS.Cryptography
{
public class ARIA
{
private static readonly uint[,] KRK = new uint[,] {
{0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0},
{0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0},
{0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e}
};
private static readonly byte[] S1 = new byte[256];
private static readonly byte[] S2 = new byte[256];
private static readonly byte[] X1 = new byte[256];
private static readonly byte[] X2 = new byte[256];
private static readonly uint[] TS1 = new uint[256];
private static readonly uint[] TS2 = new uint[256];
private static readonly uint[] TX1 = new uint[256];
private static readonly uint[] TX2 = new uint[256];
// Static initializer. For setting up the tables
static ARIA()
{
uint[] exp = new uint[256];
uint[] log = new uint[256];
exp[0] = 1;
for (int i = 1; i < 256; i++)
{
uint j = (exp[i - 1] << 1) ^ exp[i - 1];
if ((j & 0x100) != 0) j ^= 0x11b;
exp[i] = j;
}
for (int i = 1; i < 255; i++)
log[exp[i]] = (uint)i;
uint[,] A = new uint[,] {
{1, 0, 0, 0, 1, 1, 1, 1},
{1, 1, 0, 0, 0, 1, 1, 1},
{1, 1, 1, 0, 0, 0, 1, 1},
{1, 1, 1, 1, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 0, 0, 0},
{0, 1, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 1, 1, 1, 1, 0},
{0, 0, 0, 1, 1, 1, 1, 1}
};
uint[,] B = new uint[,] {
{0, 1, 0, 1, 1, 1, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 1},
{1, 1, 0, 1, 0, 1, 1, 1},
{1, 0, 0, 1, 1, 1, 0, 1},
{0, 0, 1, 0, 1, 1, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 1, 1, 1, 0, 1},
{1, 1, 0, 1, 0, 0, 1, 1}
};
for (int i = 0; i < 256; i++)
{
uint t = 0, p;
if (i == 0)
p = 0;
else
p = exp[255 - log[i]];
for (int j = 0; j < 8; j++)
{
uint s = 0;
for (int k = 0; k < 8; k++)
{
if (((p >> (7 - k)) & 0x01) != 0)
s ^= A[k, j];
}
t = (t << 1) ^ s;
}
t ^= 0x63;
S1[i] = (byte)t;
X1[t] = (byte)i;
}
for (int i = 0; i < 256; i++)
{
uint t = 0, p;
if (i == 0)
p = 0;
else
p = exp[(247 * log[i]) % 255];
for (int j = 0; j < 8; j++)
{
uint s = 0;
for (int k = 0; k < 8; k++)
{
if (((p >> k) & 0x01) != 0)
s ^= B[7 - j, k];
}
t = (t << 1) ^ s;
}
t ^= 0xe2;
S2[i] = (byte)t;
X2[t] = (byte)i;
}
for (int i = 0; i < 256; i++)
{
TS1[i] = (uint)0x00010101 * (S1[i] & (uint)0xff);
TS2[i] = (uint)0x01000101 * (S2[i] & (uint)0xff);
TX1[i] = (uint)0x01010001 * (X1[i] & (uint)0xff);
TX2[i] = (uint)0x01010100 * (X2[i] & (uint)0xff);
}
}
private int keySize = 0;
private int numberOfRounds = 0;
private byte[] masterKey = null;
private uint[] encRoundKeys = null, decRoundKeys = null;
public ARIA(int keySize)
{
SetKeySize(keySize);
}
/**
* Resets the class so that it can be reused for another master key.
*/
private void Reset()
{
keySize = 0;
numberOfRounds = 0;
masterKey = null;
encRoundKeys = null;
decRoundKeys = null;
}
public int GetKeySize()
{
return keySize;
}
private void SetKeySize(int _keySize)
{
Reset();
if (_keySize != 128 && _keySize != 192 && _keySize != 256)
throw new CryptographicException("keySize=" + _keySize);
switch (_keySize)
{
case 128:
numberOfRounds = 12;
break;
case 192:
numberOfRounds = 14;
break;
case 256:
numberOfRounds = 16;
break;
}
keySize = _keySize;
}
private void SetKey(byte[] masterKey)
{
if (masterKey.Length * 8 < keySize)
throw new CryptographicException("masterKey size=" + masterKey.Length);
decRoundKeys = null;
encRoundKeys = null;
masterKey = (byte[])masterKey.Clone();
}
private void SetupEncRoundKeys()
{
if (keySize == 0)
throw new CryptographicException("keySize");
if (masterKey == null)
throw new CryptographicException("masterKey");
if (encRoundKeys == null)
encRoundKeys = new uint[4 * (numberOfRounds + 1)];
decRoundKeys = null;
DoEncKeySetup(masterKey, encRoundKeys, keySize);
}
void SetupDecRoundKeys()
{
if (keySize == 0)
throw new CryptographicException("keySize");
if (encRoundKeys == null)
{
if (masterKey == null)
{
throw new CryptographicException("masterKey");
}
else
{
SetupEncRoundKeys();
}
}
decRoundKeys = (uint[])encRoundKeys.Clone();
DoDecKeySetup(masterKey, decRoundKeys, keySize);
}
public void SetupRoundKeys()
{
SetupDecRoundKeys();
}
private static void DoCrypt(byte[] i, int ioffset, uint[] rk, int nr, byte[] o, int ooffset)
{
uint t0, t1, t2, t3, j = 0;
t0 = ToInt(i[0 + ioffset], i[1 + ioffset], i[2 + ioffset], i[3 + ioffset]);
t1 = ToInt(i[4 + ioffset], i[5 + ioffset], i[6 + ioffset], i[7 + ioffset]);
t2 = ToInt(i[8 + ioffset], i[9 + ioffset], i[10 + ioffset], i[11 + ioffset]);
t3 = ToInt(i[12 + ioffset], i[13 + ioffset], i[14 + ioffset], i[15 + ioffset]);
for (int r = 1; r < nr / 2; r++)
{
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
t0 = TX1[(t0 >> 24) & 0xff] ^ TX2[(t0 >> 16) & 0xff] ^ TS1[(t0 >> 8) & 0xff] ^ TS2[t0 & 0xff];
t1 = TX1[(t1 >> 24) & 0xff] ^ TX2[(t1 >> 16) & 0xff] ^ TS1[(t1 >> 8) & 0xff] ^ TS2[t1 & 0xff];
t2 = TX1[(t2 >> 24) & 0xff] ^ TX2[(t2 >> 16) & 0xff] ^ TS1[(t2 >> 8) & 0xff] ^ TS2[t2 & 0xff];
t3 = TX1[(t3 >> 24) & 0xff] ^ TX2[(t3 >> 16) & 0xff] ^ TS1[(t3 >> 8) & 0xff] ^ TS2[t3 & 0xff];
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t3 = Badc(t3); t0 = Cdab(t0); t1 = Dcba(t1);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
}
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
o[0 + ooffset] = (byte)(X1[0xff & (t0 >> 24)] ^ (rk[j] >> 24));
o[1 + ooffset] = (byte)(X2[0xff & (t0 >> 16)] ^ (rk[j] >> 16));
o[2 + ooffset] = (byte)(S1[0xff & (t0 >> 8)] ^ (rk[j] >> 8));
o[3 + ooffset] = (byte)(S2[0xff & (t0)] ^ (rk[j]));
o[4 + ooffset] = (byte)(X1[0xff & (t1 >> 24)] ^ (rk[j + 1] >> 24));
o[5 + ooffset] = (byte)(X2[0xff & (t1 >> 16)] ^ (rk[j + 1] >> 16));
o[6 + ooffset] = (byte)(S1[0xff & (t1 >> 8)] ^ (rk[j + 1] >> 8));
o[7 + ooffset] = (byte)(S2[0xff & (t1)] ^ (rk[j + 1]));
o[8 + ooffset] = (byte)(X1[0xff & (t2 >> 24)] ^ (rk[j + 2] >> 24));
o[9 + ooffset] = (byte)(X2[0xff & (t2 >> 16)] ^ (rk[j + 2] >> 16));
o[10 + ooffset] = (byte)(S1[0xff & (t2 >> 8)] ^ (rk[j + 2] >> 8));
o[11 + ooffset] = (byte)(S2[0xff & (t2)] ^ (rk[j + 2]));
o[12 + ooffset] = (byte)(X1[0xff & (t3 >> 24)] ^ (rk[j + 3] >> 24));
o[13 + ooffset] = (byte)(X2[0xff & (t3 >> 16)] ^ (rk[j + 3] >> 16));
o[14 + ooffset] = (byte)(S1[0xff & (t3 >> 8)] ^ (rk[j + 3] >> 8));
o[15 + ooffset] = (byte)(S2[0xff & (t3)] ^ (rk[j + 3]));
}
public void Encrypt(byte[] i, int ioffset, byte[] o, int ooffset)
{
if (keySize == 0)
throw new CryptographicException("keySize");
if (encRoundKeys == null)
{
if (masterKey == null)
{
throw new CryptographicException("masterKey");
}
else
{
SetupEncRoundKeys();
}
}
DoCrypt(i, ioffset, encRoundKeys, numberOfRounds, o, ooffset);
}
public byte[] Encrypt(byte[] i, int ioffset)
{
byte[] o = new byte[16];
Encrypt(i, ioffset, o, 0);
return o;
}
public void Decrypt(byte[] i, int ioffset, byte[] o, int ooffset)
{
if (keySize == 0)
throw new CryptographicException("keySize");
if (decRoundKeys == null)
{
if (masterKey == null)
{
throw new CryptographicException("masterKey");
}
else
{
SetupDecRoundKeys();
}
}
DoCrypt(i, ioffset, decRoundKeys, numberOfRounds, o, ooffset);
}
public byte[] Decrypt(byte[] i, int ioffset)
{
byte[] o = new byte[16];
Decrypt(i, ioffset, o, 0);
return o;
}
private static void DoEncKeySetup(byte[] mk, uint[] rk, int keyBits)
{
uint t0, t1, t2, t3;
int q, j = 0;
uint[] w0 = new uint[4];
uint[] w1 = new uint[4];
uint[] w2 = new uint[4];
uint[] w3 = new uint[4];
w0[0] = ToInt(mk[0], mk[1], mk[2], mk[3]);
w0[1] = ToInt(mk[4], mk[5], mk[6], mk[7]);
w0[2] = ToInt(mk[8], mk[9], mk[10], mk[11]);
w0[3] = ToInt(mk[12], mk[13], mk[14], mk[15]);
q = (keyBits - 128) / 64;
t0 = w0[0] ^ KRK[q, 0]; t1 = w0[1] ^ KRK[q, 1];
t2 = w0[2] ^ KRK[q, 2]; t3 = w0[3] ^ KRK[q, 3];
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
if (keyBits > 128)
{
w1[0] = ToInt(mk[16], mk[17], mk[18], mk[19]);
w1[1] = ToInt(mk[20], mk[21], mk[22], mk[23]);
if (keyBits > 192)
{
w1[2] = ToInt(mk[24], mk[25], mk[26], mk[27]);
w1[3] = ToInt(mk[28], mk[29], mk[30], mk[31]);
}
else
{
w1[2] = w1[3] = 0;
}
}
else
{
w1[0] = w1[1] = w1[2] = w1[3] = 0;
}
w1[0] ^= t0; w1[1] ^= t1; w1[2] ^= t2; w1[3] ^= t3;
t0 = w1[0]; t1 = w1[1]; t2 = w1[2]; t3 = w1[3];
q = (q == 2) ? 0 : (q + 1);
t0 ^= KRK[q, 0]; t1 ^= KRK[q, 1]; t2 ^= KRK[q, 2]; t3 ^= KRK[q, 3];
t0 = TX1[(t0 >> 24) & 0xff] ^ TX2[(t0 >> 16) & 0xff] ^ TS1[(t0 >> 8) & 0xff] ^ TS2[t0 & 0xff];
t1 = TX1[(t1 >> 24) & 0xff] ^ TX2[(t1 >> 16) & 0xff] ^ TS1[(t1 >> 8) & 0xff] ^ TS2[t1 & 0xff];
t2 = TX1[(t2 >> 24) & 0xff] ^ TX2[(t2 >> 16) & 0xff] ^ TS1[(t2 >> 8) & 0xff] ^ TS2[t2 & 0xff];
t3 = TX1[(t3 >> 24) & 0xff] ^ TX2[(t3 >> 16) & 0xff] ^ TS1[(t3 >> 8) & 0xff] ^ TS2[t3 & 0xff];
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t3 = Badc(t3); t0 = Cdab(t0); t1 = Dcba(t1);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t0 ^= w0[0]; t1 ^= w0[1]; t2 ^= w0[2]; t3 ^= w0[3];
w2[0] = t0; w2[1] = t1; w2[2] = t2; w2[3] = t3;
q = (q == 2) ? 0 : (q + 1);
t0 ^= KRK[q, 0]; t1 ^= KRK[q, 1]; t2 ^= KRK[q, 2]; t3 ^= KRK[q, 3];
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
w3[0] = t0 ^ w1[0]; w3[1] = t1 ^ w1[1]; w3[2] = t2 ^ w1[2]; w3[3] = t3 ^ w1[3];
Gsrk(w0, w1, 19, rk, j); j += 4;
Gsrk(w1, w2, 19, rk, j); j += 4;
Gsrk(w2, w3, 19, rk, j); j += 4;
Gsrk(w3, w0, 19, rk, j); j += 4;
Gsrk(w0, w1, 31, rk, j); j += 4;
Gsrk(w1, w2, 31, rk, j); j += 4;
Gsrk(w2, w3, 31, rk, j); j += 4;
Gsrk(w3, w0, 31, rk, j); j += 4;
Gsrk(w0, w1, 67, rk, j); j += 4;
Gsrk(w1, w2, 67, rk, j); j += 4;
Gsrk(w2, w3, 67, rk, j); j += 4;
Gsrk(w3, w0, 67, rk, j); j += 4;
Gsrk(w0, w1, 97, rk, j); j += 4;
if (keyBits > 128)
{
Gsrk(w1, w2, 97, rk, j); j += 4;
Gsrk(w2, w3, 97, rk, j); j += 4;
}
if (keyBits > 192)
{
Gsrk(w3, w0, 97, rk, j); j += 4;
Gsrk(w0, w1, 109, rk, j);
}
}
/**
* Main bulk of the decryption key setup method. Here we assume that
* the int array rk already contains the encryption round keys.
* @param mk the master key
* @param rk the array which contains the encryption round keys at the
* beginning of the method execution. At the end of method execution
* this will hold the decryption round keys.
* @param keyBits the length of the master key
* @return
*/
private static void DoDecKeySetup(byte[] mk, uint[] rk, int keyBits)
{
int a = 0, z;
uint[] t = new uint[4];
z = 32 + keyBits / 8;
SwapBlocks(rk, 0, z);
a += 4; z -= 4;
for (; a < z; a += 4, z -= 4)
SwapAndDiffuse(rk, a, z, t);
Diff(rk, a, t, 0);
rk[a] = t[0]; rk[a + 1] = t[1]; rk[a + 2] = t[2]; rk[a + 3] = t[3];
}
private static uint ToInt(byte b0, byte b1, byte b2, byte b3)
{
return (uint)((b0 & 0xff) << 24 ^ (b1 & 0xff) << 16 ^ (b2 & 0xff) << 8 ^ b3 & 0xff);
}
private static uint M(uint t)
{
return 0x00010101 * ((t >> 24) & 0xff) ^ 0x01000101 * ((t >> 16) & 0xff) ^
0x01010001 * ((t >> 8) & 0xff) ^ 0x01010100 * (t & 0xff);
}
// private static final int ms(int t) {
// return TS1[(t>>>24)&0xff]^TS2[(t>>>16)&0xff]^TX1[(t>>>8)&0xff]^TX2[t&0xff];
// }
// private static final int mx(int t) {
// return TX1[(t>>>24)&0xff]^TX2[(t>>>16)&0xff]^TS1[(t>>>8)&0xff]^TS2[t&0xff];
// }
private static uint Badc(uint t)
{
return ((t << 8) & 0xff00ff00) ^ ((t >> 8) & 0x00ff00ff);
}
private static uint Cdab(uint t)
{
return ((t << 16) & 0xffff0000) ^ ((t >> 16) & 0x0000ffff);
}
private static uint Dcba(uint t)
{
return (t & 0x000000ff) << 24 ^ (t & 0x0000ff00) << 8 ^ (t & 0x00ff0000) >> 8 ^ (t & 0xff000000) >> 24;
}
private static void Gsrk(uint[] x, uint[] y, int rot, uint[] rk, int offset)
{
int q = 4 - (rot / 32), r = rot % 32, s = 32 - r;
rk[offset] = x[0] ^ y[(q) % 4] >> r ^ y[(q + 3) % 4] << s;
rk[offset + 1] = x[1] ^ y[(q + 1) % 4] >> r ^ y[(q) % 4] << s;
rk[offset + 2] = x[2] ^ y[(q + 2) % 4] >> r ^ y[(q + 1) % 4] << s;
rk[offset + 3] = x[3] ^ y[(q + 3) % 4] >> r ^ y[(q + 2) % 4] << s;
}
private static void Diff(uint[] i, int offset1, uint[] o, int offset2)
{
uint t0, t1, t2, t3;
t0 = M(i[offset1]); t1 = M(i[offset1 + 1]); t2 = M(i[offset1 + 2]); t3 = M(i[offset1 + 3]);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
o[offset2] = t0; o[offset2 + 1] = t1; o[offset2 + 2] = t2; o[offset2 + 3] = t3;
}
private static void SwapBlocks(uint[] arr, int offset1, int offset2)
{
uint t;
for (int i = 0; i < 4; i++)
{
t = arr[offset1 + i];
arr[offset1 + i] = arr[offset2 + i];
arr[offset2 + i] = t;
}
}
private static void SwapAndDiffuse(uint[] arr, int offset1, int offset2, uint[] tmp)
{
Diff(arr, offset1, tmp, 0);
Diff(arr, offset2, arr, offset1);
arr[offset2] = tmp[0]; arr[offset2 + 1] = tmp[1];
arr[offset2 + 2] = tmp[2]; arr[offset2 + 3] = tmp[3];
}
public class ECB
{
private static readonly int BLOCK_SIZE = 16;
private ARIA engine = null;
public ECB(byte[] key)
{
Init(key);
}
public ECB(string key)
{
Init(CreateKey(key));
}
private void Init(byte[] key)
{
engine = new ARIA(key.Length * 8);
engine.SetKey(key);
engine.SetupRoundKeys();
}
/// <summary>
/// allowed key size (bit): 128, 192, 256
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private byte[] CreateKey(string key)
{
SHA256 hasher = SHA256.Create();
byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
return hashData;
}
public byte[] Encrypt(byte[] data)
{
byte[] indata = AnsiX923Padding.AddPadding(data, BLOCK_SIZE);
byte[] outdata = new byte[indata.Length];
for (int i = 0; i < indata.Length; i += BLOCK_SIZE)
{
engine.Encrypt(indata, i, outdata, i);
}
return outdata;
}
public byte[] Decrypt(byte[] data)
{
byte[] outdata = new byte[data.Length];
for (int i = 0; i < data.Length; i += BLOCK_SIZE)
{
engine.Decrypt(data, i, outdata, i);
}
return AnsiX923Padding.RemovePadding(outdata, BLOCK_SIZE, true);
}
}
}
}
/* References:
* [1] KISA(Korea Internet & Security Agency) - 블록암호 ARIA
* https://seed.kisa.or.kr/kisa/Board/19/detailView.do
* [2] Naver Blog - ARIA 암호 JAVA, .NET(C#) 라이브러리 (@angelkum)
* https://blog.naver.com/angelkum/130154153446
* [3] NSRI(National Security Research Institute) - 검증대상 암호알고리즘
* https://www.ncsc.go.kr:4018/PageLink.do?link=forward:/PageContent.do&tempParam1=&menuNo=060000&subMenuNo=060200&thirdMenuNo=
* [4] NIS(National Intelligence Service) - 암호모듈 검증
* https://www.nis.go.kr/AF/1_7_3_1.do
* [5] IETF - RFC 5794 - A Description of the ARIA Encryption Algorithm
* https://datatracker.ietf.org/doc/html/rfc5794
* [6] IETF - RFC 6209 - Addition of the ARIA Cipher Suites to Transport Layer Security (TLS)
* https://datatracker.ietf.org/doc/html/rfc6209
* [7] GitHub - 표준프레임워크의 실행환경 (eGovFrame/egovframework.rte.root)
* https://github.com/eGovFrame/egovframework.rte.root/blob/master/Foundation/egovframework.rte.fdl.crypto/src/main/java/egovframework/rte/fdl/cryptography/impl/aria/ARIAEngine.java
* [8] NSRI(National Security Research Institute) - 민관겸용 블록 암호 알고리즘 ARIA 알고리즘 명세서 (Version 1.0, 2024. 5.)
* https://ics.catswords.net/ARIA-specification.pdf
* [9] NSRI(National Security Research Institute) - ARIA 테스트 벡터 (Version 1.0)
* https://ics.catswords.net/ARIA-testvector.pdf
*/