Monday, 9 September 2013

SecKeyEncrypt kSecPaddingNone

SecKeyEncrypt kSecPaddingNone

I've been experiencing some frustration when trying to use SecKeyEncrypt()
with kSecPaddingNone. After much investigation, I've found a workaround,
but I want to know what's going on. At the moment, I don't have the code
available, but I will be able to post it later today. I'm really not
convinced that the problem lies in my code, though: I tend to believe that
I'm just plain old doing something fundamentally wrong. (That is, I
believe my code is right, but that what I'm trying to do is wrong.)
My problem is this: I'd like to encrypt a large block of data using a
symmetric key, and then encrypt that key using a different public key.
Using CryptoExercise as a template, I've fairly easily got a bunch of code
that does that. I generate a symmetric key for AES128, use it to encrypt
my large buffer. My unit tests have no trouble with that.
But then my unit tests create a public/private key pair, attempt to
encrypt the symmetric key with the public key, decrypt it with the private
key, and then decrypt the large buffer. Note that I've made some
simplifying assumptions based on the restricted domain of my problem set:
I'm always using AES128 to encrypt the large buffer, so the key is always
16 bytes, and I'm always using a 1024-bit public/private key pair, so I
encrypt the AES key by creating a 128-byte buffer, filling it with random
data, and then embedding the AES key into that buffer.
Finally, since I've got a fixed set of buffer sizes, I'm using
kSecPaddingNone when I call `SecKeyEncrypt() . My assumption was that I
could rely on my method of filling the buffer and knowledge of the buffer
sizes.
What I saw when I started running my tests was frustrating: about 80% of
the time, they work just fine. But the other 20%, SecKeyEncrypt() fails
with an OSStatus of -50, bad parameter. I spent quite a bit of time
looking for stack corruption, heap corruption, premature deallocation,
etc., but that was fruitless.
Then I started looking at the public/private key pair operations on just
plain old buffers, i.e. I made a new unit test which tried to
encrypt/decrypt buffers that I created and filled manually. At this point,
I found my clues: if I sent, for example, a zero buffer, then
SecKeyEncrypt fell into an infinite loop. If I sent a buffer filled with
just ones, then it worked fine. And if I filled the buffer with ones, and
then replaced the first byte with zero, I got back into an infinite loop.
Various other patterns led me to my workaround, which is presently to
insert the AES key after the first byte and to always set the first byte
to one, but I'm heartily confused. From the documentation for
SecKeyEncrypt():
Typically, kSecPaddingPKCS1 is used, which addsPKCS1padding before
encryption. If you specifykSecPaddingNone`, the data is encrypted as-is.
The way I read that, the contents of the plaintext buffer should not
affect the execution of the encryption algorithm, and yet, my unit tests
seem to indicate that it is happening, and that the first byte of the
buffer is somehow crucial to the operation. And my workaround seems to
pass my unit tests 100% of the time.
Does anybody with more experience here have anything that'd help me
understand what's going on? Am I misinterpreting the documentation? Am I
trying to do something that I shouldn't be? Did I oversimplify?
I can post the code later tonight, once I have access to it again, if
anybody thinks it'll help.

No comments:

Post a Comment