OpenNETCF Cryptography questions - using RSA for licensing strategy

  • Thread starter Thread starter gcrasher
  • Start date Start date
G

gcrasher

I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

gcrasher said:
I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
I've never done any encryption so am interested to know where you get the
private keys. Do people generate their own keys or are they bought. Is
there a licensing issue with using the RSA algorithm or just in purchasing
keys or neither? Also, is their a standard length of key?

Thanks,

Steven

casey chesnut said:
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

gcrasher said:
I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
public and private keys are just long numbers,
so you generate them with the CryptoAPI
(these are not certificates, which do cost money).
MS has already taken care of the licensing issues with the CryptoAPI.
the RSA key lengths can vary,
for small devices with limited CPU keep the length as small as possible
(1024),
and i think anything over 4096 might have some export problems?

Thanks,
casey
http://www.brains-N-brawn.com


Steven Licciardi said:
I've never done any encryption so am interested to know where you get the
private keys. Do people generate their own keys or are they bought. Is
there a licensing issue with using the RSA algorithm or just in purchasing
keys or neither? Also, is their a standard length of key?

Thanks,

Steven

casey chesnut said:
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

gcrasher said:
I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
I was under the impression that RSA uses prime numbers for the private keys,
in which case I think generating 1024 character keys would be very difficult
and take a very long time to generate (days-weeks-months-years), is this not
the case?

Thanks,

Steven

casey chesnut said:
public and private keys are just long numbers,
so you generate them with the CryptoAPI
(these are not certificates, which do cost money).
MS has already taken care of the licensing issues with the CryptoAPI.
the RSA key lengths can vary,
for small devices with limited CPU keep the length as small as possible
(1024),
and i think anything over 4096 might have some export problems?

Thanks,
casey
http://www.brains-N-brawn.com


Steven Licciardi said:
I've never done any encryption so am interested to know where you get the
private keys. Do people generate their own keys or are they bought. Is
there a licensing issue with using the RSA algorithm or just in
purchasing keys or neither? Also, is their a standard length of key?

Thanks,

Steven

casey chesnut said:
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
that is in bits (not characters).
the CryptoAPI on some CE devices will support 16K bit key sizes ...
but it would take a LONG time to create one.
casey

Steven Licciardi said:
I was under the impression that RSA uses prime numbers for the private
keys, in which case I think generating 1024 character keys would be very
difficult and take a very long time to generate (days-weeks-months-years),
is this not the case?

Thanks,

Steven

casey chesnut said:
public and private keys are just long numbers,
so you generate them with the CryptoAPI
(these are not certificates, which do cost money).
MS has already taken care of the licensing issues with the CryptoAPI.
the RSA key lengths can vary,
for small devices with limited CPU keep the length as small as possible
(1024),
and i think anything over 4096 might have some export problems?

Thanks,
casey
http://www.brains-N-brawn.com


Steven Licciardi said:
I've never done any encryption so am interested to know where you get
the private keys. Do people generate their own keys or are they bought.
Is there a licensing issue with using the RSA algorithm or just in
purchasing keys or neither? Also, is their a standard length of key?

Thanks,

Steven

message the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the desktop
and encrypt a message using the private key. Why can't the device now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


casey chesnut said:
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

gcrasher said:
I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
According to this article :

http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001369

RSA is an asymmetric encryption algorithm and so it is required that you
encrypt with the public key and decrypt with the private key (that's just
how the equation works, if you use the private key to encrypt then you are
effectively making it the public key, in which case you need a different
private key to decrypt, which is not the original public key, hmmmm, at
least that is how I understand it). Sounds to me that you require a
symmetric algorithm such as the ones mentioned in the article.

Steven

gcrasher said:
Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the desktop
and encrypt a message using the private key. Why can't the device now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


casey chesnut said:
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

gcrasher said:
I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
I think it can work because the code I have works plus this is how
digital signatures work, its just that I'm trying to encrypt the
arbitrary data myself instead of using XML.

I don't want anyone to have the ability to encrypt, only decrypt. This
way, if it can be decrypted to meaninful data, then it is guaranteed
that I am the sender.


Steven Licciardi said:
According to this article :

http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001369

RSA is an asymmetric encryption algorithm and so it is required that you
encrypt with the public key and decrypt with the private key (that's just
how the equation works, if you use the private key to encrypt then you are
effectively making it the public key, in which case you need a different
private key to decrypt, which is not the original public key, hmmmm, at
least that is how I understand it). Sounds to me that you require a
symmetric algorithm such as the ones mentioned in the article.

Steven

gcrasher said:
Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the desktop
and encrypt a message using the private key. Why can't the device now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


casey chesnut said:
the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which the
hardware ID is sent to me, encrypted, and sent back to be decrypted on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device using
OpenNETCF classes and I'm guessing that is part of my problem. Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key is
stored somehow and even though I am specifying my own public key, the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
hmm, i have not tried encrypting with a private key and decrypting with a
public key.
nor am i sure it will work. does that work on the desktop?
i have tested encrypting with a public key, and decrypting with private.

usually verification is done with an RSA signature
(RSA can be used to encrypt and sign, DSA can only sign)
in that manner you could sign on the server side,
send the signature to the device,
and the device could verify the signature.
the RSACryptoServiceProvider class has methods for signing as well,
and they have been tested.
for signing, you sign with the private, and verify with the public.

Thanks,
casey
http://www.brains-N-brawn.com


gcrasher said:
I think it can work because the code I have works plus this is how
digital signatures work, its just that I'm trying to encrypt the
arbitrary data myself instead of using XML.

I don't want anyone to have the ability to encrypt, only decrypt. This
way, if it can be decrypted to meaninful data, then it is guaranteed
that I am the sender.


Steven Licciardi said:
According to this article :

http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001369

RSA is an asymmetric encryption algorithm and so it is required that you
encrypt with the public key and decrypt with the private key (that's just
how the equation works, if you use the private key to encrypt then you
are
effectively making it the public key, in which case you need a different
private key to decrypt, which is not the original public key, hmmmm, at
least that is how I understand it). Sounds to me that you require a
symmetric algorithm such as the ones mentioned in the article.

Steven

gcrasher said:
Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the desktop
and encrypt a message using the private key. Why can't the device now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


message the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which
the
hardware ID is sent to me, encrypted, and sent back to be decrypted
on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes
and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device
using
OpenNETCF classes and I'm guessing that is part of my problem.
Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device
so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys
the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key
is
stored somehow and even though I am specifying my own public key,
the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the
keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way
I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
I think I'm just going to have to look into using the digital
signatures.

Yes, the code that I posted encrypts with private and the device can
decrypt with public. Problem is if new keys are created on the device,
the old ones no longer work even if you try to specify your own key.

RSA signature is really what I want I guess.

casey chesnut said:
hmm, i have not tried encrypting with a private key and decrypting with a
public key.
nor am i sure it will work. does that work on the desktop?
i have tested encrypting with a public key, and decrypting with private.

usually verification is done with an RSA signature
(RSA can be used to encrypt and sign, DSA can only sign)
in that manner you could sign on the server side,
send the signature to the device,
and the device could verify the signature.
the RSACryptoServiceProvider class has methods for signing as well,
and they have been tested.
for signing, you sign with the private, and verify with the public.

Thanks,
casey
http://www.brains-N-brawn.com


gcrasher said:
I think it can work because the code I have works plus this is how
digital signatures work, its just that I'm trying to encrypt the
arbitrary data myself instead of using XML.

I don't want anyone to have the ability to encrypt, only decrypt. This
way, if it can be decrypted to meaninful data, then it is guaranteed
that I am the sender.


Steven Licciardi said:
According to this article :

http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001369

RSA is an asymmetric encryption algorithm and so it is required that you
encrypt with the public key and decrypt with the private key (that's just
how the equation works, if you use the private key to encrypt then you
are
effectively making it the public key, in which case you need a different
private key to decrypt, which is not the original public key, hmmmm, at
least that is how I understand it). Sounds to me that you require a
symmetric algorithm such as the ones mentioned in the article.

Steven

Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the desktop
and encrypt a message using the private key. Why can't the device now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


message the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in which
the
hardware ID is sent to me, encrypted, and sent back to be decrypted
on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key, and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography classes
and
System.Security.Cryptography classes on the desktop (for my license
creation utility).

I'm not understanding how the key containers work on the device
using
OpenNETCF classes and I'm guessing that is part of my problem.
Unless
I create the public/private keys on the device, I get a NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the device
so
I can attempt to provide my own public key), the old public key no
longer decrypts the old data it used to decrypt. If I use the keys
the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public key
is
stored somehow and even though I am specifying my own public key,
the
OpenNETCF classes somehow are utilizing or checking that container
(maybe?). This decryption will need to occur on devices where the
keys
were not generated. How is it possible for me to provide the public
key myself? Anyone have any ideas how I can get this working the way
I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
Hello,

I'm still getting to grips with the encryption stuff, so I am a little
confused over the code you posted. In your example you do the following to
create a text file :

sw.Write(rsa.ToXmlString(true)); //file called privatekey.txt

On the desktop and using the OpenNETCF stuff rsa.ToXmlString(true) will
write all the key information to file (private key, public key, inverses,
DPs and primes) not JUST the private key.

So when you do this later on to encrypt the data :

rsa.FromXmlString(privateKeyString);
// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);
// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);


Why would this encryption use the private key for encryption, when the text
file contained all the key information, not just the private key
information? i.e. How does rsa.encrypt know you wanted to use the private
key for the encryption?

Any advice appreciated,

Steven

gcrasher said:
I think I'm just going to have to look into using the digital
signatures.

Yes, the code that I posted encrypts with private and the device can
decrypt with public. Problem is if new keys are created on the device,
the old ones no longer work even if you try to specify your own key.

RSA signature is really what I want I guess.

casey chesnut said:
hmm, i have not tried encrypting with a private key and decrypting with a
public key.
nor am i sure it will work. does that work on the desktop?
i have tested encrypting with a public key, and decrypting with private.

usually verification is done with an RSA signature
(RSA can be used to encrypt and sign, DSA can only sign)
in that manner you could sign on the server side,
send the signature to the device,
and the device could verify the signature.
the RSACryptoServiceProvider class has methods for signing as well,
and they have been tested.
for signing, you sign with the private, and verify with the public.

Thanks,
casey
http://www.brains-N-brawn.com


gcrasher said:
I think it can work because the code I have works plus this is how
digital signatures work, its just that I'm trying to encrypt the
arbitrary data myself instead of using XML.

I don't want anyone to have the ability to encrypt, only decrypt. This
way, if it can be decrypted to meaninful data, then it is guaranteed
that I am the sender.


message According to this article :

http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001369

RSA is an asymmetric encryption algorithm and so it is required that
you
encrypt with the public key and decrypt with the private key (that's
just
how the equation works, if you use the private key to encrypt then you
are
effectively making it the public key, in which case you need a
different
private key to decrypt, which is not the original public key, hmmmm,
at
least that is how I understand it). Sounds to me that you require a
symmetric algorithm such as the ones mentioned in the article.

Steven

Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the
desktop
and encrypt a message using the private key. Why can't the device
now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


message the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out
outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't
understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in
which
the
hardware ID is sent to me, encrypted, and sent back to be
decrypted
on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key,
and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography
classes
and
System.Security.Cryptography classes on the desktop (for my
license
creation utility).

I'm not understanding how the key containers work on the device
using
OpenNETCF classes and I'm guessing that is part of my problem.
Unless
I create the public/private keys on the device, I get a
NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the
device
so
I can attempt to provide my own public key), the old public key
no
longer decrypts the old data it used to decrypt. If I use the
keys
the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public
key
is
stored somehow and even though I am specifying my own public key,
the
OpenNETCF classes somehow are utilizing or checking that
container
(maybe?). This decryption will need to occur on devices where the
keys
were not generated. How is it possible for me to provide the
public
key myself? Anyone have any ideas how I can get this working the
way
I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
From what I've learned, those libraries do not work the way I was trying to
use them. I was getting a bad key error when trying to decrypt using the
public key but from what I understand that is because decryption uses the
private key only, and encryption uses the public key. So even though I was
trying to pass it the private key and encrypt, it was actually using the
public key. And to decrypt it was looking for a private key.

So what I was really trying to accomplish was message verification. Using
the SignData and VerifyData method, I was able to first create a signature,
which is basically a message hash encrypted using a private key, then check
it with bool VerifyData(), which unencrypts the signature using the public
key and verifies the hash value against the message.


Steven Licciardi said:
Hello,

I'm still getting to grips with the encryption stuff, so I am a little
confused over the code you posted. In your example you do the following to
create a text file :

sw.Write(rsa.ToXmlString(true)); //file called privatekey.txt

On the desktop and using the OpenNETCF stuff rsa.ToXmlString(true) will
write all the key information to file (private key, public key, inverses,
DPs and primes) not JUST the private key.

So when you do this later on to encrypt the data :

rsa.FromXmlString(privateKeyString);
// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);
// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);


Why would this encryption use the private key for encryption, when the text
file contained all the key information, not just the private key
information? i.e. How does rsa.encrypt know you wanted to use the private
key for the encryption?

Any advice appreciated,

Steven

gcrasher said:
I think I'm just going to have to look into using the digital
signatures.

Yes, the code that I posted encrypts with private and the device can
decrypt with public. Problem is if new keys are created on the device,
the old ones no longer work even if you try to specify your own key.

RSA signature is really what I want I guess.

casey chesnut said:
hmm, i have not tried encrypting with a private key and decrypting with a
public key.
nor am i sure it will work. does that work on the desktop?
i have tested encrypting with a public key, and decrypting with private.

usually verification is done with an RSA signature
(RSA can be used to encrypt and sign, DSA can only sign)
in that manner you could sign on the server side,
send the signature to the device,
and the device could verify the signature.
the RSACryptoServiceProvider class has methods for signing as well,
and they have been tested.
for signing, you sign with the private, and verify with the public.

Thanks,
casey
http://www.brains-N-brawn.com


I think it can work because the code I have works plus this is how
digital signatures work, its just that I'm trying to encrypt the
arbitrary data myself instead of using XML.

I don't want anyone to have the ability to encrypt, only decrypt. This
way, if it can be decrypted to meaninful data, then it is guaranteed
that I am the sender.


message According to this article :

http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28001369

RSA is an asymmetric encryption algorithm and so it is required that
you
encrypt with the public key and decrypt with the private key (that's
just
how the equation works, if you use the private key to encrypt then you
are
effectively making it the public key, in which case you need a
different
private key to decrypt, which is not the original public key, hmmmm,
at
least that is how I understand it). Sounds to me that you require a
symmetric algorithm such as the ones mentioned in the article.

Steven

Thanks for your quick response.

Maybe I confused things by saying I was creating the keypair on the
device. I thought it shouldn't matter, but really the desktop is the
sender of the message so lets say I create the keypair on the
desktop
and encrypt a message using the private key. Why can't the device
now
decrypt this message with knowledge of the public key only? This is
what I can't understand or get to work.

Also remember I am not trying to hide data, only verify the sender.
Thats why I need to encrypt with a private key and decrypt with a
public key.


message the public / private keys are stored on the device.
the CryptoAPI does this ... on the desktop too.
they are named rSaContainer and rSaContainerImp,
depending if it is for the devices key pair or being imported
respectively.
the code is in RSACryptoServiceProvider.cs

the following code worked for me.
it creates the private key on the device,
passes the private key and plainText to a WS.
the WS loads the private key and encrypts,
then returns the cipherText and public key.
device loads public key and decrypts.

/// DEVICE CODE /////////
//create key pair on device
RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(KeySpec.KEYEXCHANGE, true);
string privKey = rsa.ToXmlString(true);
string pubKey = rsa.ToXmlString(false);

string strData = "text for server to encrypt";
byte [] baData = Format.GetBytes(strData);

//call web service on device to encrypt
CryptoServ.Crypto cServ = new CryptoServ.Crypto();
cServ.Url = csUrl;

string outPubKey;
string retCipher = cServ.AsymRsaDec(strData, privKey, out
outPubKey);
byte [] outCipher = Format.GetB64(retCipher);

//decrypt on device
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.FromXmlString(outPubKey);
byte [] baUnEnc = rsa2.DecryptValue(outCipher);
Format.SameBytes(baData, baUnEnc);

MessageBox.Show("success");

/// WEB SERVICE CODE ON DESKTOP ///////
[WebMethod]
public string AsymRsaDec(string plain, string privKey, out string
outPubKey)
{
byte[] _plain = GetBytes(plain);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privKey);
byte[] ciphertext = rsa.Encrypt(_plain, false);
outPubKey = rsa.ToXmlString(false);
return GetBase64(ciphertext);
}

casey

I've been trying to figure this out for a while and don't
understand
what's going on.

I'm using RSA algorithm to implement a licensing strategy in
which
the
hardware ID is sent to me, encrypted, and sent back to be
decrypted
on
the device, thus verifying that I actually created the data. This
requires encrypting on the desktop using my secure private key,
and
unencrypting on the device using a public key.

For the device I'm using the OpenNET.Security.Cryptography
classes
and
System.Security.Cryptography classes on the desktop (for my
license
creation utility).

I'm not understanding how the key containers work on the device
using
OpenNETCF classes and I'm guessing that is part of my problem.
Unless
I create the public/private keys on the device, I get a
NTE_BAD_KEY
error when trying to decrypt on the device. When a new key set is
generated on the device (not to be used, just to *reset* the
device
so
I can attempt to provide my own public key), the old public key
no
longer decrypts the old data it used to decrypt. If I use the
keys
the
device last generated then my code works fine.

It seems that when creating the keys on the device, the public
key
is
stored somehow and even though I am specifying my own public key,
the
OpenNETCF classes somehow are utilizing or checking that
container
(maybe?). This decryption will need to occur on devices where the
keys
were not generated. How is it possible for me to provide the
public
key myself? Anyone have any ideas how I can get this working the
way
I
need to?

Thanks!


I've included the code being used below:

--------------------------------------
---Create key pair using the device---
--------------------------------------

using OpenNET.Security.Cryptography;

RSACryptoServiceProvider rsa = new
RSACryptoServiceProvider(OpenNETCF.Security.Cryptography.NativeMethods.KeySpec.KEYEXCHANGE,
true);

// Save the public key to pubkey.txt
FileStream fs = new FileStream("pubkey.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(false));

// Save the private key to privkey.txt
fs = new FileStream("privkey.txt", FileMode.Create);
sw = new StreamWriter(fs);
sw.Write(rsa.ToXmlString(true));

---------------------------------
---Encrypt data on the desktop---
---------------------------------

using System.Security.Cryptography;

string plain = "Text to be encrypted.";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

// Get the XML string from the privkey.txt file
FileStream fs = new FileStream("privkey.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string privateKeyString = sr.ReadToEnd();

// Load private key
rsa.FromXmlString(privateKeyString);

// convert the plaintext to a byte array using UTF-8
UTF8Encoding utf8 = new UTF8Encoding();
byte[] plaintext = utf8.GetBytes(plain);

// Encrypt the plaintext
byte[] ciphertext = rsa.Encrypt(plaintext, false);

// Create encrypted output file.
FileStream ciphertextfile = new FileStream(outputFile,
FileMode.Create);
ciphertextfile.Write(ciphertext, 0, ciphertext.Length);


-----------------------------------
---Decrypt data using the device---
-----------------------------------

using OpenNET.Security.Cryptography;

string publicKey =
<RSAKeyValue><Modulus>qe9vUaTreNvSRynh36T4b74VRqdCOEHhX1xrkdmrwkRBs5yhRBAD+BM2yB5kL7aA
BLvW+biQAZCfVDnh3wIMUuzd9pwYaU8FtL8pnq7EEu6ps3a5C7M63fZTj1slFSiTMiGY6rCMOCajSFeOEULMPF
Ukj5wJ8WBjWWtRU1HYt/U=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
UTF8Encoding utf8 = new UTF8Encoding();

// Read encrypted file.
byte[] encryptedBytes = Utility.ReadFile(encryptedFileName);

// Set public key.
rsa.FromXmlString(publicKey);

// Decrypt bytes.
string unencryptedString = new
String(utf8.GetChars(rsa.DecryptValue(encryptedBytes)));
 
Back
Top