From ec03bf415d0077899583e2331523d1065cba9d7e Mon Sep 17 00:00:00 2001 From: "Namhyeon, Go" Date: Sat, 19 Jul 2025 19:07:05 +0900 Subject: [PATCH] Add ARIA cryptography algorithm Add ARIA cryptography algorithm --- .../WelsonJS.Cryptography.Test/Program.vb | 27 +- .../WelsonJS.Cryptography/AriaAlgorithm.vb | 57 ++++ .../WelsonJS.Cryptography/AriaCore.vb | 293 ++++++++++++++++++ .../WelsonJS.Cryptography/AriaEcbTransform.vb | 161 ++++++++++ 4 files changed, 531 insertions(+), 7 deletions(-) create mode 100644 WelsonJS.Toolkit/WelsonJS.Cryptography/AriaAlgorithm.vb create mode 100644 WelsonJS.Toolkit/WelsonJS.Cryptography/AriaCore.vb create mode 100644 WelsonJS.Toolkit/WelsonJS.Cryptography/AriaEcbTransform.vb diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb index f076ace..a908d53 100644 --- a/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb @@ -9,19 +9,32 @@ Imports System.Text Module Program Sub Main(args As String()) + + ' SEED algorithm Console.WriteLine("Start SEED encryption and decryption test") - Dim cipher As New WelsonJS.Cryptography.SeedAlgorithm() + Dim seedCipher As New WelsonJS.Cryptography.SeedAlgorithm() + seedCipher.Key = {&H88, &HE3, &H4F, &H8F, &H8, &H17, &H79, &HF1, &HE9, &HF3, &H94, &H37, &HA, &HD4, &H5, &H89} + ' seedCipher.IV = {&H26, &H8D, &H66, &HA7, &H35, &HA8, &H1A, &H81, &H6F, &HBA, &HD9, &HFA, &H36, &H16, &H25, &H1} + seedCipher.Mode = CipherMode.ECB + seedCipher.Padding = PaddingMode.PKCS7 + RunTest(seedCipher) + Console.WriteLine() - cipher.Key = {&H88, &HE3, &H4F, &H8F, &H8, &H17, &H79, &HF1, &HE9, &HF3, &H94, &H37, &HA, &HD4, &H5, &H89} - ' cipher.IV = {&H26, &H8D, &H66, &HA7, &H35, &HA8, &H1A, &H81, &H6F, &HBA, &HD9, &HFA, &H36, &H16, &H25, &H1} - cipher.Mode = CipherMode.ECB - cipher.Padding = PaddingMode.PKCS7 + ' ARIA algorithm + Console.WriteLine("Start ARIA encryption and decryption test") + Dim ariaCipher As New WelsonJS.Cryptography.AriaAlgorithm() + ariaCipher.Key = {&H0, &H11, &H22, &H33, &H44, &H55, &H66, &H77, &H88, &H99, &HAA, &HBB, &HCC, &HDD, &HEE, &HFF} + ' ariaChiper.IV = {&H0F, &H1E, &H2D, &H3C, &H4B, &H5A, &H69, &H78, &H87, &H96, &HA5, &HB4, &HC3, &HD2, &HE1, &HF0} + ariaCipher.Mode = CipherMode.ECB + ariaCipher.Padding = PaddingMode.PKCS7 + RunTest(ariaCipher) + Console.WriteLine() - RunTest(cipher) End Sub Public Sub RunTest(cipher As SymmetricAlgorithm) - Dim inputBytes As Byte() = {&H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &HFE} + ' Dim inputBytes As Byte() = {&H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0, &HFE} + Dim inputBytes As Byte() = {&H11, &H11, &H11, &H11, &HAA, &HAA, &HAA, &HAA, &H11, &H11, &H11, &H11, &HBB, &HBB, &HBB, &HBB} Console.WriteLine("Key (HEX):") PrintHex(cipher.Key) diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaAlgorithm.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaAlgorithm.vb new file mode 100644 index 0000000..48c5fd4 --- /dev/null +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaAlgorithm.vb @@ -0,0 +1,57 @@ +' AriaAlgorithm.cs(WelsonJS.Cryptography) +' SPDX-License-Identifier: MIT +' SPDX-FileCopyrightText: 2025 Namhyeon Go , Catswords OSS And WelsonJS Contributors +' https://github.com/gnh1201/welsonjs +' + +Imports System.Security.Cryptography + +Public Class AriaAlgorithm + Inherits SymmetricAlgorithm + + Public Sub New() + LegalBlockSizesValue = New KeySizes() {New KeySizes(128, 128, 0)} + LegalKeySizesValue = New KeySizes() {New KeySizes(128, 256, 64)} + + Me.BlockSize = 128 + Me.KeySize = 128 + Me.FeedbackSize = 128 + + Me.Mode = CipherMode.ECB + Me.Padding = PaddingMode.PKCS7 + + Me.Key = New Byte(15) {} + Me.IV = New Byte(15) {} + End Sub + + Public Overrides Sub GenerateKey() + Using rng As New RNGCryptoServiceProvider() + rng.GetBytes(Me.Key) + End Using + End Sub + + Public Overrides Sub GenerateIV() + Using rng As New RNGCryptoServiceProvider() + rng.GetBytes(Me.IV) + End Using + End Sub + + Public Overrides Function CreateEncryptor(rgbKey As Byte(), rgbIV As Byte()) As ICryptoTransform + Return CreateTransform(rgbKey, rgbIV, True) + End Function + + Public Overrides Function CreateDecryptor(rgbKey As Byte(), rgbIV As Byte()) As ICryptoTransform + Return CreateTransform(rgbKey, rgbIV, False) + End Function + + Private Function CreateTransform(key As Byte(), iv As Byte(), encrypt As Boolean) As ICryptoTransform + Select Case Me.Mode + Case CipherMode.ECB + Return New AriaEcbTransform(key, encrypt, Me.Padding) + Case Else + Throw New NotSupportedException("This mode not supported yet") + End Select + End Function + + ' TODO: CCM, GCM, CMAC +End Class \ No newline at end of file diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaCore.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaCore.vb new file mode 100644 index 0000000..a02aeab --- /dev/null +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaCore.vb @@ -0,0 +1,293 @@ +' AriaCore.vb (WelsonJS.Cryptography) +' SPDX-License-Identifier: MIT +' SPDX-FileCopyrightText: 2025 Namhyeon Go , Catswords OSS And WelsonJS Contributors +' https://github.com/gnh1201/welsonjs +' +' ARIA Core VB.NET Implementation with S-box, inverse S-box, and T-table generation +Public Class AriaCore + Public Shared ReadOnly S1(255) As Byte + Public Shared ReadOnly X1(255) As Byte + Public Shared ReadOnly S2(255) As Byte + Public Shared ReadOnly X2(255) As Byte + Public Shared ReadOnly TS1(255) As UInteger + Public Shared ReadOnly TS2(255) As UInteger + Public Shared ReadOnly TX1(255) As UInteger + Public Shared ReadOnly TX2(255) As UInteger + + Private roundKeys()() As UInteger + Private roundCount As Integer = 12 + + Public Sub New(key() As Byte) + Select Case key.Length + Case 16 + roundCount = 12 + Case 24 + roundCount = 14 + Case 32 + roundCount = 16 + Case Else + Throw New ArgumentException("Only 128, 192, or 256-bit keys are supported.") + End Select + GenerateRoundKeys(key) + End Sub + + Public Sub EncryptBlock(input() As Byte, inOffset As Integer, output() As Byte, outOffset As Integer) + Dim x(3) As UInteger + For i = 0 To 3 + x(i) = BitConverter.ToUInt32(input, inOffset + i * 4) + Next + + For i = 0 To 3 + x(i) = x(i) Xor roundKeys(0)(i) + Next + + For r = 1 To roundCount - 1 + If r = 3 Or r = 7 Then + x = FL(x, roundKeys(r)) + End If + x = FO(x) + For i = 0 To 3 + x(i) = x(i) Xor roundKeys(r)(i) + Next + Next + + x = FO(x) + + For i = 0 To 3 + x(i) = x(i) Xor roundKeys(roundCount)(i) + Next + + For i = 0 To 3 + Dim b() As Byte = BitConverter.GetBytes(x(i)) + Array.Copy(b, 0, output, outOffset + i * 4, 4) + Next + End Sub + + Public Sub DecryptBlock(input() As Byte, inOffset As Integer, output() As Byte, outOffset As Integer) + Dim x(3) As UInteger + For i = 0 To 3 + x(i) = BitConverter.ToUInt32(input, inOffset + i * 4) + Next + + For i = 0 To 3 + x(i) = x(i) Xor roundKeys(roundCount)(i) + Next + + For r = roundCount - 1 To 1 Step -1 + x = RFO(x) + If r = 3 Or r = 7 Then + x = FLInv(x, roundKeys(r)) + End If + For i = 0 To 3 + x(i) = x(i) Xor roundKeys(r)(i) + Next + Next + + x = RFO(x) + + For i = 0 To 3 + x(i) = x(i) Xor roundKeys(0)(i) + Next + + For i = 0 To 3 + Dim b() As Byte = BitConverter.GetBytes(x(i)) + Array.Copy(b, 0, output, outOffset + i * 4, 4) + Next + End Sub + + Private Function FO(x() As UInteger) As UInteger() + Dim y(3) As UInteger + For i = 0 To 3 + Dim b0 As Byte = (x(i) >> 24) And &HFF + Dim b1 As Byte = (x(i) >> 16) And &HFF + Dim b2 As Byte = (x(i) >> 8) And &HFF + Dim b3 As Byte = x(i) And &HFF + y(i) = (CUInt(S1(b0)) << 24) Or (CUInt(S2(b1)) << 16) Or (CUInt(S1(b2)) << 8) Or S2(b3) + Next + Return M(y) + End Function + + Private Function RFO(x() As UInteger) As UInteger() + Dim y(3) As UInteger + y = M(x) + For i = 0 To 3 + Dim b0 As Byte = (y(i) >> 24) And &HFF + Dim b1 As Byte = (y(i) >> 16) And &HFF + Dim b2 As Byte = (y(i) >> 8) And &HFF + Dim b3 As Byte = y(i) And &HFF + x(i) = (CUInt(X1(b0)) << 24) Or (CUInt(X2(b1)) << 16) Or (CUInt(X1(b2)) << 8) Or X2(b3) + Next + Return x + End Function + + Private Function M(x() As UInteger) As UInteger() + Dim y(3) As UInteger + y(0) = x(0) Xor RotateLeft(x(1), 8) Xor RotateLeft(x(2), 16) Xor RotateLeft(x(3), 24) + y(1) = x(1) Xor RotateLeft(x(2), 8) Xor RotateLeft(x(3), 16) Xor RotateLeft(x(0), 24) + y(2) = x(2) Xor RotateLeft(x(3), 8) Xor RotateLeft(x(0), 16) Xor RotateLeft(x(1), 24) + y(3) = x(3) Xor RotateLeft(x(0), 8) Xor RotateLeft(x(1), 16) Xor RotateLeft(x(2), 24) + Return y + End Function + + Private Function RotateLeft(val As UInteger, bits As Integer) As UInteger + Return ((val << bits) Or (val >> (32 - bits))) And &HFFFFFFFFUI + End Function + + Private Sub GenerateRoundKeys(key() As Byte) + roundKeys = New UInteger(roundCount)() {} + For r = 0 To roundCount + roundKeys(r) = New UInteger(3) {} + Next + + Dim w0(3), w1(3), w2(3), w3(3) As UInteger + Dim tempKey(7) As UInteger + For i = 0 To (key.Length \ 4) - 1 + tempKey(i) = BitConverter.ToUInt32(key, i * 4) + Next + + For i = 0 To 3 + w0(i) = tempKey(i) + Next + + Dim c1 As UInteger() = {&H517CC1B7UI, &H27220A94UI, &HFE13ABE8UI, &HFA9A6EE0UI} + Dim c2 As UInteger() = {&H6DB14ACCUI, &H9E21C820UI, &HFF28B1D5UI, &HEE36D2E6UI} + Dim c3 As UInteger() = {&HDB92F2FBUI, &H61A64DF2UI, &HDC04B4DFUI, &H1BF429C3UI} + + w1 = FO(XorBlock(w0, c1)) + w2 = FO(XorBlock(w1, c2)) + w3 = FO(XorBlock(w2, c3)) + + Dim rk(,) As UInteger = { + {0, 19}, {1, 31}, {2, 19}, {3, 31}, + {0, 19}, {1, 31}, {2, 19}, {3, 31}, + {0, 19}, {1, 31}, {2, 19}, {3, 31}, + {0, 19}, {1, 31}, {2, 19}, {3, 31} + } + For r = 0 To roundCount + For i = 0 To 3 + Select Case r + Case < 4 : roundKeys(r)(i) = RotateLeft(w1(i), rk(r, 1)) + Case < 8 : roundKeys(r)(i) = RotateLeft(w2(i), rk(r, 1)) + Case < 12 : roundKeys(r)(i) = RotateLeft(w3(i), rk(r, 1)) + Case < 16 : roundKeys(r)(i) = RotateLeft(w0(i), rk(r, 1)) + End Select + Next + Next + End Sub + + ' ----- Tables ----- + Shared Sub New() + Dim exp(255) As Integer + Dim log(255) As Integer + exp(0) = 1 + For i = 1 To 255 + Dim j As Integer = (exp(i - 1) << 1) Xor exp(i - 1) + If (j And &H100) <> 0 Then j = j Xor &H11B + exp(i) = j + Next + For i = 1 To 254 + log(exp(i)) = i + Next + + Dim A(7, 7) As Integer + Dim AInit(,) As Integer = { + {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} + } + For i = 0 To 7 : For j = 0 To 7 : A(i, j) = AInit(i, j) : Next : Next + + Dim B(7, 7) As Integer + Dim BInit(,) As Integer = { + {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 i = 0 To 7 : For j = 0 To 7 : B(i, j) = BInit(i, j) : Next : Next + + For i = 0 To 255 + Dim t As Integer = 0, p As Integer + If i = 0 Then + p = 0 + Else + p = exp(255 - log(i)) + End If + For j = 0 To 7 + Dim s As Integer = 0 + For k = 0 To 7 + If ((p >> (7 - k)) And 1) <> 0 Then + s = s Xor A(k, j) + End If + Next + t = (t << 1) Xor s + Next + t = t Xor &H63 + S1(i) = CByte(t) + X1(t) = CByte(i) + Next + + For i = 0 To 255 + Dim t As Integer = 0, p As Integer + If i = 0 Then + p = 0 + Else + p = exp((247 * log(i)) Mod 255) + End If + For j = 0 To 7 + Dim s As Integer = 0 + For k = 0 To 7 + If ((p >> k) And 1) <> 0 Then + s = s Xor B(7 - j, k) + End If + Next + t = (t << 1) Xor s + Next + t = t Xor &HE2 + S2(i) = CByte(t) + X2(t) = CByte(i) + Next + + For i = 0 To 255 + TS1(i) = CUInt(&H10101 * (S1(i) And &HFF)) + TS2(i) = CUInt(&H1000101 * (S2(i) And &HFF)) + TX1(i) = CUInt(&H1010001 * (X1(i) And &HFF)) + TX2(i) = CUInt(&H1010100 * (X2(i) And &HFF)) + Next + End Sub + Private Function XorBlock(a() As UInteger, b() As UInteger) As UInteger() + Dim r(3) As UInteger + For i = 0 To 3 + r(i) = a(i) Xor b(i) + Next + Return r + End Function + + Private Function FL(x() As UInteger, k() As UInteger) As UInteger() + Dim y(3) As UInteger + y(0) = x(0) Xor RotateLeft((x(1) And k(0)), 1) + y(1) = x(1) Xor (y(0) Or k(1)) + y(2) = x(2) Xor RotateLeft((x(3) Or k(2)), 1) + y(3) = x(3) Xor (y(2) And k(3)) + Return y + End Function + + Private Function FLInv(x() As UInteger, k() As UInteger) As UInteger() + Dim y(3) As UInteger + y(3) = x(3) Xor ((x(2) Or k(2)) And &HFFFFFFFFUI) + y(2) = x(2) Xor RotateLeft((y(3) Or k(2)), 1) + y(1) = x(1) Xor ((x(0) And k(0)) And &HFFFFFFFFUI) + y(0) = x(0) Xor RotateLeft((y(1) And k(0)), 1) + Return y + End Function + +End Class diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaEcbTransform.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaEcbTransform.vb new file mode 100644 index 0000000..20009d8 --- /dev/null +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography/AriaEcbTransform.vb @@ -0,0 +1,161 @@ +' AriaEcbTransform.cs (WelsonJS.Cryptography) +' SPDX-License-Identifier: MIT +' SPDX-FileCopyrightText: 2025 Namhyeon Go , Catswords OSS And WelsonJS Contributors +' https://github.com/gnh1201/welsonjs + +Imports System.Security.Cryptography + +Public Class AriaEcbTransform + Implements ICryptoTransform + + Private ReadOnly rnd As New Random() + Private ReadOnly seedCore As SeedCore + Private ReadOnly encrypt As Boolean + Private ReadOnly paddingMode As PaddingMode + + Public Sub New(key As Byte(), encryptMode As Boolean, Optional mode As PaddingMode = PaddingMode.PKCS7) + seedCore = New SeedCore(key) + encrypt = encryptMode + paddingMode = mode + End Sub + + Public ReadOnly Property InputBlockSize As Integer Implements ICryptoTransform.InputBlockSize + Get + Return 16 + End Get + End Property + + Public ReadOnly Property OutputBlockSize As Integer Implements ICryptoTransform.OutputBlockSize + Get + Return 16 + End Get + End Property + + Public ReadOnly Property CanTransformMultipleBlocks As Boolean Implements ICryptoTransform.CanTransformMultipleBlocks + Get + Return True + End Get + End Property + + Public ReadOnly Property CanReuseTransform As Boolean Implements ICryptoTransform.CanReuseTransform + Get + Return True + End Get + End Property + + Public Function TransformBlock(input() As Byte, inputOffset As Integer, inputCount As Integer, + output() As Byte, outputOffset As Integer) As Integer Implements ICryptoTransform.TransformBlock + If inputCount <= 0 Then Return 0 + + Dim blockSize = InputBlockSize + Dim remaining = inputCount + Dim inPtr = inputOffset + Dim outPtr = outputOffset + + While remaining >= blockSize + If encrypt Then + seedCore.EncryptBlock(input, inPtr, output, outPtr) + Else + seedCore.DecryptBlock(input, inPtr, output, outPtr) + End If + inPtr += blockSize + outPtr += blockSize + remaining -= blockSize + End While + + Return inputCount - remaining + End Function + + Public Function TransformFinalBlock(input() As Byte, inputOffset As Integer, inputCount As Integer) As Byte() Implements ICryptoTransform.TransformFinalBlock + Dim blockSize = InputBlockSize + Dim buffer() As Byte + + If encrypt Then + Dim paddedLength As Integer + Select Case paddingMode + Case PaddingMode.None + If (inputCount Mod blockSize) <> 0 Then + Throw New CryptographicException("Input data is not a multiple of block size and PaddingMode is None.") + End If + paddedLength = inputCount + + Case PaddingMode.Zeros + paddedLength = ((inputCount + blockSize - 1) \ blockSize) * blockSize + + Case PaddingMode.PKCS7, PaddingMode.ANSIX923, PaddingMode.ISO10126 + Dim padLen = blockSize - (inputCount Mod blockSize) + If padLen = 0 Then padLen = blockSize + paddedLength = inputCount + padLen + + Case Else + Throw New NotSupportedException("Unsupported padding mode: " & paddingMode.ToString()) + End Select + + buffer = New Byte(paddedLength - 1) {} + Array.Copy(input, inputOffset, buffer, 0, inputCount) + + Dim padVal As Byte = CByte(paddedLength - inputCount) + Select Case paddingMode + Case PaddingMode.PKCS7 + For i = inputCount To paddedLength - 1 + buffer(i) = padVal + Next + Case PaddingMode.ANSIX923 + For i = inputCount To paddedLength - 2 + buffer(i) = 0 + Next + buffer(paddedLength - 1) = padVal + Case PaddingMode.ISO10126 + For i = inputCount To paddedLength - 2 + buffer(i) = CByte(rnd.Next(0, 256)) + Next + buffer(paddedLength - 1) = padVal + End Select + + For i = 0 To buffer.Length - 1 Step blockSize + seedCore.EncryptBlock(buffer, i, buffer, i) + Next + Return buffer + + Else + If (inputCount Mod blockSize) <> 0 Then + Throw New CryptographicException("Encrypted data is not a multiple of block size.") + End If + + buffer = New Byte(inputCount - 1) {} + TransformBlock(input, inputOffset, inputCount, buffer, 0) + + Dim padVal As Integer = buffer(buffer.Length - 1) + If padVal <= 0 OrElse padVal > blockSize Then + Throw New CryptographicException("Invalid padding.") + End If + + Select Case paddingMode + Case PaddingMode.PKCS7 + For i = buffer.Length - padVal To buffer.Length - 1 + If buffer(i) <> padVal Then + Throw New CryptographicException("Invalid PKCS7 padding value.") + End If + Next + Case PaddingMode.ANSIX923 + For i = buffer.Length - padVal To buffer.Length - 2 + If buffer(i) <> 0 Then + Throw New CryptographicException("Invalid ANSIX923 padding value.") + End If + Next + Case PaddingMode.ISO10126 + ' no need to check random bytes, only length byte matters + Case Else + Throw New NotSupportedException("Unsupported padding mode: " & paddingMode.ToString()) + End Select + + Dim result(buffer.Length - padVal - 1) As Byte + Array.Copy(buffer, 0, result, 0, result.Length) + Return result + End If + End Function + + Public Sub Dispose() Implements IDisposable.Dispose + ' No resources to dispose + End Sub +End Class