iphone - public key in ios keychain changes on each get -


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