// NTLM (ntlm.js) authentication in JavaScript.// ------------------------------------------------------------------------// The MIT License (MIT). Copyright (c) 2012 Erland Ranvinge.// Permission is hereby granted, free of charge, to any person obtaining// a copy of this software and associated documentation files (the// "Software"), to deal in the Software without restriction, including// without limitation the rights to use, copy, modify, merge, publish,// distribute, sublicense, and/or sell copies of the Software, and to// permit persons to whom the Software is furnished to do so, subject to// the following conditions:// The above copyright notice and this permission notice shall be// included in all copies or substantial portions of the Software.// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WARNING: This file has been modified from the original work:// Ntlm.authenticate method has been updated to operate asynchronously var Msg = function(data) { this.data = []; if (!data) return; if (data.indexOf("NTLM ") === 0) data = data.substr(5); atob(data).split("").map(function(c) { this.push(c.charCodeAt(0)); }, this.data);}; Msg.prototype.addByte = function(b) { this.data.push(b);}; Msg.prototype.addShort = function(s) { this.data.push(s & 0xFF); this.data.push((s >> 8) & 0xFF);}; Msg.prototype.addString = function(str, utf16) { if (utf16) // Fake UTF16 by padding each character in string. str = str.split("").map(function(c) { return (c + "\0"); }).join(""); for (let i = 0; i < str.length; i++) this.data.push(str.charCodeAt(i));}; Msg.prototype.getString = function(offset, length) { var result = ""; for (let i = 0; i < length; i++) { if (offset + i >= this.data.length) return ""; result += String.fromCharCode(this.data[offset + i]); } return result;}; Msg.prototype.getByte = function(offset) { return this.data[offset];}; Msg.prototype.toBase64 = function() { const str = String.fromCharCode.apply(null, this.data); return btoa(str).replace(/.{76}(?=.)/g,"$&");}; var Ntlm = {}; Ntlm.domain = null;Ntlm.username = null;Ntlm.lmHashedPassword = null;Ntlm.ntHashedPassword = null; Ntlm.error = function(msg) { console.error(msg);}; Ntlm.message = function(msg) { console.log(msg);}; Ntlm.createMessage1 = function(hostname) { const msg1 = new Msg(); msg1.addString("NTLMSSP\0"); msg1.addByte(1); msg1.addString("\0\0\0"); msg1.addShort(0xb203); msg1.addString("\0\0"); msg1.addShort(Ntlm.domain.length); msg1.addShort(Ntlm.domain.length); msg1.addShort(32 + hostname.length); msg1.addString("\0\0"); msg1.addShort(hostname.length); msg1.addShort(hostname.length); msg1.addShort(32); msg1.addString("\0\0"); msg1.addString(hostname.toUpperCase()); msg1.addString(Ntlm.domain.toUpperCase()); return msg1;}; Ntlm.getChallenge = function(data) { const msg2 = new Msg(data); if (msg2.getString(0, 8) !== "NTLMSSP\0") { Ntlm.error("Invalid NTLM response header."); return ""; } if (msg2.getByte(8) !== 2) { Ntlm.error("Invalid NTLM response type."); return ""; } const challenge = msg2.getString(24, 8); return challenge;}; Ntlm.createMessage3 = function(challenge, hostname) { var lmResponse = Ntlm.buildResponse(Ntlm.lmHashedPassword, challenge); var ntResponse = Ntlm.buildResponse(Ntlm.ntHashedPassword, challenge); var username = Ntlm.username; var domain = Ntlm.domain; var msg3 = new Msg(); msg3.addString("NTLMSSP\0"); msg3.addByte(3); msg3.addString("\0\0\0"); msg3.addShort(24); // lmResponse msg3.addShort(24); msg3.addShort(64 + (domain.length + username.length + hostname.length) * 2); msg3.addString("\0\0"); msg3.addShort(24); // ntResponse msg3.addShort(24); msg3.addShort(88 + (domain.length + username.length + hostname.length) * 2); msg3.addString("\0\0"); msg3.addShort(domain.length * 2); // Domain. msg3.addShort(domain.length * 2); msg3.addShort(64); msg3.addString("\0\0"); msg3.addShort(username.length * 2); // Username. msg3.addShort(username.length * 2); msg3.addShort(64 + domain.length * 2); msg3.addShort("\0\0"); msg3.addShort(hostname.length * 2); // Hostname. msg3.addShort(hostname.length * 2); msg3.addShort(64 + (domain.length + username.length) * 2); msg3.addString("\0\0"); msg3.addString("\0\0\0\0"); msg3.addShort(112 + (domain.length + username.length + hostname.length) * 2); msg3.addString("\0\0"); msg3.addShort(0x8201); msg3.addString("\0\0"); msg3.addString(domain.toUpperCase(), true); // "Some" string are passed as UTF-16. msg3.addString(username, true); msg3.addString(hostname.toUpperCase(), true); msg3.addString(lmResponse); msg3.addString(ntResponse); return msg3;}; Ntlm.createKey = function(str) { const key56 = []; while (str.length < 7) str += "\0"; str = str.substr(0, 7); str.split("").map(function(c) { this.push(c.charCodeAt(0)); }, key56); const key = [0, 0, 0, 0, 0, 0, 0, 0]; key[0] = key56[0]; // Convert 56 bit key to 64 bit. key[1] = ((key56[0] << 7) & 0xFF) | (key56[1] >> 1); key[2] = ((key56[1] << 6) & 0xFF) | (key56[2] >> 2); key[3] = ((key56[2] << 5) & 0xFF) | (key56[3] >> 3); key[4] = ((key56[3] << 4) & 0xFF) | (key56[4] >> 4); key[5] = ((key56[4] << 3) & 0xFF) | (key56[5] >> 5); key[6] = ((key56[5] << 2) & 0xFF) | (key56[6] >> 6); key[7] = (key56[6] << 1) & 0xFF; for (let i = 0; i < key.length; i++) { // Fix DES key parity bits. let bit = 0; for (let k = 0; k < 7; k++) { const t = key[i] >> k; bit = (t ^ bit) & 0x1; } key[i] = (key[i] & 0xFE) | bit; } var result = ""; key.map(function(i) { result += String.fromCharCode(i); }); return result;}; Ntlm.buildResponse = function(key, text) { while (key.length < 21) key += "\0"; const key1 = Ntlm.createKey(key.substr(0, 7)); const key2 = Ntlm.createKey(key.substr(7, 7)); const key3 = Ntlm.createKey(key.substr(14, 7)); return des(key1, text, 1, 0) + des(key2, text, 1, 0) + des(key3, text, 1, 0);}; Ntlm.getLocation = function(url) { const l = document.createElement("a"); l.href = url; return l;}; Ntlm.setCredentials = function(domain, username, password) { const magic = "KGS!@#$%"; // Create LM password hash. var lmPassword = password.toUpperCase().substr(0, 14); while (lmPassword.length < 14) lmPassword += "\0"; const key1 = Ntlm.createKey(lmPassword); const key2 = Ntlm.createKey(lmPassword.substr(7)); const lmHashedPassword = des(key1, magic, 1, 0) + des(key2, magic, 1, 0); var ntPassword = ""; // Create NT password hash. for (let i = 0; i < password.length; i++) ntPassword += password.charAt(i) + "\0"; const ntHashedPassword = str_md4(ntPassword); Ntlm.domain = domain; Ntlm.username = username; Ntlm.lmHashedPassword = lmHashedPassword; Ntlm.ntHashedPassword = ntHashedPassword;}; Ntlm.isChallenge = function(xhr) { if (!xhr) return false; if (xhr.status !== 401) return false; const header = xhr.getResponseHeader("WWW-Authenticate"); return header && header.indexOf("NTLM") !== -1;}; Ntlm.authenticate = function(url, handleResponse, verificationHeader, verificationValue) { if (!Ntlm.domain || !Ntlm.username || !Ntlm.lmHashedPassword || !Ntlm.ntHashedPassword) { Ntlm.error("No NTLM credentials specified. Use Ntlm.setCredentials(...) before making calls."); return; } if (url.startsWith("/")) url = window.location.protocol + "//" + window.location.host + url; var hostname = Ntlm.getLocation(url).hostname; if (!hostname) hostname = window.location.hostname; $.ajax({ url: url, cache: false, crossDomain: false, xhrFields: { withCredentials: true }, complete: function (xhr) { switch (xhr.status) { case 401: $.ajax({ url: url, cache: false, crossDomain: false, xhrFields: { withCredentials: true }, complete: function (xhr2) { handleResponse(xhr2.statusCode()); }, beforeSend: function (xhr2) { const response = xhr.getResponseHeader("WWW-Authenticate"); const challenge = Ntlm.getChallenge(response); const msg3 = Ntlm.createMessage3(challenge, hostname); xhr2.setRequestHeader("Authorization", "NTLM " + msg3.toBase64()); if (verificationHeader && verificationValue) xhr2.setRequestHeader(verificationHeader, verificationValue); } }); break; default: handleResponse(xhr.statusCode()); break; } }, beforeSend: function (xhr) { const msg1 = Ntlm.createMessage1(hostname); xhr.setRequestHeader("Authorization", "NTLM " + msg1.toBase64()); if (verificationHeader && verificationValue) xhr.setRequestHeader(verificationHeader, verificationValue); } });}; /* * A JavaScript implementation of the RSA Data Security, Inc. MD4 Message * Digest Algorithm, as defined in RFC 1320. * Version 2.1 Copyright (C) Jerrad Pierce, Paul Johnston 1999 - 2002. * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet * Distributed under the BSD License * See http://pajhome.org.uk/crypt/md5 for more info. */ var chrsz = 8; function str_md4(s){ return binl2str(core_md4(str2binl(s), s.length * chrsz));} function core_md4(x, len){ x[len >> 5] |= 0x80 << (len % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md4_ff(a, b, c, d, x[i+ 0], 3 ); d = md4_ff(d, a, b, c, x[i+ 1], 7 ); c = md4_ff(c, d, a, b, x[i+ 2], 11); b = md4_ff(b, c, d, a, x[i+ 3], 19); a = md4_ff(a, b, c, d, x[i+ 4], 3 ); d = md4_ff(d, a, b, c, x[i+ 5], 7 ); c = md4_ff(c, d, a, b, x[i+ 6], 11); b = md4_ff(b, c, d, a, x[i+ 7], 19); a = md4_ff(a, b, c, d, x[i+ 8], 3 ); d = md4_ff(d, a, b, c, x[i+ 9], 7 ); c = md4_ff(c, d, a, b, x[i+10], 11); b = md4_ff(b, c, d, a, x[i+11], 19); a = md4_ff(a, b, c, d, x[i+12], 3 ); d = md4_ff(d, a, b, c, x[i+13], 7 ); c = md4_ff(c, d, a, b, x[i+14], 11); b = md4_ff(b, c, d, a, x[i+15], 19); a = md4_gg(a, b, c, d, x[i+ 0], 3 ); d = md4_gg(d, a, b, c, x[i+ 4], 5 ); c = md4_gg(c, d, a, b, x[i+ 8], 9 ); b = md4_gg(b, c, d, a, x[i+12], 13); a = md4_gg(a, b, c, d, x[i+ 1], 3 ); d = md4_gg(d, a, b, c, x[i+ 5], 5 ); c = md4_gg(c, d, a, b, x[i+ 9], 9 ); b = md4_gg(b, c, d, a, x[i+13], 13); a = md4_gg(a, b, c, d, x[i+ 2], 3 ); d = md4_gg(d, a, b, c, x[i+ 6], 5 ); c = md4_gg(c, d, a, b, x[i+10], 9 ); b = md4_gg(b, c, d, a, x[i+14], 13); a = md4_gg(a, b, c, d, x[i+ 3], 3 ); d = md4_gg(d, a, b, c, x[i+ 7], 5 ); c = md4_gg(c, d, a, b, x[i+11], 9 ); b = md4_gg(b, c, d, a, x[i+15], 13); a = md4_hh(a, b, c, d, x[i+ 0], 3 ); d = md4_hh(d, a, b, c, x[i+ 8], 9 ); c = md4_hh(c, d, a, b, x[i+ 4], 11); b = md4_hh(b, c, d, a, x[i+12], 15); a = md4_hh(a, b, c, d, x[i+ 2], 3 ); d = md4_hh(d, a, b, c, x[i+10], 9 ); c = md4_hh(c, d, a, b, x[i+ 6], 11); b = md4_hh(b, c, d, a, x[i+14], 15); a = md4_hh(a, b, c, d, x[i+ 1], 3 ); d = md4_hh(d, a, b, c, x[i+ 9], 9 ); c = md4_hh(c, d, a, b, x[i+ 5], 11); b = md4_hh(b, c, d, a, x[i+13], 15); a = md4_hh(a, b, c, d, x[i+ 3], 3 ); d = md4_hh(d, a, b, c, x[i+11], 9 ); c = md4_hh(c, d, a, b, x[i+ 7], 11); b = md4_hh(b, c, d, a, x[i+15], 15); a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d);} function md4_cmn(q, a, b, x, s, t){ return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);} function md4_ff(a, b, c, d, x, s){ return md4_cmn((b & c) | ((~b) & d), a, 0, x, s, 0);} function md4_gg(a, b, c, d, x, s){ return md4_cmn((b & c) | (b & d) | (c & d), a, 0, x, s, 1518500249);} function md4_hh(a, b, c, d, x, s){ return md4_cmn(b ^ c ^ d, a, 0, x, s, 1859775393);} function safe_add(x, y){ const lsw = (x & 0xFFFF) + (y & 0xFFFF); const msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF);} function rol(num, cnt){ return (num << cnt) | (num >>> (32 - cnt));} function str2binl(str){ const bin = Array(); const mask = (1 << chrsz) - 1; for(let i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); return bin;} function binl2str(bin){ var str = ""; const mask = (1 << chrsz) - 1; for(let i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); return str;} //Paul Tero, July 2001//http://www.tero.co.uk/des/////Optimised for performance with large blocks by Michael Hayworth, November 2001//http://www.netdealing.com////THIS SOFTWARE IS PROVIDED "AS IS" AND//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF//SUCH DAMAGE. //des//this takes the key, the message, and whether to encrypt or decryptfunction des (key, message, encrypt, mode, iv, padding) { //declaring this locally speeds things up a 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 the 16 or 48 subkeys we will 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 up the loops for single and 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 the message depending on the padding parameter if (padding == 2) message += " "; //pad the message with spacesLines 1–500 of 648. Load more
// NTLM (ntlm.js) authentication in JavaScript. // ------------------------------------------------------------------------ // The MIT License (MIT). Copyright (c) 2012 Erland Ranvinge. // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WARNING: This file has been modified from the original work: // Ntlm.authenticate method has been updated to operate asynchronously var Msg = function(data) { this.data = []; if (!data) return; if (data.indexOf("NTLM ") === 0) data = data.substr(5); atob(data).split("").map(function(c) { this.push(c.charCodeAt(0)); }, this.data); }; Msg.prototype.addByte = function(b) { this.data.push(b); }; Msg.prototype.addShort = function(s) { this.data.push(s & 0xFF); this.data.push((s >> 8) & 0xFF); }; Msg.prototype.addString = function(str, utf16) { if (utf16) // Fake UTF16 by padding each character in string. str = str.split("").map(function(c) { return (c + "\0"); }).join(""); for (let i = 0; i < str.length; i++) this.data.push(str.charCodeAt(i)); }; Msg.prototype.getString = function(offset, length) { var result = ""; for (let i = 0; i < length; i++) { if (offset + i >= this.data.length) return ""; result += String.fromCharCode(this.data[offset + i]); } return result; }; Msg.prototype.getByte = function(offset) { return this.data[offset]; }; Msg.prototype.toBase64 = function() { const str = String.fromCharCode.apply(null, this.data); return btoa(str).replace(/.{76}(?=.)/g,"$&"); }; var Ntlm = {}; Ntlm.domain = null; Ntlm.username = null; Ntlm.lmHashedPassword = null; Ntlm.ntHashedPassword = null; Ntlm.error = function(msg) { console.error(msg); }; Ntlm.message = function(msg) { console.log(msg); }; Ntlm.createMessage1 = function(hostname) { const msg1 = new Msg(); msg1.addString("NTLMSSP\0"); msg1.addByte(1); msg1.addString("\0\0\0"); msg1.addShort(0xb203); msg1.addString("\0\0"); msg1.addShort(Ntlm.domain.length); msg1.addShort(Ntlm.domain.length); msg1.addShort(32 + hostname.length); msg1.addString("\0\0"); msg1.addShort(hostname.length); msg1.addShort(hostname.length); msg1.addShort(32); msg1.addString("\0\0"); msg1.addString(hostname.toUpperCase()); msg1.addString(Ntlm.domain.toUpperCase()); return msg1; }; Ntlm.getChallenge = function(data) { const msg2 = new Msg(data); if (msg2.getString(0, 8) !== "NTLMSSP\0") { Ntlm.error("Invalid NTLM response header."); return ""; } if (msg2.getByte(8) !== 2) { Ntlm.error("Invalid NTLM response type."); return ""; } const challenge = msg2.getString(24, 8); return challenge; }; Ntlm.createMessage3 = function(challenge, hostname) { var lmResponse = Ntlm.buildResponse(Ntlm.lmHashedPassword, challenge); var ntResponse = Ntlm.buildResponse(Ntlm.ntHashedPassword, challenge); var username = Ntlm.username; var domain = Ntlm.domain; var msg3 = new Msg(); msg3.addString("NTLMSSP\0"); msg3.addByte(3); msg3.addString("\0\0\0"); msg3.addShort(24); // lmResponse msg3.addShort(24); msg3.addShort(64 + (domain.length + username.length + hostname.length) * 2); msg3.addString("\0\0"); msg3.addShort(24); // ntResponse msg3.addShort(24); msg3.addShort(88 + (domain.length + username.length + hostname.length) * 2); msg3.addString("\0\0"); msg3.addShort(domain.length * 2); // Domain. msg3.addShort(domain.length * 2); msg3.addShort(64); msg3.addString("\0\0"); msg3.addShort(username.length * 2); // Username. msg3.addShort(username.length * 2); msg3.addShort(64 + domain.length * 2); msg3.addShort("\0\0"); msg3.addShort(hostname.length * 2); // Hostname. msg3.addShort(hostname.length * 2); msg3.addShort(64 + (domain.length + username.length) * 2); msg3.addString("\0\0"); msg3.addString("\0\0\0\0"); msg3.addShort(112 + (domain.length + username.length + hostname.length) * 2); msg3.addString("\0\0"); msg3.addShort(0x8201); msg3.addString("\0\0"); msg3.addString(domain.toUpperCase(), true); // "Some" string are passed as UTF-16. msg3.addString(username, true); msg3.addString(hostname.toUpperCase(), true); msg3.addString(lmResponse); msg3.addString(ntResponse); return msg3; }; Ntlm.createKey = function(str) { const key56 = []; while (str.length < 7) str += "\0"; str = str.substr(0, 7); str.split("").map(function(c) { this.push(c.charCodeAt(0)); }, key56); const key = [0, 0, 0, 0, 0, 0, 0, 0]; key[0] = key56[0]; // Convert 56 bit key to 64 bit. key[1] = ((key56[0] << 7) & 0xFF) | (key56[1] >> 1); key[2] = ((key56[1] << 6) & 0xFF) | (key56[2] >> 2); key[3] = ((key56[2] << 5) & 0xFF) | (key56[3] >> 3); key[4] = ((key56[3] << 4) & 0xFF) | (key56[4] >> 4); key[5] = ((key56[4] << 3) & 0xFF) | (key56[5] >> 5); key[6] = ((key56[5] << 2) & 0xFF) | (key56[6] >> 6); key[7] = (key56[6] << 1) & 0xFF; for (let i = 0; i < key.length; i++) { // Fix DES key parity bits. let bit = 0; for (let k = 0; k < 7; k++) { const t = key[i] >> k; bit = (t ^ bit) & 0x1; } key[i] = (key[i] & 0xFE) | bit; } var result = ""; key.map(function(i) { result += String.fromCharCode(i); }); return result; }; Ntlm.buildResponse = function(key, text) { while (key.length < 21) key += "\0"; const key1 = Ntlm.createKey(key.substr(0, 7)); const key2 = Ntlm.createKey(key.substr(7, 7)); const key3 = Ntlm.createKey(key.substr(14, 7)); return des(key1, text, 1, 0) + des(key2, text, 1, 0) + des(key3, text, 1, 0); }; Ntlm.getLocation = function(url) { const l = document.createElement("a"); l.href = url; return l; }; Ntlm.setCredentials = function(domain, username, password) { const magic = "KGS!@#$%"; // Create LM password hash. var lmPassword = password.toUpperCase().substr(0, 14); while (lmPassword.length < 14) lmPassword += "\0"; const key1 = Ntlm.createKey(lmPassword); const key2 = Ntlm.createKey(lmPassword.substr(7)); const lmHashedPassword = des(key1, magic, 1, 0) + des(key2, magic, 1, 0); var ntPassword = ""; // Create NT password hash. for (let i = 0; i < password.length; i++) ntPassword += password.charAt(i) + "\0"; const ntHashedPassword = str_md4(ntPassword); Ntlm.domain = domain; Ntlm.username = username; Ntlm.lmHashedPassword = lmHashedPassword; Ntlm.ntHashedPassword = ntHashedPassword; }; Ntlm.isChallenge = function(xhr) { if (!xhr) return false; if (xhr.status !== 401) return false; const header = xhr.getResponseHeader("WWW-Authenticate"); return header && header.indexOf("NTLM") !== -1; }; Ntlm.authenticate = function(url, handleResponse, verificationHeader, verificationValue) { if (!Ntlm.domain || !Ntlm.username || !Ntlm.lmHashedPassword || !Ntlm.ntHashedPassword) { Ntlm.error("No NTLM credentials specified. Use Ntlm.setCredentials(...) before making calls."); return; } if (url.startsWith("/")) url = window.location.protocol + "//" + window.location.host + url; var hostname = Ntlm.getLocation(url).hostname; if (!hostname) hostname = window.location.hostname; $.ajax({ url: url, cache: false, crossDomain: false, xhrFields: { withCredentials: true }, complete: function (xhr) { switch (xhr.status) { case 401: $.ajax({ url: url, cache: false, crossDomain: false, xhrFields: { withCredentials: true }, complete: function (xhr2) { handleResponse(xhr2.statusCode()); }, beforeSend: function (xhr2) { const response = xhr.getResponseHeader("WWW-Authenticate"); const challenge = Ntlm.getChallenge(response); const msg3 = Ntlm.createMessage3(challenge, hostname); xhr2.setRequestHeader("Authorization", "NTLM " + msg3.toBase64()); if (verificationHeader && verificationValue) xhr2.setRequestHeader(verificationHeader, verificationValue); } }); break; default: handleResponse(xhr.statusCode()); break; } }, beforeSend: function (xhr) { const msg1 = Ntlm.createMessage1(hostname); xhr.setRequestHeader("Authorization", "NTLM " + msg1.toBase64()); if (verificationHeader && verificationValue) xhr.setRequestHeader(verificationHeader, verificationValue); } }); }; /* * A JavaScript implementation of the RSA Data Security, Inc. MD4 Message * Digest Algorithm, as defined in RFC 1320. * Version 2.1 Copyright (C) Jerrad Pierce, Paul Johnston 1999 - 2002. * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet * Distributed under the BSD License * See http://pajhome.org.uk/crypt/md5 for more info. */ var chrsz = 8; function str_md4(s){ return binl2str(core_md4(str2binl(s), s.length * chrsz));} function core_md4(x, len) { x[len >> 5] |= 0x80 << (len % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md4_ff(a, b, c, d, x[i+ 0], 3 ); d = md4_ff(d, a, b, c, x[i+ 1], 7 ); c = md4_ff(c, d, a, b, x[i+ 2], 11); b = md4_ff(b, c, d, a, x[i+ 3], 19); a = md4_ff(a, b, c, d, x[i+ 4], 3 ); d = md4_ff(d, a, b, c, x[i+ 5], 7 ); c = md4_ff(c, d, a, b, x[i+ 6], 11); b = md4_ff(b, c, d, a, x[i+ 7], 19); a = md4_ff(a, b, c, d, x[i+ 8], 3 ); d = md4_ff(d, a, b, c, x[i+ 9], 7 ); c = md4_ff(c, d, a, b, x[i+10], 11); b = md4_ff(b, c, d, a, x[i+11], 19); a = md4_ff(a, b, c, d, x[i+12], 3 ); d = md4_ff(d, a, b, c, x[i+13], 7 ); c = md4_ff(c, d, a, b, x[i+14], 11); b = md4_ff(b, c, d, a, x[i+15], 19); a = md4_gg(a, b, c, d, x[i+ 0], 3 ); d = md4_gg(d, a, b, c, x[i+ 4], 5 ); c = md4_gg(c, d, a, b, x[i+ 8], 9 ); b = md4_gg(b, c, d, a, x[i+12], 13); a = md4_gg(a, b, c, d, x[i+ 1], 3 ); d = md4_gg(d, a, b, c, x[i+ 5], 5 ); c = md4_gg(c, d, a, b, x[i+ 9], 9 ); b = md4_gg(b, c, d, a, x[i+13], 13); a = md4_gg(a, b, c, d, x[i+ 2], 3 ); d = md4_gg(d, a, b, c, x[i+ 6], 5 ); c = md4_gg(c, d, a, b, x[i+10], 9 ); b = md4_gg(b, c, d, a, x[i+14], 13); a = md4_gg(a, b, c, d, x[i+ 3], 3 ); d = md4_gg(d, a, b, c, x[i+ 7], 5 ); c = md4_gg(c, d, a, b, x[i+11], 9 ); b = md4_gg(b, c, d, a, x[i+15], 13); a = md4_hh(a, b, c, d, x[i+ 0], 3 ); d = md4_hh(d, a, b, c, x[i+ 8], 9 ); c = md4_hh(c, d, a, b, x[i+ 4], 11); b = md4_hh(b, c, d, a, x[i+12], 15); a = md4_hh(a, b, c, d, x[i+ 2], 3 ); d = md4_hh(d, a, b, c, x[i+10], 9 ); c = md4_hh(c, d, a, b, x[i+ 6], 11); b = md4_hh(b, c, d, a, x[i+14], 15); a = md4_hh(a, b, c, d, x[i+ 1], 3 ); d = md4_hh(d, a, b, c, x[i+ 9], 9 ); c = md4_hh(c, d, a, b, x[i+ 5], 11); b = md4_hh(b, c, d, a, x[i+13], 15); a = md4_hh(a, b, c, d, x[i+ 3], 3 ); d = md4_hh(d, a, b, c, x[i+11], 9 ); c = md4_hh(c, d, a, b, x[i+ 7], 11); b = md4_hh(b, c, d, a, x[i+15], 15); a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); } function md4_cmn(q, a, b, x, s, t) { return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); } function md4_ff(a, b, c, d, x, s) { return md4_cmn((b & c) | ((~b) & d), a, 0, x, s, 0); } function md4_gg(a, b, c, d, x, s) { return md4_cmn((b & c) | (b & d) | (c & d), a, 0, x, s, 1518500249); } function md4_hh(a, b, c, d, x, s) { return md4_cmn(b ^ c ^ d, a, 0, x, s, 1859775393); } function safe_add(x, y) { const lsw = (x & 0xFFFF) + (y & 0xFFFF); const msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } function rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); } function str2binl(str) { const bin = Array(); const mask = (1 << chrsz) - 1; for(let i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); return bin; } function binl2str(bin) { var str = ""; const mask = (1 << chrsz) - 1; for(let i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); return str; } //Paul Tero, July 2001 //http://www.tero.co.uk/des/ // //Optimised for performance with large blocks by Michael Hayworth, November 2001 //http://www.netdealing.com // //THIS SOFTWARE IS PROVIDED "AS IS" AND //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE //IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE //ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE //FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL //DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS //OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) //HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY //OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF //SUCH DAMAGE. //des //this takes the key, the message, and whether to encrypt or decrypt function des (key, message, encrypt, mode, iv, padding) { //declaring this locally speeds things up a 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 the 16 or 48 subkeys we will 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 up the loops for single and 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 the message depending on the padding parameter if (padding == 2) message += " "; //pad the message with spaces