Make pc specific hash in vb.net - vb.net

I want to make a program, which generate the same string each time, and it must be different on any each pc. So like HWID. After I have the string I send it into a php file on a remote host, the php handle it, and store it in the database.
On the first run it will make a new row in the table, but after 2nd run, it will select the row where the POST-ed hash = the hash in the table, and it has banned - not banned function. So if I give back 0 the pc is not banned, so program start to run, if I give back 1 the program close.
This is all made, my problem is, I generate hwid from processorid, and send it to the php. the processorid can be the same on different computers sometimes. So if I give fake ban, the users will be angry for me...
The question is:
How to generate a hash, which will be always the same on the pc which run the application, but different on each pc?
I know I can make it if I store a special id on the pc for example in the registry, but if somebody reinstall the pc, he can use again the service. If I generate hwid, it will takes him more time to find out how to access again to the service.

I dont think this really has anything to do with PHP, but entirely about the client side steps.
To do what it sounds like you want, you want to use a hardware signature made up of several things so that if one or two are unavailable, the result is still valid. This will use a form of the WMI polling procedure from the answer on your last question:
Private Shared Function GetHardwareItemInfo(item As String, wmiclass As String) As String
Dim data As String = ""
Dim query As String = String.Format("Select {0} From {1}", item, wmiclass)
Using mbs As ManagementObjectSearcher = New ManagementObjectSearcher(query)
For Each mo As ManagementObject In mbs.Get
For Each pd As PropertyData In mo.Properties
' should be only one
If String.Compare(pd.Name, item, StringComparison.InvariantCultureIgnoreCase) = 0 Then
' value is object, test for Nothing
If pd.Value IsNot Nothing Then
data = pd.Value.ToString
End If
Exit For
End If
Next
Next
End Using
Return data
End Function
This allows you to poll for different items in different wmi classes using the same code. Example:
' get the serialnumber item from the baseboard class:
answer = GetHardwareItemInfo("serialNumber", "Win32_BaseBoard")
For a hardware signature:
Get and store the info for each item
Combine them into one string
Convert the string to a byte array
Use crypto to hash the byte array
convert the result to a base64 string
There are other ways. For instance you could encode the result as a Hex string, but the above is what the code shows. First, these are the namespaces you need:
Imports System.Security.Cryptography
Imports System.Management
Imports System.Text
Then the procedure to get the stuff using the GetHardwareItemInfo method above:
' place to store bits of data
Dim HWStuff As New List(Of String)
Dim answer As String
' get and store some info
answer = GetHardwareItemInfo("serialNumber", "Win32_BaseBoard")
HWStuff.Add(answer)
answer = GetHardwareItemInfo("uuid", "win32_ComputerSystemProduct")
HWStuff.Add(answer)
answer = GetHardwareItemInfo("serialNumber", "Win32_OperatingSystem")
HWStuff.Add(answer)
'...etc
' glue the bits together into one string
Dim HWSig = String.Join("", HWStuff)
Dim byteHash As Byte()
' create crypto hasher
Using hasher = New SHA1Managed()
' convert the string to bytes
Dim tmpBytes = Encoding.UTF8.GetBytes(HWSig)
'hash the bytes
byteHash = hasher.ComputeHash(tmpBytes)
End Using
' encode as B64 string.
Dim HWHash = Convert.ToBase64String(byteHash)
Console.WriteLine(HWHash)
Result:
MUjeLeZtbTQ3Rc8zgFquBkOwFzA=
You could glue the string together as you get answers. But during development it helps to see the candidate info before you decide to use it or not.
Notes:
There are many many things to choose from. See WMI Win32 Classes.
Not everything needs to come from WMI. the LocalMachine name might be a good one (I have no idea of the context for this) as is the Windows Activation Key.
Other crypto hashers will produce longer hashes
This is far from foolproof.
Some things can be spoofed - the Win OS Serial number can be changed in the registry. You dont really care if the values are right, just that they do not change.
This is not copy protection. Someone could sniff out the token(s) sent from a legitimate system(s), then patch your app to send that token only.
if I store a special id...
No. Do not write anything down. Its impossible to keep a secret from the user on their own PC. Dont store the hash either - generate it every time. If you write it down it is easier to copy that value to a different machine.
I give fake ban, the users will be angry for me...
Since it sounds like you are working from a blacklist rather than a whitelist, you dont have to worry about the hash failing. The worst that will happen is that a system which should be denied access will get access. If you want to further reduce the chance of a match, use SHA512Managed; it will produce a longer hash though.
If a user changes one of the parts you are polling, they will still get in - it is quite unlikely that the hash from 2 systems will match (one white, one black).

Related

Match Words and Add Quantities vb.net

I am trying to program a way to read a text file and match all the values and their quantites. For example if the text file is like this:
Bread-10 Flour-2 Orange-2 Bread-3
I want to create a list with the total quantity of all the common words. I began my code, but I am having trouble understanding to to sum the values. I'm not asking for anyone to write the code for me but I am having trouble finding resources. I have the following code:
Dim query = From data In IO.File.ReadAllLines("C:\User\Desktop\doc.txt")
Let name As String = data.Split("-")(0)
Let quantity As Integer = CInt(data.Split("-")(1))
Let sum As Integer = 0
For i As Integer = 0 To query.Count - 1
For j As Integer = i To
Next
Thanks
Ok, lets break this down. And I not seen the LET command used for a long time (back in the GWBASIC days!).
But, that's ok.
So, first up, we going to assume your text file is like this:
Bread-10
Flour-2
Orange-2
Bread-3
As opposed to this:
Bread-10 Flour-2 Orange-2 Bread-3
Now, we could read one line, and then process the information. Or we can read all lines of text, and THEN process the data. If the file is not huge (say a few 100 lines), then performance is not much of a issue, so lets just read in the whole file in one shot (and your code also had this idea).
Your start code is good. So, lets keep it (well ok, very close).
A few things:
We don't need the LET for assignment. While older BASIC languages had this, and vb.net still supports this? We don't need it. (but you will see examples of that still floating around in vb.net - especially for what we call "class" module code, or "custom classes". But again lets just leave that for another day.
Now the next part? We could start building up a array, look for the existing value, and then add it. However, this would require a few extra arrays, and a few extra loops.
However, in .net land, we have a cool thing called a dictionary.
And that's just a fancy term of for a collection VERY much like an array, but it has some extra "fancy" features. The fancy feature is that it allows one to put into the handly list things by a "key" name, and then pull that "value" out by the key.
This saves us a good number of extra looping type of code.
And it also means we don't need a array for the results.
This key system is ALSO very fast (behind the scene it uses some cool concepts - hash coding).
So, our code to do this would look like this:
Note I could have saved a few lines here or there - but that would make this code hard to read.
Given that you look to have Fortran, or older BASIC language experience, then lets try to keep the code style somewhat similar. it is stunning that vb.net seems to consume even 40 year old GWBASIC type of syntax here.
Do note that arrays() in vb.net do have some fancy "find" options, but the dictionary structure is even nicer. It also means we can often traverse the results with out say needing a for i = 1 to end of array, and having to pull out values that way.
We can use for each.
So this would work:
Dim MyData() As String ' an array() of strings - one line per array
MyData = File.ReadAllLines("c:\test5\doc.txt") ' read each line to array()
Dim colSums As New Dictionary(Of String, Integer) ' to hold our values and sum them
Dim sKey As String
Dim sValue As Integer
For Each strLine As String In MyData
sKey = Split(strLine, "-")(0)
sValue = Split(strLine, "-")(1)
If colSums.ContainsKey(sKey) Then
colSums(sKey) = colSums(sKey) + sValue
Else
colSums.Add(sKey, sValue)
End If
Next
' display results
Dim KeyPair As KeyValuePair(Of String, Integer)
For Each KeyPair In colSums
Debug.Print(KeyPair.Key & " = " & KeyPair.Value)
Next
The above results in this output in the debug window:
Bread = 13
Flour = 2
Orange = 2
I was tempted here to write this code using just pure array() in vb.net, as that would give you a good idea of the "older" types of coding and syntax we could use here, and a approach that harks all the way back to those older PC basic systems.
While the dictionary feature is more advanced, it is worth the learning curve here, and it makes this problem a lot easier. I mean, if this was for a longer list? Then I would start to consider introduction of some kind of data base system.
However, without some data system, then the dictionary feature is a welcome approach due to that "key" value lookup ability, and not having to loop. It also a very high speed system, so the result is not much looping code, and better yet we write less code.

Properly Handling Large Amounts of Data

I've ventured into extremely unknown territory and I need some advice. I'm building an IRC bot for Twitch that could potentially contain hundreds of thousands of accounts. Previously I used Dictionary(of String, Integer) to store these accounts and their balance in memory, and just wrote them to a text file and saved it to disk. Now I'm storing a lot more data like their online time, whether they are a follower, or subscriber, how much they've donated. So I've started utilizing SQLite to store the accounts and I believe I need to utilize DataGridView with virtualmode to display these accounts and allow the user to edit any data. Am I on the right track so far? My aim is to keep it simple while managing larges amount of data, hopefully that wasn't an oxymoron.
Now I imagine the accounts in the SQLite database will need to be cached so that it's not constantly reading the database from the hard drive when a change needs to be made or when the user is scrolling through his list of accounts in the datagridview(which is in virtualmode). Am I right so far?
If there is another, more simpler method I could utilize please let me know, otherwise can someone help comprehend how I could cache these accounts? I did consider writing them to a Dictionary(of String, String) and then splitting the string when I needed to work with a specific value. Anyways I await your suggestions or comments.
Thank you.
As per my comment above, you need to look into classes. See below for little example...
Public Class Accounts
Public Property AccountID As Integer = 0
Public Property AccountName As String = String.Empty
Public Property IsFollower As Boolean = False
**'Add more properties as needed'**
Public Sub New()
End Sub
End Class
Next you can do a call to your database and get all the id's from the table; you can use these to query the rest of your data for a specific id...
Loop through your id's that you have and get their data...
Dim nAccount As Account = Nothing
For each blah blah blah....
nAccount = query from database... which will return your Account class object...
Now you can add this object (your account class) to a collection; for example a Dictionary(Of Integer, Account) Or ListOf()
As I have mentioned before there are a few different ways to go about this, it just depends on what you need to do and how you want to handle the data.

Getting Generic Errors Trying To SNMP To Cisco Switches Using SNMPSharpNET

I am trying to integrate into SNMP scanning with my application and have delved into Google to try and find examples, etc. I have thus come across the SNMPSharpNet DLL which has allowed me to start contacting devices using SNMP which is from this website.
However, I have two issues that are similary related:
I tried to refer to this website to determine what oID to use when trying to scan a Cisco Catalyst 2960 Switch but it returned nothing (no errors and no results). The only way I could get it to work correctly (pull everything) was to use an oID of 1. This then sets off to pull back everything out of the switch, so I could then use it as a reference to determine specific oIDs for specific required data.
Which leads me to my next question.... using an oID of 1 does seem to work, however, part way through it errors out with "The agent responded with an error" which doesn't really tell me anything. I get it everytime with attempting SNMP on different devices and it's not pulling back all of the data.
My code looks like this:
Sub GetNextResult()
Dim host As String = "xx.xx.xx.xx"
Dim community As String = "public"
Dim requestOid() As String
Dim result As Dictionary(Of Oid, AsnType)
Dim rootOid As Oid = New Oid("1")
Dim nextOid As Oid = rootOid
Dim keepGoing As Boolean = True
requestOid = New String() {rootOid.ToString()}
Dim snmp As SimpleSnmp = New SimpleSnmp(host, community)
snmp.SuppressExceptions = False
If Not snmp.Valid Then
Console.WriteLine("Invalid hostname/community.")
Exit Sub
End If
While keepGoing
result = snmp.GetNext(SnmpVersion.Ver1, New String() {nextOid.ToString()})
If result IsNot Nothing Then
Dim kvp As KeyValuePair(Of Oid, AsnType)
For Each kvp In result
If rootOid.IsRootOf(kvp.Key) Then
Console.WriteLine("{0}: ({1}) {2}", kvp.Key.ToString(), _
SnmpConstants.GetTypeName(kvp.Value.Type), _
kvp.Value.ToString())
nextOid = kvp.Key
Else
keepGoing = False
End If
Next
Else
Console.WriteLine("No results received.")
keepGoing = False
End If
End While
End Sub
I guess my question is: Is there some sort of reference I could refer to get a list of the different oIDs required for specific information? Or if not, can I continue to use an oID of 1 and try to fix why it continually errors out with a generic error?
Any help appreciated thanks.
If you happen to know what is a MIB browser, use it to check out standard MIB documents, and then you see that the OID of "iso" is the root of most OIDs in use. That guarantees that your WALK operation indeed dumps out the items you want.
I don't have a Cisco Catalyst 2960 so could not exactly reproduce what you mean by "it returned nothing". Don't expect a device to implement every OIDs list in a site such as OIDVIEW, as what you should resort to is always the device manual and vendor materials.
I checked snmpsharpnet documentation and found out that your code was derived from there. Sadly Milan failed to provide a WALK function, and the code fragment listed at http://www.snmpsharpnet.com/?page_id=108 can be misleading and therefore you get your second question.
The SNMP error is expected, as GET-NEXT should hit a NoSuchName error to indicate that all available OIDs are dumped out. However, the sample code from snmpsharpnet does not tell its users that's something to be expected. The GET-BULK based WALK sample is correct, as there will be no NoSuchName error.
(Not an advertisement though) For your reference, #SNMP has its Messenger.Walk and Messenger.BulkWalk methods (looks similar) that also shows how to make WALK operations.

Auto-generate Unique ID within the constructor

Using VB.net, create a new class called staff, with three properties:
Name , LastName, ID - should be suitable for use as a primary key in a database.
Provide a class constructor to populate Name and LastName. ID should be auto-generated within the constructor and should not be passed in.
I know how to create a class, properties and constructor, I just need to know how to auto-generate ID field within the constructor. Is it possible to do this?
what I usually do is either make the id field in database as identity field and primary key so it automatically inserts the next available id or In my application I read the last ID from database and add one to it. But I need to know how to auto-generate ID field within the constructor.
Guid
If you do not have any constrain about ID type you can use a GUID:
Dim id As Guid = Guid.NewGuid()
You may even keep it as string:
Dim id As String = Guid.NewGuid().ToString("N")
That should be granted to be unique across different machines (to satisfy your requirement that it has to be suitable for use as a primary key in a database). See also this post.
Timestamp
That was worse case, if you do not have such strict requirement (uniqueness across a network) you may use a timestamp. Of course, in this case, you have to consider more issues:
Legal time: time goes back and forward twice per year.
Zones: what if user enter data in London and then he moves to New York?
Concurrency: you have to assume no one else adds records to your database (you may have collisions if they use a different technique). Also you can't apply this if execution is concurrent (multiple instance of your program running together).
Timer granularity: system date has a coarse granularity: if you construct many objects in a short period of time then you may have duplicate IDs. Workaround in this post.
Counter
If all these conditions are satisfied:
Multiple instances of your application won't run in parallel.
You're working on a single computer (not a network).
Database is empty every time your application starts.
You may use a Shared counter incremented each time a new object is constructed. If system timer granularity isn't an issue (see paragraph about timestamp)you may use system up time as ID. With limitations about granularity it should work even with multiple instances of the same application running concurrently.
If you use a Shared field you have to deal with synchronization issues. As suggested in this comment you may use a SyncLock. As alternative you may use an Interlocked.Increment operation.
Hash code
If all condistions for a counter are satisfied and this one also:
Your application is 32 bit.
Your object is not a ValueType and it doesn't override GetHashCode() method.
You can use hash-code (obtained with GetHashCode()) because (from MSDN):
In other words, two objects for which the ReferenceEquals method returns true have identical hash codes.
Because Object.ReferenceEquals() returns true only if you compare same instance then each instance will have a unique hash code (because in a 32 bit application hash code is object reference itself). Be aware this is an implementation detail and it may change.
Random number
I know this may shock someone but a good random number generator for a 64 bit value has a very low probability of collisions. I repeat very very low probability (see this article for more math details). Just do not use System.Random for this!
According to which seed you use you may be able to generate random numbers in a network scenario too (do not forget - citation needed - that earlier drafts for one local network protocol proposed a 32 bit random number as address, it has been changed because of bad feedback from users but it doesn't mean it can't work).
You want a number that won't repeat ever! So why not just use this?
Dim dateAndTime As Date
dateAndTime = Now
TextBoxPID.Text = Format(dateAndTime, "yyyyMMddHHmmss").ToString
Unless your data entries are going to take place in milliseconds, this solution works great. If you are running into a millisecond issue then just add a counter to the end of the string.
counter +=1
TextBoxPID.Text = Format(dateAndTime, "yyyyMMddHHmmss").ToString & counter.ToString
If you are working on a network and have several people doing data entry then add their employee id to the string. There are easy solution to every issue, but in most, if not all cases, this will work without issue.
Generate Random Unique User ID depending on SNTP server.
My requirements are a bit different; yet I needed to generate a random and unique User ID, that is 10 numbers, spending fair time couldn't find a suitable solution.
so I ended up with the following function; its unique and random result.
As per one application instant on one test machine it is incremental unique result; because the user will generate the ten digits one time on a non pre-selective timestamp. In addition to playing with the random alpha prefix; I hope this function can provide a solution:
Imports System.Globalization
Imports System.Net
Public Class GetNetTime
Public Shared Function GetUTC()
' connect to google servers
' you could use some SNTP time servers but can't be sure port will be open
' or you could just ping your own webserver
Dim myNetRequest As WebRequest = HttpWebRequest.Create("http://www.example.com")
' read response header from connection
Dim response = myNetRequest.GetResponse()
' read date/time header
' assume its UTC format
Dim GlobalUTC As String = response.Headers("date").ToString
' convert string to datetime object
Dim parsedDateTime As DateTime = DateTime.Parse(GlobalUTC)
' get UNIX time stamp
Dim unixTime = (parsedDateTime - New DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds
Return unixTime
End Function
End Class
To test the output, you could add:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim utc As String = GetNetTime.GetUTC
' add random alpha prefix to UNIX time stamp
Dim sPrefix As String = ""
Dim rdm As New Random()
For i As Integer = 1 To 3 ' if you need more than 3 alpah random charachters adjust i length
sPrefix &= ChrW(rdm.Next(65, 90))
Next
MsgBox(sPrefix & utc) ' OR MsgBox("ID" & sPrefix & utc)
' code here to use result
End Sub
I find this solution more useful than querying the SQL table and read last record id and do increment.
Notes:
Please don't mind long answer; as I tried to comment the code and
explain the scenario in details.
I think this is good for generating
UserID for application running on multiple workstations.
Please don't put the function in for ... loop or exhaust run it.
Output examples:
GYK1501270543
VWT1501270606
WRH1501270634
SKI1501270648
QXL1501270716
This is also based on #wpcoder answers above but a basic form and this one works for me
Public Function UIDGen(ByRef f As String) As String
Dim currentTime As DateTime = DateTime.UtcNow
Dim StringTime As String = currentTime.ToString
Dim parsedDateTime As DateTime = DateTime.Parse(StringTime)
Dim unixTime = (parsedDateTime - New DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds
Dim utcString As String = unixTime.ToString
Dim sPrefix As String = ""
Dim rdm As New Random()
For i As Integer = 1 To 3 ' 3 Letters enough ?
sPrefix &= ChrW(rdm.Next(65, 90))
Next
f = (sPrefix & utcString)
Return f
End Function

Better socket communication system

Currently, the client is sending messages like this:
Public Function checkMD5(ByVal userID As Integer, ByVal gameID As Integer, ByVal file As String, ByVal fileFull As String) As String
Dim make As New CMakeMSG
Dim md5 As New CMD5
make.append("checkfileMD5")
make.append(userID)
make.append(containerID)
make.append(file)
make.append(md5.GenerateFileHash(fileFull))
Return SocketSendAndReceiveMSG(make.makestring)
End Function
The server may receive something like this:
checkfileMD5-MSGDelimit0-12-MSGDelimit1-54-MSGDelimit2-filename.txt-MSGDelimit3-*md5hash*
Which it then reads out:
Private _message As String
Public Function handleMessage() As String
Dim brokenMessage As New ArrayList
brokenMessage = breakDown() 'Split to ArrayList
If brokenMessage(0) = "checkfileMD5" Then
Try
If brokenMessage.Count > 5 Then
Return "0-structureMessedUp"
End If
Return CompareFileMD5(brokenMessage(1), brokenMessage(2), brokenMessage(3), brokenMessage(4))
Catch ex As Exception
Return "0-structureMessedUp"
End Try
End If
End Function
So what it does is take the received message, and split it to an array using the -MSGDelimit- as a delimiter. So in this case the CompareFileMD5() function would receive 12,54,filename.txt,*md5hash*. And based on that it can return to the client whether or not the MD5 matched.
Sure, it works, but it feels sloppy and code on the server gets really messy.
Here's the less relevant functions from the above code (doubt it matters, but you never know):
Private Function breakDown() As ArrayList
Try
Dim theArray As New ArrayList
Dim copymsg As String = _message
Dim counter As Integer = 0
Do Until Not copymsg.Contains("-MSGDelimit")
Dim found As String
found = copymsg.Substring(0, copymsg.IndexOf("-MSGDelimit" & counter & "-"))
theArray.Add(found)
copymsg = copymsg.Replace(found & "-MSGDelimit" & counter & "-", "")
counter += 1
Loop
theArray.Add(copymsg)
Return theArray
Catch ex As Exception
Module1.msg(ex.Message)
End Try
End Function
Private Function CompareFileMD5(ByVal userID As Integer, ByVal gameID As Integer, ByVal filename As String, ByVal source As String) As String
Try
Dim tryFindFile As String = Module1.filedatabase.findfile(userID, gameID, filename)
If Not tryFindFile = "notFound" Then
Dim fileFull As String = tryFindFile & "\" & filename
Dim md5 As New CMD5
If md5.GenerateFileHash(fileFull) = source Then
Return "Match"
Else
Return "NoMatch"
End If
Else
Return "notFound"
End If
Catch ex As Exception
Module1.msg("0")
Return "0"
End Try
End Function
So, any advice on how to handle it better/cleaner/more professional?
Depending on the application, your current solution may be perfectly fine. There are a couple of things that do stand out a little bit:
The "protocol" is a bit heavy in terms of the amount of data sent. The delimiters between the data pieces adds quite a bit of overhead. In the example, it makes up maybe 50% of the payload. In addition, sending all data as text potentially makes the payload larger than absolutely necessary. All of this, though, is not necessarily a problem. If the traffic between the client and server is relatively light, then the extra data on the wire may not be a problem at all. For a request of this size (with or without the relatively high delimiter overhead), the main cost will be round trip costs and would likely change very little by reducing the size of this packet by half. If, though, there are requests with thousands of pieces of data, then reducing the payload size would help.
The use of the delimiters as shown is potentially ambiguous depending on the data sent. It is unlikely given the length and format of the delimiters, but it's something to keep in mind if there ever exists the possibility of having actual data that "looks" like a delimiter.
Assuming that the example shown is one of many similar protocols, I would be inclined to go a different route. One possibility would be to bundle up the request as a JSON object. There are existing packages available to create and read JSON. One example is Json.NET. JSON has a well-defined structure, it is easy for a human to read and verify, and it can be expanded easily. And depending on the data that you send, it would probably a little more lightweight than the current format. And (maybe the part you are interested in), it would maybe seem more "professional".
A couple of additional things that I would do (personal opinion):
Possibly add a client version to the data being sent so the server will know if it "recognizes" the request. Start the client version at some value (e.g., 1). If there are updates to the protocol format (e.g., different data, different structure), change the version to 2 in that release of the software. Then the server can look at the version number to see if it recognizes it. If it is the first version of the server and sees version 2, then it can return an error indicating the server needs to be updated. This is not necessary if you can guarantee that the client and server releases are always matched (sometimes this is hard in practice).
Use an integer value for the request type instead of a string ('checkFileMD5'). If there are going to be a large number of request types, the server can dispatch the request a little more efficiently (maybe) based on an integer value.