Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenSSL v3 is no longer compatible due to deprecation of DES Ciphers #9

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
.*.swp
.vscode
yarn.lock
35 changes: 32 additions & 3 deletions lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* Copyright (C) 2012 Joshua M. Clulow <[email protected]>
*/

var crypto = require('crypto');
var { DES } = require('des.js');
var md4 = require('js-md4');

function zeroextend(str, len)
{
Expand Down Expand Up @@ -46,7 +47,7 @@ function oddpar(buf)
*/
function expandkey(key56)
{
var key64 = new Buffer(8);
var key64 = Buffer.alloc(8);

key64[0] = key56[0] & 0xFE;
key64[1] = ((key56[0] << 7) & 0xFF) | (key56[1] >> 1);
Expand All @@ -65,13 +66,41 @@ function expandkey(key56)
*/
function bintohex(bin)
{
var buf = (Buffer.isBuffer(buf) ? buf : new Buffer(bin, 'binary'));
var buf = (Buffer.isBuffer(buf) ? buf : Buffer.from(bin, 'binary'));
var str = buf.toString('hex').toUpperCase();
return zeroextend(str, 32);
}

function calculateDES(key, message) {
var desKey = new Buffer.alloc(8);
desKey[0] = key[0] & 0xFE;
desKey[1] = ((key[0] << 7) & 0xFF) | (key[1] >> 1);
desKey[2] = ((key[1] << 6) & 0xFF) | (key[2] >> 2);
desKey[3] = ((key[2] << 5) & 0xFF) | (key[3] >> 3);
desKey[4] = ((key[3] << 4) & 0xFF) | (key[4] >> 4);
desKey[5] = ((key[4] << 3) & 0xFF) | (key[5] >> 5);
desKey[6] = ((key[5] << 2) & 0xFF) | (key[6] >> 6);
desKey[7] = (key[6] << 1) & 0xFF;
for (var i = 0; i < 8; i++) {
var parity = 0;
for (var j = 1; j < 8; j++) {
parity += (desKey[i] >> j) % 2;
}
desKey[i] |= (parity % 2) === 0 ? 1 : 0;
}
var des = DES.create({ type: 'encrypt', key: desKey});
return Buffer.from(des.update(message));
}

function calculateMD4(message) {
var md4sum = md4.create();
md4sum.update(new Buffer.from(message, 'ucs2'));
return Buffer.from(md4sum.buffer());
}

module.exports.zeroextend = zeroextend;
module.exports.oddpar = oddpar;
module.exports.expandkey = expandkey;
module.exports.bintohex = bintohex;
module.exports.calculateDES = calculateDES;
module.exports.calculateMD4 = calculateMD4;
49 changes: 21 additions & 28 deletions lib/ntlm.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@
* Copyright (C) 2012 Joshua M. Clulow <[email protected]>
*/

var log = console.log;
var crypto = require('crypto');
var $ = require('./common');
var lmhashbuf = require('./smbhash').lmhashbuf;
var nthashbuf = require('./smbhash').nthashbuf;

var { lmhashbuf, nthashbuf } = require('./smbhash');
var { URL } = require('url');

function encodeType1(hostname, ntdomain) {
hostname = hostname.toUpperCase();
Expand All @@ -28,7 +25,7 @@ function encodeType1(hostname, ntdomain) {
var ntdomainlen = Buffer.byteLength(ntdomain, 'ascii');

var pos = 0;
var buf = new Buffer(32 + hostnamelen + ntdomainlen);
var buf = Buffer.alloc(32 + hostnamelen + ntdomainlen);

buf.write('NTLMSSP', pos, 7, 'ascii'); // byte protocol[8];
pos += 7;
Expand Down Expand Up @@ -76,7 +73,6 @@ function encodeType1(hostname, ntdomain) {
return buf;
}


/*
*
*/
Expand All @@ -102,15 +98,10 @@ function encodeType3(username, hostname, ntdomain, nonce, password) {
hostname = hostname.toUpperCase();
ntdomain = ntdomain.toUpperCase();

var lmh = new Buffer(21);
lmhashbuf(password).copy(lmh);
lmh.fill(0x00, 16); // null pad to 21 bytes
var nth = new Buffer(21);
nthashbuf(password).copy(nth);
nth.fill(0x00, 16); // null pad to 21 bytes
const challenge = new Buffer.from(nonce, 'ascii')

var lmr = makeResponse(lmh, nonce);
var ntr = makeResponse(nth, nonce);
var lmr = makeResponse(lmhashbuf(password), challenge);
var ntr = makeResponse(nthashbuf(password), challenge);

var usernamelen = Buffer.byteLength(username, 'ucs2');
var hostnamelen = Buffer.byteLength(hostname, 'ucs2');
Expand All @@ -126,7 +117,7 @@ function encodeType3(username, hostname, ntdomain, nonce, password) {

var pos = 0;
var msg_len = 64 + ntdomainlen + usernamelen + hostnamelen + lmrlen + ntrlen;
var buf = new Buffer(msg_len);
var buf = Buffer.alloc(msg_len);

buf.write('NTLMSSP', pos, 7, 'ascii'); // byte protocol[8];
pos += 7;
Expand Down Expand Up @@ -203,16 +194,18 @@ function encodeType3(username, hostname, ntdomain, nonce, password) {
return buf;
}

function makeResponse(hash, nonce)
function makeResponse(lmhash, challenge)
{
var out = new Buffer(24);
for (var i = 0; i < 3; i++) {
var keybuf = $.oddpar($.expandkey(hash.slice(i * 7, i * 7 + 7)));
var des = crypto.createCipheriv('DES-ECB', keybuf, '');
var str = des.update(nonce.toString('binary'), 'binary', 'binary');
out.write(str, i * 8, i * 8 + 8, 'binary');
}
return out;
let buf = new Buffer.alloc(24),
pwBuffer = new Buffer.alloc(21).fill(0);

lmhash.copy(pwBuffer);

$.calculateDES(pwBuffer.slice(0, 7), challenge).copy(buf);
$.calculateDES(pwBuffer.slice(7, 14), challenge).copy(buf, 8);
$.calculateDES(pwBuffer.slice(14), challenge).copy(buf, 16);

return buf;
}

exports.encodeType1 = encodeType1;
Expand All @@ -226,9 +219,9 @@ exports.challengeHeader = function (hostname, domain) {
};

exports.responseHeader = function (res, url, domain, username, password) {
var serverNonce = new Buffer((res.headers['www-authenticate'].match(/^NTLM\s+(.+?)(,|\s+|$)/) || [])[1], 'base64');
var hostname = require('url').parse(url).hostname;
return 'NTLM ' + exports.encodeType3(username, hostname, domain, exports.decodeType2(serverNonce), password).toString('base64')
const serverNonce = Buffer.from((res.headers['www-authenticate'].match(/^NTLM\s+(.+?)(,|\s+|$)/) || [])[1], 'base64');
const hostname = new URL(url).hostname;
return 'NTLM ' + exports.encodeType3(username, hostname, domain, exports.decodeType2(serverNonce), password).toString('base64');
};

// Import smbhash module.
Expand Down
44 changes: 10 additions & 34 deletions lib/smbhash.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,53 +14,29 @@
* Copyright (C) 2011-2012 Joshua M. Clulow <[email protected]>
*/

var crypto = require('crypto');
var $ = require('./common');

/*
* Generate the LM Hash
*/
function lmhashbuf(inputstr)
{
/* ASCII --> uppercase */
var x = inputstr.substring(0, 14).toUpperCase();
var xl = Buffer.byteLength(x, 'ascii');
let pwBuffer = new Buffer.alloc(14),
magicKey = new Buffer.from('KGS!@#$%', 'ascii');

/* null pad to 14 bytes */
var y = new Buffer(14);
y.write(x, 0, xl, 'ascii');
y.fill(0, xl);
if (inputstr.length > 14) {
inputstr = inputstr.slice(0, 14);
}

/* insert odd parity bits in key */
var halves = [
$.oddpar($.expandkey(y.slice(0, 7))),
$.oddpar($.expandkey(y.slice(7, 14)))
];
pwBuffer.fill(0);
pwBuffer.write(inputstr.toUpperCase(), 0, 'ascii');

/* DES encrypt magic number "KGS!@#$%" to two
* 8-byte ciphertexts, (ECB, no padding)
*/
var buf = new Buffer(16);
var pos = 0;
var cts = halves.forEach(function(z) {
var des = crypto.createCipheriv('DES-ECB', z, '');
var str = des.update('KGS!@#$%', 'binary', 'binary');
buf.write(str, pos, pos + 8, 'binary');
pos += 8;
});

/* concat the two ciphertexts to form 16byte value,
* the LM hash */
return buf;
return Buffer.from([...$.calculateDES(pwBuffer.slice(0, 7), magicKey), ...$.calculateDES(pwBuffer.slice(7), magicKey)]);
}

function nthashbuf(str)
function nthashbuf(inputstr)
{
/* take MD4 hash of UCS-2 encoded password */
var ucs2 = new Buffer(str, 'ucs2');
var md4 = crypto.createHash('md4');
md4.update(ucs2);
return new Buffer(md4.digest('binary'), 'binary');
return $.calculateMD4(inputstr)
}

function lmhash(is)
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ntlm",
"version": "0.1.3",
"version": "0.2.1",
"devDependencies": {
"nodeunit": "*"
},
Expand All @@ -18,5 +18,9 @@
],
"main": "lib/ntlm.js",
"description": "NTLM authentication and Samba LM/NT hash library",
"homepage": "https://github.com/tcr/node-ntlm"
"homepage": "https://github.com/tcr/node-ntlm",
"dependencies": {
"des.js": "^1.1.0",
"js-md4": "^0.3.2"
}
}
6 changes: 3 additions & 3 deletions tests/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
var $ = require('../lib/common');

var GOOD = [
{ key56: new Buffer([0x53, 0x45, 0x43, 0x52, 0x45, 0x54, 0x30]),
raw64: new Buffer([0x52, 0xa2, 0x50, 0x6a, 0x24, 0x2a, 0x50, 0x60]),
par64: new Buffer([0x52, 0xa2, 0x51, 0x6b, 0x25, 0x2a, 0x51, 0x61])
{ key56: Buffer.from([0x53, 0x45, 0x43, 0x52, 0x45, 0x54, 0x30]),
raw64: Buffer.from([0x52, 0xa2, 0x50, 0x6a, 0x24, 0x2a, 0x50, 0x60]),
par64: Buffer.from([0x52, 0xa2, 0x51, 0x6b, 0x25, 0x2a, 0x51, 0x61])
}
];

Expand Down
2 changes: 1 addition & 1 deletion tests/ntlm.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ module.exports.type2_success = function(test) {
test.expect(GOOD.length * 1);
for (var i = 0; i < GOOD.length; i++) {
var g = GOOD[i];
var inbuf = new Buffer(g.messages[1], 'base64');
var inbuf = Buffer.from(g.messages[1], 'base64');
var out = $.decodeType2(inbuf);
test.strictEqual(out.toString('binary'), g.nonce);
}
Expand Down
3 changes: 1 addition & 2 deletions tests/smbhash.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* Copyright (C) 2011-2012 Joshua M. Clulow <[email protected]>
*/

var lmhash = require('..').smbhash.lmhash;
var nthash = require('..').smbhash.nthash;
const { lmhash, nthash } = require('../lib/smbhash');

var GOOD = [
{ password: 'pass123',
Expand Down