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 radius from 'radius';
 | 
			
		||||
// import * as dgram from "dgram";
 | 
			
		||||
import * as fs from 'fs';
 | 
			
		||||
// import * as fs from 'fs';
 | 
			
		||||
import { EAPHandler } from './eap';
 | 
			
		||||
import { encodeTunnelPW } from './tls/crypt';
 | 
			
		||||
import { makeid } from './helpers';
 | 
			
		||||
 | 
			
		||||
import { LDAPAuth } from './ldap';
 | 
			
		||||
import { AdditionalAuthHandler } from './types/Handler';
 | 
			
		||||
 | 
			
		||||
const server = dgram.createSocket('udp4');
 | 
			
		||||
 | 
			
		||||
// not used right now, using stunnel to connect to ldap
 | 
			
		||||
const tlsOptions = {
 | 
			
		||||
/* const tlsOptions = {
 | 
			
		||||
	key: fs.readFileSync('ldap.gsuite.hokify.com.40567.key'),
 | 
			
		||||
	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.
 | 
			
		||||
	ca: [fs.readFileSync('ldap.gsuite.hokify.com.40567.key')]
 | 
			
		||||
};
 | 
			
		||||
}; */
 | 
			
		||||
 | 
			
		||||
const { argv } = require('yargs')
 | 
			
		||||
	.usage('Simple Google LDAP <> RADIUS Server\nUsage: $0')
 | 
			
		||||
@ -62,81 +62,33 @@ server.on('message', async function(msg, 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}`);
 | 
			
		||||
		let code: 'Access-Accept' | 'Access-Reject';
 | 
			
		||||
 | 
			
		||||
		let success = false;
 | 
			
		||||
		try {
 | 
			
		||||
			await ldap.authenticate(username, password);
 | 
			
		||||
			code = 'Access-Accept';
 | 
			
		||||
			success = true;
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			console.error(err);
 | 
			
		||||
			code = 'Access-Reject';
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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({
 | 
			
		||||
			packet,
 | 
			
		||||
			code,
 | 
			
		||||
			code: success ? 'Access-Accept' : 'Access-Reject',
 | 
			
		||||
			secret: argv.secret,
 | 
			
		||||
			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) {
 | 
			
		||||
			if (err) {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import * as events from 'events';
 | 
			
		||||
import { openTLSSockets, startTLSServer } from '../tls/crypt';
 | 
			
		||||
import { IResponseHandlers } from '../types/Handler';
 | 
			
		||||
import * as tls from 'tls';
 | 
			
		||||
import { encodeTunnelPW, openTLSSockets, startTLSServer } from '../tls/crypt';
 | 
			
		||||
import { AdditionalAuthHandler, IResponseHandlers } from '../types/Handler';
 | 
			
		||||
import { PAPChallenge } from './challenges/pap';
 | 
			
		||||
import { IEAPType } from '../types/EAPType';
 | 
			
		||||
 | 
			
		||||
@ -44,16 +45,20 @@ export class EAPTTLS implements IEAPType {
 | 
			
		||||
			dataStr: data.toString()
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		let sslLayer = openTLSSockets.get(state) as
 | 
			
		||||
			| { socket: events.EventEmitter; currentHandlers: IResponseHandlers }
 | 
			
		||||
		let currentConnection = openTLSSockets.get(state) as
 | 
			
		||||
			| { events: events.EventEmitter; tls: tls.TLSSocket; currentHandlers: IResponseHandlers }
 | 
			
		||||
			| undefined;
 | 
			
		||||
		if (!sslLayer) {
 | 
			
		||||
			const newSocket = startTLSServer();
 | 
			
		||||
			sslLayer = { socket: newSocket, currentHandlers: handlers };
 | 
			
		||||
			openTLSSockets.set(state, sslLayer);
 | 
			
		||||
		if (!currentConnection) {
 | 
			
		||||
			const connection = startTLSServer();
 | 
			
		||||
			currentConnection = {
 | 
			
		||||
				events: connection.events,
 | 
			
		||||
				tls: connection.tls,
 | 
			
		||||
				currentHandlers: handlers
 | 
			
		||||
			};
 | 
			
		||||
			openTLSSockets.set(state, currentConnection);
 | 
			
		||||
 | 
			
		||||
			// register event listeners
 | 
			
		||||
			newSocket.on('incoming', (incomingData: Buffer) => {
 | 
			
		||||
			currentConnection.events.on('incoming', (incomingData: Buffer) => {
 | 
			
		||||
				const type = incomingData.slice(3, 4).readUInt8(0);
 | 
			
		||||
				// const code = data.slice(4, 5).readUInt8(0);
 | 
			
		||||
 | 
			
		||||
@ -61,13 +66,18 @@ export class EAPTTLS implements IEAPType {
 | 
			
		||||
					case 1: // PAP / CHAP
 | 
			
		||||
						try {
 | 
			
		||||
							const { username, password } = this.papChallenge.decode(incomingData);
 | 
			
		||||
							sslLayer!.currentHandlers.checkAuth(username, password, identifier);
 | 
			
		||||
							currentConnection!.currentHandlers.checkAuth(username, password);
 | 
			
		||||
						} catch (err) {
 | 
			
		||||
							// pwd not found..
 | 
			
		||||
							console.error('pwd not found', err);
 | 
			
		||||
							// NAK
 | 
			
		||||
							this.sendEAPResponse(sslLayer!.currentHandlers.response, identifier, undefined, 3);
 | 
			
		||||
							newSocket.emit('end');
 | 
			
		||||
							this.sendEAPResponse(
 | 
			
		||||
								currentConnection!.currentHandlers.response,
 | 
			
		||||
								identifier,
 | 
			
		||||
								undefined,
 | 
			
		||||
								3
 | 
			
		||||
							);
 | 
			
		||||
							currentConnection!.events.emit('end');
 | 
			
		||||
							throw new Error(`pwd not found`);
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
@ -75,20 +85,20 @@ export class EAPTTLS implements IEAPType {
 | 
			
		||||
						console.log('data', incomingData);
 | 
			
		||||
						console.log('data str', incomingData.toString());
 | 
			
		||||
 | 
			
		||||
						newSocket.emit('end');
 | 
			
		||||
						currentConnection!.events.emit('end');
 | 
			
		||||
						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);
 | 
			
		||||
 | 
			
		||||
				// send back...
 | 
			
		||||
				this.sendEAPResponse(sslLayer!.currentHandlers.response, identifier, responseData);
 | 
			
		||||
				this.sendEAPResponse(currentConnection!.currentHandlers.response, identifier, responseData);
 | 
			
		||||
				// this.sendMessage(TYPE.PRELOGIN, data, false);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			newSocket.on('end', () => {
 | 
			
		||||
			currentConnection.events.on('end', () => {
 | 
			
		||||
				// cleanup socket
 | 
			
		||||
				console.log('ENDING SOCKET');
 | 
			
		||||
				openTLSSockets.del(state);
 | 
			
		||||
@ -98,13 +108,78 @@ export class EAPTTLS implements IEAPType {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// update handlers
 | 
			
		||||
		sslLayer.currentHandlers = {
 | 
			
		||||
		currentConnection.currentHandlers = {
 | 
			
		||||
			...handlers,
 | 
			
		||||
			checkAuth: (username: string, password: string) =>
 | 
			
		||||
				handlers.checkAuth(username, password, identifier)
 | 
			
		||||
			checkAuth: (username: string, password: string) => {
 | 
			
		||||
				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
 | 
			
		||||
		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);
 | 
			
		||||
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 emitter = new events.EventEmitter();
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ export function startTLSServer(): events.EventEmitter {
 | 
			
		||||
			emitter.emit('incoming', data);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		cleartext.once('close', (data: Buffer) => {
 | 
			
		||||
		cleartext.once('close', (_data: Buffer) => {
 | 
			
		||||
			console.log('cleartext close');
 | 
			
		||||
			emitter.emit('end');
 | 
			
		||||
		});
 | 
			
		||||
@ -82,7 +82,10 @@ export function startTLSServer(): events.EventEmitter {
 | 
			
		||||
		emitter.emit('end');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	return emitter;
 | 
			
		||||
	return {
 | 
			
		||||
		events: emitter,
 | 
			
		||||
		tls: cleartext
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function md5Hex(buffer: Buffer): Buffer {
 | 
			
		||||
@ -91,18 +94,15 @@ function md5Hex(buffer: Buffer): Buffer {
 | 
			
		||||
	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 {
 | 
			
		||||
	// 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
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@ -120,9 +120,6 @@ export function encodeTunnelPW(key: Buffer, authenticator: Buffer, secret: strin
 | 
			
		||||
		Buffer.from(makeid(1))
 | 
			
		||||
	]);
 | 
			
		||||
 | 
			
		||||
	console.log('salt', salt);
 | 
			
		||||
	// ensure left most bit is set to 1
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
   String
 | 
			
		||||
   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.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
	console.log('key', key.length, key);
 | 
			
		||||
	let P = Buffer.concat([new Uint8Array([key.length]), key]); // + key + padding;
 | 
			
		||||
 | 
			
		||||
	// fill up with 0x00 till we have % 16
 | 
			
		||||
	while (P.length % 16 !== 0) {
 | 
			
		||||
		P = Buffer.concat([P, Buffer.from([0x00])]);
 | 
			
		||||
	}
 | 
			
		||||
	// console.log('PLAINTEXT', P.length, P);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
   Call the shared secret S, the pseudo-random 128-bit Request
 | 
			
		||||
   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
 | 
			
		||||
   is performed in the following manner ('+' indicates
 | 
			
		||||
   concatenation):
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
	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]
 | 
			
		||||
   
 | 
			
		||||
      Zorn                         Informational                     [Page 21]
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
   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 ResponseAuthHandler = (username: string, password: string, identifier: number) => void;
 | 
			
		||||
export type ResponseAuthHandler = (
 | 
			
		||||
	username: string,
 | 
			
		||||
	password: string,
 | 
			
		||||
	additionalAuthHandler?: AdditionalAuthHandler
 | 
			
		||||
) => void;
 | 
			
		||||
 | 
			
		||||
export interface IResponseHandlers {
 | 
			
		||||
	response: ResponseHandler;
 | 
			
		||||
	checkAuth: ResponseAuthHandler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type AdditionalAuthHandler = (
 | 
			
		||||
	success: boolean,
 | 
			
		||||
	params: { packet: RadiusPacket; attributes: any[]; secret: string }
 | 
			
		||||
) => void;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user