mirror of
https://github.com/gradle/gradle-build-action.git
synced 2024-10-19 12:11:11 +08:00
390 lines
14 KiB
JavaScript
390 lines
14 KiB
JavaScript
var crypto = require('crypto');
|
|
|
|
var flags = {
|
|
NTLM_NegotiateUnicode : 0x00000001,
|
|
NTLM_NegotiateOEM : 0x00000002,
|
|
NTLM_RequestTarget : 0x00000004,
|
|
NTLM_Unknown9 : 0x00000008,
|
|
NTLM_NegotiateSign : 0x00000010,
|
|
NTLM_NegotiateSeal : 0x00000020,
|
|
NTLM_NegotiateDatagram : 0x00000040,
|
|
NTLM_NegotiateLanManagerKey : 0x00000080,
|
|
NTLM_Unknown8 : 0x00000100,
|
|
NTLM_NegotiateNTLM : 0x00000200,
|
|
NTLM_NegotiateNTOnly : 0x00000400,
|
|
NTLM_Anonymous : 0x00000800,
|
|
NTLM_NegotiateOemDomainSupplied : 0x00001000,
|
|
NTLM_NegotiateOemWorkstationSupplied : 0x00002000,
|
|
NTLM_Unknown6 : 0x00004000,
|
|
NTLM_NegotiateAlwaysSign : 0x00008000,
|
|
NTLM_TargetTypeDomain : 0x00010000,
|
|
NTLM_TargetTypeServer : 0x00020000,
|
|
NTLM_TargetTypeShare : 0x00040000,
|
|
NTLM_NegotiateExtendedSecurity : 0x00080000,
|
|
NTLM_NegotiateIdentify : 0x00100000,
|
|
NTLM_Unknown5 : 0x00200000,
|
|
NTLM_RequestNonNTSessionKey : 0x00400000,
|
|
NTLM_NegotiateTargetInfo : 0x00800000,
|
|
NTLM_Unknown4 : 0x01000000,
|
|
NTLM_NegotiateVersion : 0x02000000,
|
|
NTLM_Unknown3 : 0x04000000,
|
|
NTLM_Unknown2 : 0x08000000,
|
|
NTLM_Unknown1 : 0x10000000,
|
|
NTLM_Negotiate128 : 0x20000000,
|
|
NTLM_NegotiateKeyExchange : 0x40000000,
|
|
NTLM_Negotiate56 : 0x80000000
|
|
};
|
|
var typeflags = {
|
|
NTLM_TYPE1_FLAGS : flags.NTLM_NegotiateUnicode
|
|
+ flags.NTLM_NegotiateOEM
|
|
+ flags.NTLM_RequestTarget
|
|
+ flags.NTLM_NegotiateNTLM
|
|
+ flags.NTLM_NegotiateOemDomainSupplied
|
|
+ flags.NTLM_NegotiateOemWorkstationSupplied
|
|
+ flags.NTLM_NegotiateAlwaysSign
|
|
+ flags.NTLM_NegotiateExtendedSecurity
|
|
+ flags.NTLM_NegotiateVersion
|
|
+ flags.NTLM_Negotiate128
|
|
+ flags.NTLM_Negotiate56,
|
|
|
|
NTLM_TYPE2_FLAGS : flags.NTLM_NegotiateUnicode
|
|
+ flags.NTLM_RequestTarget
|
|
+ flags.NTLM_NegotiateNTLM
|
|
+ flags.NTLM_NegotiateAlwaysSign
|
|
+ flags.NTLM_NegotiateExtendedSecurity
|
|
+ flags.NTLM_NegotiateTargetInfo
|
|
+ flags.NTLM_NegotiateVersion
|
|
+ flags.NTLM_Negotiate128
|
|
+ flags.NTLM_Negotiate56
|
|
};
|
|
|
|
function createType1Message(options){
|
|
var domain = escape(options.domain.toUpperCase());
|
|
var workstation = escape(options.workstation.toUpperCase());
|
|
var protocol = 'NTLMSSP\0';
|
|
|
|
var BODY_LENGTH = 40;
|
|
|
|
var type1flags = typeflags.NTLM_TYPE1_FLAGS;
|
|
if(!domain || domain === '')
|
|
type1flags = type1flags - flags.NTLM_NegotiateOemDomainSupplied;
|
|
|
|
var pos = 0;
|
|
var buf = new Buffer(BODY_LENGTH + domain.length + workstation.length);
|
|
|
|
|
|
buf.write(protocol, pos, protocol.length); pos += protocol.length; // protocol
|
|
buf.writeUInt32LE(1, pos); pos += 4; // type 1
|
|
buf.writeUInt32LE(type1flags, pos); pos += 4; // TYPE1 flag
|
|
|
|
buf.writeUInt16LE(domain.length, pos); pos += 2; // domain length
|
|
buf.writeUInt16LE(domain.length, pos); pos += 2; // domain max length
|
|
buf.writeUInt32LE(BODY_LENGTH + workstation.length, pos); pos += 4; // domain buffer offset
|
|
|
|
buf.writeUInt16LE(workstation.length, pos); pos += 2; // workstation length
|
|
buf.writeUInt16LE(workstation.length, pos); pos += 2; // workstation max length
|
|
buf.writeUInt32LE(BODY_LENGTH, pos); pos += 4; // workstation buffer offset
|
|
|
|
buf.writeUInt8(5, pos); pos += 1; //ProductMajorVersion
|
|
buf.writeUInt8(1, pos); pos += 1; //ProductMinorVersion
|
|
buf.writeUInt16LE(2600, pos); pos += 2; //ProductBuild
|
|
|
|
buf.writeUInt8(0 , pos); pos += 1; //VersionReserved1
|
|
buf.writeUInt8(0 , pos); pos += 1; //VersionReserved2
|
|
buf.writeUInt8(0 , pos); pos += 1; //VersionReserved3
|
|
buf.writeUInt8(15, pos); pos += 1; //NTLMRevisionCurrent
|
|
|
|
buf.write(workstation, pos, workstation.length, 'ascii'); pos += workstation.length; // workstation string
|
|
buf.write(domain , pos, domain.length , 'ascii'); pos += domain.length;
|
|
|
|
return 'NTLM ' + buf.toString('base64');
|
|
}
|
|
|
|
function parseType2Message(rawmsg, callback){
|
|
var match = rawmsg.match(/NTLM (.+)?/);
|
|
if(!match || !match[1])
|
|
return callback(new Error("Couldn't find NTLM in the message type2 comming from the server"));
|
|
|
|
var buf = new Buffer(match[1], 'base64');
|
|
|
|
var msg = {};
|
|
|
|
msg.signature = buf.slice(0, 8);
|
|
msg.type = buf.readInt16LE(8);
|
|
|
|
if(msg.type != 2)
|
|
return callback(new Error("Server didn't return a type 2 message"));
|
|
|
|
msg.targetNameLen = buf.readInt16LE(12);
|
|
msg.targetNameMaxLen = buf.readInt16LE(14);
|
|
msg.targetNameOffset = buf.readInt32LE(16);
|
|
msg.targetName = buf.slice(msg.targetNameOffset, msg.targetNameOffset + msg.targetNameMaxLen);
|
|
|
|
msg.negotiateFlags = buf.readInt32LE(20);
|
|
msg.serverChallenge = buf.slice(24, 32);
|
|
msg.reserved = buf.slice(32, 40);
|
|
|
|
if(msg.negotiateFlags & flags.NTLM_NegotiateTargetInfo){
|
|
msg.targetInfoLen = buf.readInt16LE(40);
|
|
msg.targetInfoMaxLen = buf.readInt16LE(42);
|
|
msg.targetInfoOffset = buf.readInt32LE(44);
|
|
msg.targetInfo = buf.slice(msg.targetInfoOffset, msg.targetInfoOffset + msg.targetInfoLen);
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
function createType3Message(msg2, options){
|
|
var nonce = msg2.serverChallenge;
|
|
var username = options.username;
|
|
var password = options.password;
|
|
var negotiateFlags = msg2.negotiateFlags;
|
|
|
|
var isUnicode = negotiateFlags & flags.NTLM_NegotiateUnicode;
|
|
var isNegotiateExtendedSecurity = negotiateFlags & flags.NTLM_NegotiateExtendedSecurity;
|
|
|
|
var BODY_LENGTH = 72;
|
|
|
|
var domainName = escape(options.domain.toUpperCase());
|
|
var workstation = escape(options.workstation.toUpperCase());
|
|
|
|
var workstationBytes, domainNameBytes, usernameBytes, encryptedRandomSessionKeyBytes;
|
|
|
|
var encryptedRandomSessionKey = "";
|
|
if(isUnicode){
|
|
workstationBytes = new Buffer(workstation, 'utf16le');
|
|
domainNameBytes = new Buffer(domainName, 'utf16le');
|
|
usernameBytes = new Buffer(username, 'utf16le');
|
|
encryptedRandomSessionKeyBytes = new Buffer(encryptedRandomSessionKey, 'utf16le');
|
|
}else{
|
|
workstationBytes = new Buffer(workstation, 'ascii');
|
|
domainNameBytes = new Buffer(domainName, 'ascii');
|
|
usernameBytes = new Buffer(username, 'ascii');
|
|
encryptedRandomSessionKeyBytes = new Buffer(encryptedRandomSessionKey, 'ascii');
|
|
}
|
|
|
|
var lmChallengeResponse = calc_resp(create_LM_hashed_password_v1(password), nonce);
|
|
var ntChallengeResponse = calc_resp(create_NT_hashed_password_v1(password), nonce);
|
|
|
|
if(isNegotiateExtendedSecurity){
|
|
var pwhash = create_NT_hashed_password_v1(password);
|
|
var clientChallenge = "";
|
|
for(var i=0; i < 8; i++){
|
|
clientChallenge += String.fromCharCode( Math.floor(Math.random()*256) );
|
|
}
|
|
var clientChallengeBytes = new Buffer(clientChallenge, 'ascii');
|
|
var challenges = ntlm2sr_calc_resp(pwhash, nonce, clientChallengeBytes);
|
|
lmChallengeResponse = challenges.lmChallengeResponse;
|
|
ntChallengeResponse = challenges.ntChallengeResponse;
|
|
}
|
|
|
|
var signature = 'NTLMSSP\0';
|
|
|
|
var pos = 0;
|
|
var buf = new Buffer(BODY_LENGTH + domainNameBytes.length + usernameBytes.length + workstationBytes.length + lmChallengeResponse.length + ntChallengeResponse.length + encryptedRandomSessionKeyBytes.length);
|
|
|
|
buf.write(signature, pos, signature.length); pos += signature.length;
|
|
buf.writeUInt32LE(3, pos); pos += 4; // type 1
|
|
|
|
buf.writeUInt16LE(lmChallengeResponse.length, pos); pos += 2; // LmChallengeResponseLen
|
|
buf.writeUInt16LE(lmChallengeResponse.length, pos); pos += 2; // LmChallengeResponseMaxLen
|
|
buf.writeUInt32LE(BODY_LENGTH + domainNameBytes.length + usernameBytes.length + workstationBytes.length, pos); pos += 4; // LmChallengeResponseOffset
|
|
|
|
buf.writeUInt16LE(ntChallengeResponse.length, pos); pos += 2; // NtChallengeResponseLen
|
|
buf.writeUInt16LE(ntChallengeResponse.length, pos); pos += 2; // NtChallengeResponseMaxLen
|
|
buf.writeUInt32LE(BODY_LENGTH + domainNameBytes.length + usernameBytes.length + workstationBytes.length + lmChallengeResponse.length, pos); pos += 4; // NtChallengeResponseOffset
|
|
|
|
buf.writeUInt16LE(domainNameBytes.length, pos); pos += 2; // DomainNameLen
|
|
buf.writeUInt16LE(domainNameBytes.length, pos); pos += 2; // DomainNameMaxLen
|
|
buf.writeUInt32LE(BODY_LENGTH, pos); pos += 4; // DomainNameOffset
|
|
|
|
buf.writeUInt16LE(usernameBytes.length, pos); pos += 2; // UserNameLen
|
|
buf.writeUInt16LE(usernameBytes.length, pos); pos += 2; // UserNameMaxLen
|
|
buf.writeUInt32LE(BODY_LENGTH + domainNameBytes.length, pos); pos += 4; // UserNameOffset
|
|
|
|
buf.writeUInt16LE(workstationBytes.length, pos); pos += 2; // WorkstationLen
|
|
buf.writeUInt16LE(workstationBytes.length, pos); pos += 2; // WorkstationMaxLen
|
|
buf.writeUInt32LE(BODY_LENGTH + domainNameBytes.length + usernameBytes.length, pos); pos += 4; // WorkstationOffset
|
|
|
|
buf.writeUInt16LE(encryptedRandomSessionKeyBytes.length, pos); pos += 2; // EncryptedRandomSessionKeyLen
|
|
buf.writeUInt16LE(encryptedRandomSessionKeyBytes.length, pos); pos += 2; // EncryptedRandomSessionKeyMaxLen
|
|
buf.writeUInt32LE(BODY_LENGTH + domainNameBytes.length + usernameBytes.length + workstationBytes.length + lmChallengeResponse.length + ntChallengeResponse.length, pos); pos += 4; // EncryptedRandomSessionKeyOffset
|
|
|
|
buf.writeUInt32LE(typeflags.NTLM_TYPE2_FLAGS, pos); pos += 4; // NegotiateFlags
|
|
|
|
buf.writeUInt8(5, pos); pos++; // ProductMajorVersion
|
|
buf.writeUInt8(1, pos); pos++; // ProductMinorVersion
|
|
buf.writeUInt16LE(2600, pos); pos += 2; // ProductBuild
|
|
buf.writeUInt8(0, pos); pos++; // VersionReserved1
|
|
buf.writeUInt8(0, pos); pos++; // VersionReserved2
|
|
buf.writeUInt8(0, pos); pos++; // VersionReserved3
|
|
buf.writeUInt8(15, pos); pos++; // NTLMRevisionCurrent
|
|
|
|
domainNameBytes.copy(buf, pos); pos += domainNameBytes.length;
|
|
usernameBytes.copy(buf, pos); pos += usernameBytes.length;
|
|
workstationBytes.copy(buf, pos); pos += workstationBytes.length;
|
|
lmChallengeResponse.copy(buf, pos); pos += lmChallengeResponse.length;
|
|
ntChallengeResponse.copy(buf, pos); pos += ntChallengeResponse.length;
|
|
encryptedRandomSessionKeyBytes.copy(buf, pos); pos += encryptedRandomSessionKeyBytes.length;
|
|
|
|
return 'NTLM ' + buf.toString('base64');
|
|
}
|
|
|
|
function create_LM_hashed_password_v1(password){
|
|
// fix the password length to 14 bytes
|
|
password = password.toUpperCase();
|
|
var passwordBytes = new Buffer(password, 'ascii');
|
|
|
|
var passwordBytesPadded = new Buffer(14);
|
|
passwordBytesPadded.fill("\0");
|
|
var sourceEnd = 14;
|
|
if(passwordBytes.length < 14) sourceEnd = passwordBytes.length;
|
|
passwordBytes.copy(passwordBytesPadded, 0, 0, sourceEnd);
|
|
|
|
// split into 2 parts of 7 bytes:
|
|
var firstPart = passwordBytesPadded.slice(0,7);
|
|
var secondPart = passwordBytesPadded.slice(7);
|
|
|
|
function encrypt(buf){
|
|
var key = insertZerosEvery7Bits(buf);
|
|
var des = crypto.createCipheriv('DES-ECB', key, '');
|
|
return des.update("KGS!@#$%"); // page 57 in [MS-NLMP]);
|
|
}
|
|
|
|
var firstPartEncrypted = encrypt(firstPart);
|
|
var secondPartEncrypted = encrypt(secondPart);
|
|
|
|
return Buffer.concat([firstPartEncrypted, secondPartEncrypted]);
|
|
}
|
|
|
|
function insertZerosEvery7Bits(buf){
|
|
var binaryArray = bytes2binaryArray(buf);
|
|
var newBinaryArray = [];
|
|
for(var i=0; i<binaryArray.length; i++){
|
|
newBinaryArray.push(binaryArray[i]);
|
|
|
|
if((i+1)%7 === 0){
|
|
newBinaryArray.push(0);
|
|
}
|
|
}
|
|
return binaryArray2bytes(newBinaryArray);
|
|
}
|
|
|
|
function bytes2binaryArray(buf){
|
|
var hex2binary = {
|
|
0: [0,0,0,0],
|
|
1: [0,0,0,1],
|
|
2: [0,0,1,0],
|
|
3: [0,0,1,1],
|
|
4: [0,1,0,0],
|
|
5: [0,1,0,1],
|
|
6: [0,1,1,0],
|
|
7: [0,1,1,1],
|
|
8: [1,0,0,0],
|
|
9: [1,0,0,1],
|
|
A: [1,0,1,0],
|
|
B: [1,0,1,1],
|
|
C: [1,1,0,0],
|
|
D: [1,1,0,1],
|
|
E: [1,1,1,0],
|
|
F: [1,1,1,1]
|
|
};
|
|
|
|
var hexString = buf.toString('hex').toUpperCase();
|
|
var array = [];
|
|
for(var i=0; i<hexString.length; i++){
|
|
var hexchar = hexString.charAt(i);
|
|
array = array.concat(hex2binary[hexchar]);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
function binaryArray2bytes(array){
|
|
var binary2hex = {
|
|
'0000': 0,
|
|
'0001': 1,
|
|
'0010': 2,
|
|
'0011': 3,
|
|
'0100': 4,
|
|
'0101': 5,
|
|
'0110': 6,
|
|
'0111': 7,
|
|
'1000': 8,
|
|
'1001': 9,
|
|
'1010': 'A',
|
|
'1011': 'B',
|
|
'1100': 'C',
|
|
'1101': 'D',
|
|
'1110': 'E',
|
|
'1111': 'F'
|
|
};
|
|
|
|
var bufArray = [];
|
|
|
|
for(var i=0; i<array.length; i +=8 ){
|
|
if((i+7) > array.length)
|
|
break;
|
|
|
|
var binString1 = '' + array[i] + '' + array[i+1] + '' + array[i+2] + '' + array[i+3];
|
|
var binString2 = '' + array[i+4] + '' + array[i+5] + '' + array[i+6] + '' + array[i+7];
|
|
var hexchar1 = binary2hex[binString1];
|
|
var hexchar2 = binary2hex[binString2];
|
|
|
|
var buf = new Buffer(hexchar1 + '' + hexchar2, 'hex');
|
|
bufArray.push(buf);
|
|
}
|
|
|
|
return Buffer.concat(bufArray);
|
|
}
|
|
|
|
function create_NT_hashed_password_v1(password){
|
|
var buf = new Buffer(password, 'utf16le');
|
|
var md4 = crypto.createHash('md4');
|
|
md4.update(buf);
|
|
return new Buffer(md4.digest());
|
|
}
|
|
|
|
function calc_resp(password_hash, server_challenge){
|
|
// padding with zeros to make the hash 21 bytes long
|
|
var passHashPadded = new Buffer(21);
|
|
passHashPadded.fill("\0");
|
|
password_hash.copy(passHashPadded, 0, 0, password_hash.length);
|
|
|
|
var resArray = [];
|
|
|
|
var des = crypto.createCipheriv('DES-ECB', insertZerosEvery7Bits(passHashPadded.slice(0,7)), '');
|
|
resArray.push( des.update(server_challenge.slice(0,8)) );
|
|
|
|
des = crypto.createCipheriv('DES-ECB', insertZerosEvery7Bits(passHashPadded.slice(7,14)), '');
|
|
resArray.push( des.update(server_challenge.slice(0,8)) );
|
|
|
|
des = crypto.createCipheriv('DES-ECB', insertZerosEvery7Bits(passHashPadded.slice(14,21)), '');
|
|
resArray.push( des.update(server_challenge.slice(0,8)) );
|
|
|
|
return Buffer.concat(resArray);
|
|
}
|
|
|
|
function ntlm2sr_calc_resp(responseKeyNT, serverChallenge, clientChallenge){
|
|
// padding with zeros to make the hash 16 bytes longer
|
|
var lmChallengeResponse = new Buffer(clientChallenge.length + 16);
|
|
lmChallengeResponse.fill("\0");
|
|
clientChallenge.copy(lmChallengeResponse, 0, 0, clientChallenge.length);
|
|
|
|
var buf = Buffer.concat([serverChallenge, clientChallenge]);
|
|
var md5 = crypto.createHash('md5');
|
|
md5.update(buf);
|
|
var sess = md5.digest();
|
|
var ntChallengeResponse = calc_resp(responseKeyNT, sess.slice(0,8));
|
|
|
|
return {
|
|
lmChallengeResponse: lmChallengeResponse,
|
|
ntChallengeResponse: ntChallengeResponse
|
|
};
|
|
}
|
|
|
|
exports.createType1Message = createType1Message;
|
|
exports.parseType2Message = parseType2Message;
|
|
exports.createType3Message = createType3Message;
|
|
|
|
|
|
|