mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-10-26 18:41:18 +00:00
210 lines
8.8 KiB
VB.net
210 lines
8.8 KiB
VB.net
' SeedEcbTransform.cs (WelsonJS.Cryptography)
|
|
' SPDX-License-Identifier: MIT
|
|
' SPDX-FileCopyrightText: 2025 Namhyeon Go <gnh1201@catswords.re.kr>, Catswords OSS And WelsonJS Contributors
|
|
' https://github.com/gnh1201/welsonjs
|
|
'
|
|
Imports System.Security.Cryptography
|
|
|
|
Public Class SeedEcbTransform
|
|
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
|
|
End If
|
|
|
|
Dim blockSize = InputBlockSize
|
|
|
|
For i As Integer = 0 To inputCount - 1 Step blockSize
|
|
If encrypt Then
|
|
seedCore.EncryptBlock(input, inputOffset + i, output, outputOffset + i)
|
|
Else
|
|
seedCore.DecryptBlock(input, inputOffset + i, output, outputOffset + i)
|
|
End If
|
|
Next
|
|
|
|
Return inputCount
|
|
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 buffer() As Byte
|
|
|
|
If encrypt Then
|
|
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
|
|
|
|
Case Else
|
|
Throw New NotSupportedException("Unsupported padding mode: " & paddingMode.ToString())
|
|
End Select
|
|
|
|
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
|
|
|
|
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)
|
|
Return buffer
|
|
|
|
Else
|
|
' Decryption
|
|
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)
|
|
|
|
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
|
|
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
|
|
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
|
|
|
|
Case Else
|
|
Throw New NotSupportedException("Unsupported padding mode: " & paddingMode.ToString())
|
|
End Select
|
|
End If
|
|
End Function
|
|
|
|
Public Sub Dispose() Implements IDisposable.Dispose
|
|
' Nothing
|
|
End Sub
|
|
End Class |