I have been banging my head on a wall with this one. I need to code my iPhone application to encrypt a 4 digit "pin" using 3DES in ECB mode for transmission to a webservice which I believe is written in .NET.

I do get a value encrypted using the above code, however it does not match the value from the .NET web service.

I believe the issue is that the encryption key I have been supplied by the web service developers is 48 characters long.

I see that the iPhone SDK constant "kCCKeySize3DES" is 24. So I SUSPECT, but don't know, that the commoncrypto API call is only using the first 24 characters of the supplied key.

Is this correct?

Is there ANY way I can get this to generate the correct encrypted pin? I have output the data bytes from the encryption PRIOR to base64 encoding it and have attempted to match this against those generated from the .NET code (with the help of a .NET developer who sent the byte array output to me). Neither the non-base64 encoded byte array nor the final base64 encoded strings match.

3 Answers
3

3DES is a symmetric block cipher. Using a 24-byte key, 3DES encrypts an 8-byte block into another 8-byte block. With the same 24-byte key, the encryption is reversible (i.e. you can decrypt).

The key is an arbitrary sequence of bytes. That's not the same as "characters". In particular, having one of those bytes with value zero is perfectly legal. Similarly, input and output may be arbitrary bytes.

If the key you were given consists in "characters" then it must be transformed into an appropriate sequence of bytes in some way. Since you got a 48-character "key string" and 48 is exactly 24*2, a plausible guess is that the key is given in hexadecimal notation: see if it contains only digits, and letters from 'a' to 'f'.

As for padding: 3DES encrypts only 8-byte blocks. When a "message" is to be encrypted and has some length distinct from 8 bytes, then it is customary to format and split and process the message so that it can be encrypted in a number of invocations to 3DES. The two keywords are padding and chaining. Padding is about adding some extra bytes at the end (in such a way that those byte can be unambiguously removed) so that the length is appropriate (e.g. multiple of 8). Chaining is about deciding what exactly goes into each 3DES invocation (simply splitting the padded message into independently encrypted blocks is known as "ECB" and has weaknesses).

If your PIN code contains 4 digits, then there must be some convention on how these four
digits become at least 8 bytes, to be fed to 3DES. If the iPhone behaves similarly to what this man page for MacOS X describes, then your code should not run successfully unless the length of encryptData is a multiple of eight. Which means that the code you do not show, which converts a 4-digit PIN into an 8-byte buffer, already does some non-trivial transformations. For instance, that code might put the four digits into four bytes (using ASCII encoding) and set the four other bytes to zero. Or maybe it fails to do so. Either way, each of the 64 input bits to 3DES is important, and you have to get it exactly in the same way than the server. You should inspect that code as well.

Thanks Thomas for your detailed answer here. The concepts you mention are exactly what I ended up looking into in more detail. I was lucky in that I had access to the .NET version of the encryption code and that gave me valuable pointers. The 4 digit PIN was turned into an 8 digit value to be fed into the 3DES algorithm by appending 4 0's. I added my code to this answer, but marked your as the solution because your knowledge was totally correct.
–
Russell HillMar 16 '10 at 17:14

well, I managed to resolve this with a lot of reading and the comments here on stackoverflow. There where several issues. The key I had been given by the .NET developers was 48 characters. This of course needed to be read as a hex string and converted down to 24 characters instead.

I added code to do this, and the complete routine is as follows. I am not sure it will be of any use as it's quite specific to our implementation.

Thanks for the suggestion, however I have been told that the .NET code sets padding to "PaddingMode.None". It's therefore an assumption of mine that I don't need to pad from the iPhone app. I may be wrong of course!
–
Russell HillMar 16 '10 at 14:34

Do you have access to the .Net code? If you do then I suggest to read it to reverse engineer the actual encryption used.
–
Stefan ArentzMar 16 '10 at 15:28