Porting C# CryptoSys-assisted 3DES encryption to Objective-C CommonCrypto issues -
i working on iphone app port of subset of .net c# functionality. must log server using 3des encrypted password (yes, know not optimal standard, please bear me).
so far, however, no joy. cannot replicate encryption in c# code. code in both c# in objective-c shares these common variables:
strpassword
unencrypted password, "secret"abplain
byte array hex values of strpassword{73, 65, 63, 72, 65, 74, 02, 02}
rpmpassword
string of random characters.rpmpasswordasdata
objective-c representation of rpmpassword nsdata using utf8 encodingabpassword
byte array values of rpmpassword- i've added code derive
nlen
in objective-c code below
here's c# code first:
static int iterationcount = 2048; static int keybytes = 24; static int blockbytes = 8; byte[] abinitv = cryptosysapi.rng.noncebytes(blockbytes); byte[] abkey = cryptosysapi.pbe.kdf2(keybytes, abpassword, abinitv, iterationcount); cryptosysapi.tdea cipher = cryptosysapi.tdea.instance(); cipher.initencrypt(abkey, mode.cbc, abinitv); byte[] abcipher = cipher.update(abplain); aboutput = new byte[abcipher.length + blockbytes]; (int = 0; < blockbytes; i++) aboutput[i] = abinitv[i]; (int = 0; < nlen + npad; i++) aboutput[blockbytes + i] = abcipher[i]; return cryptosysapi.cnv.tohex(aboutput)
as can see, encrypted value returns concatenation of hex values of abinitv
, abcipher
.
i have been cribbing rob napier try , transform working objective-c code, far, it's not happening. producing abinitv
, abcipher
values of right length, , i'm concatenating them aboutput
, being rejected server when try log in.
here's objective-c code (the constants declared, promise):
int nlen = [strpassword length]; int npad = ((nlen / blockbytes) + 1) * blockbytes - nlen; nsdata *abinitv = [self randomdataoflength:blockbytes]; // salthex encryption const unsigned char *abinitvasbytes = [abinitv bytes]; nsdata *abkey = [self tdeakeyforpassword:strpassword salt:abinitv]; size_t movedbytes = 0; nsmutabledata *abcipher = [nsmutabledata datawithlength:blockbytes]; cccryptorstatus result = cccrypt(kccencrypt, kccalgorithm3des, ccnopadding & kccmodecbc, [abkey bytes], kcckeysize3des, [abinitv bytes], abpassword, [rpmpasswordasdata length], abcipher.mutablebytes, keybytes, &movedbytes); if (result == kccsuccess) { nslog(@"abcipher == %@ \n", [abcipher description] ); } nsmutabledata *aboutput = [nsmutabledata datawithcapacity:[abcipher length] + blockbytes]; const unsigned char *abcipherasbytes = [abcipher bytes]; (int = 0; < blockbytes; i++) { [aboutput replacebytesinrange:nsmakerange(i, sizeof(abinitvasbytes[i])) withbytes:&abinitvasbytes[i]]; } (int = 0; < nlen + npad; i++) { [aboutput replacebytesinrange:nsmakerange(blockbytes + i, sizeof(abcipherasbytes[i])) withbytes:&abcipherasbytes[i]]; } return [encryptionutil nsdatatohex:aboutput];
and here supporting methods called in code above:
+(nsstring*) nsdatatohex:(nsdata*)data { const unsigned char *dbytes = [data bytes]; nsmutablestring *hexstr = [nsmutablestring stringwithcapacity:[data length]*2]; int i; (i = 0; < [data length]; i++) { [hexstr appendformat:@"%02x ", dbytes[i]]; } return [nsstring stringwithstring: hexstr]; } +(nsdata*)hextonsdata:(nsstring*)hex { nsmutabledata* data = [nsmutabledata data]; int idx; (idx = 0; idx+2 <= [hex length]; idx+=2) { nsrange range = nsmakerange(idx, 2); nsstring* hexstr = [hex substringwithrange:range]; nsscanner* scanner = [nsscanner scannerwithstring:hexstr]; unsigned int intvalue; [scanner scanhexint:&intvalue]; [data appendbytes:&intvalue length:1]; } return data; } +(nsdata *)randomdataoflength:(size_t)length { nsmutabledata *data = [nsmutabledata datawithlength:length]; int result = secrandomcopybytes(ksecrandomdefault, length, data.mutablebytes); nsassert(result == 0, @"unable generate random bytes: %d", errno); return data; } +(nsdata *)tdeakeyforpassword:(nsstring *)password salt:(nsdata *)salt { nsmutabledata * derivedkey = [nsmutabledata datawithlength:kcckeysize3des]; int result = cckeyderivationpbkdf(kccpbkdf2, // algorithm password.utf8string, // password password.length, // passwordlength salt.bytes, // salt salt.length, // saltlen kccprfhmacalgsha1, // prf iterationcount, // rounds derivedkey.mutablebytes, // derivedkey derivedkey.length); // derivedkeylen return derivedkey; }
so, if can tell me i'm doing wrong, i'd sincerely appreciate it. if had hazard guess, i'd assume problem in 1 of 2 places:
- generating key, either in call to, or code of
tdeakeyforpassword
- calling
cccrypt
.
that said, i've tried every available prf constant, padding , no padding.
i'm inexperienced encryption, i'd appreciate can offer.
thanks!
first, code samples seem different. c# code encrypting abplain
. objc code encrypting abpassword
. indicate abplain
static, while abpassword
random. have kind of padding going on in objc don't see in c# (maybe 0 padding? that's not standard way pad.)
if remove randomness, each implementation should return same result same input. first, hard-code random value (i use 0, random other number), , choose common abpassword
. then, @ each step of process, make sure both implementations generate same result. significantly, abkey
same, , abcipher
, , aboutput
. @ 1 of these points implementations diverge. (from quick reading, seem doing different things along.)
one thing confusing how switch between abpassword
, rpmpassword
. in 1 case pass abpassword
, length of rpmpasswordasdata
. feels place it's easy make mistake.
the length of abpassword
unclear. assume it's multiple of 8, or else ccnopadding
going blow up.
nsmutabledata
has appenddata
method. that's easier replacebytesinrange:…
Comments
Post a Comment