I\'ve spent two days on this so far and combed through every source at my disposal, so this is the last resort.
I have an X509 certificate whose public key I have stored
this is my first answer on stackoverflow, so please forgive me if I do it wrong!
I can't give you a complete answer, however I had very similar issues when I tried to integrate with PHP - it seems that the format of Apple's certificate files is a little different from that which other software expects (including openssl).
Here's how I decrypt an encrypted signature in PHP - I actually extract the modulus and PK from the transmitted public key manually and use that for the RSA stuff, rather than trying to import the key:
// Public key format in hex (2 hex chars = 1 byte):
//30480241009b63495644db055437602b983f9a9e63d9af2540653ee91828483c7e302348760994e88097d223b048e42f561046c602405683524f00b4cd3eec7e67259c47e90203010001
//<IGNORE><--------------------------------------------- MODULUS --------------------------------------------------------------------------><??>< PK >
// We're interested in the modulus and the public key.
// PK = Public key, probably 65537
// First, generate the sha1 of the hash string:
$sha1 = sha1($hashString,true);
// Unencode the user's public Key:
$pkstr = base64_decode($publicKey);
// Skip the <IGNORE> section:
$a = 4;
// Find the very last occurrence of \x02\x03 which seperates the modulus from the PK:
$d = strrpos($pkstr,"\x02\x03");
// If something went wrong, give up:
if ($a == false || $d == false) return false;
// Extract the modulus and public key:
$modulus = substr($pkstr,$a,($d-$a));
$pk = substr($pkstr,$d+2);
// 1) Take the $signature from the user
// 2) Decode it from base64 to binary
// 3) Convert the binary $pk and $modulus into (very large!) integers (stored in strings in PHP)
// 4) Run rsa_verify, from http://www.edsko.net/misc/rsa.php
$unencoded_signature = rsa_verify(base64_decode($signature), binary_to_number($pk), binary_to_number($modulus), "512");
//Finally, does the $sha1 we calculated match the $unencoded_signature (less any padding bytes on the end)?
return ($sha1 == substr($unencoded_signature,-20)); // SHA1 is only 20 bytes, whilst signature is longer than this.
The objective-c that generates this public key is:
NSData * data = [[SecKeyWrapper sharedWrapper] getPublicKeyBits];
[req addValue:[data base64Encoding] forHTTPHeaderField: @"X-Public-Key"];
data = [[SecKeyWrapper sharedWrapper] getSignatureBytes:[signatureData dataUsingEncoding:NSUTF8StringEncoding]];
[req addValue:[data base64Encoding] forHTTPHeaderField: @"X-Signature"];
Using SecKeyWrapper from Apple's example project CryptoExercise (you can view the file here: https://developer.apple.com/iphone/library/samplecode/CryptoExercise/listing15.html)
I hope this helps?
I believe you've answered the question yourself. The problem most certainly lies within the endianness.
This is a possible way of writing two-way conversion methods:
short convert_short(short in)
{
short out;
char *p_in = (char *) ∈
char *p_out = (char *) &out;
p_out[0] = p_in[1];
p_out[1] = p_in[0];
return out;
}
long convert_long(long in)
{
long out;
char *p_in = (char *) ∈
char *p_out = (char *) &out;
p_out[0] = p_in[3];
p_out[1] = p_in[2];
p_out[2] = p_in[1];
p_out[3] = p_in[0];
return out;
}
This might be a good resource for you (other than wikipedia): http://betterexplained.com/articles/understanding-big-and-little-endian-byte-order/
Will this help you ?
Asymmetric Key Encryption w/ .NET & C#
Well... the first step (as you say you have done) is to encrypt the same messages with the same initialization vectors using both the iPhone and the C# implementation. You should get the same output. You said you didn't, so there is a problem.
This means either:
I would suggest the first two are unlikely, however they are remotely possible.
You state: "Installed .cer file in different cert store and server-encrypted string roundtripped just fine"... this doesn't prove anything: all this proves is that given a particular random set of numbers you can encrypt/decrypt successfully on one platform. You are not guaranteeing that both platforms are seeing the same set of random numbers.
So I suggest you take it down to the lowest level possible here. Inspect the direct (byte array) inputs and outputs of the encryption on both platforms. If with the exact same (binary) inputs you don't get the same output, then you have a platform problem. I think this is unlikely, so I'm guessing you will find that the IVs are being interpreted differently.