Question Something else than Random

elianeasmar

Well-known member
Joined
Oct 3, 2013
Messages
76
Programming Experience
Beginner
Hello experts. Please i need your help.
i have 4 stations.and i need to generate a code on each station that contains 4 letters and a digit(e.g: abcd1) in order to appear on the tickets, and this code should be generated on a daily bases,and has to be the same code on all the stations, and should be secret too.only a privileged person can have access to it.
in this case Random won't do me any good.
so please. if anyone can help me.
thank you so much
waiting for your reply :)
 
Random is exactly what you need, you just need to know how to apply it...

        Dim rnd As New Random

        Dim strResult As String = ""

        For i = 1 To 4
            strResult += Chr(rnd.Next(97, 122))
        Next
        strResult += rnd.Next(0, 9).ToString()


That will generate your code. However, in order to distribute it to all the stations AND for it to stay secret, you will have to devise some way of exchanging the information. My first guess would be a web service that requires authentication, to which your app would talk to directly.
 
Your piece of code works perfectly. But i'm looking for something a bit different
the problem is that the stations are not suppose to be connected.
I was thinking if i can encrypt the date (##/##/####) and get a code.
That way the code will be the encryption of the date. witch means if i have a ticket with a code written on it,if i decrypted it, i would be able to retrieve the release date of the ticket.
that way i won't need any network to connect the stations.
and the code would be directly related to the date. and if i generate the code many times on the same day, i would have the same code as a result.
but i'm a bit stuck in this method that i just explained.

Any help would be appreciated.
Thank you.




Lilly
 
Last edited:
sub main()
Dim dt As Date
dt = Format(Now, "dd/MM/yyyy")
Dim s1 As String = dt.ToBinary.ToString
Dim d1 As Date = Date.FromBinary(Val(s1)) ' convert string back to date
Console.WriteLine(s1)
Console.WriteLine(d1)
Console.ReadLine()
Ens Sub


i managed to encrypt the date like this.but it's doing this process over and over. And another problem that some codes generated has been repeated many times.
So i'll try to fix it :)
 
Hi,

Your initial post confused me since I did not completely understand what you wanted to do but after answering Herman's post you clarified a few things in my mind.

So, to confirm, you want a Random, but Logically Generated string for each day that can be recognised on any of your 4 machines for the purposes of logging in for that day only? A bit like a paid for Internet Cafe password for the day?

If so, then here is another idea for you. You can use Cryptography to Hash the Current Date and produce a Random, but Logical, password that can be tested for and recognised on each of your 4 machines. The important thing for this to work is to make sure that each machine always has the correct date and time and you also have to realise that someone could change the System Date on the machine they want to work from to work with a previously generated code. (There are ways round this issue but that is a different conversation)

So, knowing those two flaws above, here is an example of creating an MD5 Hash to generate a password from the current given date:-

Imports System.Security.Cryptography
Imports System.Text
 
Public Class Form1
 
  Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    'Get todays date as a string
    Dim todaysDate As String = Now.ToLongDateString
 
    'Set up an MD5 Hash Object
    Using md5Hash As MD5 = MD5.Create()
      Dim myDateBytes As Byte() = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(todaysDate))
      Dim hashedData As String = String.Empty
 
      'Loop through each Byte of the Byte Array and Format each one as a Hexadecimal String to create a hashedData String
      For Counter As Integer = 0 To myDateBytes.Length - 1
        hashedData &= myDateBytes(Counter).ToString("x2").ToUpper
      Next
 
      'Finally, Generate the Days Ticket code by Taking the first 4 letters of the hashedData String and the First Number of the hashedData String
      Dim myDayTicketCode = hashedData.ToCharArray.Where(Function(x) Char.IsLetter(x)).Take(4).ToArray & _
                            hashedData.ToCharArray.Where(Function(x) Char.IsDigit(x)).Take(1).ToArray
 
      'Display the result to demonstrate
      MsgBox(myDayTicketCode)
    End Using
  End Sub
End Class


Hope that helps.

Cheers,

Ian
 
You should also include the station name in the hash to make it station specific, however the resulting hash will NOT be in your preferred format if you need to verify it (and that is the whole point of including the hash in the first place isn't it?). You also will need to include a password to protect it. However if you need to be able to get both station name and date back from the hash, short of brute forcing it out, a reversible encryption algorithm might be preferable. Here is an example of encrypt/decrypt through AES-256:

Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim MyPlainTextMessage As String = "Station 1 " & DateTime.Now.ToString()
        Dim MyKey As String = "00000000000000000000000000000000"

        Dim EncryptedCipherText As String = AESEncryptStringToBase64(MyPlainTextMessage, MyKey)

        Dim DecryptedPlainText As String = AESDecryptBase64ToString(EncryptedCipherText, MyKey)

        MessageBox.Show("Plain text: " & MyPlainTextMessage & vbCrLf & _
                        "Encrypted Base64 cipher: " & EncryptedCipherText & vbCrLf & _
                        "Decrypted plain text: " & DecryptedPlainText)
    End Sub

    Private Function AESEncryptStringToBase64(strPlainText As String, strKey As String) As String
        Dim Algo As RijndaelManaged = RijndaelManaged.Create()

        With Algo
            .BlockSize = 128
            .FeedbackSize = 128
            .KeySize = 256
            .Mode = CipherMode.CBC
            .IV = Guid.NewGuid().ToByteArray()
            .Key = Encoding.ASCII.GetBytes(strKey)
        End With


        Using Encryptor As ICryptoTransform = Algo.CreateEncryptor()
            Using MemStream As New MemoryStream
                Using CryptStream As New CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)
                    Using Writer As New StreamWriter(CryptStream)
                        Writer.Write(strPlainText)
                    End Using

                    AESEncryptStringToBase64 = Convert.ToBase64String(Algo.IV.Concat(MemStream.ToArray()).ToArray())
                End Using
            End Using
        End Using
    End Function

    Private Function AESDecryptBase64ToString(strCipherText As String, strKey As String) As String
        Dim arrSaltAndCipherText As Byte() = Convert.FromBase64String(strCipherText)

        Dim Algo As RijndaelManaged = RijndaelManaged.Create()

        With Algo
            .BlockSize = 128
            .FeedbackSize = 128
            .KeySize = 256
            .Mode = CipherMode.CBC
            .IV = arrSaltAndCipherText.Take(16).ToArray()
            .Key = Encoding.ASCII.GetBytes(strKey)
        End With


        Using Decryptor As ICryptoTransform = Algo.CreateDecryptor()
            Using MemStream As New MemoryStream(arrSaltAndCipherText.Skip(16).ToArray())
                Using CryptStream As New CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read)
                    Using Reader As New StreamReader(CryptStream)
                        AESDecryptBase64ToString = Reader.ReadToEnd()
                    End Using
                End Using
            End Using
        End Using
    End Function

End Class


The main advantage here is that you can include all sorts of additional data in your crypted cipher. Station name, date and time, user name, etc... And everything included can be recovered.
 
Last edited:
Hi Herman,

You should also include the station name in the hash to make it station specific,

Agreed. As well as this something else should be added that can deal with the changing the system date issue. Something like a generic days password that all the machines could know based on another hashed string of sorts?

however the resulting hash will NOT be in your preferred format if you need to verify it (and that is the whole point of including the hash in the first place isn't it?).

Also agreed, although the idea here was not to generate a hash that can be Verified but to generate a day by day Random, but very logical, 5 digit string that can be generated and used on each of the computers.

Cheers,

Ian
 
Also agreed, although the idea here was not to generate a hash that can be Verified but to generate a day by day Random, but very logical, 5 digit string that can be generated and used on each of the computers.

Was that the point?

I was thinking if i can encrypt the date (##/##/####) and get a code.
That way the code will be the encryption of the date. witch means if i have a ticket with a code written on it,if i decrypted it, i would be able to retrieve the release date of the ticket.

I think the code above will be more appropriate, however only the OP can really answer I guess.
 
I guess some explanation of the code is warranted, if someone doesn't really know how AES and other block ciphers work.

To encrypt something using AES, you need some text to encrypt, a key and a salt (or IV, "initialization vector"; more on this below...).

The key has to be of a supported length for the algorithm. In this case I chose a 256 bits key (32 bytes), but it could also have been 128 bits (16 bytes) or 192 bits (24 bytes). The key HAS to stay secret, it's your password. Ideally it should be randomly generated and securely stored in some manner. Here I just used "00000000000000000000000000000000" for the example.

The salt (or IV) is needed to make sure that if the same data is encrypted twice with the same key, two different cipher texts will be output. In the case of a file, this is also to make sure that the first encrypted block is always different. If you had two different files with the same first 128 bits, and encrypted them with the same salt and key, the first encrypted block would be the same. This is essentially just random data and it does not need to be secret, it just needs to be different each time you encrypt something. In this case I used a GUID as it is by nature unique and random (and incidentally, just the right length; the salt should be the same length as a single block of data, 128 bits). The salt is needed to decrypt the data, but it should not be stored with the key (because it needs to be different for every encryption iteration). Normally you just prepend the encrypted data with the salt when distributing it. This is what I did here, the data is encrypted, the salt is added at the beginning, and the whole thing is Base64 encoded for easy string representation.

To decrypt the data, you just backtrack. Take the Base64 string, convert it to a decoded byte array. The byte array contains the salt in the first 16 bytes (because a GUID is 16 bytes long), and the encrypted cipher text following it. Then you decrypt the cipher text using the secret key and the salt.

The reason you see Rijndael in the code, is because AES is derived from Rijndael, but limited to 128-bits block sizes. I could also have used the AESManaged class, with essentially everything else the same.

Let me know if you have any questions.

PS: Keep in mind the code above is simplified a bit and by no means completely secure. SecureString should be used instead of String for the key and plain text, amongst other things.
 
Last edited:
Back
Top