From 848a4359fa981d49b683039039af0e7d77c005df Mon Sep 17 00:00:00 2001 From: "Namhyeon, Go" Date: Wed, 9 Jul 2025 11:20:54 +0900 Subject: [PATCH] Fix SEED cryptography algorithm Fix SEED cryptography algorithm --- .../WelsonJS.Cryptography.Test/Program.vb | 3 + .../WelsonJS.Cryptography/SeedCore.vb | 84 +++++----- .../WelsonJS.Cryptography/SeedEcbTransform.vb | 155 ++++++------------ 3 files changed, 101 insertions(+), 141 deletions(-) diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb index ca81ac7..f076ace 100644 --- a/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography.Test/Program.vb @@ -23,6 +23,9 @@ Module Program 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} + Console.WriteLine("Key (HEX):") + PrintHex(cipher.Key) + Console.WriteLine("Original bytes (HEX):") PrintHex(inputBytes) diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedCore.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedCore.vb index 30cbcfd..b92cd76 100644 --- a/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedCore.vb +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedCore.vb @@ -156,11 +156,21 @@ Public Class SeedCore KeySchedule(key) End Sub - ' Extract a byte (0 = LSB, 3 = MSB) Private Shared Function GetByte(n As UInteger, index As Integer) As Byte Return CByte((n >> (index * 8)) And &HFF) End Function + Private Shared Function ToUInt32BE(data() As Byte, offset As Integer) As UInteger + Return (CUInt(data(offset)) << 24) Or (CUInt(data(offset + 1)) << 16) Or (CUInt(data(offset + 2)) << 8) Or CUInt(data(offset + 3)) + End Function + + Private Shared Sub WriteUInt32BE(value As UInteger, output() As Byte, offset As Integer) + output(offset) = CByte((value >> 24) And &HFF) + output(offset + 1) = CByte((value >> 16) And &HFF) + output(offset + 2) = CByte((value >> 8) And &HFF) + output(offset + 3) = CByte(value And &HFF) + End Sub + Private Shared Function RoundFunction(T0 As UInteger, T1 As UInteger) As Tuple(Of UInteger, UInteger) T1 = T1 Xor T0 T1 = SS0(GetByte(T1, 0)) Xor SS1(GetByte(T1, 1)) Xor SS2(GetByte(T1, 2)) Xor SS3(GetByte(T1, 3)) @@ -173,10 +183,10 @@ Public Class SeedCore End Function Private Sub KeySchedule(userKey As Byte()) - Dim A As UInteger = BitConverter.ToUInt32(userKey, 0) - Dim B As UInteger = BitConverter.ToUInt32(userKey, 4) - Dim C As UInteger = BitConverter.ToUInt32(userKey, 8) - Dim D As UInteger = BitConverter.ToUInt32(userKey, 12) + Dim A As UInteger = ToUInt32BE(userKey, 0) + Dim B As UInteger = ToUInt32BE(userKey, 4) + Dim C As UInteger = ToUInt32BE(userKey, 8) + Dim D As UInteger = ToUInt32BE(userKey, 12) For i As Integer = 0 To 15 Dim T0 As UInteger = (A + C - KC(i)) And &HFFFFFFFFUI @@ -185,66 +195,62 @@ Public Class SeedCore roundKey(2 * i + 1) = SS0(GetByte(T1, 0)) Xor SS1(GetByte(T1, 1)) Xor SS2(GetByte(T1, 2)) Xor SS3(GetByte(T1, 3)) If i Mod 2 = 0 Then - Dim tmpA = A - A = (A >> 8) Or (B << 24) - B = (B >> 8) Or (tmpA << 24) + Dim AB As ULong = (CLng(A) << 32) Or B + AB = ((AB >> 8) Or (AB << 56)) And &HFFFFFFFFFFFFFFFFUL + A = CUInt(AB >> 32) + B = CUInt(AB And &HFFFFFFFFUL) Else - Dim tmpC = C - C = (C << 8) Or (D >> 24) - D = (D << 8) Or (tmpC >> 24) + Dim CD As ULong = (CLng(C) << 32) Or D + CD = ((CD << 8) Or (CD >> 56)) And &HFFFFFFFFFFFFFFFFUL + C = CUInt(CD >> 32) + D = CUInt(CD And &HFFFFFFFFUL) End If Next End Sub Public Sub EncryptBlock(input() As Byte, inOffset As Integer, output() As Byte, outOffset As Integer) - Dim L0 = BitConverter.ToUInt32(input, inOffset) - Dim L1 = BitConverter.ToUInt32(input, inOffset + 4) - Dim R0 = BitConverter.ToUInt32(input, inOffset + 8) - Dim R1 = BitConverter.ToUInt32(input, inOffset + 12) + Dim L0 = ToUInt32BE(input, inOffset) + Dim L1 = ToUInt32BE(input, inOffset + 4) + Dim R0 = ToUInt32BE(input, inOffset + 8) + Dim R1 = ToUInt32BE(input, inOffset + 12) For i As Integer = 0 To 15 Dim t = RoundFunction(R0 Xor roundKey(2 * i), R1 Xor roundKey(2 * i + 1)) Dim T0 = t.Item1 Dim T1 = t.Item2 - L0 = L0 Xor T0 - L1 = L1 Xor T1 - - ' swap - Dim tmp0 = L0 : Dim tmp1 = L1 + Dim temp0 = L0 Xor T0 + Dim temp1 = L1 Xor T1 L0 = R0 : L1 = R1 - R0 = tmp0 : R1 = tmp1 + R0 = temp0 : R1 = temp1 Next - Array.Copy(BitConverter.GetBytes(R0), 0, output, outOffset, 4) - Array.Copy(BitConverter.GetBytes(R1), 0, output, outOffset + 4, 4) - Array.Copy(BitConverter.GetBytes(L0), 0, output, outOffset + 8, 4) - Array.Copy(BitConverter.GetBytes(L1), 0, output, outOffset + 12, 4) + WriteUInt32BE(R0, output, outOffset) + WriteUInt32BE(R1, output, outOffset + 4) + WriteUInt32BE(L0, output, outOffset + 8) + WriteUInt32BE(L1, output, outOffset + 12) End Sub Public Sub DecryptBlock(input() As Byte, inOffset As Integer, output() As Byte, outOffset As Integer) - Dim L0 = BitConverter.ToUInt32(input, inOffset) - Dim L1 = BitConverter.ToUInt32(input, inOffset + 4) - Dim R0 = BitConverter.ToUInt32(input, inOffset + 8) - Dim R1 = BitConverter.ToUInt32(input, inOffset + 12) + Dim L0 = ToUInt32BE(input, inOffset) + Dim L1 = ToUInt32BE(input, inOffset + 4) + Dim R0 = ToUInt32BE(input, inOffset + 8) + Dim R1 = ToUInt32BE(input, inOffset + 12) For i As Integer = 0 To 15 Dim t = RoundFunction(R0 Xor roundKey(30 - 2 * i), R1 Xor roundKey(31 - 2 * i)) Dim T0 = t.Item1 Dim T1 = t.Item2 - L0 = L0 Xor T0 - L1 = L1 Xor T1 - - ' swap - Dim tmp0 = L0 : Dim tmp1 = L1 + Dim temp0 = L0 Xor T0 + Dim temp1 = L1 Xor T1 L0 = R0 : L1 = R1 - R0 = tmp0 : R1 = tmp1 + R0 = temp0 : R1 = temp1 Next - Array.Copy(BitConverter.GetBytes(R0), 0, output, outOffset, 4) - Array.Copy(BitConverter.GetBytes(R1), 0, output, outOffset + 4, 4) - Array.Copy(BitConverter.GetBytes(L0), 0, output, outOffset + 8, 4) - Array.Copy(BitConverter.GetBytes(L1), 0, output, outOffset + 12, 4) + WriteUInt32BE(R0, output, outOffset) + WriteUInt32BE(R1, output, outOffset + 4) + WriteUInt32BE(L0, output, outOffset + 8) + WriteUInt32BE(L1, output, outOffset + 12) End Sub End Class \ No newline at end of file diff --git a/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedEcbTransform.vb b/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedEcbTransform.vb index 77ba113..c7535a7 100644 --- a/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedEcbTransform.vb +++ b/WelsonJS.Toolkit/WelsonJS.Cryptography/SeedEcbTransform.vb @@ -2,7 +2,7 @@ ' 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 SeedEcbTransform @@ -45,55 +45,47 @@ Public Class SeedEcbTransform 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 - End If + If inputCount <= 0 Then Return 0 Dim blockSize = InputBlockSize + Dim remaining = inputCount + Dim inPtr = inputOffset + Dim outPtr = outputOffset - For i As Integer = 0 To inputCount - 1 Step blockSize + While remaining >= blockSize If encrypt Then - seedCore.EncryptBlock(input, inputOffset + i, output, outputOffset + i) + seedCore.EncryptBlock(input, inPtr, output, outPtr) Else - seedCore.DecryptBlock(input, inputOffset + i, output, outputOffset + i) + seedCore.DecryptBlock(input, inPtr, output, outPtr) End If - Next + inPtr += blockSize + outPtr += blockSize + remaining -= blockSize + End While - Return inputCount + Return inputCount - remaining End Function Public Function TransformFinalBlock(input() As Byte, inputOffset As Integer, inputCount As Integer) As Byte() Implements ICryptoTransform.TransformFinalBlock - If inputCount = 0 Then - Return Array.Empty(Of Byte)() - End If - - Dim blockSize As Integer = InputBlockSize - Dim paddedLength As Integer + 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 - ' None 패딩은 추가 블록 없음 paddedLength = inputCount Case PaddingMode.Zeros - ' Zeros 패딩은 추가 블록 필요 없음 paddedLength = ((inputCount + blockSize - 1) \ blockSize) * blockSize Case PaddingMode.PKCS7, PaddingMode.ANSIX923, PaddingMode.ISO10126 - ' PKCS7. ANSIX923, ISO10126 패딩은 입력이 블록 배수면 +1 블록 추가 - ' (설명) 블록암호에서 블록 길이와 같은 길이의 원문을 넣으면, 암호화문 길이가 원문 길이의 2배가 되는 원인은 여기에 기인한다. - Dim fullBlocks As Integer = inputCount \ blockSize - Dim remainder As Integer = inputCount Mod blockSize - If remainder = 0 Then - paddedLength = (fullBlocks + 1) * blockSize ' 추가 블록 붙임 - Else - paddedLength = (fullBlocks + 1) * blockSize - End If + 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()) @@ -102,32 +94,30 @@ Public Class SeedEcbTransform buffer = New Byte(paddedLength - 1) {} Array.Copy(input, inputOffset, buffer, 0, inputCount) - If paddingMode = PaddingMode.PKCS7 Then - Dim padValue As Byte = CByte(paddedLength - inputCount) - For i As Integer = inputCount To paddedLength - 1 - buffer(i) = padValue - Next + 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 - ElseIf paddingMode = PaddingMode.ANSIX923 Then - Dim padValue As Byte = CByte(paddedLength - inputCount) - For i As Integer = inputCount To paddedLength - 2 - buffer(i) = 0 - Next - buffer(paddedLength - 1) = padValue - - ElseIf paddingMode = PaddingMode.ISO10126 Then - Dim padValue As Byte = CByte(paddedLength - inputCount) - For i As Integer = inputCount To paddedLength - 2 - buffer(i) = CByte(rnd.Next(0, 256)) - Next - buffer(paddedLength - 1) = padValue - End If - - TransformBlock(buffer, 0, paddedLength, buffer, 0) + For i = 0 To buffer.Length - 1 Step blockSize + seedCore.EncryptBlock(buffer, i, buffer, i) + Next Return buffer Else - ' Decryption If (inputCount Mod blockSize) <> 0 Then Throw New CryptographicException("Encrypted data is not a multiple of block size.") End If @@ -135,76 +125,37 @@ Public Class SeedEcbTransform 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.None - Return buffer - - Case PaddingMode.Zeros - Dim trimLength As Integer = buffer.Length - While trimLength > 0 AndAlso buffer(trimLength - 1) = 0 - trimLength -= 1 - End While - Dim result(trimLength - 1) As Byte - Array.Copy(buffer, 0, result, 0, trimLength) - Return result - Case PaddingMode.PKCS7 - Dim padValue As Integer = buffer(buffer.Length - 1) - If padValue <= 0 OrElse padValue > blockSize Then - Throw New CryptographicException("Invalid PKCS7 padding.") - End If - For i As Integer = buffer.Length - padValue To buffer.Length - 1 - If buffer(i) <> padValue Then + For i = buffer.Length - padVal To buffer.Length - 1 + If buffer(i) <> padVal Then Throw New CryptographicException("Invalid PKCS7 padding value.") End If Next - Dim unpaddedLength As Integer = buffer.Length - padValue - If unpaddedLength < 0 Then - Throw New CryptographicException("Invalid unpadded length.") - End If - Dim result(unpaddedLength - 1) As Byte - Array.Copy(buffer, 0, result, 0, unpaddedLength) - Return result - Case PaddingMode.ANSIX923 - Dim padValue As Integer = buffer(buffer.Length - 1) - If padValue <= 0 OrElse padValue > blockSize Then - Throw New CryptographicException("Invalid ANSIX923 padding.") - End If - For i As Integer = buffer.Length - padValue To buffer.Length - 2 + For i = buffer.Length - padVal To buffer.Length - 2 If buffer(i) <> 0 Then Throw New CryptographicException("Invalid ANSIX923 padding value.") End If Next - Dim unpaddedLengthAnsix As Integer = buffer.Length - padValue - If unpaddedLengthAnsix < 0 Then - Throw New CryptographicException("Invalid unpadded length.") - End If - Dim resultAnsix(unpaddedLengthAnsix - 1) As Byte - Array.Copy(buffer, 0, resultAnsix, 0, unpaddedLengthAnsix) - Return resultAnsix - Case PaddingMode.ISO10126 - Dim padValue As Integer = buffer(buffer.Length - 1) - If padValue <= 0 OrElse padValue > blockSize Then - Throw New CryptographicException("Invalid ISO10126 padding.") - End If - ' Check the last byte (length) - Dim unpaddedLengthIso As Integer = buffer.Length - padValue - If unpaddedLengthIso < 0 Then - Throw New CryptographicException("Invalid unpadded length.") - End If - Dim resultIso(unpaddedLengthIso - 1) As Byte - Array.Copy(buffer, 0, resultIso, 0, unpaddedLengthIso) - Return resultIso - + ' 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 - ' Nothing + ' No resources to dispose End Sub -End Class \ No newline at end of file +End Class