javascript - Using ntlm authentication in Nativescript ios platform -


i building app authenticates user against sharepoint site uses ntlm authentication. found ntlm.js has been patched nativescript here https://github.com/hdeshev/nativescript-ntlm-demo.

i have managed working android platform, fails on ios showing 401 error. far can tell, difference happens in segment:

ntlm.setcredentials = function(domain, username, password) {     var magic = 'kgs!@#$%'; // create lm password hash.     var lmpassword = password.touppercase().substr(0, 14);     while (lmpassword.length < 14) lmpassword += '\0';     var key1 = ntlm.createkey(lmpassword);     var key2 = ntlm.createkey(lmpassword.substr(7));     var lmhashedpassword = des(key1, magic, 1, 0) + des(key2, magic, 1, 0);     var ntpassword = ''; // create nt password hash.     (var = 0; < password.length; i++)         ntpassword += password.charat(i) + '\0';     var nthashedpassword = str_md4(ntpassword);     ntlm.domain = domain;     ntlm.username = username;     ntlm.lmhashedpassword = lmhashedpassword;     ntlm.nthashedpassword = nthashedpassword; }; 

when log result of 'lmhashedpassword' after going through des() function, returns 'a'. whereas on android, returns longer string. in des function must cutting off, cannot see what.

here des function:

function des (key, message, encrypt, mode, iv, padding) {     //declaring locally speeds things bit     var spfunction1 = new array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);     var spfunction2 = new array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);     var spfunction3 = new array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);     var spfunction4 = new array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);     var spfunction5 = new array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);     var spfunction6 = new array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);     var spfunction7 = new array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);     var spfunction8 = new array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);      //create 16 or 48 subkeys need     var keys = des_createkeys (key);     var m=0, i, j, temp, temp2, right1, right2, left, right, looping;     var cbcleft, cbcleft2, cbcright, cbcright2     var endloop, loopinc;     var len = message.length;     var chunk = 0;     //set loops single , triple des     var iterations = keys.length == 32 ? 3 : 9; //single or triple des     if (iterations == 3) {looping = encrypt ? new array (0, 32, 2) : new array (30, -2, -2);}     else {looping = encrypt ? new array (0, 32, 2, 62, 30, -2, 64, 96, 2) : new array (94, 62, -2, 32, 64, 2, 30, -2, -2);}      //pad message depending on padding parameter     if (padding == 2) message += "        "; //pad message spaces     else if (padding == 1) {temp = 8-(len%8); message += string.fromcharcode (temp,temp,temp,temp,temp,temp,temp,temp); if (temp==8) len+=8;} //pkcs7 padding     else if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad message out null bytes      //store result here     result = "";     tempresult = "";      if (mode == 1) { //cbc mode         cbcleft = (iv.charcodeat(m++) << 24) | (iv.charcodeat(m++) << 16) | (iv.charcodeat(m++) << 8) | iv.charcodeat(m++);         cbcright = (iv.charcodeat(m++) << 24) | (iv.charcodeat(m++) << 16) | (iv.charcodeat(m++) << 8) | iv.charcodeat(m++);         m=0;     }      //loop through each 64 bit chunk of message     while (m < len) {         left = (message.charcodeat(m++) << 24) | (message.charcodeat(m++) << 16) | (message.charcodeat(m++) << 8) | message.charcodeat(m++);         right = (message.charcodeat(m++) << 24) | (message.charcodeat(m++) << 16) | (message.charcodeat(m++) << 8) | message.charcodeat(m++);          //for cipher block chaining mode, xor message previous result         if (mode == 1) {if (encrypt) {left ^= cbcleft; right ^= cbcright;} else {cbcleft2 = cbcleft; cbcright2 = cbcright; cbcleft = left; cbcright = right;}}          //first each 64 chunk of message must permuted according ip         temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);         temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);         temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);         temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);         temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);          left = ((left << 1) | (left >>> 31));         right = ((right << 1) | (right >>> 31));          //do either 1 or 3 times each chunk of message         (j=0; j<iterations; j+=3) {             endloop = looping[j+1];             loopinc = looping[j+2];             //now go through , perform encryption or decryption             (i=looping[j]; i!=endloop; i+=loopinc) { //for efficiency                 right1 = right ^ keys[i];                 right2 = ((right >>> 4) | (right << 28)) ^ keys[i+1];                 //the result attained passing these bytes through s selection functions                 temp = left;                 left = right;                 right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]                     | spfunction6[(right1 >>>  8) & 0x3f] | spfunction8[right1 & 0x3f]                     | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]                     | spfunction5[(right2 >>>  8) & 0x3f] | spfunction7[right2 & 0x3f]);             }             temp = left; left = right; right = temp; //unreverse left , right         } //for either 1 or 3 iterations          //move each 1 bit right         left = ((left >>> 1) | (left << 31));         right = ((right >>> 1) | (right << 31));          //now perform ip-1, ip in opposite direction         temp = ((left >>> 1) ^ right) & 0x55555555; right ^= temp; left ^= (temp << 1);         temp = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= temp; right ^= (temp << 8);         temp = ((right >>> 2) ^ left) & 0x33333333; left ^= temp; right ^= (temp << 2);         temp = ((left >>> 16) ^ right) & 0x0000ffff; right ^= temp; left ^= (temp << 16);         temp = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= temp; left ^= (temp << 4);          //for cipher block chaining mode, xor message previous result         if (mode == 1) {if (encrypt) {cbcleft = left; cbcright = right;} else {left ^= cbcleft2; right ^= cbcright2;}}         tempresult += string.fromcharcode ((left>>>24), ((left>>>16) & 0xff), ((left>>>8) & 0xff), (left & 0xff), (right>>>24), ((right>>>16) & 0xff), ((right>>>8) & 0xff), (right & 0xff));          chunk += 8;         if (chunk == 512) {result += tempresult; tempresult = ""; chunk = 0;}     } //for every 8 characters, or 64 bits in message      //return result array     return result + tempresult; } //end of des 

in case may relevant, have changed way request made too. when user clicks login, following promise called:

ntlm.login('url')             .then(() => {                 console.log('success');                 appsettings.setstring('token', 'abc123');                 this.router.navigate(['/ilt']);             })             .catch(error => {                 console.log('failed');                 appsettings.remove('token');                 alert('failed! ' + error );             }) 

i created new login function in ntlm.js file:

ntlm.login = function(url) {      return new promise((resolve, reject) => {         if (!ntlm.domain || !ntlm.username || !ntlm.lmhashedpassword || !ntlm.nthashedpassword) {              ntlm.error('no ntlm credentials specified. use ntlm.setcredentials(...) before making calls.');         }         var hostname = ntlm.getlocation(url).hostname;         var msg1 = ntlm.createmessage1(hostname);         var request = new xmlhttprequest();          request.onload = function() {             var response = request.getresponseheader('www-authenticate');             var challenge = ntlm.getchallenge(response);              var msg3 = ntlm.createmessage3(challenge, hostname);             request.open('get', url, false);             var authorization = 'ntlm ' + msg3.tobase64();             request.setrequestheader('authorization', authorization);              request.onload = function() {                 if (request.readystate == 4 && request.status == 200) {                     resolve(request.status);                 }                 else if (request.readystate == 4 && request.status != 200) {                     reject(request.status);                 }             };             request.send(null);         };         request.open('get', url, false);         request.setrequestheader('authorization', 'ntlm ' + msg1.tobase64());         request.send(null);        })  }; 

this working fine on android version, cant understand why isnt on ios. frustrating! if can make sense of this, eternally grateful. realise lot of code , quite niche area!

many thanks,


update

i think there may difference in way console.log behaves in android , ios, explain of missing characters. created new test account (testuser / testing), , logged various points try , establish happening in ntlm process step step. here logs android:

ntlm walkthrough on android  step 1: creates cryptographic hash of users password: lmhashedpassword = -ue}{}*ªÓ´5µî nthashedpassword = |sÏ¥ê}�;�� ûq£õ  step 2: sends first request server, following authorisation header: ntlm tlrmtvntuaabaaaaa7iaaauabqbeaaaajaakacaaaabhqvrfv0fzllnuuefvtfndqvrit0xjq0nptexfr0uuq08uvutbre1jtg==  step 3: server sends challenge client: ¡2@�³q%Ï  step 4: client encrypts challenge hash of users password , sends server (response). authorization header is: ntlm tlrmtvntuaadaaaagaayakqaaaayabgavaaaaaoacgbaaaaaegasaeoaaabiaegaxaaaaaaaaaduaaaaayiaaeearabnaekatgb0aguacwb0ahmadabhagyazgbhaeeavabfafcaqqbzac4auwbuafaaqqbvaewauwbdaeeavabiae8atabjaemaqwbpaewatabfaecarqauaematwauafuaswbseslcvtqhhy3+rgktqufbzfrmuffknkahxjrca6thoau105+njbgnsn2ri6ziuv8=  step 5: server has sent username, challenge , response domain controller. dc compares , returns status of: 200 

here logs ios:

ntlm walkthrough on ios  step 1: creates cryptographic hash of users password: lmhashedpassword = -ue}{}*ªÓ´5µî nthashedpassword = |sÏ¥ê}�;�� ûq£õ  step 2: sends first request server, following authorisation header: ntlm tlrmtvntuaabaaaaa7iaaauabqbeaaaajaakacaaaabhqvrfv0fzllnuuefvtfndqvrit0xjq0nptexfr0uuq08uvutbre1jtg==  step 3: server sends challenge client: q�v¹,  step 4: client encrypts challenge hash of users password , sends server (response). authorization header is: ntlm tlrmtvntuaadaaaagaayakqaaaayabgavaaaaaoacgbaaaaaegasaeoaaabiaegaxaaaaaaaaaduaaaaayiaaeearabnaekatgb0aguacwb0ahmadabhagyazgbhaeeavabfafcaqqbzac4auwbuafaaqqbvaewauwbdaeeavabiae8atabjaemaqwbpaewatabfaecarqauaematwauafuaswap9hn5wjpcs9hmrrmttnyhiefrthwyuawankwtvdzoqdoj2isudqev0ismv9tt0ek=  step 5: server has sent username, challenge , response domain controller. dc compares returns status of: 401 

seems credentials worked out same, , challenge returned server random. on ios, challenge seems missing characters - possibly due type of characters. client encrypts challenge hashed passwords , sends server. imagine might part not correct on ios.


Comments

Popular posts from this blog

php - Vagrant up error - Uncaught Reflection Exception: Class DOMDocument does not exist -

vue.js - Create hooks for automated testing -

Add new key value to json node in java -