• ntlm.js
  • 'use strict';
    // Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/ntlm.js
    var os = require('os'), flags = require('./flags'), hash = require('./hash');
    var NTLMSIGNATURE = "NTLMSSP\0";
    function createType1Message(workstation, target) {
        var dataPos = 32, pos = 0, buf = new Buffer.alloc(1024);
        workstation = workstation === undefined ? os.hostname() : workstation;
        target = target === undefined ? '' : target;
        //signature
        buf.write(NTLMSIGNATURE, pos, NTLMSIGNATURE.length, 'ascii');
        pos += NTLMSIGNATURE.length;
        //message type
        buf.writeUInt32LE(1, pos);
        pos += 4;
        //flags
        buf.writeUInt32LE(flags.NTLMFLAG_NEGOTIATE_OEM |
            flags.NTLMFLAG_REQUEST_TARGET |
            flags.NTLMFLAG_NEGOTIATE_NTLM_KEY |
            flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY |
            flags.NTLMFLAG_NEGOTIATE_ALWAYS_SIGN, pos);
        pos += 4;
        //domain security buffer
        buf.writeUInt16LE(target.length, pos);
        pos += 2;
        buf.writeUInt16LE(target.length, pos);
        pos += 2;
        buf.writeUInt32LE(target.length === 0 ? 0 : dataPos, pos);
        pos += 4;
        if (target.length > 0) {
            dataPos += buf.write(target, dataPos, 'ascii');
        }
        //workstation security buffer
        buf.writeUInt16LE(workstation.length, pos);
        pos += 2;
        buf.writeUInt16LE(workstation.length, pos);
        pos += 2;
        buf.writeUInt32LE(workstation.length === 0 ? 0 : dataPos, pos);
        pos += 4;
        if (workstation.length > 0) {
            dataPos += buf.write(workstation, dataPos, 'ascii');
        }
        return 'NTLM ' + buf.toString('base64', 0, dataPos);
    }
    function decodeType2Message(str) {
        if (str === undefined) {
            throw new Error('Invalid argument');
        }
        //convenience
        if (Object.prototype.toString.call(str) !== '[object String]') {
            if (str.hasOwnProperty('headers') && str.headers.hasOwnProperty('www-authenticate')) {
                str = str.headers['www-authenticate'];
            }
            else {
                throw new Error('Invalid argument');
            }
        }
        var ntlmMatch = /^NTLM ([^,\s]+)/.exec(str);
        if (ntlmMatch) {
            str = ntlmMatch[1];
        }
        var buf = new Buffer.from(str, 'base64'), obj = {};
        //check signature
        if (buf.toString('ascii', 0, NTLMSIGNATURE.length) !== NTLMSIGNATURE) {
            throw new Error('Invalid message signature: ' + str);
        }
        //check message type
        if (buf.readUInt32LE(NTLMSIGNATURE.length) !== 2) {
            throw new Error('Invalid message type (no type 2)');
        }
        //read flags
        obj.flags = buf.readUInt32LE(20);
        obj.encoding = (obj.flags & flags.NTLMFLAG_NEGOTIATE_OEM) ? 'ascii' : 'ucs2';
        obj.version = (obj.flags & flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY) ? 2 : 1;
        obj.challenge = buf.slice(24, 32);
        //read target name
        obj.targetName = (function () {
            var length = buf.readUInt16LE(12);
            //skipping allocated space
            var offset = buf.readUInt32LE(16);
            if (length === 0) {
                return '';
            }
            if ((offset + length) > buf.length || offset < 32) {
                throw new Error('Bad type 2 message');
            }
            return buf.toString(obj.encoding, offset, offset + length);
        })();
        //read target info
        if (obj.flags & flags.NTLMFLAG_NEGOTIATE_TARGET_INFO) {
            obj.targetInfo = (function () {
                var info = {};
                var length = buf.readUInt16LE(40);
                //skipping allocated space
                var offset = buf.readUInt32LE(44);
                var targetInfoBuffer = new Buffer.alloc(length);
                buf.copy(targetInfoBuffer, 0, offset, offset + length);
                if (length === 0) {
                    return info;
                }
                if ((offset + length) > buf.length || offset < 32) {
                    throw new Error('Bad type 2 message');
                }
                var pos = offset;
                while (pos < (offset + length)) {
                    var blockType = buf.readUInt16LE(pos);
                    pos += 2;
                    var blockLength = buf.readUInt16LE(pos);
                    pos += 2;
                    if (blockType === 0) {
                        //reached the terminator subblock
                        break;
                    }
                    var blockTypeStr = void 0;
                    switch (blockType) {
                        case 1:
                            blockTypeStr = 'SERVER';
                            break;
                        case 2:
                            blockTypeStr = 'DOMAIN';
                            break;
                        case 3:
                            blockTypeStr = 'FQDN';
                            break;
                        case 4:
                            blockTypeStr = 'DNS';
                            break;
                        case 5:
                            blockTypeStr = 'PARENT_DNS';
                            break;
                        default:
                            blockTypeStr = '';
                            break;
                    }
                    if (blockTypeStr) {
                        info[blockTypeStr] = buf.toString('ucs2', pos, pos + blockLength);
                    }
                    pos += blockLength;
                }
                return {
                    parsed: info,
                    buffer: targetInfoBuffer
                };
            })();
        }
        return obj;
    }
    function createType3Message(type2Message, username, password, workstation, target) {
        var dataPos = 52, buf = new Buffer.alloc(1024);
        if (workstation === undefined) {
            workstation = os.hostname();
        }
        if (target === undefined) {
            target = type2Message.targetName;
        }
        //signature
        buf.write(NTLMSIGNATURE, 0, NTLMSIGNATURE.length, 'ascii');
        //message type
        buf.writeUInt32LE(3, 8);
        if (type2Message.version === 2) {
            dataPos = 64;
            var ntlmHash = hash.createNTLMHash(password), nonce = hash.createPseudoRandomValue(16), lmv2 = hash.createLMv2Response(type2Message, username, ntlmHash, nonce, target), ntlmv2 = hash.createNTLMv2Response(type2Message, username, ntlmHash, nonce, target);
            //lmv2 security buffer
            buf.writeUInt16LE(lmv2.length, 12);
            buf.writeUInt16LE(lmv2.length, 14);
            buf.writeUInt32LE(dataPos, 16);
            lmv2.copy(buf, dataPos);
            dataPos += lmv2.length;
            //ntlmv2 security buffer
            buf.writeUInt16LE(ntlmv2.length, 20);
            buf.writeUInt16LE(ntlmv2.length, 22);
            buf.writeUInt32LE(dataPos, 24);
            ntlmv2.copy(buf, dataPos);
            dataPos += ntlmv2.length;
        }
        else {
            var lmHash = hash.createLMHash(password), ntlmHash = hash.createNTLMHash(password), lm = hash.createLMResponse(type2Message.challenge, lmHash), ntlm = hash.createNTLMResponse(type2Message.challenge, ntlmHash);
            //lm security buffer
            buf.writeUInt16LE(lm.length, 12);
            buf.writeUInt16LE(lm.length, 14);
            buf.writeUInt32LE(dataPos, 16);
            lm.copy(buf, dataPos);
            dataPos += lm.length;
            //ntlm security buffer
            buf.writeUInt16LE(ntlm.length, 20);
            buf.writeUInt16LE(ntlm.length, 22);
            buf.writeUInt32LE(dataPos, 24);
            ntlm.copy(buf, dataPos);
            dataPos += ntlm.length;
        }
        //target name security buffer
        buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 28);
        buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 30);
        buf.writeUInt32LE(dataPos, 32);
        dataPos += buf.write(target, dataPos, type2Message.encoding);
        //user name security buffer
        buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 36);
        buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 38);
        buf.writeUInt32LE(dataPos, 40);
        dataPos += buf.write(username, dataPos, type2Message.encoding);
        //workstation name security buffer
        buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 44);
        buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 46);
        buf.writeUInt32LE(dataPos, 48);
        dataPos += buf.write(workstation, dataPos, type2Message.encoding);
        if (type2Message.version === 2) {
            //session key security buffer
            buf.writeUInt16LE(0, 52);
            buf.writeUInt16LE(0, 54);
            buf.writeUInt32LE(0, 56);
            //flags
            buf.writeUInt32LE(type2Message.flags, 60);
        }
        return 'NTLM ' + buf.toString('base64', 0, dataPos);
    }
    module.exports = {
        createType1Message: createType1Message,
        decodeType2Message: decodeType2Message,
        createType3Message: createType3Message
    };
    //# sourceMappingURL=ntlm.js.map