Итак, я использовал класс SecKeyWrapper
для генерации случайного ключа, затем использовал метод -getPublicKeyBits
для получения двоичного представления открытого ключа (в любом формате, который используется внутри). Предполагая, что это какая-то форма DER ASN.1, я перешел на консоль в шестнадцатеричном виде и загрузил ее в этой программы . Конечно, внутренним представлением является DER ASN.1, но это очень упрощенная версия того, что я обычно нашел для представлений ключей RSA:
![SEQUENCE { INTEGER, INTEGER }][2]
Не должно быть слишком сложно строить на лету из двоичного представителя. модуля и показателя степени, так как кодировка DER просто
30 (for SEQUENCE) LL (total sequence byte length)
02 (INTEGER) LL (modulus byte length) XX XX... (modulus data bytes)
02 LL XX XX XX... (exponent length and bytes)
Вот мой код, для простоты. Он использует несколько библиотек Google для XML + base64, просто один на один; также демонстрационный код Apple SecKeyWrapper. См. мой другой вопрос для заметки о том, как сделать эту работу. Также обратите внимание, что он не ARC-совместим; это оставлено как упражнение для читателя (я написал это много лет назад, сейчас).
#define kTempPublicKey @"tempPayKey"
-(NSData *)encryptedDataWithXMLPublicKey:(NSString *)base64PublicKey data:(NSData *)data {
if(![data length]){
@throw [NSException exceptionWithName:@"NSInvalidArgumentException" reason:@"Data not set." userInfo:nil];
}
GTMStringEncoding *base64 = [GTMStringEncoding rfc4648Base64StringEncoding];
NSData *keyData = [base64 decode:base64PublicKey];
NSError *err = nil;
GDataXMLDocument *keyDoc = [[GDataXMLDocument alloc] initWithData:keyData options:0 error:&err];
if(err){
NSLog(@"Public key parse error: %@",err);
[keyDoc release];
return nil;
}
NSString *mod64 = [[[[keyDoc rootElement] elementsForName:@"Modulus"] lastObject] stringValue];
NSString *exp64 = [[[[keyDoc rootElement] elementsForName:@"Exponent"] lastObject] stringValue];
[keyDoc release];
if(![mod64 length] || ![exp64 length]){
@throw [NSException exceptionWithName:@"NSInvalidArgumentException" reason:@"Malformed public key xml." userInfo:nil];
}
NSData *modBits = [base64 decode:mod64];
NSData *expBits = [base64 decode:exp64];
/* the following is my (bmosher) hack to hand-encode the mod and exp
* into full DER encoding format, using the following as a guide:
* http://luca.ntop.org/Teaching/Appunti/asn1.html
* this is due to the unfortunate fact that the underlying API will
* only accept this format (not the separate values)
*/
// 6 extra bytes for tags and lengths
NSMutableData *fullKey = [[NSMutableData alloc] initWithLength:6+[modBits length]+[expBits length]];
unsigned char *fullKeyBytes = [fullKey mutableBytes];
unsigned int bytep = 0; // current byte pointer
fullKeyBytes[bytep++] = 0x30;
if(4+[modBits length]+[expBits length] >= 128){
fullKeyBytes[bytep++] = 0x81;
[fullKey increaseLengthBy:1];
}
unsigned int seqLenLoc = bytep;
fullKeyBytes[bytep++] = 4+[modBits length]+[expBits length];
fullKeyBytes[bytep++] = 0x02;
if([modBits length] >= 128){
fullKeyBytes[bytep++] = 0x81;
[fullKey increaseLengthBy:1];
fullKeyBytes[seqLenLoc]++;
}
fullKeyBytes[bytep++] = [modBits length];
[modBits getBytes:&fullKeyBytes[bytep]];
bytep += [modBits length];
fullKeyBytes[bytep++] = 0x02;
fullKeyBytes[bytep++] = [expBits length];
[expBits getBytes:&fullKeyBytes[bytep++]];
SecKeyRef publicKey = [[SecKeyWrapper sharedWrapper] addPeerPublicKey:kTempPublicKey keyBits:fullKey];
[fullKey release];
NSData *encrypted = [[SecKeyWrapper sharedWrapper] wrapSymmetricKey:data keyRef:publicKey];
// remove temporary key from keystore
[[SecKeyWrapper sharedWrapper] removePeerPublicKey:kTempPublicKey];
return encrypted;
}