mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-05-30 05:27:00 +00:00
606 lines
23 KiB
C#
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
|
|
*/
|