0

I am new to RSA licensing and I used an online RSA key generator that creates a private and public key. I want to sign some data using these keys and verify the key using the public.

I am using .NET Framework 4.7.2.

These are the functions I tried:

public static string GenerateLicenseFromUserInfo(UserLicense info)  //  To Generate user license
{

//  Temporary license keys I am trying to use
    byte[] privateKeyBytes = Convert.FromBase64String("MIICXAIBAAKBgQC8IG4CySTEOZhmDwlTdR4Yd6xoqoJGsfze/RvrZgY72HAuWK0Y3DKrNdFiM+Z2O1weArCyoTbGsZ7UcxhCFKQLSsHooZveQTTHDHvm7cIts8jEMDw/xbPDrMQH/vYjRshNo8vOsVwxQELVzvrMA7+A/3ITKvbL0PTSDxxMcHRQDwIDAQABAoGAUNNqEH5U8o2AQZECQ74U0RRRmaJwWGlOKIv8e9WYpgumnvLwY7bvegmkTRnZUUDNogMr4YNMIm/bupE8gd+WXpo8TrHoFDNYFGB07eAnDR/ZNcSboBLGw9JKnRCD8kZ2QYwmH/wKdJL2VppC+ooVit2AcDWeCh9pPl8gF5R054kCQQDwxfnogy19yEF6eXEBQD4um/nDUbjRaudyc/i16H6SBw1+q/sQhX/QArgDwxnU5vfUWRZ4BQGw6IlQWYNzbxuzAkEAyAYgCRIWu+lWbJEErLg4gGq4D7+B3kP7SP3+QU6SBL/eVwqtgSiWUEjB84jlu73u9eqcsDJMfVF3WxnAaOQcNQJAY7vuQBUOY/ruvJfPapA88bukYvbYEs8wniVR0bBDtaN8QItmzTovbm+h39USPzGJWQmqF/8i6y/3qTPbEpbkpwJAWzrH87snWU+EloHSEwD27ENAbhZXokt5WgJWq+ytFrN4MlTxa75aSIXWyD/BIE7xpYH7MzXNwz6b5JYrNuwLnQJBAIChHs1sxLfp0HPKnPtMEJDmYlRmM176HKywg7q77yyij2K/90ijjgSG8YrXkeLrDBieCbMdxuruevZ+yBQPhr4=");
    byte[] publicKeyBytes = Convert.FromBase64String("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8IG4CySTEOZhmDwlTdR4Yd6xoqoJGsfze/RvrZgY72HAuWK0Y3DKrNdFiM+Z2O1weArCyoTbGsZ7UcxhCFKQLSsHooZveQTTHDHvm7cIts8jEMDw/xbPDrMQH/vYjRshNo8vOsVwxQELVzvrMA7+A/3ITKvbL0PTSDxxMcHRQDwIDAQAB");


    // Create an RSA object with the public and private keys
    var rsa = new RSACryptoServiceProvider();
    rsa.ImportParameters(new RSAParameters
    {
        Modulus = publicKeyBytes,
        Exponent = new byte[] { 1, 0, 1 },
        D = privateKeyBytes
    });

    string userInfo = info.ToString();

    byte[] userInfoBytes = Encoding.UTF8.GetBytes(userInfo);

    // Sign the user information using the private key
    byte[] signature = rsa.SignData(userInfoBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);  //  Exception thrown here : Keyset does not exist

    // Convert the signature to a string for distribution to the user as the license key
    return Convert.ToBase64String(signature);
}


public static bool VerifyLicenseFromUserInfo(string receivedLicenseKey, UserLicense info)  //  To Verify license is for this user
{

    byte[] publicKeyBytes = Convert.FromBase64String("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8IG4CySTEOZhmDwlTdR4Yd6xoqoJGsfze/RvrZgY72HAuWK0Y3DKrNdFiM+Z2O1weArCyoTbGsZ7UcxhCFKQLSsHooZveQTTHDHvm7cIts8jEMDw/xbPDrMQH/vYjRshNo8vOsVwxQELVzvrMA7+A/3ITKvbL0PTSDxxMcHRQDwIDAQAB");

    // Convert the public key from bytes to an RSA object
    var rsa = new RSACryptoServiceProvider();
    rsa.ImportParameters(new RSAParameters
    {
        Modulus = publicKeyBytes,
        Exponent = new byte[] { 1, 0, 1 }
    });

    string userInfo = info.ToString();

    byte[] userInfoBytes = Encoding.UTF8.GetBytes(userInfo);


    // Convert the license key back to a byte array
    byte[] receivedSignature = Convert.FromBase64String(receivedLicenseKey);

    // Verify the license key using the public key
    return rsa.VerifyData(userInfoBytes, receivedSignature, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);
}

When I run the program, when using the GenerateLicenseFromUserInfo function, I get the following:

System.Security.Cryptography.CryptographicException: 'Keyset does not exist'

in the SignData function in GenerateLicenseFromUserInfo

I think my problem is converting my private and public keys to RSAParameters but I couldn't find a way to do it.

Hasan H
  • 142
  • 11
  • You've posted code, but not told us exactly what happens. ("Keyset does not exist" is not a very precise description.) Is this a compile-time error? If so, on which line, and what's the error? Is it an exception? If so, please show a stack trace. – Jon Skeet Apr 12 '23 at 10:02
  • `privateKeyBytes` is not simply the private exponent, but the private key in PKCS#1 format (Base64, DER encoded). Neither is `publicKeyBytes` the modulus, but the public key in X.509/SPKI format (Base64, DER encoded). How such keys are imported depends on the .NET version, which you did not specify. – Topaco Apr 12 '23 at 10:20
  • 1
    .NET Framework has little support for importing PEM/DER encoded keys. The most convenient way to import is with C#/BouncyCastle. There are many posts describing this in detail, e.g. [here](https://stackoverflow.com/a/46598020/9014097). – Topaco Apr 12 '23 at 10:50
  • The public key is generated from the private key. You need the private key to verify as well as the public key. The private key is never sent with the data, The private key is installed before the data is sent on both the sending code and receiving code. – jdweng Apr 12 '23 at 11:51
  • @jdweng If I need the private key to verify, then what's the purpose of having a public and private one. Shouldn't I use the public key only for verification to prevent generating license keys by anyone – Hasan H Apr 12 '23 at 11:55
  • The are different encryption algorithms. Some have only one key and others two keys. RSA has two keys and is more secure than algorithms with one key. Most companies when distributing use for the Private key something in hardware like the MAC address of the ethernet card so the license can only be used on one machine. When you have a license server there is a service running on one machine that checks in/out the licenses and the service is setup to run on one machine with a private key. – jdweng Apr 12 '23 at 12:07
  • @jdweng yes in my case I want to create a license according to the MAC address and Serial number of the user's hardware. This is what the UserLicense struct in my code is. So I want to use the two-key process in order to have private key at my side to generate license, and public key in the application to do the verification. What's the best option for this? – Hasan H Apr 12 '23 at 12:11
  • You need the same seed in to the encryption algorithm when you generate the public key on both the create end and the verify end. So when you create the public key you ask for the serial number and MAC. Then in code that verifies you also need to obtain from the hardware the MAC and serial number. Most places they add code to modify the seed so it is not just a simple combining of the MAC and serial number to create the seed. The private key is obtained from the seed. The public key is obtained from the private key. – jdweng Apr 12 '23 at 12:25
  • @jdweng I'm not sure if I quite understood your point. My idea of this is to have a static private and public RSA keys. Then using these keys and the user info, I will generate a license key. On the verification app, which already has the same public key, I would receive the license key, use the public key and the user info to verify the data – Hasan H Apr 12 '23 at 13:18
  • The keys work similar to Random in Net. The Random constructor has a constructor with no parameters that uses the time for the seed to the number generator, and constructor with a int which always gives the same sequence. A private key is not a string, It has a constructor with a string input. In your case it is the MAC and serial number. Your code when deployed has to call this constructor to make sure only the one deploy machine will be used to run your code. – jdweng Apr 12 '23 at 17:11

0 Answers0