Problems with public key decryption with RSA

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
You need to use MACHINE_KEYSET (in CryptAcquireContext)

Laszlo Elteto
SafeNet, Inc.

pike said:
I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
Thanks Laszlo.

However I think my initial posting was misleading because of my lack of
knowledge on the Cryptography subject. The Key containers were just
complicating the matter and were a "red herring", as was the Windows Service.

A weekends worth of research has told me that I cannot encrypt data with the
Private Key and decrypt with the Public Key with Microsofts implementation of
RSA (RSACryptoServiceProvider).

So my question now is do I redesign what I haven written to incorporate the
customers requirements, which are, "to be able to receive encrypted (&
signed) data packages where I can also verify they have come from a specific
sender." or do I try to find another implementation of RSA?

A possible solution I have thought of is to :-
Create a signed hash for the "data to encrypt" with a RSA Private Key
Encrypt the data symmetrically
Encrypt the symmetric key with a fixed symmetric key known to sender/recipient

Then the client would know that the package had come from that specific
sender (from the signature) and would be able to decrypt the data
symmetrically once it had decrypted the key (with the fixed key). This
solution is not as secure as my initial one but may be workable?

Are there any other implementations of the RSA that I could use with .NET
out there or does someone have a suggestion for me please?

Hope someone out there can help!

Best Regards,
Pike

lelteto said:
You need to use MACHINE_KEYSET (in CryptAcquireContext)

Laszlo Elteto
SafeNet, Inc.

pike said:
I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
Certainly your solution is not secure as now both sides need to pre-share a
secret. (If you solve that problem you may be OK; some systems use
pre-arranged keys loaded into crypto modules on both sides and it can be very
secure)
The 'normal' way - and that's certainly supported by MS CAPI as well as all
other crypto libraries - is that
1. You have two separate key pairs: one for encryption and one for signing.
The sender has a signing private key and the receiver's public key; the
receiver has the encryption private key and the sender's signing public key.
2. The sender hashes the data / document and signs it with the signing
private key
3. The sender generates a random symmetric session key
4. The sender encrypts the data / document with the session key
5. The sender encrypts the session key with the receiver's PUBLIC key
6. The sender sends the signature (from 2), the encrypted data (from 4) and
encrypted session key (from 5) to the receiver
7. The receiver decrypts the session key (from 5) with its private key
8. The receiver decrypts the data / document with the recovered session key
9. The receiver verifies the signature on the decrypted document using the
sender's public key

Laszlo Elteto
SafeNet, Inc.

pike said:
Thanks Laszlo.

However I think my initial posting was misleading because of my lack of
knowledge on the Cryptography subject. The Key containers were just
complicating the matter and were a "red herring", as was the Windows Service.

A weekends worth of research has told me that I cannot encrypt data with the
Private Key and decrypt with the Public Key with Microsofts implementation of
RSA (RSACryptoServiceProvider).

So my question now is do I redesign what I haven written to incorporate the
customers requirements, which are, "to be able to receive encrypted (&
signed) data packages where I can also verify they have come from a specific
sender." or do I try to find another implementation of RSA?

A possible solution I have thought of is to :-
Create a signed hash for the "data to encrypt" with a RSA Private Key
Encrypt the data symmetrically
Encrypt the symmetric key with a fixed symmetric key known to sender/recipient

Then the client would know that the package had come from that specific
sender (from the signature) and would be able to decrypt the data
symmetrically once it had decrypted the key (with the fixed key). This
solution is not as secure as my initial one but may be workable?

Are there any other implementations of the RSA that I could use with .NET
out there or does someone have a suggestion for me please?

Hope someone out there can help!

Best Regards,
Pike

lelteto said:
You need to use MACHINE_KEYSET (in CryptAcquireContext)

Laszlo Elteto
SafeNet, Inc.

pike said:
I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
Thanks for the explanation, Laszlo.

Unfortunately, the customer does not wish to have 'private' keys on the
receiving machines, therefore I will use pre-arranged keys pre-loaded into
the crypto modules (as you suggested) to do the encrypting.

My final solution is, for encrypting :-
Encrypt the data symmetrically with random key
Encrypt the key / IV with fixed (pre-loaded) key
Package as byte array
Digitally sign hash (with Private key) on package and send to receiver

Best Regards,
Pike

lelteto said:
Certainly your solution is not secure as now both sides need to pre-share a
secret. (If you solve that problem you may be OK; some systems use
pre-arranged keys loaded into crypto modules on both sides and it can be very
secure)
The 'normal' way - and that's certainly supported by MS CAPI as well as all
other crypto libraries - is that
1. You have two separate key pairs: one for encryption and one for signing.
The sender has a signing private key and the receiver's public key; the
receiver has the encryption private key and the sender's signing public key.
2. The sender hashes the data / document and signs it with the signing
private key
3. The sender generates a random symmetric session key
4. The sender encrypts the data / document with the session key
5. The sender encrypts the session key with the receiver's PUBLIC key
6. The sender sends the signature (from 2), the encrypted data (from 4) and
encrypted session key (from 5) to the receiver
7. The receiver decrypts the session key (from 5) with its private key
8. The receiver decrypts the data / document with the recovered session key
9. The receiver verifies the signature on the decrypted document using the
sender's public key

Laszlo Elteto
SafeNet, Inc.

pike said:
Thanks Laszlo.

However I think my initial posting was misleading because of my lack of
knowledge on the Cryptography subject. The Key containers were just
complicating the matter and were a "red herring", as was the Windows Service.

A weekends worth of research has told me that I cannot encrypt data with the
Private Key and decrypt with the Public Key with Microsofts implementation of
RSA (RSACryptoServiceProvider).

So my question now is do I redesign what I haven written to incorporate the
customers requirements, which are, "to be able to receive encrypted (&
signed) data packages where I can also verify they have come from a specific
sender." or do I try to find another implementation of RSA?

A possible solution I have thought of is to :-
Create a signed hash for the "data to encrypt" with a RSA Private Key
Encrypt the data symmetrically
Encrypt the symmetric key with a fixed symmetric key known to sender/recipient

Then the client would know that the package had come from that specific
sender (from the signature) and would be able to decrypt the data
symmetrically once it had decrypted the key (with the fixed key). This
solution is not as secure as my initial one but may be workable?

Are there any other implementations of the RSA that I could use with .NET
out there or does someone have a suggestion for me please?

Hope someone out there can help!

Best Regards,
Pike

lelteto said:
You need to use MACHINE_KEYSET (in CryptAcquireContext)

Laszlo Elteto
SafeNet, Inc.

:

I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
Hi Pike,

Just to add some information, you can encrypt/decrypt with both keys using
..NET RSA implementation. See the code at
http://www.eggheadcafe.com/articles/20020630.asp. On the lines

Dim publicKey as String = RSA.ToXmlString(False) ' gets the public key
Dim privateKey as String = RSA.ToXmlString(True) ' gets the private key

if you exchange "True" and "False", you reverse the encyption and decription
keys. I had the "Bad key" problem too, but it was solved by the code on the
url above (I was creating a RSACryptoServiceProvider instance but not passing
any CspParameters on the constructor, and - God knows why - the decryption
operation generated the "bad key" error).

I'll be using that on a web service, and I'm expecting the bad key error
will happen again, just like in your case. If that happens, my next try will
be to run the class inside Component Services, with an identity set to some
domain user I'll create. We had a few problems here with encryption and the
key store, generally being related to the fact tha ASP.NET does not load a
user profile. If you look at "How To: Use DPAPI (User Store) from ASP.NET
with Enterprise Services"
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT08.asp),
it is the solution MS gives to a similar problem. I know it's kind of a shot
in the dark, but I'm close to a deadline too and unfortunately without time
to do some decent researching.

Hope it helps,

GB

pike said:
I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
Ops,

The code sample I refered to has a gotcha: both instances of
RSACryptoSerivceProvider are created *with the same CspParameters object*. If
you create them with different CspParameters instances, even if the
CspParameters flag has been set the same, the code fails with the bad key
error.

Since in my solution the encryption will be done on the client and the
decryption on the web service, the problem now is sharing the CspParameters
object.

Don't miss the next chapter of the saga "RSA doesn't love me" :)

PS: Since both the encryption and decryption were sharing some information,
I don't really know if it's possible to encrypt and decrypt with both keys,
or if my test was ok only because the shared CspParameters object....

GB said:
Hi Pike,

Just to add some information, you can encrypt/decrypt with both keys using
.NET RSA implementation. See the code at
http://www.eggheadcafe.com/articles/20020630.asp. On the lines

Dim publicKey as String = RSA.ToXmlString(False) ' gets the public key
Dim privateKey as String = RSA.ToXmlString(True) ' gets the private key

if you exchange "True" and "False", you reverse the encyption and decription
keys. I had the "Bad key" problem too, but it was solved by the code on the
url above (I was creating a RSACryptoServiceProvider instance but not passing
any CspParameters on the constructor, and - God knows why - the decryption
operation generated the "bad key" error).

I'll be using that on a web service, and I'm expecting the bad key error
will happen again, just like in your case. If that happens, my next try will
be to run the class inside Component Services, with an identity set to some
domain user I'll create. We had a few problems here with encryption and the
key store, generally being related to the fact tha ASP.NET does not load a
user profile. If you look at "How To: Use DPAPI (User Store) from ASP.NET
with Enterprise Services"
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT08.asp),
it is the solution MS gives to a similar problem. I know it's kind of a shot
in the dark, but I'm close to a deadline too and unfortunately without time
to do some decent researching.

Hope it helps,

GB

pike said:
I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
Hi GB

I suspect it will be because it is the same CspParameters object,
unfortunately!

It just is not possible (technically) to encrypt data with a private key and
decrypt with a public key using Microsofts RSA cryptography. The digital
signing however, works fine (but generally isn't as desired as the
encryption)...

If it's any consolation RSA's no friend of mine either! ;-)

Pike

GB said:
Ops,

The code sample I refered to has a gotcha: both instances of
RSACryptoSerivceProvider are created *with the same CspParameters object*. If
you create them with different CspParameters instances, even if the
CspParameters flag has been set the same, the code fails with the bad key
error.

Since in my solution the encryption will be done on the client and the
decryption on the web service, the problem now is sharing the CspParameters
object.

Don't miss the next chapter of the saga "RSA doesn't love me" :)

PS: Since both the encryption and decryption were sharing some information,
I don't really know if it's possible to encrypt and decrypt with both keys,
or if my test was ok only because the shared CspParameters object....

GB said:
Hi Pike,

Just to add some information, you can encrypt/decrypt with both keys using
.NET RSA implementation. See the code at
http://www.eggheadcafe.com/articles/20020630.asp. On the lines

Dim publicKey as String = RSA.ToXmlString(False) ' gets the public key
Dim privateKey as String = RSA.ToXmlString(True) ' gets the private key

if you exchange "True" and "False", you reverse the encyption and decription
keys. I had the "Bad key" problem too, but it was solved by the code on the
url above (I was creating a RSACryptoServiceProvider instance but not passing
any CspParameters on the constructor, and - God knows why - the decryption
operation generated the "bad key" error).

I'll be using that on a web service, and I'm expecting the bad key error
will happen again, just like in your case. If that happens, my next try will
be to run the class inside Component Services, with an identity set to some
domain user I'll create. We had a few problems here with encryption and the
key store, generally being related to the fact tha ASP.NET does not load a
user profile. If you look at "How To: Use DPAPI (User Store) from ASP.NET
with Enterprise Services"
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT08.asp),
it is the solution MS gives to a similar problem. I know it's kind of a shot
in the dark, but I'm close to a deadline too and unfortunately without time
to do some decent researching.

Hope it helps,

GB

pike said:
I have created an encryption class whose main encryption method encrypts
small amounts of bytes (in this case the Key & IV for Rijndael encryption of
main data) using .NET's RSA methods.

This had all been working fine until I tried using the class within a
"Windows Service" application. The application fails on a Decrypt with a "bad
key" error in the "Windows Service" but runs fine (with same key & encrypted
data) in a normal windows application.

The main sections of code from within my class are the following:-

I generate my Public / Private keys in a function like this:-

// Create RSA Crypto object
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();

// get public & private key xml
sPublicKeyXml = rsaCSP.ToXmlString(false);
sPrivateKeyXml = rsaCSP.ToXmlString(true);


I encrypt like this:-

// encrypt symmetric key
// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// encrypt byte[] using asymmetric method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the private key
rsaCSP.FromXmlString(sPrivateKeyXml);
// encrypt using private key
byte[] byteEncrypted = rsaCSP.Encrypt(byteToEncrypt, false);


And I decrypt later like this:-


// Create CSPParameters required object
CspParameters cspParam = new CspParameters();
cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer;

// decrypt byte[] using method RSA
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cspParam);
// load the public key
rsaCSP.FromXmlString(sPublicKeyXml);

// decrypt using public key
byte[] byteDecrypt = rsaCSP.Decrypt(byteEncrypted, false);


I have tried running the Windows Service as Administrator but got the same
"bad key" error.

The stack trace here is
"System.Security.Cryptography.RSACryptoServiceProvider._DecryptPKWin2KEnh(IntPtr hPubKey, Byte[] rgbKey, Boolean fOAEP)"

I also tried :-

* changing the CspProviderFlags property to to "UseMachineKeyStore" and the
code doesn't work at all, even in the normal windows application running as
my user.

* Importing key using RSAParameters object - will not work encrypting with
private key / decrypting with public key - works other way round.

* Various combinations of setting up CspParameters - with KeyContainerName
set, Flags = UseMachineKeyStore, to no avail

My suspicion is that Key stores are somehow involved but with a deadline
looming I now require someone with more knowledge on the subject to help me!

Also, can you encrypt using the private key and decrypt using the public
key? The above code works like this, but the UseMachineStore solution would
only work encrypting with Public Key & decrypting with the Private Key.
Really, I need to be able to Encrypt with the Private Key.

The customer requirement is to be able to receive encrypted (& signed) data
packages where I can also verify they have come from a specific sender.

My solution is to encrypt the data with Rijndael encryption, encrypt the
Rijndael Key & IV with the RSA Private Key & package that up in one file. To
decrypt this use the public key to obtain the Rijndael Key & IV (and know who
that this can only have come from someone with the private key) & then
finally retrieve the data.

Sorry for such a long posting, and there are probably multiple issues here
but any help would be hugely appreciated!
 
My final solution is, for encrypting :-
Encrypt the data symmetrically with random key
Encrypt the key / IV with fixed (pre-loaded) key
Package as byte array
Digitally sign hash (with Private key) on package and send to receiver

The "pre-loaded" key should be the public key of the server in your signed
assembly and/or embedded in your code. Also above you would have an issue
with securing the "Private key" at the clients. So a better solution may
become:
1) Generate random symmetric key and iv.
2) Encrypt key / IV with public RSA key of server.
3) Encrypt data with symmetric key.
4) Sign hash and sign data elements with HMAC-SHA1 using symmetric key.
Note we use the HMAC-SHA1 to sign as we don't have a RSA private key. We
could however create one dynamically for the session and encrypt our public
xml string in the request using RSA public key of server. However, as we
need the new RSA key only for signing the request, we can avoid that and
just use a keyed hash like HMAC-SHA1. You could also encrypt the resulting
signature using the server's public RSA key - but don't think that is
required.

5) Server decrypts key / IV with it's private key.
6) Server verifies hash with HMAC-SHA1 using the key.
7) Server decrypts data with key / iv.
8) Server generates reply.
9) Server encrypts data with key / iv.
10) Server signs data elements with RSA private key.

11) Client verifies signature using RSA public key.
12) Client decrypts data and uses.

This does not require any prior stored private key on client's - only during
the session. This follows the SSL pattern where key exchange is done using
RSA pki first and after that symmetric encryption is used. You could also
modify to allow server to contribute to the entropy of the shared key, but
that would require a request/reply pair before you could use symmetric
encryption and I am not sure how much value that would as with above model
you still can get the shared key unless you brute force pki to discover it
using all combinations keys. For that reason, I would keep your shared key
as large as possible - say 64-100 bytes. Then both sides will use the sha1
hash of the 64 bytes or just the first 16-32 bytes for your AES crypto. You
may also want to include a Timestamp and/or msg ID on the requests to help
prevent reply attacks. Cheers!
 
Thanks Michel. I have been wanting to get public key from cert and this
article showed how. I made it a bit simplier here:

// Usage
string certFile = @"c:\mycert.cer";
X509Certificate cert = X509Certificate.CreateFromCertFile(certFile);
RSACryptoServiceProvider rsa = CertUtil.GetCertPublicKey(cert);
Console.WriteLine(rsa.ToXmlString(false));

/// CertUtil helper Class.
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

namespace WSESimpleTCPDLL
{
[StructLayout(LayoutKind.Sequential)]
public struct PUBKEYBLOBHEADERS
{
public byte bType; //BLOBHEADER
public byte bVersion; //BLOBHEADER
public short reserved; //BLOBHEADER
public uint aiKeyAlg; //BLOBHEADER
public uint magic; //RSAPUBKEY
public uint bitlen; //RSAPUBKEY
public uint pubexp; //RSAPUBKEY
}

/// <summary>
/// Summary description for CertUtil.
/// </summary>
public sealed class CertUtil
{
const uint CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000;
const uint CERT_STORE_READONLY_FLAG = 0x00008000;
const uint CERT_STORE_OPEN_EXISTING_FLAG = 0x00004000;
const uint CERT_FIND_SUBJECT_STR = 0x00080007;
const uint X509_ASN_ENCODING = 0x00000001;
const uint PKCS_7_ASN_ENCODING = 0x00010000;
const uint RSA_CSP_PUBLICKEYBLOB = 19;
const int AT_KEYEXCHANGE = 1; //keyspec values
const int AT_SIGNATURE = 2;
static uint ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ;

private CertUtil()
{
}

public static RSACryptoServiceProvider GetCertPublicKey(X509Certificate
cert)
{
byte[] publickeyblob ;
byte[] encodedpubkey = cert.GetPublicKey(); //asn.1 encoded public key

uint blobbytes = 0;

if(Win32.CryptDecodeObject(ENCODING_TYPE, RSA_CSP_PUBLICKEYBLOB,
encodedpubkey, (uint)encodedpubkey.Length, 0, null, ref blobbytes))
{
publickeyblob = new byte[blobbytes];
Win32.CryptDecodeObject(ENCODING_TYPE, RSA_CSP_PUBLICKEYBLOB,
encodedpubkey, (uint)encodedpubkey.Length, 0, publickeyblob, ref blobbytes);
}
else
{
throw new Exception("Could not decode publickeyblob from certificate
publickey") ;
}

PUBKEYBLOBHEADERS pkheaders = new PUBKEYBLOBHEADERS() ;
int headerslength = Marshal.SizeOf(pkheaders);
IntPtr buffer = Marshal.AllocHGlobal( headerslength);
Marshal.Copy( publickeyblob, 0, buffer, headerslength );
pkheaders = (PUBKEYBLOBHEADERS) Marshal.PtrToStructure( buffer,
typeof(PUBKEYBLOBHEADERS) );
Marshal.FreeHGlobal( buffer );

//----- Get public exponent -------------
byte[] exponent = BitConverter.GetBytes(pkheaders.pubexp);
//little-endian ordered
Array.Reverse(exponent); //convert to big-endian order

//----- Get modulus -------------
int modulusbytes = (int)pkheaders.bitlen/8 ;
byte[] modulus = new byte[modulusbytes];
try
{
Array.Copy(publickeyblob, headerslength, modulus, 0, modulusbytes);
Array.Reverse(modulus); //convert from little to big-endian ordering.
}
catch(Exception)
{
throw new Exception("Problem getting modulus from publickeyblob");
}

RSAParameters parms = new RSAParameters();
parms.Modulus = modulus;
parms.Exponent = exponent;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(parms);
return rsa;
}
}
}

//// Win32 Helpers
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections;
using System.Text;

namespace WSESimpleTCPDLL
{
public class Win32
{
[DllImport("crypt32.dll")]
public static extern bool CryptDecodeObject(
uint CertEncodingType,
uint lpszStructType,
byte[] pbEncoded,
uint cbEncoded,
uint flags,
[In, Out] byte[] pvStructInfo,
ref uint cbStructInfo);


[DllImport("crypt32.dll", SetLastError=true)]
public static extern IntPtr CertFindCertificateInStore(
IntPtr hCertStore,
uint dwCertEncodingType,
uint dwFindFlags,
uint dwFindType,
[In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString,
IntPtr pPrevCertCntxt) ;

[DllImport("crypt32.dll", SetLastError=true)]
public static extern bool CertFreeCertificateContext(
IntPtr hCertStore) ;


[DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
//overloaded
public static extern IntPtr CertOpenStore(
[MarshalAs(UnmanagedType.LPStr)] String storeProvider,
uint dwMsgAndCertEncodingType,
IntPtr hCryptProv,
uint dwFlags,
String cchNameString) ;


[DllImport("crypt32.dll", SetLastError=true)]
public static extern bool CertCloseStore(
IntPtr hCertStore,
uint dwFlags) ;
}
}
 
Why blame it on RSA (or Microsoft)? You try to abuse the intention. What is
the point of ENCRYPTing some data if ANYBODY can decrypt it with the public
key??? If you keep both keys secret (ie. the public key is not really public)
than why don't just use secret key (symmetric) encryption?

Laszlo Elteto
SafeNet, Inc.
 
Hi William

Thanks for that explanation, a very comprehensive answer!

My required solution does not quite fit this unfortunately, as the data
"packages" encrypted on the server may have been prepared days or weeks
before the receiving client(s) have even been set up. Therefore using Private
keys on the Clients would be undesirable (and also the customer does not want
this either). Also the package may arrive at the client via an email or CD so
there cannot be an online 'key exchange'. Would this change your solution any?

Thanks in advance.

Regards,
Pike
:-)
 
I was just trying to make the point that this is not technically possible to
do this (encrypt with Private Key & decrypt with Public key with Microsofts
RSA (RSACryptoServiceProvider)) in the hope that it will save somebody
somewhere some time (I spent 5 days before creating a different solution) if
trying to solve the same solution.

I am certainly not blaming RSA (an excellent encryption method) and, hey,
Microsoft's big enough to take, what is, only a small complaint!

REGARDS,
PIKE ;-)
 
rarara good point, despite the tone. you have to forgive newbies on
cryptography that sometimes don't see things so obvious as this one. If I'm
hiding *both* keys, what the point really on using asymetric cryptography? :)

two things learned:
- microsoft rsa implementation in "one-way": encrypt with public key,
decrypt with private key.
- the "public" in "public key" is what it means, or you're probably on the
wrong track.

thanks both, pike and lelteto!
 
np .. there are several alternate ways of doing this, described in
some articles here:
http://www.jensign.com/JavaScience/cryptoutils
specifically the .NET Keypal tool:
http://www.jensign.com/JavaScience/dotnet/keypal
- Mitch

William Stacey said:
Thanks Michel. I have been wanting to get public key from cert and this
article showed how. I made it a bit simplier here:

// Usage
string certFile = @"c:\mycert.cer";
X509Certificate cert = X509Certificate.CreateFromCertFile(certFile);
RSACryptoServiceProvider rsa = CertUtil.GetCertPublicKey(cert);
Console.WriteLine(rsa.ToXmlString(false));

/// CertUtil helper Class.
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

namespace WSESimpleTCPDLL
{
[StructLayout(LayoutKind.Sequential)]
public struct PUBKEYBLOBHEADERS
{
public byte bType; //BLOBHEADER
public byte bVersion; //BLOBHEADER
public short reserved; //BLOBHEADER
public uint aiKeyAlg; //BLOBHEADER
public uint magic; //RSAPUBKEY
public uint bitlen; //RSAPUBKEY
public uint pubexp; //RSAPUBKEY
}

/// <summary>
/// Summary description for CertUtil.
/// </summary>
public sealed class CertUtil
{
const uint CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000;
const uint CERT_STORE_READONLY_FLAG = 0x00008000;
const uint CERT_STORE_OPEN_EXISTING_FLAG = 0x00004000;
const uint CERT_FIND_SUBJECT_STR = 0x00080007;
const uint X509_ASN_ENCODING = 0x00000001;
const uint PKCS_7_ASN_ENCODING = 0x00010000;
const uint RSA_CSP_PUBLICKEYBLOB = 19;
const int AT_KEYEXCHANGE = 1; //keyspec values
const int AT_SIGNATURE = 2;
static uint ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ;

private CertUtil()
{
}

public static RSACryptoServiceProvider GetCertPublicKey(X509Certificate
cert)
{
byte[] publickeyblob ;
byte[] encodedpubkey = cert.GetPublicKey(); //asn.1 encoded public key

uint blobbytes = 0;

if(Win32.CryptDecodeObject(ENCODING_TYPE, RSA_CSP_PUBLICKEYBLOB,
encodedpubkey, (uint)encodedpubkey.Length, 0, null, ref blobbytes))
{
publickeyblob = new byte[blobbytes];
Win32.CryptDecodeObject(ENCODING_TYPE, RSA_CSP_PUBLICKEYBLOB,
encodedpubkey, (uint)encodedpubkey.Length, 0, publickeyblob, ref blobbytes);
}
else
{
throw new Exception("Could not decode publickeyblob from certificate
publickey") ;
}

PUBKEYBLOBHEADERS pkheaders = new PUBKEYBLOBHEADERS() ;
int headerslength = Marshal.SizeOf(pkheaders);
IntPtr buffer = Marshal.AllocHGlobal( headerslength);
Marshal.Copy( publickeyblob, 0, buffer, headerslength );
pkheaders = (PUBKEYBLOBHEADERS) Marshal.PtrToStructure( buffer,
typeof(PUBKEYBLOBHEADERS) );
Marshal.FreeHGlobal( buffer );

//----- Get public exponent -------------
byte[] exponent = BitConverter.GetBytes(pkheaders.pubexp);
//little-endian ordered
Array.Reverse(exponent); //convert to big-endian order

//----- Get modulus -------------
int modulusbytes = (int)pkheaders.bitlen/8 ;
byte[] modulus = new byte[modulusbytes];
try
{
Array.Copy(publickeyblob, headerslength, modulus, 0, modulusbytes);
Array.Reverse(modulus); //convert from little to big-endian ordering.
}
catch(Exception)
{
throw new Exception("Problem getting modulus from publickeyblob");
}

RSAParameters parms = new RSAParameters();
parms.Modulus = modulus;
parms.Exponent = exponent;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(parms);
return rsa;
}
}
}

//// Win32 Helpers
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections;
using System.Text;

namespace WSESimpleTCPDLL
{
public class Win32
{
[DllImport("crypt32.dll")]
public static extern bool CryptDecodeObject(
uint CertEncodingType,
uint lpszStructType,
byte[] pbEncoded,
uint cbEncoded,
uint flags,
[In, Out] byte[] pvStructInfo,
ref uint cbStructInfo);


[DllImport("crypt32.dll", SetLastError=true)]
public static extern IntPtr CertFindCertificateInStore(
IntPtr hCertStore,
uint dwCertEncodingType,
uint dwFindFlags,
uint dwFindType,
[In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString,
IntPtr pPrevCertCntxt) ;

[DllImport("crypt32.dll", SetLastError=true)]
public static extern bool CertFreeCertificateContext(
IntPtr hCertStore) ;


[DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
//overloaded
public static extern IntPtr CertOpenStore(
[MarshalAs(UnmanagedType.LPStr)] String storeProvider,
uint dwMsgAndCertEncodingType,
IntPtr hCryptProv,
uint dwFlags,
String cchNameString) ;


[DllImport("crypt32.dll", SetLastError=true)]
public static extern bool CertCloseStore(
IntPtr hCertStore,
uint dwFlags) ;
}
}
 
hmmm... Don't ask for much? :-)
Lets see, you want to secure some data payload to any client that has never
negotiated a shared secret and the customer does not want any keys stored on
the client. Did I get that right?
I can't think of a secure way to do that. You either need to store a shared
secret on the client side EXE (not good) or negotiate some secret. If the
client could a least make a request via email or "on-line" then we could
work something out, but sending data to some anonymous client - not sure.
PKI would not work, at the client would at least need a private key and the
server would need to know the client's public key. Shared secrets can not
work, as you don't want client to talk to server or make a request. I am at
a loss. The only way I can think of is to hard code some shared secret
which is not good for obvious reasons. Maybe someone else has an idea?

PS. Maybe if when the client gets the package that kicks off a "talk" with
the server, then the client could exchange the key that the server used to
encrypt the package. That would require some more thinking, but at some
point the client needs to talk to the server (via soap msg/xml msg (or
other) in email or on-line, etc.)
 
Hi William

Just keeping you guys on your toes! ;-)

Just helping clarifying the scenario (and my current solution) a little
more...

The server creates encrypted packages of data and signs them with the
private key.
The encryption method is :-
The data encrypted symmetrically with random key
Random Key encrypted symmetrically with secret key (in software)
+ signature to make package
These packages can get to the client via email or CD or another method.

Each client will be setup with a public key on their machine and our
software will check the signature then decrypt the packages (using secret key
in software).

The weak area here is the 'secret key' in the software but as you say it not
ideal because if that gets compromised you have a problem.

I do like your idea of a package initiating a 'talk' with the server to get
the secret key to unencrypt the data and this is a scenario I shall mull over
and discuss with the customer. Thanks for that!

Regards,
Pike
:-)
 
Hi Laszlo et. al.

This has been a very educational thread, I had too run into the Bad Key
problem.

However I am curios as to why it would not be the intention of RSA, or
desireable with RSA, to be able to do encryption with my private key in
order to allow the other party to decrypt with my public key. I thought
that was the whole point of signatures. I.e.

1. I take the payload to be protected and encrypt it with Party B's
public key.
2. I take the encrypted payload and encrypt it with my private key. I
send the encrypted payload to Party B.
3. Party B decrypts the payload using my public key.
4. Party B decrypts the result from 3 using their private key.

Of course the payload could be just a hash of the content or a hash +
symmetric key etc.

I am aware that there are separate APIs for doing signatures but what
would be the purpose of explicitly preventing being able to perform the
steps above?

Thanks
Fredrik Sjodin
 
It works both ways as the signature is the encrypted digest using the
private key. TMK other implementations allow you to encrypt other data with
the private key. Obviously, anyone with the public key could decrypt the
data, so that is why they don't support public interfaces for that.
 
Back
Top