@tier0/node-red-contrib-opcda-client 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/opcda/opcda-read.html +1 -1
- package/opcda/opcda-read.js +21 -50
- package/opcda/opcda-server.html +11 -20
- package/opcda/opcda-server.js +28 -42
- package/opcda/opcda-write.html +1 -1
- package/opcda/opcda-write.js +17 -20
- package/package.json +4 -4
- package/OPCDA_Bridge_Setup_Guide.md +0 -132
- package/docker-compose.yml +0 -460
- package/opctest.py +0 -214
- package/patch-debug.js +0 -13
- package/patch-ntlm.js +0 -46
- package/patch-pwdcheck.js +0 -17
- package/test-connect.js +0 -69
- package/test-connect2.js +0 -30
- package/test-direct.js +0 -53
- package/test-ntlm-vectors.js +0 -100
- package/test-ntlm-verify.js +0 -77
- package/uns_import.json +0 -204
package/patch-ntlm.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const file = '/usr/src/node-red/node_modules/node-dcom/dcom/rpc/security/ntlmauthentication.js';
|
|
3
|
-
let code = fs.readFileSync(file, 'utf8');
|
|
4
|
-
|
|
5
|
-
// Fix 1: Replace all Encdec references with inline uint16le decode
|
|
6
|
-
code = code.replace(
|
|
7
|
-
/new Encdec\(\)\.dec_uint16le\(targetInformation,\s*i\)/g,
|
|
8
|
-
'(targetInformation[i] | (targetInformation[i+1] << 8))'
|
|
9
|
-
);
|
|
10
|
-
code = code.replace(
|
|
11
|
-
/new Encdec\.dec_uint16le\(targetInformation,\s*i\)/g,
|
|
12
|
-
'(targetInformation[i] | (targetInformation[i+1] << 8))'
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
// Fix 2: Add debug logging for NTLM credentials
|
|
16
|
-
code = code.replace(
|
|
17
|
-
'let target = null;',
|
|
18
|
-
'let target = null;\n console.log("[NTLM-DBG] domain=" + info.domain + " user=" + this.credentials.username);'
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
// Verify no syntax errors
|
|
22
|
-
try {
|
|
23
|
-
new Function(code);
|
|
24
|
-
console.log('ERROR: wrapped in function - not a module');
|
|
25
|
-
} catch(e) {
|
|
26
|
-
// Expected since it's a class/module, not a function body
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
fs.writeFileSync(file, code);
|
|
30
|
-
|
|
31
|
-
// Verify it loads
|
|
32
|
-
try {
|
|
33
|
-
delete require.cache[require.resolve(file)];
|
|
34
|
-
require(file);
|
|
35
|
-
console.log('Patched and verified OK');
|
|
36
|
-
} catch(e) {
|
|
37
|
-
console.log('WARNING: Load check result:', e.message);
|
|
38
|
-
// May fail due to missing dependencies in standalone context, that's OK
|
|
39
|
-
// as long as it's not a syntax error
|
|
40
|
-
if (e.message.includes('Unexpected token')) {
|
|
41
|
-
console.log('SYNTAX ERROR - reverting!');
|
|
42
|
-
// Don't revert for now, let's see the error
|
|
43
|
-
} else {
|
|
44
|
-
console.log('Non-syntax error (expected in standalone context)');
|
|
45
|
-
}
|
|
46
|
-
}
|
package/patch-pwdcheck.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const file = '/usr/src/node-red/node_modules/node-dcom/dcom/rpc/security/ntlmauthentication.js';
|
|
3
|
-
let code = fs.readFileSync(file, 'utf8');
|
|
4
|
-
|
|
5
|
-
// Add password length and MD4 check debug
|
|
6
|
-
code = code.replace(
|
|
7
|
-
'let target = null;',
|
|
8
|
-
`let target = null;
|
|
9
|
-
console.log("[NTLM-DBG] domain=" + info.domain + " user=" + this.credentials.username + " pwdLen=" + (this.credentials.password ? this.credentials.password.length : "NULL"));
|
|
10
|
-
try { const _h = Crypto.createHash('md4'); _h.update(Buffer.from(this.credentials.password || '', 'utf16le')); console.log("[NTLM-DBG] md4-ok ntHash=" + _h.digest('hex')); } catch(e) { console.log("[NTLM-DBG] md4-FAIL: " + e.message); }`
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
fs.writeFileSync(file, code);
|
|
14
|
-
|
|
15
|
-
// Verify loads
|
|
16
|
-
try { require('node-opc-da'); console.log('Patched OK, module loads'); }
|
|
17
|
-
catch(e) { console.log('Load result:', e.message); }
|
package/test-connect.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const opcda = require('node-opc-da');
|
|
2
|
-
const { OPCServer } = opcda;
|
|
3
|
-
const { ComServer, Session, Clsid } = opcda.dcom;
|
|
4
|
-
|
|
5
|
-
const config = {
|
|
6
|
-
address: '192.168.31.75',
|
|
7
|
-
domain: 'DESKTOP-BBD7VBL',
|
|
8
|
-
username: 'Administrator',
|
|
9
|
-
password: 'Supos@1304',
|
|
10
|
-
clsid: '7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729',
|
|
11
|
-
timeout: 10000
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
async function test() {
|
|
15
|
-
console.log('=== OPC DA Connection Test ===');
|
|
16
|
-
console.log('Address:', config.address);
|
|
17
|
-
console.log('Domain:', config.domain);
|
|
18
|
-
console.log('Username:', config.username);
|
|
19
|
-
console.log('CLSID:', config.clsid);
|
|
20
|
-
console.log('');
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
console.log('[1] Creating session...');
|
|
24
|
-
var session = new Session();
|
|
25
|
-
session = session.createSession(config.domain, config.username, config.password);
|
|
26
|
-
session.setGlobalSocketTimeout(config.timeout);
|
|
27
|
-
console.log('[1] Session created OK');
|
|
28
|
-
|
|
29
|
-
console.log('[2] Creating ComServer...');
|
|
30
|
-
var comServer = new ComServer(new Clsid(config.clsid), config.address, session);
|
|
31
|
-
console.log('[2] ComServer created, calling init()...');
|
|
32
|
-
|
|
33
|
-
await comServer.init();
|
|
34
|
-
console.log('[2] ComServer.init() OK!');
|
|
35
|
-
|
|
36
|
-
console.log('[3] Creating COM instance...');
|
|
37
|
-
var comObject = await comServer.createInstance();
|
|
38
|
-
console.log('[3] COM instance created OK!');
|
|
39
|
-
|
|
40
|
-
console.log('[4] Creating OPC Server...');
|
|
41
|
-
var opcServer = new OPCServer();
|
|
42
|
-
await opcServer.init(comObject);
|
|
43
|
-
console.log('[4] OPC Server connected!');
|
|
44
|
-
|
|
45
|
-
console.log('[5] Getting browser...');
|
|
46
|
-
var browser = await opcServer.getBrowser();
|
|
47
|
-
var items = await browser.browseAllFlat();
|
|
48
|
-
console.log('[5] Found', items.length, 'items');
|
|
49
|
-
items.slice(0, 10).forEach(i => console.log(' ', i));
|
|
50
|
-
|
|
51
|
-
await browser.end();
|
|
52
|
-
await opcServer.end();
|
|
53
|
-
await comServer.closeStub();
|
|
54
|
-
console.log('\n=== SUCCESS ===');
|
|
55
|
-
} catch (e) {
|
|
56
|
-
console.log('\n=== FAILED ===');
|
|
57
|
-
console.log('Error type:', typeof e);
|
|
58
|
-
console.log('Error value:', e);
|
|
59
|
-
if (e instanceof Error) {
|
|
60
|
-
console.log('Message:', e.message);
|
|
61
|
-
console.log('Stack:', e.stack);
|
|
62
|
-
}
|
|
63
|
-
if (typeof e === 'number') {
|
|
64
|
-
console.log('Hex:', '0x' + (e >>> 0).toString(16));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
test();
|
package/test-connect2.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const opcda = require('node-opc-da');
|
|
2
|
-
const { OPCServer } = opcda;
|
|
3
|
-
const { ComServer, Session, Clsid } = opcda.dcom;
|
|
4
|
-
|
|
5
|
-
async function test(domain) {
|
|
6
|
-
console.log('\n--- Testing with domain="' + domain + '" ---');
|
|
7
|
-
try {
|
|
8
|
-
var session = new Session();
|
|
9
|
-
session = session.createSession(domain, 'Administrator', 'Supos@1304');
|
|
10
|
-
session.setGlobalSocketTimeout(10000);
|
|
11
|
-
|
|
12
|
-
var comServer = new ComServer(
|
|
13
|
-
new Clsid('7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729'),
|
|
14
|
-
'192.168.31.75', session);
|
|
15
|
-
|
|
16
|
-
await comServer.init();
|
|
17
|
-
console.log('SUCCESS with domain="' + domain + '"');
|
|
18
|
-
await comServer.closeStub();
|
|
19
|
-
} catch (e) {
|
|
20
|
-
var code = typeof e === 'number' ? '0x' + (e >>> 0).toString(16) : (e.message || String(e));
|
|
21
|
-
console.log('FAILED:', code);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
(async () => {
|
|
26
|
-
await test('DESKTOP-BBD7VBL');
|
|
27
|
-
await test('.');
|
|
28
|
-
await test('');
|
|
29
|
-
await test('WORKGROUP');
|
|
30
|
-
})();
|
package/test-direct.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const opcda = require('/usr/src/node-red/node_modules/node-opc-da/src/index.js');
|
|
2
|
-
const dcom = require('node-dcom');
|
|
3
|
-
const { ComServer, Session, Clsid } = dcom;
|
|
4
|
-
|
|
5
|
-
const address = '192.168.31.75';
|
|
6
|
-
const domain = 'DESKTOP-BBD7VBL';
|
|
7
|
-
const username = 'Administrator';
|
|
8
|
-
const password = 'Supos@1304';
|
|
9
|
-
const clsidStr = '7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729';
|
|
10
|
-
|
|
11
|
-
async function main() {
|
|
12
|
-
console.log('=== OPC DA Direct Connection Test ===');
|
|
13
|
-
|
|
14
|
-
let comSession, comServer;
|
|
15
|
-
try {
|
|
16
|
-
comSession = new Session();
|
|
17
|
-
comSession = comSession.createSession(domain, username, password);
|
|
18
|
-
comSession.setGlobalSocketTimeout(15000);
|
|
19
|
-
console.log('Session: domain=' + comSession.getDomain() + ' user=' + comSession.getUserName());
|
|
20
|
-
|
|
21
|
-
comServer = new ComServer(new Clsid(clsidStr), address, comSession);
|
|
22
|
-
console.log('Connecting...');
|
|
23
|
-
await comServer.init();
|
|
24
|
-
console.log('Connected!');
|
|
25
|
-
|
|
26
|
-
const comObject = await comServer.createInstance();
|
|
27
|
-
console.log('Instance created');
|
|
28
|
-
|
|
29
|
-
const server = new opcda.OPCServer();
|
|
30
|
-
await server.init(comObject);
|
|
31
|
-
console.log('OPCServer initialized');
|
|
32
|
-
|
|
33
|
-
const status = await server.getStatus();
|
|
34
|
-
console.log('Server Status:', JSON.stringify(status, null, 2));
|
|
35
|
-
|
|
36
|
-
const browser = await server.getBrowser();
|
|
37
|
-
console.log('Got browser');
|
|
38
|
-
|
|
39
|
-
const items = await browser.browse();
|
|
40
|
-
console.log('Items found:', items.length);
|
|
41
|
-
if (items.length > 0) {
|
|
42
|
-
console.log('First 5 items:', items.slice(0, 5));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
console.log('\n=== SUCCESS ===');
|
|
46
|
-
} catch (err) {
|
|
47
|
-
console.error('ERROR:', err.message || err);
|
|
48
|
-
console.error('Stack:', err.stack);
|
|
49
|
-
}
|
|
50
|
-
process.exit(0);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
main();
|
package/test-ntlm-vectors.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// MS-NLMP Appendix A test vectors for NTLMv2
|
|
2
|
-
// Reference: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/
|
|
3
|
-
const Crypto = require('crypto');
|
|
4
|
-
|
|
5
|
-
// Force legacy provider for MD4
|
|
6
|
-
process.env.NODE_OPTIONS = '--openssl-legacy-provider';
|
|
7
|
-
|
|
8
|
-
const Responses = require('/usr/src/node-red/node_modules/node-dcom/dcom/rpc/security/responses.js');
|
|
9
|
-
|
|
10
|
-
const r = new Responses();
|
|
11
|
-
|
|
12
|
-
// MS-NLMP test vectors
|
|
13
|
-
const User = 'User';
|
|
14
|
-
const UserDom = 'Domain';
|
|
15
|
-
const Passwd = 'Password';
|
|
16
|
-
const ServerChallenge = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
|
|
17
|
-
const ClientChallenge = [0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa];
|
|
18
|
-
const Time = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
|
19
|
-
|
|
20
|
-
// Expected values from MS-NLMP spec
|
|
21
|
-
const EXPECTED_NT_HASH = 'a4f49c406510bdcab6824ee7c30fd852';
|
|
22
|
-
const EXPECTED_NTLMv2_HASH = '0c868a403bfd7a93a3001ef22ef02e3f';
|
|
23
|
-
|
|
24
|
-
// Test 1: NT Hash (MD4 of UTF-16LE password)
|
|
25
|
-
console.log('=== Test 1: NT Hash ===');
|
|
26
|
-
const ntHash = r.ntlmHash(Passwd);
|
|
27
|
-
const ntHashHex = Buffer.from(ntHash).toString('hex');
|
|
28
|
-
console.log('Computed:', ntHashHex);
|
|
29
|
-
console.log('Expected:', EXPECTED_NT_HASH);
|
|
30
|
-
console.log('Match:', ntHashHex === EXPECTED_NT_HASH ? 'PASS' : 'FAIL');
|
|
31
|
-
|
|
32
|
-
// Test 2: NTLMv2 Hash
|
|
33
|
-
console.log('\n=== Test 2: NTLMv2 Hash ===');
|
|
34
|
-
const ntlmv2Hash = r.ntlmv2Hash(UserDom, User, Passwd);
|
|
35
|
-
const ntlmv2HashHex = Buffer.from(ntlmv2Hash).toString('hex');
|
|
36
|
-
console.log('Computed:', ntlmv2HashHex);
|
|
37
|
-
console.log('Expected:', EXPECTED_NTLMv2_HASH);
|
|
38
|
-
console.log('Match:', ntlmv2HashHex === EXPECTED_NTLMv2_HASH ? 'PASS' : 'FAIL');
|
|
39
|
-
|
|
40
|
-
// Test 3: LMv2 Response
|
|
41
|
-
console.log('\n=== Test 3: LMv2 Response ===');
|
|
42
|
-
const lmv2 = r.getLMv2Response(UserDom, User, Passwd, ServerChallenge, ClientChallenge);
|
|
43
|
-
const lmv2Hex = Buffer.from(lmv2).toString('hex');
|
|
44
|
-
console.log('Computed:', lmv2Hex);
|
|
45
|
-
// Expected from MS-NLMP: d6e6152ea25d03b7c6ba6629c2d6aaf0aaaaaaaaaaaaaaaa
|
|
46
|
-
const EXPECTED_LMv2 = 'd6e6152ea25d03b7c6ba6629c2d6aaf0aaaaaaaaaaaaaaaa';
|
|
47
|
-
console.log('Expected:', EXPECTED_LMv2);
|
|
48
|
-
console.log('Match:', lmv2Hex === EXPECTED_LMv2 ? 'PASS' : 'FAIL');
|
|
49
|
-
|
|
50
|
-
// Test 4: hmacMD5 argument order verification
|
|
51
|
-
console.log('\n=== Test 4: HMAC-MD5 argument order ===');
|
|
52
|
-
const testHmac = r.hmacMD5([0x01, 0x02, 0x03], [0x04, 0x05, 0x06]);
|
|
53
|
-
console.log('hmacMD5([1,2,3], [4,5,6]) =', Buffer.from(testHmac).toString('hex'));
|
|
54
|
-
// Verify: HMAC-MD5(key=040506, data=010203)
|
|
55
|
-
const verifyHmac = Crypto.createHmac('md5', Buffer.from([0x04, 0x05, 0x06]));
|
|
56
|
-
verifyHmac.update(Buffer.from([0x01, 0x02, 0x03]));
|
|
57
|
-
console.log('Crypto.HMAC(key=040506, data=010203) =', verifyHmac.digest('hex'));
|
|
58
|
-
|
|
59
|
-
// Test 5: NTLMv2 Response with known blob
|
|
60
|
-
console.log('\n=== Test 5: NTLMv2 Response ===');
|
|
61
|
-
// Build a minimal target info for testing
|
|
62
|
-
const targetInfo = [
|
|
63
|
-
0x02, 0x00, 0x0c, 0x00, // MsvAvNbDomainName, len=12
|
|
64
|
-
0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, // "Domain" in UTF-16LE
|
|
65
|
-
0x01, 0x00, 0x0c, 0x00, // MsvAvNbComputerName, len=12
|
|
66
|
-
0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, // "Server" in UTF-16LE
|
|
67
|
-
0x00, 0x00, 0x00, 0x00 // MsvAvEOL
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
// Test blob creation
|
|
71
|
-
const blob = r.createBlob(targetInfo, ClientChallenge);
|
|
72
|
-
console.log('Blob length:', blob.length);
|
|
73
|
-
console.log('Blob header (first 8):', Buffer.from(blob.slice(0, 8)).toString('hex'));
|
|
74
|
-
console.log('Blob timestamp (next 8):', Buffer.from(blob.slice(8, 16)).toString('hex'));
|
|
75
|
-
console.log('Blob clientNonce (next 8):', Buffer.from(blob.slice(16, 24)).toString('hex'));
|
|
76
|
-
|
|
77
|
-
// Verify blob structure
|
|
78
|
-
console.log('\nBlob structure check:');
|
|
79
|
-
console.log('Byte 0-1 (signature):', blob[0] === 1 && blob[1] === 1 ? 'PASS (0x0101)' : 'FAIL');
|
|
80
|
-
console.log('Byte 2-7 (zeros):', blob.slice(2, 8).every(b => b === 0) ? 'PASS' : 'FAIL');
|
|
81
|
-
console.log('Byte 16-23 (client nonce):', Buffer.from(blob.slice(16, 24)).toString('hex') === 'aaaaaaaaaaaaaaaa' ? 'PASS' : 'FAIL');
|
|
82
|
-
console.log('Byte 24-27 (Z4):', blob.slice(24, 28).every(b => b === 0) ? 'PASS' : 'FAIL');
|
|
83
|
-
|
|
84
|
-
// Verify the full NTLMv2 response computation
|
|
85
|
-
const retval = r.getNTLMv2Response(UserDom, User, Passwd, targetInfo, ServerChallenge, ClientChallenge);
|
|
86
|
-
console.log('\nNTLMv2Response length:', retval[0].length);
|
|
87
|
-
console.log('NTProofStr:', Buffer.from(retval[0].slice(0, 16)).toString('hex'));
|
|
88
|
-
|
|
89
|
-
// Test session base key
|
|
90
|
-
const ntProofStr = retval[0].slice(0, 16);
|
|
91
|
-
const hashForSession = r.ntlmv2Hash(UserDom, User, Passwd);
|
|
92
|
-
const sessionBaseKey = r.hmacMD5(ntProofStr, hashForSession);
|
|
93
|
-
console.log('SessionBaseKey:', Buffer.from(sessionBaseKey).toString('hex'));
|
|
94
|
-
|
|
95
|
-
// Now test with actual credentials
|
|
96
|
-
console.log('\n\n=== Test with actual credentials ===');
|
|
97
|
-
const actualNtHash = r.ntlmHash('Supos@1304');
|
|
98
|
-
console.log('NT Hash (Supos@1304):', Buffer.from(actualNtHash).toString('hex'));
|
|
99
|
-
const actualV2Hash = r.ntlmv2Hash('DESKTOP-BBD7VBL', 'Administrator', 'Supos@1304');
|
|
100
|
-
console.log('NTLMv2 Hash:', Buffer.from(actualV2Hash).toString('hex'));
|
package/test-ntlm-verify.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
const Crypto = require('crypto');
|
|
2
|
-
|
|
3
|
-
// Verify DES update() vs final() behavior in this Node.js version
|
|
4
|
-
console.log('=== Node.js version:', process.version, '===');
|
|
5
|
-
console.log('=== OpenSSL version:', process.versions.openssl, '===\n');
|
|
6
|
-
|
|
7
|
-
// Test 1: DES-ECB update() behavior
|
|
8
|
-
console.log('--- Test 1: DES-ECB update vs final ---');
|
|
9
|
-
const key1 = Buffer.from('0123456789ABCDEF', 'hex');
|
|
10
|
-
const data1 = Buffer.from('4E6F772069732074', 'hex');
|
|
11
|
-
const des1 = Crypto.createCipheriv('des-ecb', key1, '');
|
|
12
|
-
const update1 = des1.update(data1);
|
|
13
|
-
const final1 = des1.final();
|
|
14
|
-
console.log('update() returned', update1.length, 'bytes:', update1.toString('hex'));
|
|
15
|
-
console.log('final() returned', final1.length, 'bytes:', final1.toString('hex'));
|
|
16
|
-
console.log('Expected update=3fa40e8a984d4815 (8 bytes)\n');
|
|
17
|
-
|
|
18
|
-
// Test 2: Verify NT hash
|
|
19
|
-
console.log('--- Test 2: NT Hash of Supos@1304 ---');
|
|
20
|
-
const md4 = Crypto.createHash('md4');
|
|
21
|
-
md4.update(Buffer.from('Supos@1304', 'utf16le'));
|
|
22
|
-
const ntHash = md4.digest();
|
|
23
|
-
console.log('NT Hash:', ntHash.toString('hex'));
|
|
24
|
-
console.log('Length:', ntHash.length, '\n');
|
|
25
|
-
|
|
26
|
-
// Test 3: NTLM2 Session Response with known values
|
|
27
|
-
console.log('--- Test 3: Full NTLM2 Session Response ---');
|
|
28
|
-
const Responses = require('node-opc-da/node_modules/node-dcom/dcom/rpc/security/responses.js');
|
|
29
|
-
const r = new Responses();
|
|
30
|
-
|
|
31
|
-
const fakeChallenge = Buffer.from('0123456789abcdef', 'hex');
|
|
32
|
-
const fakeClientNonce = Buffer.from('ffffff0011223344', 'hex');
|
|
33
|
-
const testResponse = r.getNTLM2SessionResponse('Password', fakeChallenge, fakeClientNonce);
|
|
34
|
-
console.log('Response type:', typeof testResponse, testResponse.constructor.name);
|
|
35
|
-
console.log('Response length:', testResponse.length);
|
|
36
|
-
console.log('Response hex:', testResponse.toString('hex'));
|
|
37
|
-
|
|
38
|
-
// Independent verification of the same computation
|
|
39
|
-
const ntHash2 = Crypto.createHash('md4').update(Buffer.from('Password', 'utf16le')).digest();
|
|
40
|
-
console.log('\nIndependent NT hash:', ntHash2.toString('hex'));
|
|
41
|
-
const sessionNonce = Buffer.concat([fakeChallenge, fakeClientNonce]);
|
|
42
|
-
const sessionHash = Crypto.createHash('md5').update(sessionNonce).digest().slice(0, 8);
|
|
43
|
-
console.log('Session hash:', sessionHash.toString('hex'));
|
|
44
|
-
|
|
45
|
-
// Manual DES with NT hash
|
|
46
|
-
function createDESKey(bytes, offset) {
|
|
47
|
-
let keyBytes = bytes.slice(offset, 7 + offset);
|
|
48
|
-
let material = Buffer.alloc(8);
|
|
49
|
-
material[0] = keyBytes[0];
|
|
50
|
-
material[1] = ((keyBytes[0] << 7) & 0xff | ((keyBytes[1] & 0xff) >>> 1));
|
|
51
|
-
material[2] = ((keyBytes[1] << 6) & 0xff | ((keyBytes[2] & 0xff) >>> 2));
|
|
52
|
-
material[3] = ((keyBytes[2] << 5) & 0xff | ((keyBytes[3] & 0xff) >>> 3));
|
|
53
|
-
material[4] = ((keyBytes[3] << 4) & 0xff | ((keyBytes[4] & 0xff) >>> 4));
|
|
54
|
-
material[5] = ((keyBytes[4] << 3) & 0xff | ((keyBytes[5] & 0xff) >>> 5));
|
|
55
|
-
material[6] = ((keyBytes[5] << 2) & 0xff | ((keyBytes[6] & 0xff) >>> 6));
|
|
56
|
-
material[7] = ((keyBytes[6] << 1));
|
|
57
|
-
// odd parity
|
|
58
|
-
for (let i = 0; i < 8; i++) {
|
|
59
|
-
let b = material[i];
|
|
60
|
-
let needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0;
|
|
61
|
-
if (needsParity) material[i] |= 0x01;
|
|
62
|
-
else material[i] &= 0xfe;
|
|
63
|
-
}
|
|
64
|
-
return material;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const padded = Buffer.concat([ntHash2, Buffer.alloc(5)]);
|
|
68
|
-
let manualResult = Buffer.alloc(0);
|
|
69
|
-
for (let off of [0, 7, 14]) {
|
|
70
|
-
const k = createDESKey(padded, off);
|
|
71
|
-
const d = Crypto.createCipheriv('des-ecb', k, '');
|
|
72
|
-
const enc = d.update(sessionHash);
|
|
73
|
-
d.final();
|
|
74
|
-
manualResult = Buffer.concat([manualResult, enc]);
|
|
75
|
-
}
|
|
76
|
-
console.log('Manual response:', manualResult.toString('hex'));
|
|
77
|
-
console.log('Match:', testResponse.toString('hex') === manualResult.toString('hex') ? 'YES' : 'NO');
|
package/uns_import.json
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"UNS": [
|
|
3
|
-
{
|
|
4
|
-
"type": "path",
|
|
5
|
-
"name": "opcda",
|
|
6
|
-
"children": [
|
|
7
|
-
{
|
|
8
|
-
"type": "path",
|
|
9
|
-
"name": "通道_1",
|
|
10
|
-
"children": [
|
|
11
|
-
{
|
|
12
|
-
"type": "path",
|
|
13
|
-
"name": "设备_1",
|
|
14
|
-
"children": [
|
|
15
|
-
{
|
|
16
|
-
"dataType": "METRIC",
|
|
17
|
-
"displayName": "Metric",
|
|
18
|
-
"type": "path",
|
|
19
|
-
"name": "Metric",
|
|
20
|
-
"children": [
|
|
21
|
-
{
|
|
22
|
-
"topicType": "METRIC",
|
|
23
|
-
"generateDashboard": "TRUE",
|
|
24
|
-
"writeData": "FALSE",
|
|
25
|
-
"name": "标记_1",
|
|
26
|
-
"enableHistory": "TRUE",
|
|
27
|
-
"dataType": "TIME_SEQUENCE_TYPE",
|
|
28
|
-
"fields": [
|
|
29
|
-
{
|
|
30
|
-
"systemField": true,
|
|
31
|
-
"unique": true,
|
|
32
|
-
"type": "DATETIME",
|
|
33
|
-
"name": "timeStamp"
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"tbValueName": "tag",
|
|
37
|
-
"systemField": true,
|
|
38
|
-
"unique": true,
|
|
39
|
-
"type": "LONG",
|
|
40
|
-
"name": "tag"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"index": "double_1",
|
|
44
|
-
"type": "FLOAT",
|
|
45
|
-
"name": "value"
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"systemField": true,
|
|
49
|
-
"type": "LONG",
|
|
50
|
-
"name": "quality"
|
|
51
|
-
}
|
|
52
|
-
],
|
|
53
|
-
"type": "topic",
|
|
54
|
-
"mockData": "FALSE"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"topicType": "METRIC",
|
|
58
|
-
"generateDashboard": "TRUE",
|
|
59
|
-
"writeData": "FALSE",
|
|
60
|
-
"name": "标记_2",
|
|
61
|
-
"enableHistory": "TRUE",
|
|
62
|
-
"dataType": "TIME_SEQUENCE_TYPE",
|
|
63
|
-
"fields": [
|
|
64
|
-
{
|
|
65
|
-
"systemField": true,
|
|
66
|
-
"unique": true,
|
|
67
|
-
"type": "DATETIME",
|
|
68
|
-
"name": "timeStamp"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"tbValueName": "tag",
|
|
72
|
-
"systemField": true,
|
|
73
|
-
"unique": true,
|
|
74
|
-
"type": "LONG",
|
|
75
|
-
"name": "tag"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"index": "double_1",
|
|
79
|
-
"type": "FLOAT",
|
|
80
|
-
"name": "value"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"systemField": true,
|
|
84
|
-
"type": "LONG",
|
|
85
|
-
"name": "quality"
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
"type": "topic",
|
|
89
|
-
"mockData": "FALSE"
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
}
|
|
95
|
-
]
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"type": "path",
|
|
99
|
-
"name": "模拟器示例",
|
|
100
|
-
"children": [
|
|
101
|
-
{
|
|
102
|
-
"type": "path",
|
|
103
|
-
"name": "功能",
|
|
104
|
-
"children": [
|
|
105
|
-
{
|
|
106
|
-
"dataType": "METRIC",
|
|
107
|
-
"displayName": "Metric",
|
|
108
|
-
"type": "path",
|
|
109
|
-
"name": "Metric",
|
|
110
|
-
"children": [
|
|
111
|
-
{
|
|
112
|
-
"topicType": "METRIC",
|
|
113
|
-
"generateDashboard": "TRUE",
|
|
114
|
-
"writeData": "FALSE",
|
|
115
|
-
"name": "Sine1",
|
|
116
|
-
"enableHistory": "TRUE",
|
|
117
|
-
"dataType": "TIME_SEQUENCE_TYPE",
|
|
118
|
-
"fields": [
|
|
119
|
-
{
|
|
120
|
-
"systemField": true,
|
|
121
|
-
"unique": true,
|
|
122
|
-
"type": "DATETIME",
|
|
123
|
-
"name": "timeStamp"
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"tbValueName": "tag",
|
|
127
|
-
"systemField": true,
|
|
128
|
-
"unique": true,
|
|
129
|
-
"type": "LONG",
|
|
130
|
-
"name": "tag"
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"index": "double_1",
|
|
134
|
-
"type": "FLOAT",
|
|
135
|
-
"name": "value"
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
"systemField": true,
|
|
139
|
-
"type": "LONG",
|
|
140
|
-
"name": "quality"
|
|
141
|
-
}
|
|
142
|
-
],
|
|
143
|
-
"type": "topic",
|
|
144
|
-
"mockData": "FALSE"
|
|
145
|
-
}
|
|
146
|
-
]
|
|
147
|
-
}
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"type": "path",
|
|
154
|
-
"name": "_System",
|
|
155
|
-
"children": [
|
|
156
|
-
{
|
|
157
|
-
"dataType": "METRIC",
|
|
158
|
-
"displayName": "Metric",
|
|
159
|
-
"type": "path",
|
|
160
|
-
"name": "Metric",
|
|
161
|
-
"children": [
|
|
162
|
-
{
|
|
163
|
-
"topicType": "METRIC",
|
|
164
|
-
"generateDashboard": "TRUE",
|
|
165
|
-
"writeData": "FALSE",
|
|
166
|
-
"name": "_Time",
|
|
167
|
-
"enableHistory": "TRUE",
|
|
168
|
-
"dataType": "TIME_SEQUENCE_TYPE",
|
|
169
|
-
"fields": [
|
|
170
|
-
{
|
|
171
|
-
"systemField": true,
|
|
172
|
-
"unique": true,
|
|
173
|
-
"type": "DATETIME",
|
|
174
|
-
"name": "timeStamp"
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"tbValueName": "tag",
|
|
178
|
-
"systemField": true,
|
|
179
|
-
"unique": true,
|
|
180
|
-
"type": "LONG",
|
|
181
|
-
"name": "tag"
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
"index": "double_1",
|
|
185
|
-
"type": "FLOAT",
|
|
186
|
-
"name": "value"
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
"systemField": true,
|
|
190
|
-
"type": "LONG",
|
|
191
|
-
"name": "quality"
|
|
192
|
-
}
|
|
193
|
-
],
|
|
194
|
-
"type": "topic",
|
|
195
|
-
"mockData": "FALSE"
|
|
196
|
-
}
|
|
197
|
-
]
|
|
198
|
-
}
|
|
199
|
-
]
|
|
200
|
-
}
|
|
201
|
-
]
|
|
202
|
-
}
|
|
203
|
-
]
|
|
204
|
-
}
|