i have followed apple developer documents , examples showing how generate key pair, encrypt public key , decrypt private key. have 3 example methods in guide (page 19 onwards here).
i have copied pasted these 3 methods project, changing them public class methods, added logging , hooked buttons call them feeding output of encryption decrypt:
in viewcontroller:
-(ibaction)generatekey:(uibutton*)sender { [cryptoclass generatekeypairplease]; } -(ibaction)encryptanddecrypt { nsdata *data = [cryptoclass encryptwithpublickey]; [cryptoclass decryptwithprivatekey:data]; } the code 3 methods are:
static const uint8 publickeyidentifier[] = "com.apple.sample.publickey\0"; static const uint8 privatekeyidentifier[] = "com.apple.sample.privatekey\0"; + (nsdata *)encryptwithpublickey { osstatus status = noerr; size_t cipherbuffersize; uint8_t *cipherbuffer; // 1 // [cipherbuffersize] const uint8_t datatoencrypt[] = "the quick brown fox jumps " "over lazy dog\0"; // 2 size_t datalength = sizeof(datatoencrypt)/sizeof(datatoencrypt[0]); seckeyref publickey = null; // 3 nsdata * publictag = [nsdata datawithbytes:publickeyidentifier length:strlen((const char *)publickeyidentifier)]; // 4 nsmutabledictionary *querypublickey = [[nsmutabledictionary alloc] init]; // 5 [querypublickey setobject:(__bridge id)ksecclasskey forkey:(__bridge id)ksecclass]; [querypublickey setobject:publictag forkey:(__bridge id)ksecattrapplicationtag]; [querypublickey setobject:(__bridge id)ksecattrkeytypersa forkey:(__bridge id)ksecattrkeytype]; [querypublickey setobject:[nsnumber numberwithbool:yes] forkey:(__bridge id)ksecreturnref]; // 6 status = secitemcopymatching ((__bridge cfdictionaryref)querypublickey, (cftyperef *)&publickey); // 7 // allocate buffer cipherbuffersize = seckeygetblocksize(publickey); cipherbuffer = malloc(cipherbuffersize); // error handling if (cipherbuffersize < sizeof(datatoencrypt)) { // ordinarily, split data blocks // equal cipherbuffersize, last block being // shorter. simplicity, example assumes // data short enough fit. printf("could not decrypt. packet large.\n"); return null; } // encrypt using public. status = seckeyencrypt( publickey, ksecpaddingpkcs1, datatoencrypt, (size_t) datalength, cipherbuffer, &cipherbuffersize ); // 8 // error handling // store or transmit encrypted text if (publickey) cfrelease(publickey); nsdata *encrypteddata = [nsdata datawithbytes:cipherbuffer length:datalength]; free(cipherbuffer); return encrypteddata; } + (void)generatekeypairplease { osstatus status = noerr; nsmutabledictionary *privatekeyattr = [[nsmutabledictionary alloc] init]; nsmutabledictionary *publickeyattr = [[nsmutabledictionary alloc] init]; nsmutabledictionary *keypairattr = [[nsmutabledictionary alloc] init]; // 2 nsdata * publictag = [nsdata datawithbytes:publickeyidentifier length:strlen((const char *)publickeyidentifier)]; nsdata * privatetag = [nsdata datawithbytes:privatekeyidentifier length:strlen((const char *)privatekeyidentifier)]; // 3 seckeyref publickey = null; seckeyref privatekey = null; // 4 [keypairattr setobject:(__bridge id)ksecattrkeytypersa forkey:(__bridge id)ksecattrkeytype]; // 5 [keypairattr setobject:[nsnumber numberwithint:1024] forkey:(__bridge id)ksecattrkeysizeinbits]; // 6 [privatekeyattr setobject:[nsnumber numberwithbool:yes] forkey:(__bridge id)ksecattrispermanent]; // 7 [privatekeyattr setobject:privatetag forkey:(__bridge id)ksecattrapplicationtag]; // 8 [publickeyattr setobject:[nsnumber numberwithbool:yes] forkey:(__bridge id)ksecattrispermanent]; // 9 [publickeyattr setobject:publictag forkey:(__bridge id)ksecattrapplicationtag]; // 10 [keypairattr setobject:privatekeyattr forkey:(__bridge id)ksecprivatekeyattrs]; // 11 [keypairattr setobject:publickeyattr forkey:(__bridge id)ksecpublickeyattrs]; // 12 status = seckeygeneratepair((__bridge cfdictionaryref)keypairattr, &publickey, &privatekey); // 13 // error handling... if(publickey) cfrelease(publickey); if(privatekey) cfrelease(privatekey); // 14 } + (void)decryptwithprivatekey: (nsdata *)datatodecrypt { osstatus status = noerr; size_t cipherbuffersize = [datatodecrypt length]; uint8_t *cipherbuffer = (uint8_t *)[datatodecrypt bytes]; size_t plainbuffersize; uint8_t *plainbuffer; seckeyref privatekey = null; nsdata * privatetag = [nsdata datawithbytes:privatekeyidentifier length:strlen((const char *)privatekeyidentifier)]; nsmutabledictionary *queryprivatekey = [[nsmutabledictionary alloc] init]; // set private key query dictionary. [queryprivatekey setobject:(__bridge id)ksecclasskey forkey:(__bridge id)ksecclass]; [queryprivatekey setobject:privatetag forkey:(__bridge id)ksecattrapplicationtag]; [queryprivatekey setobject:(__bridge id)ksecattrkeytypersa forkey:(__bridge id)ksecattrkeytype]; [queryprivatekey setobject:[nsnumber numberwithbool:yes] forkey:(__bridge id)ksecreturnref]; // 1 status = secitemcopymatching ((__bridge cfdictionaryref)queryprivatekey, (cftyperef *)&privatekey); // 2 // allocate buffer plainbuffersize = seckeygetblocksize(privatekey); plainbuffer = malloc(plainbuffersize); if (plainbuffersize < cipherbuffersize) { // ordinarily, split data blocks // equal plainbuffersize, last block being // shorter. simplicity, example assumes // data short enough fit. printf("could not decrypt. packet large.\n"); return; } // error handling status = seckeydecrypt( privatekey, ksecpaddingpkcs1, cipherbuffer, cipherbuffersize, plainbuffer, &plainbuffersize ); // 3 // error handling // store or display decrypted text nslog(@"plain: %@",[nsstring stringwithutf8string:(const char *)plainbuffer]); if(privatekey) cfrelease(privatekey); } i have been trying many different guides , read lot of posts here trying work. tried apples keychainwrapperitem store , retrieve keys no luck. found post here describing , showing exact code key in data-format, returns nil reason.
the last thing did using matt gallagher's nsdata+base64 category print encrypted string , can visually see string wildly different each pass if not generate new key code:
-(ibaction)encryptanddecrypt { nsdata *data = [cryptoclass encryptwithpublickey]; nslog(@"string: %@", [data base64encodedstring]); // print encrypted data base64 [cryptoclass decryptwithprivatekey:data]; } fyi i'm running on simulator if of importance. , reset clear keychain before each generation.
can please me understand this?
errors in provided code
in + (nsdata *)encryptwithpublickey, line strip encrypted data (and destroy it)
nsdata *encrypteddata = [nsdata datawithbytes:cipherbuffer length:datalength]; it should
nsdata *encrypteddata = [nsdata datawithbytes:cipherbuffer length:cipherbuffersize]; different result each time
it not error see different results each time. pkcs#1 encryption algorithm uses random seed make cipher-text different each time. called padding , protects against several attacks, e.g. frequency analysis , ciphertext matching. see wikipedia article section: http://en.wikipedia.org/wiki/rsa_(algorithm)#padding_schemes
Comments
Post a Comment