Generation and verification of simple off line registration code based on C

  • 2021-08-12 03:22:35
  • OfStack

The main idea is that the provider holds the key, encrypts the client identity or time identity through RSA, and then encrypts it into a less ugly registration code through Base64, and then distributes it to the client.

After the client decodes Base64, it verifies whether the registration code matches the local identity or time identity through the public key it holds.

1. Generate a public key

RSACryptoServiceProvider cryptor = new RSACryptoServiceProvider();
File.WriteAllText("PrivateKey.xml", cryptor.ToXmlString(true));
File.WriteAllText("PublicKey.xml", cryptor.ToXmlString(false));

For the convenience of long-term storage, it is directly stored in the file here.

To avoid losing the client public key, I prefer to compile the public key directly into the validator, but this means that if the key is replaced, the old validator will not be able to verify the newly generated registration code.

2. Generate the registration code


 static string CreateRegCode(string mac, DateTime date)
 {
   RSACryptoServiceProvider cryptor = new RSACryptoServiceProvider();
   cryptor.FromXmlString(File.ReadAllText("PrivateKey.xml"));
   string signature = String.Format("[{}][{}]", mac, date.ToString("yyyy-MM-dd"));
   byte[] regCodeBytes = cryptor.SignData(
     Encoding.UTF.GetBytes(signature),
     "SHA");
   return Convert.ToBaseString(regCodeBytes);
 }

This method generates the registration code by encrypting the combination of MAC and date. There are several points to note:

1. MAC in the parameter is the address of the client 2. The file in Line 4 is the key file generated in Step 1

3. Because only validation is considered, the client must also know the date in the parameter

3. Verify the registration code


static bool Verify(string regCode)
 {
   const string PUBLIC_KEY = "";
   try
   {
     RSACryptoServiceProvider cryptor = new RSACryptoServiceProvider();
     cryptor.FromXmlString(PUBLIC_KEY);
     byte[] signedData = Convert.FromBaseString(regCode);
 
     bool today = cryptor.VerifyData(
       Encoding.UTF.GetBytes(String.Format("[{}][{}]", DateTime.Now.ToString("yyyy-MM-dd"))),
       "SHA", signedData);
     bool machineToday = cryptor.VerifyData(
       Encoding.UTF.GetBytes(String.Format("[{}][{}]", MAC, DateTime.Now.ToString("yyyy-MM-dd"))),
       "SHA", signedData);
     bool forever = cryptor.VerifyData(
       Encoding.UTF.GetBytes(String.Format("[{}][{}]", MAC, Environment.MachineName)),
       "SHA", signedData);
     return today || machineToday || forever;
   }
   catch
   {
     return false;
   }
 }

This method validates three types of registration codes: available on the same day, native available on the same day, and permanently available.

It should be noted that:

1. The public key in Line 3 is the content of PublicKey. xml in Step 1

MAC in lines 2.104 and 107 is the physical address of the client. As for how to get it is not the focus of this article, please read it by yourself

3. Considering that the registration code filled in by the client may not be legal Base64 text, it is necessary to catch an exception when parsing

In fact, RSACryptoServiceProvider also provides a decryption method, so that more kinds of verification codes can be verified.


Related articles: