Re: CAPI and RC4: can not decrypt when Final parameter is set to F
- From: "lelteto" <lelteto@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Tue, 21 Feb 2006 10:04:59 -0800
Mehid,
I think you have some misconception on "key containers". They are used ONLY
to store ASYMMETRIC key pairs - never symmetric keys like RC4, DES etc.
Tou use any symmetric key in CAPI you need to
(a) generate one or
(b) import one.
Now when you need to encrypt at one place and decrypt at the other normally
yoy do the following:
- generate (or have) an asymmetric KEY PAIR at the receiving end
- export the public key
- send the public key to the data originator
- the other side imports the public key
- generates a random symmetric SESSION KEY
- you export this key WRAPPED with the public key
- you encrypt your data
- you send the encrypted data AND the wrapped (encrypted) session key
- the receiver imports the session key (it has the private key to decrypt it)
- now the receiver has the same session key and can decrypt the data
You should NEVER send the plaintext encryption key to the other party
(together with your encrypted data) because in that case there is no point to
encrypt your data (as anybody intercepting the communication would get the
key, too - so can decrypt it anyway.
If you have pre-established trust between the parties you MAY (although not
recommended) to have a pre-established symmetric key on both sides. Using
CAPI you woudl still have to import that every time (remember: CAPI doesn't
store symmetric keys in containers).
Even in that case you SHOULD generate random session key and send that
wrapped with the pre-established (long-term) master key. The reason is that
you don't want too much data encrypted with the same key. This is especially
important with STREAM ciphers because if you use the same key it would re-use
the same KEY STREAM (which is just XORed with your data). The latter means
that if you have one data both in encrypted and plain-text form you can get
back the key stream (XORing the encrypted data and plaintext data) so you can
decrypt ANY other ciphertext which used the same key (stream).
As you can see crypto is non-trivial and you can use crypto in ways that
doesn't protect your data at all. You better have your design reviewed by
somebody with security / crypto knowledge.
Laszlo Elteto
SafeNet, Inc.
"Mehdi" wrote:
On Mon, 20 Feb 2006 09:38:27 -0800, lelteto wrote:.
For stream ciphers you would just NEVER use the FINAL=TRUE; that's the
simplest way. I don't know what do you mean that the server "won't work" when
you stream-cipher encrypt 8 bytes but send only the first four (or decrypt
only the first four). Do you get an error from CryptDecrypt? If it's at an
upper layer than you need to check what the application is doing with the
provided data - it may be an issue unrelated to the encryption / decryption
process.
Thanks for your answer. I was actually just about to write a follow up to
that issue. What i meant by "it won't work" when the server only decrypts
the first part of what the client had encrypted is that the decrypted data
did not correspond to the original data.
I've found the solution to this problem though (but i still don't
understand why it didn't work in the first place). Here is what i was doing
before:
On the server (unmanaged C++):
1) Get a HCRYPTPROV handle to a key container with CryptAcquireContext
2) Generate a new random RC4 key and get a HCRYPTKEY handle with
CryptGenKey specifying the CALG_RC4 algotithm
3) Export the RC4 to a plain text byte array using the trick described in
MS KB Q228786
4) Send the RC4 key to the client application
On the client (C#)
1) Get the RC4 key from the server
2) Create a RC4CryptoServiceProvider object (provided by Mentalis' security
library)
3) Create the RC4 encryptors and decryptors from my
RC4CryptoServiceProvider object
Then i was using CryptEncrypt to encrypt the data in the client application
and CryptDecrypt to decrypt it in the server application. The problem was
that it worked only with the Final parameter set to TRUE, which was a pain
since that forced me to decrypt the data in same chunk sizes as it has been
encrypted. When Final was set to FALSE, the server always decrypted
rubbish.
So i've had a look at how the RC4CryptoServiceProvider CAPI C# wrapper had
been implemented and found out that whenever it created either an Encryptor
or a Decryptor object, it always imported the plain text key to the key
container (using the KB Q228786 trick). This resulted in the Encryptor and
Descriptor objects having a different HCRYPTKEY key handle even though they
were both using the same key and key container (both objects had the same
HCRYPTPROV handle to the key container).
So i've modified my implementation on the server to do the same thing:
after the step 4) above, i am now importing my plain text RC4 key using
CryptImportKey back to the key container from which i had exported it a few
lines of code before. This alowed me to get another HCRYPTKEY handle to my
RC4 key. Using the first HCRYPTKEY (obtained in the server step 2 above) to
encrypt the data and the second HCRYPTKEY to decrypt the data resulted in
the expected result: i can now encrypt and decrypt data with the Final
parameter set to FALSE, which allows to not bother about chunk size when i
encrypt or decrypt the data. Hurrah!
I still don't understand why i have to re-import my encryption key into my
key container and use 2 different HCRYPTKEY handles for the same key to do
the encryption and the decryption. This is maybe due to Mentalis's wrapper
generating a different HCRYPTKEY handle to do the encryption and
decryption... Oh well, at least it's working fine now
Thanks for the help.
- Follow-Ups:
- References:
- Prev by Date: Re: MY (personal) certificate store
- Next by Date: Re: Logon Broker
- Previous by thread: Re: CAPI and RC4: can not decrypt when Final parameter is set to F
- Next by thread: Re: CAPI and RC4: can not decrypt when Final parameter is set to F
- Index(es):
Relevant Pages
|