I have a requirement to implement Pbkdf2 to secure a very old application that uses aspnet membership provider. I am following this answer which is recent and useful, but unable to follow what is inside MyRfc2898DeriveBytes class and it is giving me following issue.. (also I am a c# dev but for this project working in vb.net)
So the issue could be related to language conversion.
I am getting
Non-negative number required. Parameter name: srcOffset
at the following
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, size)
the m_startIndex here somehow becomes -1
Here is my code in vb
Imports System.IO
Imports System.Security.Cryptography
Namespace custom.hashing.keyderivation
Public Class PBKDF2Hash
Inherits KeyedHashAlgorithm
Private Const kHashBytes As Integer = 64
Private _ms As System.IO.MemoryStream
Public Property WorkFactor As Integer
Public Sub New()
MyBase.New()
Me.WorkFactor = 128000
Me.Key = New Byte(31) {}
Using rngCsp = New RNGCryptoServiceProvider()
rngCsp.GetBytes(Me.Key)
End Using
End Sub
Public Overrides ReadOnly Property HashSize As Integer
Get
Return kHashBytes * 8
End Get
End Property
Protected Overrides Sub HashCore(ByVal array As Byte(), ByVal ibStart As Integer, ByVal cbSize As Integer)
If IsNothing(_ms) Then
_ms = New MemoryStream()
End If
_ms.Write(array, ibStart, cbSize)
'(CSharpImpl.__Assign(_ms, If(_ms, New System.IO.MemoryStream()))).Write(array, ibStart, cbSize)
End Sub
Protected Overrides Function HashFinal() As Byte()
If Me.Key Is Nothing OrElse Me.Key.Length = 0 Then
Throw New CryptographicException("Missing KeyedAlgorithm key")
End If
_ms.Flush()
Dim arr = _ms.ToArray()
_ms = Nothing
Using hmac As HMACSHA512 = New HMACSHA512()
Return New MyRfc2898DeriveBytes(arr, Me.Key, Me.WorkFactor, hmac).GetBytes(kHashBytes)
End Using
End Function
Public Overrides Sub Initialize()
_ms = Nothing
End Sub
End Class
End Namespace
Imports System.Diagnostics.Contracts
Imports System.Security
Imports System.Security.Cryptography
Public Class MyRfc2898DeriveBytes
Inherits DeriveBytes
Private m_buffer As Byte()
Private m_salt As Byte()
Private m_hmac As HMAC
Private m_iterations As UInteger
Private m_block As UInteger
Private m_startIndex As Integer = 0
Private m_endIndex As Integer = 0
Private m_blockSize As Integer = 0
<SecuritySafeCritical>
Public Sub New(ByVal password As Byte(), ByVal salt As Byte(), ByVal iterations As Integer, ByVal hmac As HMAC)
salt = salt
IterationCount = iterations
hmac.Key = password
m_hmac = hmac
m_blockSize = hmac.HashSize >> 3
'''
Initialize()
End Sub
Public Property IterationCount As Integer
Get
Return CInt(m_iterations)
End Get
Set(ByVal value As Integer)
If value <= 0 Then Throw New ArgumentOutOfRangeException("value", "Error: Iteration count is zero or less")
m_iterations = CUInt(value)
Initialize()
End Set
End Property
Public Property Salt As Byte()
Get
Return CType(m_salt.Clone(), Byte())
End Get
Set(ByVal value As Byte())
If value Is Nothing Then Throw New ArgumentNullException("value")
If value.Length < 8 Then Throw New ArgumentException("Error: Salt size is less than 8")
m_salt = CType(value.Clone(), Byte())
Initialize()
End Set
End Property
Public Overrides Function GetBytes(ByVal cb As Integer) As Byte()
If cb <= 0 Then
Throw New ArgumentOutOfRangeException("cb", "Error: Hash size is zero or less")
End If
Contract.Assert(m_blockSize > 0)
Dim password As Byte() = New Byte(cb - 1) {}
Dim offset As Integer = 0
Dim size As Integer = m_endIndex - m_startIndex
If size > 0 Then
If cb >= size Then
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, size)
m_startIndex = m_endIndex = 0
offset += size
Else
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, cb)
m_startIndex += cb
Return password
End If
End If
Contract.Assert(m_startIndex = 0 AndAlso m_endIndex = 0, "Invalid start or end index in the internal buffer.")
While offset < cb
Dim T_block As Byte() = Func()
Dim remainder As Integer = cb - offset
If remainder > m_blockSize Then
Buffer.BlockCopy(T_block, 0, password, offset, m_blockSize)
offset += m_blockSize
Else
Buffer.BlockCopy(T_block, 0, password, offset, remainder)
offset += remainder
Buffer.BlockCopy(T_block, remainder, m_buffer, m_startIndex, m_blockSize - remainder)
m_endIndex += (m_blockSize - remainder)
Return password
End If
End While
Return password
End Function
Public Overrides Sub Reset()
Initialize()
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
If disposing Then
If m_hmac IsNot Nothing Then
m_hmac.Dispose()
End If
If m_buffer IsNot Nothing Then
Array.Clear(m_buffer, 0, m_buffer.Length)
End If
If m_salt IsNot Nothing Then
Array.Clear(m_salt, 0, m_salt.Length)
End If
End If
End Sub
Private Sub Initialize()
If m_buffer IsNot Nothing Then Array.Clear(m_buffer, 0, m_buffer.Length)
m_buffer = New Byte(m_blockSize - 1) {}
m_block = 1
m_startIndex = m_endIndex = 0
End Sub
Friend Shared Function GetBytesFromInt(ByVal i As UInteger) As Byte()
End Function
Private Function Func() As Byte()
Dim INT_block As Byte() = GetBytesFromInt(m_block)
m_hmac.TransformBlock(m_salt, 0, m_salt.Length, Nothing, 0)
m_hmac.TransformBlock(INT_block, 0, INT_block.Length, Nothing, 0)
m_hmac.TransformFinalBlock(New Byte(-1) {}, 0, 0)
Dim temp As Byte() = m_hmac.Hash
m_hmac.Initialize()
Dim ret As Byte() = temp
For i As Integer = 2 To m_iterations
m_hmac.TransformBlock(temp, 0, temp.Length, Nothing, 0)
m_hmac.TransformFinalBlock(New Byte(-1) {}, 0, 0)
temp = m_hmac.Hash
For j As Integer = 0 To m_blockSize - 1
ret(j) = ret(j) Xor temp(j)
Next
m_hmac.Initialize()
Next
If m_block = UInteger.MaxValue Then
Throw New InvalidOperationException("Derived key too long.")
End If
m_block += 1
Return ret
End Function
End Class
So yes it was c# to vb conversion issues:
double assignment does not work in vb, so the following line was changed from
m_startIndex = m_endIndex = 0
to
m_startIndex = 0
m_endIndex = 0
Other things that I found
Property with same name as variable was not converted properly so
Public Sub New(ByVal password As Byte(), ByVal salt As Byte(), ByVal iterations As Integer, ByVal hmac As HMAC)
salt = salt
was really supposed to be
Public Sub New(ByVal password As Byte(), ByVal salt As Byte(), ByVal iterations As Integer, ByVal hmac As HMAC)
Me.Salt = salt
as Salt was a property
GetBytesFromInt(m_block) was not properly converted to vb
Friend Shared Function GetBytesFromInt(ByVal i As UInteger) As Byte()
Dim vIn As UInteger = 0
Dim vOut As Byte() = BitConverter.GetBytes(i)
Return vOut
'return unchecked(new byte[] { (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i });
End Function
Related
I'm working on my final project in college. It is about advanced encryption standard (AES) for multimedia files (Text and image), but I need some explanation about codes that I don't understand.
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.IO
Imports System.Security
Imports System.Security.Cryptography
Imports System.Diagnostics
Imports System.Runtime.CompilerServices
Imports System.Drawing.Imaging
Module CryptoStuff
Public key_size_bits_ku As Integer = 128
Public iv_ku() As Byte
Private Sub MakeKeyAndIV(ByVal password As String, ByVal salt() As Byte, ByVal key_size_bits As Integer,
ByVal block_size_bits As Integer, ByRef key() As Byte, ByRef iv() As Byte)
Dim derive_bytes As New Rfc2898DeriveBytes(password, salt, 1000)
key = Encoding.ASCII.GetBytes(password)
iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
End Sub
Region "Enkripsi file dan stream"
Public Function imgToByteArray(ByVal img As Image) As Byte()
Using mStream As New MemoryStream()
img.Save(mStream, img.RawFormat)
Return mStream.ToArray()
End Using
End Function
Public Sub EncryptFile(ByVal password As String, ByVal in_file As String,
ByVal out_file As String)
CryptFile(password, in_file, out_file, True)
End Sub
Public Sub DecryptFile(ByVal password As String, ByVal in_file As String,
ByVal out_file As String)
CryptFile(password, in_file, out_file, False)
End Sub
Public Sub CryptFile(ByVal password As String, ByVal in_file As String,
ByVal out_file As String, ByVal encrypt As Boolean)
Using in_stream As New FileStream(in_file, FileMode.Open, FileAccess.Read)
Using out_stream As New FileStream(out_file, FileMode.Create, FileAccess.Write)
CryptStream(password, in_stream, out_stream, encrypt)
End Using
End Using
End Sub
Public Function byteArrayToImage(ByVal byteArrayIn As Byte()) As Image
Using mStream As New MemoryStream(byteArrayIn)
Return Image.FromStream(mStream)
End Using
End Function
Public Sub CryptStream(ByVal password As String, ByVal in_stream As Stream,
ByVal out_stream As Stream, ByVal encrypt As Boolean)
Dim aes_provider As New AesCryptoServiceProvider()
Dim key_size_bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
key_size_bits = i
Exit For
End If
Next i
Debug.Assert(key_size_bits > 0)
Console.WriteLine("Key size: " & key_size_bits)
Dim block_size_bits As Integer = aes_provider.BlockSize
Dim key() As Byte = Nothing
Dim iv() As Byte = Nothing
'Dim salt() As Byte = {&H0, &H0, &H1, &H2, &H3, &H4, &H5, &H6, &HF1, &HF0, &HEE, &H21, &H22, &H45}
'MakeKeyAndIV(password, salt, key_size_bits_ku, block_size_bits, key, iv)
key = Encoding.ASCII.GetBytes(password)
iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
Dim crypto_transform As ICryptoTransform
If (encrypt) Then
crypto_transform = aes_provider.CreateEncryptor(key, iv)
Else
crypto_transform = aes_provider.CreateDecryptor(key, iv)
End If
Try
Using crypto_stream As New CryptoStream(out_stream, crypto_transform, CryptoStreamMode.Write)
Const block_size As Integer = 1024
Dim buffer(block_size) As Byte
Dim bytes_read As Integer
Do
bytes_read = in_stream.Read(buffer, 0, block_size)
If (bytes_read = 0) Then Exit Do
crypto_stream.Write(buffer, 0, bytes_read)
Loop
End Using
Catch
End Try
crypto_transform.Dispose()
End Sub
End Region ' Encrypt Files and Streams"
End Module
The codes that I don't understand are these:
Dim key_size_bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
key_size_bits = i
Exit For
End If
Next i
Debug.Assert(key_size_bits > 0)
Console.WriteLine("Key size: " & key_size_bits)
Dim block_size_bits As Integer = aes_provider.BlockSize
Can you explain the use of these codes?
Thanks before
This application I wrote is very effective and will encrypt whatever you want. I left notes in it to answer all your questions. At the bottom, you will see an added class to reduce memory usage of the program. It works rather well, (by 8% -10%) Enjoy.
Items needed:
*3 buttons (Browse) (Encrypt) (Decrypt)
*1 TextBox
For the project video, see my link:
Part 1: https://www.youtube.com/watch?v=sVaA2q8ttzQ
Part 2: https://www.youtube.com/watch?v=TyafeBJ53YU
'Created by: Rythorian77 | github.com/rythorian77
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ramClass As New AESRam()
End Sub
Private Sub Browse_Click(sender As Object, e As EventArgs) Handles Browse.Click
'Allows you to access files from folders
Dim fetchCryptDialog As New OpenFileDialog With {
.CheckFileExists = True,
.InitialDirectory = "C:\",
.Multiselect = False
}
If fetchCryptDialog.ShowDialog = DialogResult.OK Then
TextBox1.Text = fetchCryptDialog.FileName
End If
End Sub
Private Sub Encrypt_Click(sender As Object, e As EventArgs) Handles Encrypt.Click
'File path goes to textbox
Dim Rythorian77 As String = TextBox1.Text
'This password can be whater you want.
Dim password As String = "123456789ABCDEFG!##$%^&*()_+"
'A data type is the characteristic of a variable that determines what kind of data it can hold.
'Data types include those in the following table as well as user-defined types and specific types of objects.
Dim key As Byte() = New Byte(31) {}
'When overridden in a derived class, encodes a set of characters into a sequence of bytes.
Encoding.Default.GetBytes(password).CopyTo(key, 0)
'RijndaelManaged still works but is considered obsolete in todays world so we use AES
'Represents the abstract base class from which all implementations of the Advanced Encryption Standard (AES) must inherit.
'https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-6.0
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
'Reads a sequence of bytes from the current memory stream and advances the position within the memory stream by the number of bytes read.
Using mnemonicData As New MemoryStream
'Defines a stream that links data streams to cryptographic transformations.
Using cStream As New CryptoStream(mnemonicData, aes.CreateEncryptor(key, key), CryptoStreamMode.Write)
Dim buffer As Byte() = File.ReadAllBytes(Rythorian77)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = mnemonicData.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(Rythorian77, finalBuffer)
End Using
End Using
End Sub
'The above code notes compliment the same
Private Sub Decrypt_Click(sender As Object, e As EventArgs) Handles Decrypt.Click
Dim Rythorian77 As String = TextBox1.Text
Dim password As String = "123456789ABCDEFG!##$%^&*()_+"
Dim key As Byte() = New Byte(31) {}
Encoding.Default.GetBytes(password).CopyTo(key, 0)
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
Using mnemonicData As New MemoryStream
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> < aes.CreateDecryptor > is the only change from above aes.CreateEncryptor
Using cStream As New CryptoStream(mnemonicData, aes.CreateDecryptor(key, key), CryptoStreamMode.Write)
Dim buffer As Byte() = File.ReadAllBytes(Rythorian77)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = mnemonicData.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(Rythorian77, finalBuffer)
End Using
End Using
End Sub
End Class
**Add this separate Class:**
Imports System.Runtime.InteropServices
Public Class AESRam
'This controls the amount of RAM that your process uses, it doesn't otherwise have any affect on the virtual memory size of your process.
'Sets the minimum and maximum working set sizes for the specified process.
'This will cut memory usage in half.
<DllImport("KERNEL32.DLL", EntryPoint:="SetProcessWorkingSetSize", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)>
Friend Shared Function SetProcessWorkingSetSize(pProcess As IntPtr, dwMinimumWorkingSetSize As Integer, dwMaximumWorkingSetSize As Integer) As Boolean
End Function
'Retrieves a pseudo handle for the current process.
<DllImport("KERNEL32.DLL", EntryPoint:="GetCurrentProcess", SetLastError:=True, CallingConvention:=CallingConvention.StdCall)>
Friend Shared Function GetCurrentProcess() As IntPtr
End Function
'See Above
Public Sub New()
Dim pHandle As IntPtr = GetCurrentProcess()
SetProcessWorkingSetSize(pHandle, -1, -1)
End Sub
End Class
Hope someone can help.
I want to load the Sections of an external ini file into a ComboBox in Visual Basic 2015 and then load the Keys and Values of a selected Section into TextBoxes.
I've been pulling my hair out with this and can't even get a start on how to accomplish this.
Any helping start you can give would be greatly appreciated.
Thanks,
Dan
First create this class(Source - CodeProject Article):
Imports System.Text
Imports System.Runtime.InteropServices
Public Class INI
<DllImport("kernel32")> _
Private Shared Function GetPrivateProfileString(Section As String, Key As String, Value As String, Result As StringBuilder, Size As Integer, FileName As String) As Integer
End Function
<DllImport("kernel32")> _
Private Shared Function GetPrivateProfileString(Section As String, Key As Integer, Value As String, <MarshalAs(UnmanagedType.LPArray)> Result As Byte(), Size As Integer, FileName As String) As Integer
End Function
<DllImport("kernel32")> _
Private Shared Function GetPrivateProfileString(Section As Integer, Key As String, Value As String, <MarshalAs(UnmanagedType.LPArray)> Result As Byte(), Size As Integer, FileName As String) As Integer
End Function
Public path As String
Public Sub New(INIPath As String)
path = INIPath
End Sub
Public Function GetSectionNames() As String()
Dim maxsize As Integer = 500
While True
Dim bytes As Byte() = New Byte(maxsize - 1) {}
Dim size As Integer = GetPrivateProfileString(0, "", "", bytes, maxsize, path)
If size < maxsize - 2 Then
Dim Selected As String = Encoding.ASCII.GetString(bytes, 0, size - (If(size > 0, 1, 0)))
Return Selected.Split(New Char() {ControlChars.NullChar})
End If
maxsize *= 2
End While
End Function
Public Function GetEntryNames(section As String) As String()
Dim maxsize As Integer = 500
While True
Dim bytes As Byte() = New Byte(maxsize - 1) {}
Dim size As Integer = GetPrivateProfileString(section, 0, "", bytes, maxsize, path)
If size < maxsize - 2 Then
Dim entries As String = Encoding.ASCII.GetString(bytes, 0, size - (If(size > 0, 1, 0)))
Return entries.Split(New Char() {ControlChars.NullChar})
End If
maxsize *= 2
End While
End Function
Public Function GetEntryValue(section As String, entry As String) As Object
Dim maxsize As Integer = 250
While True
Dim result As New StringBuilder(maxsize)
Dim size As Integer = GetPrivateProfileString(section, entry, "", result, maxsize, path)
If size < maxsize - 1 Then
Return result.ToString()
End If
maxsize *= 2
End While
End Function
End Class
Add sections to the ComboBox like this:
Dim _ini As New INI("somefile.ini")
ComboBox1.Items.AddRange(ini.GetSectionNames()) 'For all sections
ComboBox1.Items.Add("section1") 'For specific section(s)
Then, in the selection changed event of the ComboBox:
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim _ini As New INI("somefile.ini")
Dim section As String = ComboBox1.SelectedItem
TextBox1.Text = _ini.GetEntryValue(section, "someKey") 'for specific entry
For Each item In _ini.GetEntryNames(section) 'this is for all entries
'do whatever you want here with the item variable like this:
'TextBox1.Text = _ini.GetEntryValue(section, item)...
Next
End Sub
As opposed to the TextBox control which use CrLf line endings the RichTextBox control use Lf line endings. I don't want that. I need consistency. I need a RichTextBox control whom use CrLf line endings.
I opened the control in reflector and noticed that the getter of the Text property calls the following function:
Private Function StreamOut(ByVal flags As Integer) As String
'...
Me.StreamOut(data, flags, False)
'...
End Function
Which ends up calling:
Private Sub StreamOut(ByVal data As Stream, ByVal flags As Integer, ByVal includeCrLfs As Boolean)
'...
Dim es As New EDITSTREAM
'...
ElseIf includeCrLfs Then
num = (num Or &H20)
Else
'...
es.dwCookie = DirectCast(num, IntPtr)
'...
End Sub
And as you can see, the includeCrLfs parameter will always be False.
So I subclassed the control and intercepted the EM_STREAMOUT message. The LParam of this message contains the pointer to the EDITSTREAM structure. I appended the &H20 flag as seen in the function above, but this didn't work. The Text property started to return an empty string. I believe that I might have to remove/append other flags, but I have no clue as to which flags. Also, MSDN do not provide any hints other than application-defined value.
dwCookieSpecifies an application-defined value that the rich edit control passes to the EditStreamCallback callback function specified by the pfnCallback member.
Here's my subclassed control:
Public Class UIRichTextBox
Inherits System.Windows.Forms.RichTextBox
Private Sub EmStreamOut(ByRef m As Message)
Dim es As New EDITSTREAM
es = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(EDITSTREAM)), EDITSTREAM)
If (IntPtr.Size = 4) Then
Dim cookie As Int32 = es.dwCookie.ToInt32()
'cookie = (cookie Or &H20I) '<- Didn't work
es.dwCookie = New IntPtr(cookie)
Else
Dim cookie As Int64 = es.dwCookie.ToInt64()
'cookie = (cookie Or &H20L) '<- Didn't work
es.dwCookie = New IntPtr(cookie)
End If
Marshal.StructureToPtr(es, m.LParam, True)
MyBase.WndProc(m)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case EM_STREAMOUT
Me.EmStreamOut(m)
Exit Select
Case Else
MyBase.WndProc(m)
Exit Select
End Select
End Sub
Private Const EM_STREAMOUT As Integer = &H44A
Private Delegate Function EDITSTREAMCALLBACK(ByVal dwCookie As IntPtr, ByVal buf As IntPtr, ByVal cb As Integer, <Out()> ByRef transferred As Integer) As Integer
<StructLayout(LayoutKind.Sequential)> _
Private Class EDITSTREAM
Public dwCookie As IntPtr = IntPtr.Zero
Public dwError As Integer
Public pfnCallback As EDITSTREAMCALLBACK
End Class
End Class
Update
So it turns out that the flags are not undocumented at all. They are part of the EM_GETEDITSTYLE and EM_SETEDITSTYLE messages. But as you can see, the flag is obsolete.
SES_USECRLF Obsolete. Do not use.
So I guess I'm back at square one overriding the text property.
Public Overrides Property Text() As String
Get
Dim value As String = MyBase.Text
If (Not value Is Nothing) Then
value = value.Replace(ChrW(13), "")
value = value.Replace(ChrW(10), Environment.NewLine)
End If
Return value
End Get
Set(value As String)
MyBase.Text = value
End Set
End Property
So I managed to create a working solution using reflection. I'm sure there must be a good reason as to why SES_USECRLF is obsolete, so proceed with caution.
Public Class UIRichTextBox
Inherits System.Windows.Forms.RichTextBox
Shared Sub New()
UIRichTextBox.InternalEditStream = GetType(System.Windows.Forms.RichTextBox).GetField("editStream", (BindingFlags.NonPublic Or BindingFlags.Instance))
UIRichTextBox.InternalStreamIn = GetType(System.Windows.Forms.RichTextBox).GetMethod("StreamIn", (BindingFlags.NonPublic Or BindingFlags.Instance), Nothing, New Type() {GetType(System.IO.Stream), GetType(System.Int32)}, Nothing)
UIRichTextBox.InternalStreamOut = GetType(System.Windows.Forms.RichTextBox).GetMethod("StreamOut", (BindingFlags.NonPublic Or BindingFlags.Instance), Nothing, New Type() {GetType(System.IO.Stream), GetType(System.Int32), GetType(System.Boolean)}, Nothing)
End Sub
Public Sub New()
Me.m_includeCrLfs = True
End Sub
<DefaultValue(True), Category("Behavior")> _
Public Property IncludeCrLfs() As Boolean
Get
Return Me.m_includeCrLfs
End Get
Set(value As Boolean)
If (value <> Me.m_includeCrLfs) Then
Me.m_includeCrLfs = value
Me.RecreateHandle()
End If
End Set
End Property
Public Overrides Property [Text]() As String
Get
Dim value As String = Nothing
If (Me.StreamOut(&H11, value)) Then
Return value
End If
Return MyBase.[Text]
End Get
Set(ByVal value As String)
If (Not Me.StreamIn(value, &H11)) Then
MyBase.[Text] = value
End If
End Set
End Property
Private Function StreamIn(ByVal str As String, ByVal flags As Integer) As Boolean
If (((Me.IsHandleCreated AndAlso ((Not Me.IsDisposed) AndAlso (Not Me.Disposing))) AndAlso ((Not str Is Nothing) AndAlso (str.Length > 0))) AndAlso ((Not UIRichTextBox.InternalEditStream Is Nothing) AndAlso (Not UIRichTextBox.InternalStreamIn Is Nothing))) Then
Dim bytes As Byte()
Dim index As Integer = str.IndexOf(ChrW(0))
If (index <> -1) Then
str = str.Substring(0, index)
End If
If ((flags And &H10) <> 0) Then
bytes = Encoding.Unicode.GetBytes(str)
Else
bytes = Encoding.Default.GetBytes(str)
End If
Dim data As New System.IO.MemoryStream()
UIRichTextBox.InternalEditStream.SetValue(Me, data)
data.Write(bytes, 0, bytes.Length)
data.Position = 0
UIRichTextBox.InternalStreamIn.Invoke(Me, New Object() {data, flags})
Return True
End If
Return False
End Function
Private Function StreamOut(ByVal flags As Integer, ByRef result As String) As Boolean
If ((Me.IsHandleCreated AndAlso ((Not Me.IsDisposed) AndAlso (Not Me.Disposing))) AndAlso (Not UIRichTextBox.InternalStreamOut Is Nothing)) Then
Dim data As New System.IO.MemoryStream()
UIRichTextBox.InternalStreamOut.Invoke(Me, New Object() {data, flags, Me.m_includeCrLfs})
data.Position = 0
Dim length As Integer = CInt(data.Length)
Dim str As String = String.Empty
If (length > 0) Then
Dim buffer As Byte() = New Byte(length - 1) {}
data.Read(buffer, 0, length)
If ((flags And &H10) <> 0) Then
str = Encoding.Unicode.GetString(buffer, 0, buffer.Length)
Else
str = Encoding.Default.GetString(buffer, 0, buffer.Length)
End If
If ((Not String.IsNullOrEmpty(str)) AndAlso (str.Chars((str.Length - 1)) = ChrW(0))) Then
str = str.Substring(0, (str.Length - 1))
End If
End If
result = str
Return True
End If
Return False
End Function
Private Shared ReadOnly InternalEditStream As FieldInfo
Private Shared ReadOnly InternalStreamIn As MethodInfo
Private Shared ReadOnly InternalStreamOut As MethodInfo
Private m_includeCrLfs As Boolean
End Class
I'm using the below function to generate an MD5\SH1 hash for SQL backup files.
This works well, has progress report etc but is slow if using large files.
Could I generate the MD5 at the same time as SH1 rather than having to process the file twice, doubling the time taken? What about converting an MD5 result to SHA1?
Imports System
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public Class ASyncFileHashAlgorithm
Protected hashAlgorithm As HashAlgorithm
Protected m_hash As Byte()
Protected cancel As Boolean = False
Protected m_bufferSize As Integer = 4096
Public Delegate Sub FileHashingProgressHandler(ByVal sender As Object, _
ByVal e As FileHashingProgressArgs)
Public Event FileHashingProgress As FileHashingProgressHandler
Public Sub New(ByVal hashAlgorithm As HashAlgorithm)
Me.hashAlgorithm = hashAlgorithm
End Sub
Public Function ComputeHash(ByVal stream As Stream) As Byte()
cancel = False
m_hash = Nothing
Dim _bufferSize As Integer = m_bufferSize
' this makes it impossible to change the buffer size while computing
Dim readAheadBuffer As Byte(), buffer As Byte()
Dim readAheadBytesRead As Integer, bytesRead As Integer
Dim size As Long, totalBytesRead As Long = 0
size = stream.Length
readAheadBuffer = New Byte(_bufferSize - 1) {}
readAheadBytesRead = stream.Read(readAheadBuffer, 0, _
readAheadBuffer.Length)
totalBytesRead += readAheadBytesRead
Do
bytesRead = readAheadBytesRead
buffer = readAheadBuffer
readAheadBuffer = New Byte(_bufferSize - 1) {}
readAheadBytesRead = stream.Read(readAheadBuffer, 0, _
readAheadBuffer.Length)
totalBytesRead += readAheadBytesRead
If readAheadBytesRead = 0 Then
hashAlgorithm.TransformFinalBlock(buffer, 0, bytesRead)
Else
hashAlgorithm.TransformBlock(buffer, 0, bytesRead, buffer, 0)
End If
RaiseEvent FileHashingProgress(Me, New _
FileHashingProgressArgs(totalBytesRead, size))
Loop While readAheadBytesRead <> 0 AndAlso Not cancel
If cancel Then
Return InlineAssignHelper(m_hash, Nothing)
End If
Return InlineAssignHelper(m_hash, hashAlgorithm.Hash)
End Function
Public Property BufferSize() As Integer
Get
Return m_bufferSize
End Get
Set(ByVal value As Integer)
m_bufferSize = value
End Set
End Property
Public ReadOnly Property Hash() As Byte()
Get
Return m_hash
End Get
End Property
'Public Sub Cancel()
' cancel = True
'End Sub
Public Overrides Function ToString() As String
Dim hex As String = ""
For Each b As Byte In Hash
hex += b.ToString("x2")
Next
Return hex
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, _
ByVal value As T) As T
target = value
Return value
End Function
End Class
Public Class FileHashingProgressArgs
Inherits EventArgs
Public Property TotalBytesRead() As Long
Get
Return m_TotalBytesRead
End Get
Set(ByVal value As Long)
m_TotalBytesRead = Value
End Set
End Property
Private m_TotalBytesRead As Long
Public Property Size() As Long
Get
Return m_Size
End Get
Set(ByVal value As Long)
m_Size = Value
End Set
End Property
Private m_Size As Long
Public Sub New(ByVal totalBytesRead__1 As Long, ByVal size__2 As Long)
TotalBytesRead = totalBytesRead__1
Size = size__2
End Sub
End Class
The following is how I'm generating a hash using the above:
Shared hasher As New ASyncFileHashAlgorithm(SHA1.Create())
Private Function Test(Byval (strFilePathAndName, as String)
Dim stream As IO.Stream = DirectCast(File.Open(strFilePathAndName, _
FileMode.Open), Stream)
AddHandler hasher.FileHashingProgress, _
AddressOf OnFileHashingProgress
Dim t = New Thread(AddressOf hasher.ComputeHash)
t.Start(stream)
While t.IsAlive
Application.DoEvents()
End While
'LblMD5.Text = hasher.ToString???
LblSHA1.Text = hasher.ToString
stream.Dispose()
End Sub
Public Sub OnFileHashingProgress(ByVal sender As Object, _
ByVal e As FileHashingProgressArgs)
SetControlPropertyValue(uxChildForm.ProgressBar, "Position", _
CInt(e.TotalBytesRead / e.Size * 100))
End Sub
You ToString method may create tremendous overhead for large strings since concatenation is expensive (it creates large temporary buffer) and you do it often. Use a StringBuilder (initialised with the correct size) instead.
Does anyone have a working class or function to create the hashed email that is sent to facebook to register email addresses with connect.registerUsers?
Connect.registerUsers uses, I believe merely the normal MD5 hash as implemented in the .NET runtime.
The MD5 documentation page even includes an example code:
Function getMd5Hash(ByVal input As String) As String
' Create a new instance of the MD5 object. '
Dim md5Hasher As MD5 = MD5.Create()
' Convert the input string to a byte array and compute the hash. '
Dim data As Byte() = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input))
' Create a new Stringbuilder to collect the bytes '
' and create a string. '
Dim sBuilder As New StringBuilder()
' Loop through each byte of the hashed data '
' and format each one as a hexadecimal string. '
For i As Integer = 0 To data.Length - 1
sBuilder.Append(data(i).ToString("x2"))
Next
' Return the hexadecimal string. '
Return sBuilder.ToString()
End Function
However, there’s a .NET client library for Facebook anyway, why not use it?
Duh. The .NET library doesn’t have support for Connect (yet)
figured this out on my own
Imports System.Net
Imports tb2CoreLib
Imports Microsoft.Xml.Schema.Linq
Imports System.Security.Cryptography
Imports facebook.Utility
Imports Microsoft.Xml
Imports System.Xml
Imports System.Web
Public Class FacebookConnect
Public Function EmailHash(ByVal email As String) As String
email = email.ToLower().Trim()
Dim rawBytes As Byte() = System.Text.UTF8Encoding.UTF8.GetBytes(email)
Dim crc As New Crc32()
Dim crcResult As Byte() = crc.ComputeHash(rawBytes)
Dim hexstring As String = Me.ToHexString(crcResult)
Dim crcLResult As Long = Me.HexToDec(hexstring)
Dim md5 As MD5 = New MD5CryptoServiceProvider()
Dim md5Result As Byte() = md5.ComputeHash(rawBytes)
Dim md5Data As String = Me.ToHexString(md5Result).ToLower()
Return (crcLResult.ToString() & "_") + md5Data
End Function
end class
Imports System
Imports System.Security.Cryptography
Public Class Crc32
Inherits HashAlgorithm
Public Const DefaultPolynomial As UInt32 = &HEDB88320UI
Public Const DefaultSeed As UInt32 = &HFFFFFFFFUI
Private Shadows hash As UInt32
Private seed As UInt32
Private table As UInt32()
Private Shared defaultTable As UInt32()
Public Sub New()
table = InitializeTable(DefaultPolynomial)
seed = DefaultSeed
Initialize()
End Sub
Public Sub New(ByVal polynomial As UInt32, ByVal seed As UInt32)
table = InitializeTable(polynomial)
Me.seed = seed
Initialize()
End Sub
Public Overloads Overrides Sub Initialize()
hash = seed
End Sub
Protected Overloads Overrides Sub HashCore(ByVal buffer As Byte(), ByVal start As Integer, ByVal length As Integer)
hash = CalculateHash(table, hash, buffer, start, length)
End Sub
Protected Overloads Overrides Function HashFinal() As Byte()
Dim hashBuffer As Byte() = UInt32ToBigEndianBytes(Not hash)
Me.HashValue = hashBuffer
Return hashBuffer
End Function
Public Overloads Overrides ReadOnly Property HashSize() As Integer
Get
Return 32
End Get
End Property
Public Shared Function Compute(ByVal buffer As Byte()) As UInt32
Return Not CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length)
End Function
Public Shared Function Compute(ByVal seed As UInt32, ByVal buffer As Byte()) As UInt32
Return Not CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length)
End Function
Public Shared Function Compute(ByVal polynomial As UInt32, ByVal seed As UInt32, ByVal buffer As Byte()) As UInt32
Return Not CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length)
End Function
Private Shared Function InitializeTable(ByVal polynomial As UInt32) As UInt32()
If polynomial = DefaultPolynomial AndAlso defaultTable IsNot Nothing Then
Return defaultTable
End If
Dim createTable As UInt32() = New UInt32(255) {}
For i As UInt32 = 0 To 255
Dim entry As UInt32 = DirectCast(i, UInt32)
For j As Integer = 0 To 7
If (entry And 1) = 1 Then
entry = (entry >> 1) Xor polynomial
Else
entry = entry >> 1
End If
Next
createTable(i) = entry
Next
If polynomial = DefaultPolynomial Then
defaultTable = createTable
End If
Return createTable
End Function
Private Shared Function CalculateHash(ByVal table As UInt32(), ByVal seed As UInt32, ByVal buffer As Byte(), ByVal start As Integer, ByVal size As Integer) As UInt32
Dim crc As UInt32 = seed
For i As Integer = start To size - 1
crc = (crc >> 8) Xor table(buffer(i) Xor crc And &HFF)
Next
Return crc
End Function
Private Function UInt32ToBigEndianBytes(ByVal x As UInt32) As Byte()
Return New Byte() {CByte(((x >> 24) And &HFF)), CByte(((x >> 16) And &HFF)), CByte(((x >> 8) And &HFF)), CByte((x And &HFF))}
End Function
End Class