fix: add MS-MPPE-Send-Key and MS-MPPE-Recv-Key
This commit is contained in:
parent
13f10bae59
commit
7e28c60d81
78
src/app.ts
78
src/app.ts
@ -1,17 +1,17 @@
|
|||||||
import * as dgram from 'dgram';
|
import * as dgram from 'dgram';
|
||||||
import * as radius from 'radius';
|
import * as radius from 'radius';
|
||||||
// import * as dgram from "dgram";
|
// import * as dgram from "dgram";
|
||||||
import * as fs from 'fs';
|
// import * as fs from 'fs';
|
||||||
import { EAPHandler } from './eap';
|
import { EAPHandler } from './eap';
|
||||||
import { encodeTunnelPW } from './tls/crypt';
|
|
||||||
import { makeid } from './helpers';
|
import { makeid } from './helpers';
|
||||||
|
|
||||||
import { LDAPAuth } from './ldap';
|
import { LDAPAuth } from './ldap';
|
||||||
|
import { AdditionalAuthHandler } from './types/Handler';
|
||||||
|
|
||||||
const server = dgram.createSocket('udp4');
|
const server = dgram.createSocket('udp4');
|
||||||
|
|
||||||
// not used right now, using stunnel to connect to ldap
|
// not used right now, using stunnel to connect to ldap
|
||||||
const tlsOptions = {
|
/* const tlsOptions = {
|
||||||
key: fs.readFileSync('ldap.gsuite.hokify.com.40567.key'),
|
key: fs.readFileSync('ldap.gsuite.hokify.com.40567.key'),
|
||||||
cert: fs.readFileSync('ldap.gsuite.hokify.com.40567.crt'),
|
cert: fs.readFileSync('ldap.gsuite.hokify.com.40567.crt'),
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ const tlsOptions = {
|
|||||||
|
|
||||||
// This is necessary only if the client uses the self-signed certificate.
|
// This is necessary only if the client uses the self-signed certificate.
|
||||||
ca: [fs.readFileSync('ldap.gsuite.hokify.com.40567.key')]
|
ca: [fs.readFileSync('ldap.gsuite.hokify.com.40567.key')]
|
||||||
};
|
}; */
|
||||||
|
|
||||||
const { argv } = require('yargs')
|
const { argv } = require('yargs')
|
||||||
.usage('Simple Google LDAP <> RADIUS Server\nUsage: $0')
|
.usage('Simple Google LDAP <> RADIUS Server\nUsage: $0')
|
||||||
@ -62,81 +62,33 @@ server.on('message', async function(msg, rinfo) {
|
|||||||
|
|
||||||
// console.log('rinfo', rinfo);
|
// console.log('rinfo', rinfo);
|
||||||
|
|
||||||
async function checkAuth(username: string, password: string, EAPMessageIdentifier?: number) {
|
async function checkAuth(
|
||||||
|
username: string,
|
||||||
|
password: string,
|
||||||
|
additionalAuthHandler?: AdditionalAuthHandler
|
||||||
|
) {
|
||||||
console.log(`Access-Request for ${username}`);
|
console.log(`Access-Request for ${username}`);
|
||||||
let code: 'Access-Accept' | 'Access-Reject';
|
let success = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ldap.authenticate(username, password);
|
await ldap.authenticate(username, password);
|
||||||
code = 'Access-Accept';
|
success = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
code = 'Access-Reject';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const attributes: any[] = [];
|
const attributes: any[] = [];
|
||||||
if (EAPMessageIdentifier) {
|
|
||||||
const buffer = Buffer.from([
|
|
||||||
code === 'Access-Accept' ? 3 : 4, // 3.. success, 4... failure
|
|
||||||
EAPMessageIdentifier,
|
|
||||||
0, // length (1/2)
|
|
||||||
4 // length (2/2)
|
|
||||||
]);
|
|
||||||
|
|
||||||
attributes.push(['EAP-Message', buffer]);
|
if (additionalAuthHandler) {
|
||||||
|
await additionalAuthHandler(success, { packet, attributes, secret: argv.secret });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.attributes && packet.attributes['User-Name']) {
|
|
||||||
// reappend username to response
|
|
||||||
attributes.push(['User-Name', packet.attributes['User-Name']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (sess->eap_if->eapKeyDataLen > 64) {
|
|
||||||
len = 32;
|
|
||||||
} else {
|
|
||||||
len = sess->eap_if->eapKeyDataLen / 2;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// eapKeyData + len
|
|
||||||
attributes.push([
|
|
||||||
'Vendor-Specific',
|
|
||||||
311,
|
|
||||||
[
|
|
||||||
[
|
|
||||||
16,
|
|
||||||
encodeTunnelPW(
|
|
||||||
(packet as any).authenticator,
|
|
||||||
packet.attributes['Message-Authenticator'],
|
|
||||||
argv.secret
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]); // MS-MPPE-Send-Key
|
|
||||||
|
|
||||||
// eapKeyData
|
|
||||||
attributes.push([
|
|
||||||
'Vendor-Specific',
|
|
||||||
311,
|
|
||||||
[
|
|
||||||
[
|
|
||||||
17,
|
|
||||||
encodeTunnelPW(
|
|
||||||
(packet as any).authenticator,
|
|
||||||
packet.attributes['Message-Authenticator'],
|
|
||||||
argv.secret
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]); // MS-MPPE-Recv-Key
|
|
||||||
|
|
||||||
const response = radius.encode_response({
|
const response = radius.encode_response({
|
||||||
packet,
|
packet,
|
||||||
code,
|
code: success ? 'Access-Accept' : 'Access-Reject',
|
||||||
secret: argv.secret,
|
secret: argv.secret,
|
||||||
attributes
|
attributes
|
||||||
});
|
});
|
||||||
console.log(`Sending ${code} for user ${username}`);
|
console.log(`Sending ${success ? 'accept' : 'reject'} for user ${username}`);
|
||||||
|
|
||||||
server.send(response, 0, response.length, rinfo.port, rinfo.address, function(err, _bytes) {
|
server.send(response, 0, response.length, rinfo.port, rinfo.address, function(err, _bytes) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as events from 'events';
|
import * as events from 'events';
|
||||||
import { openTLSSockets, startTLSServer } from '../tls/crypt';
|
import * as tls from 'tls';
|
||||||
import { IResponseHandlers } from '../types/Handler';
|
import { encodeTunnelPW, openTLSSockets, startTLSServer } from '../tls/crypt';
|
||||||
|
import { AdditionalAuthHandler, IResponseHandlers } from '../types/Handler';
|
||||||
import { PAPChallenge } from './challenges/pap';
|
import { PAPChallenge } from './challenges/pap';
|
||||||
import { IEAPType } from '../types/EAPType';
|
import { IEAPType } from '../types/EAPType';
|
||||||
|
|
||||||
@ -44,16 +45,20 @@ export class EAPTTLS implements IEAPType {
|
|||||||
dataStr: data.toString()
|
dataStr: data.toString()
|
||||||
});
|
});
|
||||||
|
|
||||||
let sslLayer = openTLSSockets.get(state) as
|
let currentConnection = openTLSSockets.get(state) as
|
||||||
| { socket: events.EventEmitter; currentHandlers: IResponseHandlers }
|
| { events: events.EventEmitter; tls: tls.TLSSocket; currentHandlers: IResponseHandlers }
|
||||||
| undefined;
|
| undefined;
|
||||||
if (!sslLayer) {
|
if (!currentConnection) {
|
||||||
const newSocket = startTLSServer();
|
const connection = startTLSServer();
|
||||||
sslLayer = { socket: newSocket, currentHandlers: handlers };
|
currentConnection = {
|
||||||
openTLSSockets.set(state, sslLayer);
|
events: connection.events,
|
||||||
|
tls: connection.tls,
|
||||||
|
currentHandlers: handlers
|
||||||
|
};
|
||||||
|
openTLSSockets.set(state, currentConnection);
|
||||||
|
|
||||||
// register event listeners
|
// register event listeners
|
||||||
newSocket.on('incoming', (incomingData: Buffer) => {
|
currentConnection.events.on('incoming', (incomingData: Buffer) => {
|
||||||
const type = incomingData.slice(3, 4).readUInt8(0);
|
const type = incomingData.slice(3, 4).readUInt8(0);
|
||||||
// const code = data.slice(4, 5).readUInt8(0);
|
// const code = data.slice(4, 5).readUInt8(0);
|
||||||
|
|
||||||
@ -61,13 +66,18 @@ export class EAPTTLS implements IEAPType {
|
|||||||
case 1: // PAP / CHAP
|
case 1: // PAP / CHAP
|
||||||
try {
|
try {
|
||||||
const { username, password } = this.papChallenge.decode(incomingData);
|
const { username, password } = this.papChallenge.decode(incomingData);
|
||||||
sslLayer!.currentHandlers.checkAuth(username, password, identifier);
|
currentConnection!.currentHandlers.checkAuth(username, password);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// pwd not found..
|
// pwd not found..
|
||||||
console.error('pwd not found', err);
|
console.error('pwd not found', err);
|
||||||
// NAK
|
// NAK
|
||||||
this.sendEAPResponse(sslLayer!.currentHandlers.response, identifier, undefined, 3);
|
this.sendEAPResponse(
|
||||||
newSocket.emit('end');
|
currentConnection!.currentHandlers.response,
|
||||||
|
identifier,
|
||||||
|
undefined,
|
||||||
|
3
|
||||||
|
);
|
||||||
|
currentConnection!.events.emit('end');
|
||||||
throw new Error(`pwd not found`);
|
throw new Error(`pwd not found`);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -75,20 +85,20 @@ export class EAPTTLS implements IEAPType {
|
|||||||
console.log('data', incomingData);
|
console.log('data', incomingData);
|
||||||
console.log('data str', incomingData.toString());
|
console.log('data str', incomingData.toString());
|
||||||
|
|
||||||
newSocket.emit('end');
|
currentConnection!.events.emit('end');
|
||||||
throw new Error(`unsupported auth type${type}`);
|
throw new Error(`unsupported auth type${type}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
newSocket.on('response', (responseData: Buffer) => {
|
currentConnection.events.on('response', (responseData: Buffer) => {
|
||||||
console.log('sending encrypted data back to client', responseData);
|
console.log('sending encrypted data back to client', responseData);
|
||||||
|
|
||||||
// send back...
|
// send back...
|
||||||
this.sendEAPResponse(sslLayer!.currentHandlers.response, identifier, responseData);
|
this.sendEAPResponse(currentConnection!.currentHandlers.response, identifier, responseData);
|
||||||
// this.sendMessage(TYPE.PRELOGIN, data, false);
|
// this.sendMessage(TYPE.PRELOGIN, data, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
newSocket.on('end', () => {
|
currentConnection.events.on('end', () => {
|
||||||
// cleanup socket
|
// cleanup socket
|
||||||
console.log('ENDING SOCKET');
|
console.log('ENDING SOCKET');
|
||||||
openTLSSockets.del(state);
|
openTLSSockets.del(state);
|
||||||
@ -98,13 +108,78 @@ export class EAPTTLS implements IEAPType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update handlers
|
// update handlers
|
||||||
sslLayer.currentHandlers = {
|
currentConnection.currentHandlers = {
|
||||||
...handlers,
|
...handlers,
|
||||||
checkAuth: (username: string, password: string) =>
|
checkAuth: (username: string, password: string) => {
|
||||||
handlers.checkAuth(username, password, identifier)
|
const additionalAuthHandler: AdditionalAuthHandler = (success, params) => {
|
||||||
|
const buffer = Buffer.from([
|
||||||
|
success ? 3 : 4, // 3.. success, 4... failure
|
||||||
|
identifier,
|
||||||
|
0, // length (1/2)
|
||||||
|
4 // length (2/2)
|
||||||
|
]);
|
||||||
|
|
||||||
|
params.attributes.push(['EAP-Message', buffer]);
|
||||||
|
|
||||||
|
if (params.packet.attributes && params.packet.attributes['User-Name']) {
|
||||||
|
// reappend username to response
|
||||||
|
params.attributes.push(['User-Name', params.packet.attributes['User-Name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (sess->eap_if->eapKeyDataLen > 64) {
|
||||||
|
len = 32;
|
||||||
|
} else {
|
||||||
|
len = sess->eap_if->eapKeyDataLen / 2;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const keyingMaterial = (currentConnection?.tls as any).exportKeyingMaterial(
|
||||||
|
128,
|
||||||
|
'ttls keying material'
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('keyingMaterial', keyingMaterial);
|
||||||
|
|
||||||
|
// eapKeyData + len
|
||||||
|
params.attributes.push([
|
||||||
|
'Vendor-Specific',
|
||||||
|
311,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
16,
|
||||||
|
encodeTunnelPW(
|
||||||
|
keyingMaterial.slice(64),
|
||||||
|
(params.packet as any).authenticator,
|
||||||
|
// params.packet.attributes['Message-Authenticator'],
|
||||||
|
params.secret
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]); // MS-MPPE-Send-Key
|
||||||
|
|
||||||
|
// eapKeyData
|
||||||
|
params.attributes.push([
|
||||||
|
'Vendor-Specific',
|
||||||
|
311,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
17,
|
||||||
|
encodeTunnelPW(
|
||||||
|
keyingMaterial.slice(0, 64),
|
||||||
|
(params.packet as any).authenticator,
|
||||||
|
// params.packet.attributes['Message-Authenticator'],
|
||||||
|
params.secret
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]); // MS-MPPE-Recv-Key
|
||||||
|
};
|
||||||
|
|
||||||
|
return handlers.checkAuth(username, password, additionalAuthHandler);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// emit data to tls server
|
// emit data to tls server
|
||||||
sslLayer.socket.emit('send', data);
|
currentConnection.events.emit('send', data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
115
src/tls/crypt.ts
115
src/tls/crypt.ts
@ -16,7 +16,7 @@ const tlsOptions = {
|
|||||||
const secureContext = createSecureContext(tlsOptions);
|
const secureContext = createSecureContext(tlsOptions);
|
||||||
export const openTLSSockets = new NodeCache({ useClones: false, stdTTL: 3600 }); // keep sockets for about one hour
|
export const openTLSSockets = new NodeCache({ useClones: false, stdTTL: 3600 }); // keep sockets for about one hour
|
||||||
|
|
||||||
export function startTLSServer(): events.EventEmitter {
|
export function startTLSServer(): { events: events.EventEmitter; tls: tls.TLSSocket } {
|
||||||
const duplexpair = new DuplexPair();
|
const duplexpair = new DuplexPair();
|
||||||
const emitter = new events.EventEmitter();
|
const emitter = new events.EventEmitter();
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export function startTLSServer(): events.EventEmitter {
|
|||||||
emitter.emit('incoming', data);
|
emitter.emit('incoming', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
cleartext.once('close', (data: Buffer) => {
|
cleartext.once('close', (_data: Buffer) => {
|
||||||
console.log('cleartext close');
|
console.log('cleartext close');
|
||||||
emitter.emit('end');
|
emitter.emit('end');
|
||||||
});
|
});
|
||||||
@ -82,7 +82,10 @@ export function startTLSServer(): events.EventEmitter {
|
|||||||
emitter.emit('end');
|
emitter.emit('end');
|
||||||
});
|
});
|
||||||
|
|
||||||
return emitter;
|
return {
|
||||||
|
events: emitter,
|
||||||
|
tls: cleartext
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function md5Hex(buffer: Buffer): Buffer {
|
function md5Hex(buffer: Buffer): Buffer {
|
||||||
@ -91,18 +94,15 @@ function md5Hex(buffer: Buffer): Buffer {
|
|||||||
return hasher.digest(); // new Buffer(hasher.digest("binary"), "binary");
|
return hasher.digest(); // new Buffer(hasher.digest("binary"), "binary");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alloc_size
|
||||||
|
|
||||||
|
// 0,
|
||||||
|
// EAP_TLS_KEY_LEN 64
|
||||||
|
// EAP_EMSK_LEN 64
|
||||||
|
// const buffer = tlsSocket.exportKeyingMaterial(128, 'ttls keying material');
|
||||||
|
|
||||||
export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: string): Buffer {
|
export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: string): Buffer {
|
||||||
// see freeradius TTLS implementation how to obtain "key"......
|
// see freeradius TTLS implementation how to obtain "key"......
|
||||||
|
|
||||||
// key should be:
|
|
||||||
// https://www.openssl.org/docs/man1.0.2/man3/SSL_export_keying_material.html
|
|
||||||
// https://github.com/nodejs/ffi/blob/master/deps/openssl/openssl/doc/man3/SSL_export_keying_material.pod
|
|
||||||
|
|
||||||
// but not available in NODE JS
|
|
||||||
|
|
||||||
console.log('KEY', key);
|
|
||||||
console.log('authenticator', authenticator);
|
|
||||||
console.log('secret', secret);
|
|
||||||
// https://tools.ietf.org/html/rfc2548
|
// https://tools.ietf.org/html/rfc2548
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,9 +120,6 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|||||||
Buffer.from(makeid(1))
|
Buffer.from(makeid(1))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log('salt', salt);
|
|
||||||
// ensure left most bit is set to 1
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
String
|
String
|
||||||
The plaintext String field consists of three logical sub-fields:
|
The plaintext String field consists of three logical sub-fields:
|
||||||
@ -143,14 +140,13 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|||||||
used for padding. Call this plaintext P.
|
used for padding. Call this plaintext P.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
console.log('key', key.length, key);
|
|
||||||
let P = Buffer.concat([new Uint8Array([key.length]), key]); // + key + padding;
|
let P = Buffer.concat([new Uint8Array([key.length]), key]); // + key + padding;
|
||||||
|
|
||||||
// fill up with 0x00 till we have % 16
|
// fill up with 0x00 till we have % 16
|
||||||
while (P.length % 16 !== 0) {
|
while (P.length % 16 !== 0) {
|
||||||
P = Buffer.concat([P, Buffer.from([0x00])]);
|
P = Buffer.concat([P, Buffer.from([0x00])]);
|
||||||
}
|
}
|
||||||
// console.log('PLAINTEXT', P.length, P);
|
|
||||||
/*
|
/*
|
||||||
Call the shared secret S, the pseudo-random 128-bit Request
|
Call the shared secret S, the pseudo-random 128-bit Request
|
||||||
Authenticator (from the corresponding Access-Request packet) R,
|
Authenticator (from the corresponding Access-Request packet) R,
|
||||||
@ -160,54 +156,8 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|||||||
Intermediate values b(1), b(2)...c(i) are required. Encryption
|
Intermediate values b(1), b(2)...c(i) are required. Encryption
|
||||||
is performed in the following manner ('+' indicates
|
is performed in the following manner ('+' indicates
|
||||||
concatenation):
|
concatenation):
|
||||||
*/
|
|
||||||
|
Zorn Informational [Page 21]
|
||||||
const p: Buffer[] = [];
|
|
||||||
for (let i = 0; i < P.length; i += 16) {
|
|
||||||
p.push(P.slice(i, i + 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
const S = secret;
|
|
||||||
const R = authenticator;
|
|
||||||
const A = salt;
|
|
||||||
|
|
||||||
// console.log('S', S);
|
|
||||||
// console.log('R', R);
|
|
||||||
// console.log('A', A);
|
|
||||||
|
|
||||||
// const P = Buffer.alloc(16);
|
|
||||||
|
|
||||||
let C;
|
|
||||||
const c: { [key: number]: Buffer } = {};
|
|
||||||
const b: { [key: number]: Buffer } = {};
|
|
||||||
|
|
||||||
// console.log('S + R + A', S + R + A);
|
|
||||||
|
|
||||||
for (let i = 0; i < p.length; i++) {
|
|
||||||
// one octet is 8.. therefore +=2 means next 16
|
|
||||||
if (!i) {
|
|
||||||
b[i] = md5Hex(Buffer.concat([Buffer.from(S), R, A]));
|
|
||||||
} else {
|
|
||||||
b[i] = md5Hex(Buffer.concat([Buffer.from(S), c[i - 1]]));
|
|
||||||
}
|
|
||||||
|
|
||||||
c[i] = Buffer.alloc(16); // ''; //p[i];
|
|
||||||
for (let n = 0; n < p[i].length; n++) {
|
|
||||||
// eslint-disable-next-line no-bitwise
|
|
||||||
c[i][n] = p[i][n] ^ b[i][n];
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('c['+i+']', c[i]);
|
|
||||||
// console.log('b['+i+']', b[i]);
|
|
||||||
|
|
||||||
C = C ? Buffer.concat([C, c[i]]) : c[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
const bufferC = Buffer.from(C);
|
|
||||||
console.log('BUFFER C', bufferC.length, bufferC);
|
|
||||||
return Buffer.concat([salt, bufferC]);
|
|
||||||
/*
|
|
||||||
Zorn Informational [Page 21]
|
|
||||||
|
|
||||||
RFC 2548 Microsoft Vendor-specific RADIUS Attributes March 1999
|
RFC 2548 Microsoft Vendor-specific RADIUS Attributes March 1999
|
||||||
|
|
||||||
@ -222,4 +172,37 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
|
|||||||
The resulting encrypted String field will contain
|
The resulting encrypted String field will contain
|
||||||
c(1)+c(2)+...+c(i).
|
c(1)+c(2)+...+c(i).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const p: Buffer[] = [];
|
||||||
|
for (let i = 0; i < P.length; i += 16) {
|
||||||
|
p.push(P.slice(i, i + 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
const S = secret;
|
||||||
|
const R = authenticator;
|
||||||
|
const A = salt;
|
||||||
|
|
||||||
|
let C;
|
||||||
|
const c: { [key: number]: Buffer } = {};
|
||||||
|
const b: { [key: number]: Buffer } = {};
|
||||||
|
|
||||||
|
for (let i = 0; i < p.length; i++) {
|
||||||
|
if (!i) {
|
||||||
|
b[i] = md5Hex(Buffer.concat([Buffer.from(S), R, A]));
|
||||||
|
} else {
|
||||||
|
b[i] = md5Hex(Buffer.concat([Buffer.from(S), c[i - 1]]));
|
||||||
|
}
|
||||||
|
|
||||||
|
c[i] = Buffer.alloc(16); // ''; //p[i];
|
||||||
|
for (let n = 0; n < p[i].length; n++) {
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
c[i][n] = p[i][n] ^ b[i][n];
|
||||||
|
}
|
||||||
|
|
||||||
|
C = C ? Buffer.concat([C, c[i]]) : c[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const bufferC = Buffer.from(C);
|
||||||
|
|
||||||
|
return Buffer.concat([salt, bufferC]);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,18 @@
|
|||||||
|
import { RadiusPacket } from 'radius';
|
||||||
|
|
||||||
export type ResponseHandler = (msg: Buffer) => void;
|
export type ResponseHandler = (msg: Buffer) => void;
|
||||||
export type ResponseAuthHandler = (username: string, password: string, identifier: number) => void;
|
export type ResponseAuthHandler = (
|
||||||
|
username: string,
|
||||||
|
password: string,
|
||||||
|
additionalAuthHandler?: AdditionalAuthHandler
|
||||||
|
) => void;
|
||||||
|
|
||||||
export interface IResponseHandlers {
|
export interface IResponseHandlers {
|
||||||
response: ResponseHandler;
|
response: ResponseHandler;
|
||||||
checkAuth: ResponseAuthHandler;
|
checkAuth: ResponseAuthHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AdditionalAuthHandler = (
|
||||||
|
success: boolean,
|
||||||
|
params: { packet: RadiusPacket; attributes: any[]; secret: string }
|
||||||
|
) => void;
|
||||||
|
Loading…
Reference in New Issue
Block a user