即使缺少循环位旋转,ChaCha20 对称加密也可以在 VB.NET 中实现吗?
Can ChaCha20 symmetric encryption be implemented in VB.NET even though it lacks circular bit rotation?
在阅读了加密算法并从 Maarten 那里得到了一些非常好的建议之后,我发现 ChaCha20 加密算法有潜力在缺乏专用 AES 的旧计算机上提供强大的对称加密和良好的性能 encryption/decryption说明。
在VB.NET中有实现ChaCha20加密算法的VB.NET代码的好例子吗?
VB.NET 可能并不理想,因为它缺少很多具体的指令,例如无符号整数的循环位旋转(这是 ChaCha20 的关键部分),所以问题是这个算法仍然可以在 VB.NET?
中得到很好的实施
在VB.NET中尝试写了ChaCha20加密算法后,貌似效果还不错。请看下面的代码。
VB.NET 中没有整数的循环位旋转,但在代码中您会找到实现循环位旋转的可靠解决方法。
我添加了一个测试子例程,用于根据最终规范中的一些官方 ChaCha20 测试向量测试代码 here。
请在使用此代码之前考虑这些准则:
它未经加密专家评估,可能包含安全问题,尤其是在充满 Meltdown 和 Spectre 类型安全漏洞以及一大堆更多安全漏洞的旧 CPU 上.
非常欢迎改进代码和性能的反馈,您可以自由且不受限制地使用此代码。
在经验丰富的加密算法开发人员评估此代码之前,请在您寻求混淆而不是强加密的地方使用它。 (很可能已经提供了,但零保证)
确保保护您使用的密钥,切勿在未加密的情况下存储它。
永远不要(永远永远)两次使用相同的 Nonce + Counter 组合。您需要这些来解密信息,无需保护这些信息免受对手的侵害,尽一切努力确保您的密钥安全。
加密和解密的子完全相同,因为这是对称加密(这就是子名称中包含EncDec的原因)。
不要忘记选中删除整数溢出检查复选框,请参阅如何操作。
祝您愉快,让我知道需要改进的地方!
Sub ValidateChaCha20AlgorithmAgainstStandard()
'See final spec for ChaCha20 with test vectors here: https://datatracker.ietf.org/doc/rfc7539/
Dim Key As String
Dim Nonce As String
Dim Counter As UInt32
Dim HowMany As UInt32
'Final spec for two blocks!
Key = "03020100-07060504-0b0a0908-0f0e0d0c-13121110-17161514-1b1a1918-1f1e1d1c"
Nonce = "00000000-4a000000-00000000"
Counter = 1
HowMany = 2
Dim KeyStream() As Byte
KeyStream = ChaCha20_GenerateEncDecByteStream(Key, Nonce, Counter, HowMany)
Dim KeyStreamOutputHexString As String
KeyStreamOutputHexString = ByteArrayToString(KeyStream)
Dim ValidatedKeyStreamOutput As String
ValidatedKeyStreamOutput = "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cba40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a832c89c167eacd901d7e2bf363740373201aa188fbbce83991c4ed"
Dim StringCompareThatMustFail As String
StringCompareThatMustFail = "I will fail for sure!"
If KeyStreamOutputHexString.Equals(StringCompareThatMustFail) = False Then Debug.Print("String compare works properly")
If KeyStreamOutputHexString.Equals(StringCompareThatMustFail) = True Then Debug.Print("String compare has FAILED DO NOT TRUST this verification!!!")
If KeyStreamOutputHexString.Equals(ValidatedKeyStreamOutput) = True Then Debug.Print("ChaCha20 algorithm has passed the validation check, output is 100% correct")
If KeyStreamOutputHexString.Equals(ValidatedKeyStreamOutput) = False Then Debug.Print("ChaCha20 algorithm has FAILED the validation check do NOT USE the algorithm!!!")
'Now we test the bytestream encoding!
Dim PlainText As String
Dim PlainByteStream As Byte()
PlainText = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, suncreen would be it."
PlainByteStream = UTF8StringToBytes(PlainText)
Dim EncryptedStream As Byte()
Dim DecryptedStream As Byte()
Dim DecryptedString As String
EncryptedStream = ChaCha20_EncDecByteStream(PlainByteStream, KeyStream)
DecryptedStream = ChaCha20_EncDecByteStream(EncryptedStream, KeyStream)
DecryptedString = UTF8BytesToString(DecryptedStream)
If DecryptedString.Equals(PlainText) = True Then Debug.Print("2dn ChaCha20 validation check passed, algorithm has SUCCESFULLY performed a full encryption/decryption round trip yielding exactly the source data!")
End Sub
Function ChaCha20_EncDecByteStream(StreamToEncDec() As Byte, KeyStream() As Byte) As Byte()
Dim b As Byte
Dim ProcessedStream As Byte()
Dim LoopCounter As Integer
ReDim ProcessedStream(StreamToEncDec.Length - 1)
For LoopCounter = 0 To (StreamToEncDec.Length - 1)
ProcessedStream(LoopCounter) = StreamToEncDec(LoopCounter) Xor KeyStream(LoopCounter)
Next
Return ProcessedStream
End Function
Function ChaCha20_GenerateEncDecByteStream(Key As String, Nonce As String, CounterStartPosition As UInt32, HowManyBlocks As UInt32) As Byte()
'This function creates a bytestream with the ChaCha20 encryption algorithm that can be used for further processing
'The stream is always in units of 64 bytes (512 bits).
'The key and the nonce are Hexadecimal strings with every 8 Hex characters (32 bits) separated by a - for readability 'coz that is just very convenient to use :)
Dim KeyStringArray() As String
Dim NonceStringArray() As String
KeyStringArray = Split(Key, "-")
NonceStringArray = Split(Nonce, "-")
Dim ChaChaStartBlock(15) As UInt32
'See specified under https://datatracker.ietf.org/doc/html/rfc7539
' The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574.
'Here we set the constants
ChaChaStartBlock(0) = &H61707865
ChaChaStartBlock(1) = &H3320646E
ChaChaStartBlock(2) = &H79622D32
ChaChaStartBlock(3) = &H6B206574
'Here we set the key
ChaChaStartBlock(4) = CUInt("&H" & KeyStringArray(0))
ChaChaStartBlock(5) = CUInt("&H" & KeyStringArray(1))
ChaChaStartBlock(6) = CUInt("&H" & KeyStringArray(2))
ChaChaStartBlock(7) = CUInt("&H" & KeyStringArray(3))
ChaChaStartBlock(8) = CUInt("&H" & KeyStringArray(4))
ChaChaStartBlock(9) = CUInt("&H" & KeyStringArray(5))
ChaChaStartBlock(10) = CUInt("&H" & KeyStringArray(6))
ChaChaStartBlock(11) = CUInt("&H" & KeyStringArray(7))
'Here we set the initial counter position
ChaChaStartBlock(12) = CounterStartPosition
'Here we set the Nonce
ChaChaStartBlock(13) = CUInt("&H" & NonceStringArray(0))
ChaChaStartBlock(14) = CUInt("&H" & NonceStringArray(1))
ChaChaStartBlock(15) = CUInt("&H" & NonceStringArray(2))
Debug.Print("Start block:")
Debug.Print(Hex(ChaChaStartBlock(0)) & " " & Hex(ChaChaStartBlock(1)) & " " & Hex(ChaChaStartBlock(2)) & " " & Hex(ChaChaStartBlock(3)))
Debug.Print(Hex(ChaChaStartBlock(4)) & " " & Hex(ChaChaStartBlock(5)) & " " & Hex(ChaChaStartBlock(6)) & " " & Hex(ChaChaStartBlock(7)))
Debug.Print(Hex(ChaChaStartBlock(8)) & " " & Hex(ChaChaStartBlock(9)) & " " & Hex(ChaChaStartBlock(10)) & " " & Hex(ChaChaStartBlock(11)))
Debug.Print(Hex(ChaChaStartBlock(12)) & " " & Hex(ChaChaStartBlock(13)) & " " & Hex(ChaChaStartBlock(14)) & " " & Hex(ChaChaStartBlock(15)))
'Now we create a byte array of the size we will need
Dim ChaChaByteArray() As Byte
ReDim ChaChaByteArray(HowManyBlocks * 64 - 1)
Dim ByteArrayFillLoop As Integer
Dim ChaChaResultBlock(15) As UInt32
Dim InnerLoop As Integer
Dim FourByteArray(3) As Byte
Dim FourByteArrayReverseOrder(3) As Byte
For ByteArrayFillLoop = 0 To (HowManyBlocks - 1)
ChaChaStartBlock(12) = CounterStartPosition + ByteArrayFillLoop
ChaChaResultBlock = ChaCha20_GenerateEncDecBlock(ChaChaStartBlock)
Debug.Print("Result block:")
Debug.Print(Hex(ChaChaResultBlock(0)) & " " & Hex(ChaChaResultBlock(1)) & " " & Hex(ChaChaResultBlock(2)) & " " & Hex(ChaChaResultBlock(3)))
Debug.Print(Hex(ChaChaResultBlock(4)) & " " & Hex(ChaChaResultBlock(5)) & " " & Hex(ChaChaResultBlock(6)) & " " & Hex(ChaChaResultBlock(7)))
Debug.Print(Hex(ChaChaResultBlock(8)) & " " & Hex(ChaChaResultBlock(9)) & " " & Hex(ChaChaResultBlock(10)) & " " & Hex(ChaChaResultBlock(11)))
Debug.Print(Hex(ChaChaResultBlock(12)) & " " & Hex(ChaChaResultBlock(13)) & " " & Hex(ChaChaResultBlock(14)) & " " & Hex(ChaChaResultBlock(15)))
'Here we copy the block into the byte array
For InnerLoop = 0 To 15
FourByteArray = BitConverter.GetBytes(ChaChaResultBlock(InnerLoop))
If BitConverter.IsLittleEndian = False Then
FourByteArrayReverseOrder(0) = FourByteArray(3)
FourByteArrayReverseOrder(1) = FourByteArray(2)
FourByteArrayReverseOrder(2) = FourByteArray(1)
FourByteArrayReverseOrder(3) = FourByteArray(0)
FourByteArray = FourByteArrayReverseOrder
End If
Buffer.BlockCopy(FourByteArray, 0, ChaChaByteArray, ByteArrayFillLoop * 64 + InnerLoop * 4, 4)
Next
Next
Return ChaChaByteArray
End Function
Function ChaCha20_GenerateEncDecBlock(CC20M As UInt32()) As UInt32()
Dim M(15) As UInt32
Array.Copy(CC20M, M, M.Length)
Dim R10CTR As Integer
For R10CTR = 1 To 10
Call ChaCha20_QR(M(0), M(4), M(8), M(12))
Call ChaCha20_QR(M(1), M(5), M(9), M(13))
Call ChaCha20_QR(M(2), M(6), M(10), M(14))
Call ChaCha20_QR(M(3), M(7), M(11), M(15))
Call ChaCha20_QR(M(0), M(5), M(10), M(15))
Call ChaCha20_QR(M(1), M(6), M(11), M(12))
Call ChaCha20_QR(M(2), M(7), M(8), M(13))
Call ChaCha20_QR(M(3), M(4), M(9), M(14))
Next
Dim CTR As Integer
For CTR = 0 To 15
M(CTR) = M(CTR) + CC20M(CTR)
Next
Return M
End Function
Sub ChaCha20_QR(ByRef a As UInt32, ByRef b As UInt32, ByRef c As UInt32, ByRef d As UInt32)
a = a + b
d = d Xor a
d = d << 16 Or d >> 16
c = c + d
b = b Xor c
b = b << 12 Or b >> 20
a = a + b
d = d Xor a
d = d << 8 Or d >> 24
c = c + d
b = b Xor c
b = b << 7 Or b >> 25
End Sub
Function ByteArrayToString(ba() As Byte) As String
Dim hex As New StringBuilder(ba.Length * 2)
Dim b As Byte
For Each b In ba
hex.AppendFormat("{0:x2}", b)
Next
Return hex.ToString()
End Function
Private Function UTF8StringToBytes(
ByVal str As String) As Byte()
Return System.Text.Encoding.UTF8.GetBytes(str)
End Function
Private Function UTF8BytesToString(
ByVal bytes() As Byte) As String
Return System.Text.Encoding.UTF8.GetString(bytes)
End Function
在阅读了加密算法并从 Maarten 那里得到了一些非常好的建议之后,我发现 ChaCha20 加密算法有潜力在缺乏专用 AES 的旧计算机上提供强大的对称加密和良好的性能 encryption/decryption说明。
在VB.NET中有实现ChaCha20加密算法的VB.NET代码的好例子吗?
VB.NET 可能并不理想,因为它缺少很多具体的指令,例如无符号整数的循环位旋转(这是 ChaCha20 的关键部分),所以问题是这个算法仍然可以在 VB.NET?
中得到很好的实施在VB.NET中尝试写了ChaCha20加密算法后,貌似效果还不错。请看下面的代码。
VB.NET 中没有整数的循环位旋转,但在代码中您会找到实现循环位旋转的可靠解决方法。
我添加了一个测试子例程,用于根据最终规范中的一些官方 ChaCha20 测试向量测试代码 here。
请在使用此代码之前考虑这些准则:
它未经加密专家评估,可能包含安全问题,尤其是在充满 Meltdown 和 Spectre 类型安全漏洞以及一大堆更多安全漏洞的旧 CPU 上.
非常欢迎改进代码和性能的反馈,您可以自由且不受限制地使用此代码。
在经验丰富的加密算法开发人员评估此代码之前,请在您寻求混淆而不是强加密的地方使用它。 (很可能已经提供了,但零保证)
确保保护您使用的密钥,切勿在未加密的情况下存储它。
永远不要(永远永远)两次使用相同的 Nonce + Counter 组合。您需要这些来解密信息,无需保护这些信息免受对手的侵害,尽一切努力确保您的密钥安全。
加密和解密的子完全相同,因为这是对称加密(这就是子名称中包含EncDec的原因)。
不要忘记选中删除整数溢出检查复选框,请参阅
祝您愉快,让我知道需要改进的地方!
Sub ValidateChaCha20AlgorithmAgainstStandard()
'See final spec for ChaCha20 with test vectors here: https://datatracker.ietf.org/doc/rfc7539/
Dim Key As String
Dim Nonce As String
Dim Counter As UInt32
Dim HowMany As UInt32
'Final spec for two blocks!
Key = "03020100-07060504-0b0a0908-0f0e0d0c-13121110-17161514-1b1a1918-1f1e1d1c"
Nonce = "00000000-4a000000-00000000"
Counter = 1
HowMany = 2
Dim KeyStream() As Byte
KeyStream = ChaCha20_GenerateEncDecByteStream(Key, Nonce, Counter, HowMany)
Dim KeyStreamOutputHexString As String
KeyStreamOutputHexString = ByteArrayToString(KeyStream)
Dim ValidatedKeyStreamOutput As String
ValidatedKeyStreamOutput = "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cba40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a832c89c167eacd901d7e2bf363740373201aa188fbbce83991c4ed"
Dim StringCompareThatMustFail As String
StringCompareThatMustFail = "I will fail for sure!"
If KeyStreamOutputHexString.Equals(StringCompareThatMustFail) = False Then Debug.Print("String compare works properly")
If KeyStreamOutputHexString.Equals(StringCompareThatMustFail) = True Then Debug.Print("String compare has FAILED DO NOT TRUST this verification!!!")
If KeyStreamOutputHexString.Equals(ValidatedKeyStreamOutput) = True Then Debug.Print("ChaCha20 algorithm has passed the validation check, output is 100% correct")
If KeyStreamOutputHexString.Equals(ValidatedKeyStreamOutput) = False Then Debug.Print("ChaCha20 algorithm has FAILED the validation check do NOT USE the algorithm!!!")
'Now we test the bytestream encoding!
Dim PlainText As String
Dim PlainByteStream As Byte()
PlainText = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, suncreen would be it."
PlainByteStream = UTF8StringToBytes(PlainText)
Dim EncryptedStream As Byte()
Dim DecryptedStream As Byte()
Dim DecryptedString As String
EncryptedStream = ChaCha20_EncDecByteStream(PlainByteStream, KeyStream)
DecryptedStream = ChaCha20_EncDecByteStream(EncryptedStream, KeyStream)
DecryptedString = UTF8BytesToString(DecryptedStream)
If DecryptedString.Equals(PlainText) = True Then Debug.Print("2dn ChaCha20 validation check passed, algorithm has SUCCESFULLY performed a full encryption/decryption round trip yielding exactly the source data!")
End Sub
Function ChaCha20_EncDecByteStream(StreamToEncDec() As Byte, KeyStream() As Byte) As Byte()
Dim b As Byte
Dim ProcessedStream As Byte()
Dim LoopCounter As Integer
ReDim ProcessedStream(StreamToEncDec.Length - 1)
For LoopCounter = 0 To (StreamToEncDec.Length - 1)
ProcessedStream(LoopCounter) = StreamToEncDec(LoopCounter) Xor KeyStream(LoopCounter)
Next
Return ProcessedStream
End Function
Function ChaCha20_GenerateEncDecByteStream(Key As String, Nonce As String, CounterStartPosition As UInt32, HowManyBlocks As UInt32) As Byte()
'This function creates a bytestream with the ChaCha20 encryption algorithm that can be used for further processing
'The stream is always in units of 64 bytes (512 bits).
'The key and the nonce are Hexadecimal strings with every 8 Hex characters (32 bits) separated by a - for readability 'coz that is just very convenient to use :)
Dim KeyStringArray() As String
Dim NonceStringArray() As String
KeyStringArray = Split(Key, "-")
NonceStringArray = Split(Nonce, "-")
Dim ChaChaStartBlock(15) As UInt32
'See specified under https://datatracker.ietf.org/doc/html/rfc7539
' The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574.
'Here we set the constants
ChaChaStartBlock(0) = &H61707865
ChaChaStartBlock(1) = &H3320646E
ChaChaStartBlock(2) = &H79622D32
ChaChaStartBlock(3) = &H6B206574
'Here we set the key
ChaChaStartBlock(4) = CUInt("&H" & KeyStringArray(0))
ChaChaStartBlock(5) = CUInt("&H" & KeyStringArray(1))
ChaChaStartBlock(6) = CUInt("&H" & KeyStringArray(2))
ChaChaStartBlock(7) = CUInt("&H" & KeyStringArray(3))
ChaChaStartBlock(8) = CUInt("&H" & KeyStringArray(4))
ChaChaStartBlock(9) = CUInt("&H" & KeyStringArray(5))
ChaChaStartBlock(10) = CUInt("&H" & KeyStringArray(6))
ChaChaStartBlock(11) = CUInt("&H" & KeyStringArray(7))
'Here we set the initial counter position
ChaChaStartBlock(12) = CounterStartPosition
'Here we set the Nonce
ChaChaStartBlock(13) = CUInt("&H" & NonceStringArray(0))
ChaChaStartBlock(14) = CUInt("&H" & NonceStringArray(1))
ChaChaStartBlock(15) = CUInt("&H" & NonceStringArray(2))
Debug.Print("Start block:")
Debug.Print(Hex(ChaChaStartBlock(0)) & " " & Hex(ChaChaStartBlock(1)) & " " & Hex(ChaChaStartBlock(2)) & " " & Hex(ChaChaStartBlock(3)))
Debug.Print(Hex(ChaChaStartBlock(4)) & " " & Hex(ChaChaStartBlock(5)) & " " & Hex(ChaChaStartBlock(6)) & " " & Hex(ChaChaStartBlock(7)))
Debug.Print(Hex(ChaChaStartBlock(8)) & " " & Hex(ChaChaStartBlock(9)) & " " & Hex(ChaChaStartBlock(10)) & " " & Hex(ChaChaStartBlock(11)))
Debug.Print(Hex(ChaChaStartBlock(12)) & " " & Hex(ChaChaStartBlock(13)) & " " & Hex(ChaChaStartBlock(14)) & " " & Hex(ChaChaStartBlock(15)))
'Now we create a byte array of the size we will need
Dim ChaChaByteArray() As Byte
ReDim ChaChaByteArray(HowManyBlocks * 64 - 1)
Dim ByteArrayFillLoop As Integer
Dim ChaChaResultBlock(15) As UInt32
Dim InnerLoop As Integer
Dim FourByteArray(3) As Byte
Dim FourByteArrayReverseOrder(3) As Byte
For ByteArrayFillLoop = 0 To (HowManyBlocks - 1)
ChaChaStartBlock(12) = CounterStartPosition + ByteArrayFillLoop
ChaChaResultBlock = ChaCha20_GenerateEncDecBlock(ChaChaStartBlock)
Debug.Print("Result block:")
Debug.Print(Hex(ChaChaResultBlock(0)) & " " & Hex(ChaChaResultBlock(1)) & " " & Hex(ChaChaResultBlock(2)) & " " & Hex(ChaChaResultBlock(3)))
Debug.Print(Hex(ChaChaResultBlock(4)) & " " & Hex(ChaChaResultBlock(5)) & " " & Hex(ChaChaResultBlock(6)) & " " & Hex(ChaChaResultBlock(7)))
Debug.Print(Hex(ChaChaResultBlock(8)) & " " & Hex(ChaChaResultBlock(9)) & " " & Hex(ChaChaResultBlock(10)) & " " & Hex(ChaChaResultBlock(11)))
Debug.Print(Hex(ChaChaResultBlock(12)) & " " & Hex(ChaChaResultBlock(13)) & " " & Hex(ChaChaResultBlock(14)) & " " & Hex(ChaChaResultBlock(15)))
'Here we copy the block into the byte array
For InnerLoop = 0 To 15
FourByteArray = BitConverter.GetBytes(ChaChaResultBlock(InnerLoop))
If BitConverter.IsLittleEndian = False Then
FourByteArrayReverseOrder(0) = FourByteArray(3)
FourByteArrayReverseOrder(1) = FourByteArray(2)
FourByteArrayReverseOrder(2) = FourByteArray(1)
FourByteArrayReverseOrder(3) = FourByteArray(0)
FourByteArray = FourByteArrayReverseOrder
End If
Buffer.BlockCopy(FourByteArray, 0, ChaChaByteArray, ByteArrayFillLoop * 64 + InnerLoop * 4, 4)
Next
Next
Return ChaChaByteArray
End Function
Function ChaCha20_GenerateEncDecBlock(CC20M As UInt32()) As UInt32()
Dim M(15) As UInt32
Array.Copy(CC20M, M, M.Length)
Dim R10CTR As Integer
For R10CTR = 1 To 10
Call ChaCha20_QR(M(0), M(4), M(8), M(12))
Call ChaCha20_QR(M(1), M(5), M(9), M(13))
Call ChaCha20_QR(M(2), M(6), M(10), M(14))
Call ChaCha20_QR(M(3), M(7), M(11), M(15))
Call ChaCha20_QR(M(0), M(5), M(10), M(15))
Call ChaCha20_QR(M(1), M(6), M(11), M(12))
Call ChaCha20_QR(M(2), M(7), M(8), M(13))
Call ChaCha20_QR(M(3), M(4), M(9), M(14))
Next
Dim CTR As Integer
For CTR = 0 To 15
M(CTR) = M(CTR) + CC20M(CTR)
Next
Return M
End Function
Sub ChaCha20_QR(ByRef a As UInt32, ByRef b As UInt32, ByRef c As UInt32, ByRef d As UInt32)
a = a + b
d = d Xor a
d = d << 16 Or d >> 16
c = c + d
b = b Xor c
b = b << 12 Or b >> 20
a = a + b
d = d Xor a
d = d << 8 Or d >> 24
c = c + d
b = b Xor c
b = b << 7 Or b >> 25
End Sub
Function ByteArrayToString(ba() As Byte) As String
Dim hex As New StringBuilder(ba.Length * 2)
Dim b As Byte
For Each b In ba
hex.AppendFormat("{0:x2}", b)
Next
Return hex.ToString()
End Function
Private Function UTF8StringToBytes(
ByVal str As String) As Byte()
Return System.Text.Encoding.UTF8.GetBytes(str)
End Function
Private Function UTF8BytesToString(
ByVal bytes() As Byte) As String
Return System.Text.Encoding.UTF8.GetString(bytes)
End Function