I am working on an application for Android and iOS which relies on RSA shared keys to create and verify data signatures. So far, I have had success creating and exporting public keys from each platform which are uploaded to a server. The server is able to read the keys from either platform. The keys are exported as an X.509 encoded PEM file. The server reads the keys created by Android using a PKIX encoding. The server reads the keys from iOS using a PKCS encoding. (This was discovered through trial and error).
Android keys are created using an RSA/OAEP/SHA-1 scheme. Keys created by an Android client can be read and loaded by other Android clients, the server, and iOS clients. Android exports and loads keys using a combination of Java and Bouncy Castle. (Written below in C#).
Android Key Export
X509EncodedKeySpec spec = new X509EncodedKeySpec(_pkey.GetEncoded());
string pem = string.Empty;
using (TextWriter writer = new StringWriter())
{
PemWriter pw = new PemWriter(writer);
pw.WriteObject(new PemObject("PUBLIC KEY", spec.GetEncoded()));
pem = writer.ToString();
}
return pem;
Android Key Import
PemObject spki = new PemReader(new StringReader(cert)).ReadPemObject();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(spki.Content);
KeyFactory kf = KeyFactory.GetInstance(KeyProperties.KeyAlgorithmRsa);
_pkey = kf.GeneratePublic(keySpec);
Using these routines, Android produces a PEM encoded public key which resembles the following:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkmaJzUb1E3fl2kPgi/Vi
8wZHKDuGw6RAzO8F9S86qwtwPKFzksKJ8O9AXrRsxe0YCrWX9SGNVSuP4XUoKQtA
QVUfpgsmsAejjgXn+CaS/MKmhFJSZ0f9vegkMmLiQJp3u0+ggXI6fBOCK48n865D
XAsWw/TzhFCWRsmaywwkvxyymRj68pDyU75sjyaefQbbXfrLEzD2YaZVG8rHtO/o
wddPbtKZRMwD1C4nDptNfdMPmlAWk08L5eQQFYBn0EWbDfkyDTi5DYrfGTwRzuo4
HKorltiyP/LfgSL9a/nEh40tJg3Dw2E61RJtEyhA1hJHhM1Uk84Fncii9KHkJYPM
KwIDAQAB
-----END PUBLIC KEY-----
Testing such a key using openssl (openssl rsa -pubin -in temp/author.pkey) produces output such as the following:
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkmaJzUb1E3fl2kPgi/Vi
8wZHKDuGw6RAzO8F9S86qwtwPKFzksKJ8O9AXrRsxe0YCrWX9SGNVSuP4XUoKQtA
QVUfpgsmsAejjgXn+CaS/MKmhFJSZ0f9vegkMmLiQJp3u0+ggXI6fBOCK48n865D
XAsWw/TzhFCWRsmaywwkvxyymRj68pDyU75sjyaefQbbXfrLEzD2YaZVG8rHtO/o
wddPbtKZRMwD1C4nDptNfdMPmlAWk08L5eQQFYBn0EWbDfkyDTi5DYrfGTwRzuo4
HKorltiyP/LfgSL9a/nEh40tJg3Dw2E61RJtEyhA1hJHhM1Uk84Fncii9KHkJYPM
KwIDAQAB
-----END PUBLIC KEY-----
iOS keys are created using an RSA/OAEP/SHA-256 scheme. Keys created by an iOS client can be read and loaded by other iOS clients and the server, but not by Android clients. iOS exports and loads keys using a combination of Objective-C and Bouncy Castle. (Written below in C#).
iOS Key Export
var bytes = lookupKey()?.GetPublicKey().GetExternalRepresentation().ToArray();
string pem = string.Empty;
using (TextWriter writer = new StringWriter())
{
PemWriter pw = new PemWriter(writer);
pw.WriteObject(new PemObject("PUBLIC KEY", bytes));
pem = writer.ToString();
}
return pem;
iOS Key Import
byte[] encoded = Convert.FromBase64String(pem);
string cert = Encoding.UTF8.GetString(encoded);
string[] parts = cert.Split('\n');
string b64 = string.Join(string.Empty, parts.Skip(1).Take(parts.Length - 1));
NSData data = new NSData(b64, NSDataBase64DecodingOptions.IgnoreUnknownCharacters);
_pkey = SecKey.Create(data, SecKeyType.RSA, SecKeyClass.Public, 2048, null, out NSError err);
Using these routines, iOS produces a PEM encoded public key which resembles the following:
-----BEGIN PUBLIC KEY-----
MIIBCgKCAQEApg8H5D/HZE7RcvV1QkZ//HE+D9PNjxZw1Gur5S3l8QN731S28d3l
iMuVmf/4FCDvJ5GLoQKmbvslrL/s2Fc6WzS4cr84psg4dCxZVYrKY65vMMdTIoni
Z0jE6oFnl8+j3wuOA6bAid4wpSK6vIwo+u3N48csQfdj0wEG7QDsNhbj+btGVU8G
/pS3RRcSRlhxhpz+1LALjd0xZ6iXrAn85r39dsEZohIuOC4/+A5EIpUUw12k4+Dy
3qxI7nDiLpJySeE8NV4K9Fk0+4flmMDBNkLMJBT8Vt6DGHtc4ImBnhBLxFt/oSq9
8iW3TwxrRptBZUkdU2U+QXigLUYcj/T+MQIDAQAB
-----END PUBLIC KEY-----
Testing such a key using openssl (openssl rsa -pubin -in temp/author.pkey) produces output such as the following:
unable to load Public Key
140230339794240:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:../crypto/asn1/tasn_dec.c:1149:
140230339794240:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:309:Type=X509_ALGOR
140230339794240:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:646:Field=algor, Type=X509_PUBKEY
140230339794240:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:../crypto/pem/pem_oth.c:33:
I noticed how the public key export from iOS has one line fewer than the key exported from Android. I believe that iOS exports public keys using an encoding slightly different from an X.509 certificate. I found a document regarding PKCS #1 specifications from a separate SO thread, but the thread offered no direction on what to do with the information provided. https://www.rfc-editor.org/rfc/rfc3447#page-6
I have very little experience with cryptography in general, so I may be using some of the terms incorrectly and am clearly missing something which may be obvious to someone with more experience. I do not know if there is something that can be done to convert a PKCS encoded key into a PKIX one (or if that is even my problem). Can anyone offer any clues as to what I should try here?