Arithmetic overflow when trying to process message block in MD5 algorithm - vb.net

Hi so im making a program in VB.Net which will hopefully output the MD5 hash of a string without using System.Security.Cryptography (not the smartest but i fancied a challenge) using the implementation from here: https://www.rfc-editor.org/rfc/rfc1321
Anyway im getting an Arithmetic overflow when i run my code. Up until this point it has been running rather smoothly with the inputted string being converted to binary, padded correctly etc.
However when i get to stage 4 where i have to process the message block it goes a little strange. Specifically on this function where it returns an Arithmetic overflow on the line labelled:
Function R1(ByRef a As ULong, ByRef b As Integer, ByRef c As Integer, ByRef d As Integer, ByRef splitmessagepart As String, ByRef S As Integer, ByRef i As Integer, ByRef T() As Long)
'the line below returns the arithmetic overflow
a = b + ((a + (f(b, c, d)) + splitmessagepart + T(i)) << S)
Return a
End Function
This is function F:
Function f(ByRef X As String, ByRef Y As String, ByRef Z As String)
Dim endresult As String
endresult = (X And Y) Or (Not X And Z)
Return endresult
End Function
And then this is the line which calls the function R1:
splitmessagepart = splitmessage(0)
a = R1(a, b, c, d, splitmessagepart, 7, 1, T)
Through some debugging i have found that my splitmessagepart variable isnt correctly translated from Binary to decimal in another function but even if i change it so that it is the correct decimal version i still get the overflow. Im assuming this happens on the other 3 functions also which do something similar to this however the program encounters an error on the first line.
I was wondering if i could have a little help figuring out why this is happening? If theres any code needed that i havent put in please ask i really want to get this to work!
Thanks

You should split the calculation into its parts and check precisely with the watch which operator throws the exception.
More importantly, it looks like you have set the option strict off. This not a good practice unless you absolutely have to. You define the parameters of the function f as string, but you pass Integers to it, so they will implicitly converted to strings. Inside f you use and and or which will again implicitly convert your parameters because these operators are not defined on strings. Also you have not defined the type of the output of the function.
More over you have defined splitmessagepart as string and you try to use + between strings and integers. Are you aware what the result will be.
I advise you to turn the option strict on and check on all these implicit conversions, they are probably not what you expect.
FYI, the doc states that a word is a 32-bit object, so an integer. I doubt there should be a string anywhere in the algorithm.

Related

"VBA.len" is 4 times slower than "len" (?!) [duplicate]

When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.

VBA "Left"-function as integer

been playing around with the "left"-function in VBA and noticed that the result is stored as a string. For example:
Left(ws2.range("C2").value,3)
Where ws2 is some worksheet and c2 is some cell in ws2 containing, say, 1234.
The left function would then return "123" but it would be formated as a string. This in turn causes errors for me when i try to access a directories key with this string (which is not possible). I've found a workaround where I :
dim tag as integer
tag = Left(ws2.range("C2").value,3)
This would cause the tag with the value 123 to be stored as an integer which I then can use for accessing the directory.
But i'm wondering if it's possible to modify the "left"-function to return values as integers? or any other format for that matter (long, variant, range, whatever)
Notice that I have figured out a solution but I thought it might be helpful to others and/or a interesting discussion.
For this it is easiest to use Cint() function. There is no need to modify functions, you can always create yours.
The proper way to do it would be to use the Cint() function to cast an expression to an integer.
For details see https://msdn.microsoft.com/en-us/library/fctcwhw9(v=vs.84).aspx
Here are some more conversion functions:
CInt() 'convert to integer
CLng() 'convert to long (long is preferred over integer since integer only has 2 bytes in VBA)
CDbl() 'convert to double
CDec() 'convert to decimal (variable has to be declared as variant)
Made it an answer :)
cint(left(ws2.range("C2").value,3)) would be "better" as you're still relying on VBA to make the conversion for you, also checking the output first to work out if you in fact need to use a long maybe. Also checking the input string is numeric first of all would also be a good check.
using cint
function IntLeft(byval value as string, byval length as integer) as Integer
IntLeft=0 'default if non numeric
if isnumeric(value) then
IntLeft=cint(left(value,length))
end if
end function
using int
function IntLeft(byval value as string, byval length as integer) as Integer
IntLeft=int(left(value,length)) 'int returns the first numbers as an int, 0 if no numbers
end function
You can use Abs function instead to return the left function as integer.
i.e., Abs(Left(ws2.range("C2").value,3))

Why min(d1, d2) has byref in argument for vb.net?

I noticed that if I do
a = min (b,c)
I often got a warning that both b and c must be double and not integer. That's because while double can be converted to integer on the fly, the other way around doesn't work.
And the reason why it should work is because b and c is passed by reference.
However, why?
min (b,c) simply takes the smaller value of b or c and return it into a
Why should the argument is passed by ref? The function doesn't change the value of it's parameter?
Since you set vb.net as the tag:
Min() function (Math.Min) is overloaded and can take arguments of the following types: byte, decimal, single, double, signed and unsigned integers of different sizes (2, 4 or 8 bytes)
Both arguments should be of the same type, otherwise implicit conversion will take place. Your statement "That's because while double can be converted to integer on the fly, the other way around doesn't work." is not accurate; see code below.
Your statement "And the reason why it should work is because b and c is passed by reference." is not true either; see code below.
This following code should compile and run fine:
Module VBModule
Sub Main()
Console.WriteLine(Math.Min(5.1, 4))
End Sub
End Module

Why do Len and VBA.Len return different results?

When I run the following macro:
Sub try()
Dim num As Integer
num = 123
MsgBox Len(num)
MsgBox VBA.Len(num)
End Sub
The first Msgbox displays 2 and the second Msgbox displays 3.
If I remove the first line which says Dim num As Integer, both MsgBoxes display 3.
Can anyone explain why?
Len and LenB are not just ordinary functions, they are keywords, and as such are found on the list of VBA keywords (although LenB is only mentioned after you click through to Len).
Mid would be another example of such keyword disguised as function, whereas e.g. Left isn't on the list at all, because that is just an ordinary function.
It has to be a keyword because one of its jobs is to perform the compile-time task of determining the storage size of a variable. E.g. with private user-defined types, an ordinary function could not do that at all:
Private Type foo
a As Long
b As String
End Type
Sub TestLens()
Dim f As foo
MsgBox Len(f) ' OK
MsgBox VBA.Len(f) ' Compile time error
End Sub
The fact that the object browser brings you to VBA.Len when you press Shift+F2 on that Len(f) is both correct and misleading.
The Len(f) here does not actually call the VBA.Len function that determines the string size, it simply cannot do that because it would require coercing a private struct into a Variant. Instead it calculates the size of foo at compile time and substitutes the result as a literal constant into the executable.
In your example the Len(num) calculates the compile-time size of variable num (which is 2) and substitutes the constant 2 into the resulting object code, whereas VBA.Len(num) packs the value of num into a Variant and passes that variant to VBA.Len where it's further converted to string "123" and the length of that is returned.
It has to do with the way that VB stores integers and how the Len() function handles arguments that are not strings.
When a datatype that is not a string is passed to the Len() function, it returns the nominal number of bytes used to store the data (VB uses 2 bytes to store an integer). See the documentation for the Len function.
The Len() function will automatically cast the variant variable (which is created by assigning a value to a variable without declaring it first) as a string. The return isn't changing because the storage allocation changes (although it does; variants require 16 bytes of storage space, minimum). Since the implicitly declared variable is actually a variant type, VB will automatically change its type based on the situation. In this case, Len() expects a string so VB makes the variable a string.
You could use Msgbox Len(Cstr(num)) to cast the integer variable as a string before passing it to the Len function if your intent is to return the number of characters in your integer value.

How to use CStr to convert generic parameter to String?

I wrote a generic Sub and need to convert the input values to String to get them into a TextBox(in this case a powerpoint textbox). This looks like:
Sub InsertValueIntoTextbox(Of t)(ByVal sldNr As Integer, ByVal tbName As String, ByVal valueToInsert As T)
_pptSld = _pptPre.Slides(sldNr)
_pptSld.Shapes(tbName).TextFrame.TextRange.Text = CStr(valueToInsert)
End Sub
My problem is that it gives me this compiler-error:
The value of t cannot be converted into string
I tried a CStr (as you can see in the snippet) but this doesnt help too. Could anyone help me get this to work and can tell me why I cannot convert T to CStr?
Every Object can ToString, so why dont you use that?
Dim text = If(valueToInsert Is Nothing, "", valueToInsert.ToString())
_pptSld.Shapes(tbName).TextFrame.TextRange.Text = text
You cannot use CStr on generics. The type of the parameter must be convertible to String which is not guaranteed in your case. That's why you get the compiler error. I wouldn't use those old VB functions anymore. There are always .NET alternatives.