diff --git a/scripts/simulateClient.js b/scripts/simulateClient.js index 2f51cb70..67afff0f 100644 --- a/scripts/simulateClient.js +++ b/scripts/simulateClient.js @@ -7,10 +7,8 @@ import { decode } from 'msgpackr'; console.time('Connected'); // Universal Web Socket const uwClient = await client({ - service: `${currentPath(import.meta)}/../services/universal.web-Ephemeral.cert`, - profile: `${currentPath(import.meta)}/../profiles/default.cert`, - ip: '::1', - port: 8888 + service: `${currentPath(import.meta)}/../services/universal.web-EphemeralPublic.cert`, + profile: `${currentPath(import.meta)}/../profiles/default-Ephemeral.cert`, }); console.timeEnd('Connected'); console.log('INTRO =>', uwClient); diff --git a/serverApp/index.js b/serverApp/index.js index 01c45161..730929af 100644 --- a/serverApp/index.js +++ b/serverApp/index.js @@ -31,7 +31,7 @@ const appServer = await createServer({ // default file extension default is .js but WWW default is www defaultExtension: 'html', // Domain certificate to be loaded used for connection encryption - certificate: `${currentPath(import.meta)}../services/universal.web-Profile.cert`, + certificate: `${currentPath(import.meta)}../services/universal.web-Ephemeral.cert`, // Where to load app resources from resourceDirectory: `${currentPath(import.meta)}resources/`, // Server ID used for load balancing and attaching to the end of connection IDs @@ -42,4 +42,4 @@ const appServer = await createServer({ // port: 8888, // ip: '::1' }); -info('App Server Status', appServer); +// info('App Server Status', appServer); diff --git a/udsp/client/index.js b/udsp/client/index.js index be2c032c..4d32bc79 100644 --- a/udsp/client/index.js +++ b/udsp/client/index.js @@ -22,8 +22,7 @@ import dgram from 'dgram'; // Default utility imports import { success, configure, info } from '#logs'; import { - createSessionKey, clientSession, keypair, toBase64, emptyNonce, sessionKeys, - createConnectionIdKey, encodeConnectionId, randomConnectionId + createSessionKey, clientSession, keypair, toBase64, emptyNonce, sessionKeys, randomConnectionId, ed25519ToCurve25519PublicKey } from '#crypto'; import { pluckBuffer } from '#pluckBuffer'; import { getCertificate } from '#certificate'; @@ -37,7 +36,6 @@ import { onMessage } from './onPacket.js'; import { connect } from './connect.js'; import { onListening } from './listening.js'; import { currentPath } from '#directory'; -import { encrypt } from '../../utilities/crypto'; // UNIVERSAL WEB Client Class export class Client { constructor(configuration) { @@ -48,20 +46,34 @@ export class Client { service, profile, ip: configIP, - port: configPort, - encryptConnectionId + port: configPort } = configuration; const { ip, port - } = service.ephemeral; - configure('CLIENT CONFIGURATION'); + } = service; + configure('CLIENT CONFIGURATION', service); assign(this, { ip: configIP || ip, port: configPort || port, service, profile, }); + thisClient.keypair = keypair(); + thisClient.destinationPublicKey = service.publicKey; + thisClient.destinationBoxPublicKey = ed25519ToCurve25519PublicKey(service.publicKey); + const { + publicKey, + privateKey, + } = thisClient.keypair; + const clientSessionKeys = sessionKeys(publicKey, privateKey, thisClient.destinationPublicKey); + const { + transmitKey, + receiveKey + } = clientSessionKeys; + thisClient.transmitKey = transmitKey; + thisClient.receiveKey = receiveKey; + configure(`Shared Keys Created`); this.connect = connect.bind(this); this.send = send.bind(this); this.request = request.bind(this); @@ -69,49 +81,15 @@ export class Client { this.emit = emit.bind(this); this.onListening = onListening.bind(this); this.onMessage = onMessage.bind(this); - thisClient.baseId = randomConnectionId(); - thisClient.id = encodeConnectionId(thisClient.baseId, thisClient.connectionIdKey); - thisClient.idString = toBase64(thisClient.baseId); + thisClient.id = randomConnectionId(); + thisClient.idString = toBase64(thisClient.id); thisClient.clientId = thisClient.id; success(`clientId:`, toBase64(this.id)); success(`Creating Shared Keys`); - const transmitKey = thisClient.transmitKey = createSessionKey(); - const receiveKey = thisClient.receiveKey = createSessionKey(); - // Currently unused but may in the future - const ephemeralProfileTransmitKey = thisClient.ephemeralProfileTransmitKey = createSessionKey(); - const ephemeralProfileReceiveKey = thisClient.ephemeralProfileReceiveKey = createSessionKey(); success(`Creating Connection Keypair`); - thisClient.keypair = keypair(); - if (encryptConnectionId) { + if (service.encryptConnectionId) { thisClient.connectionIdKeypair = thisClient.keypair; } - thisClient.keypair = keypair(); - thisClient.ephemeralPublic = omit(profile.ephemeral, ['private']); - if (profile.master) { - thisClient.masterPublic = omit(profile.master, ['private']); - } - const { ephemeral: { signature: profileSignature } } = profile; - const { - ephemeral: { - key: destinationPublicKey, - signature: destinationSignature - } - } = service; - thisClient.destination = { - publicKey: destinationPublicKey, - }; - const { - publicKey, - privateKey, - } = thisClient.keypair; - clientSession(receiveKey, transmitKey, publicKey, privateKey, destinationPublicKey); - configure(`Shared Keys Created`); - console.log(receiveKey, transmitKey); - const serviceKey = toBase64(destinationSignature); - const profileKey = toBase64(profileSignature); - success(`serviceKey:`, serviceKey); - success(`profileKey:`, profileKey); - // Needs to be more complex if forcing no connection with the same credentials Client.connections.set(thisClient.idString, thisClient); thisClient.server.on('message', thisClient.onMessage.bind(thisClient)); thisClient.server.on('listening', thisClient.onListening); @@ -149,15 +127,6 @@ export class Client { } packetIdGenerator = construct(UniqID); } -export function getClient(configuration) { - const serviceKey = configuration.service.ephemeral.signature.toString('base64'); - const profileKey = configuration.profile.ephemeral.signature.toString('base64'); - const connectionId = `${serviceKey}${profileKey}`; - const clientFound = Client.connections.get(connectionId); - if (clientFound) { - return clientFound; - } -} export async function createClient(configuration, ignoreConnections) { console.log(configuration); return construct(Client, [configuration]); @@ -169,10 +138,6 @@ export async function client(configuration, ignoreConnections) { if (isString(configuration.profile)) { configuration.profile = await getCertificate(configuration.profile); } - const result = getClient(configuration, Client); - if (result) { - return result; - } const uwClient = await createClient(configuration); console.time('CONNECTING'); const connectRequest = await uwClient.connect(); diff --git a/udsp/client/send.js b/udsp/client/send.js index f71fecd9..7e5f9d5b 100644 --- a/udsp/client/send.js +++ b/udsp/client/send.js @@ -14,8 +14,6 @@ export async function send(config) { info(`Send to server`); const client = this; const { - destination, - ephemeralPublic, id, ip, keypair, @@ -26,12 +24,13 @@ export async function send(config) { serverId, state, transmitKey, - connectionIdKey + connectionIdKeypair, + service, + service: { encryptConnectionId }, + destinationBoxPublicKey } = client; const packet = await encodePacket({ client, - destination, - ephemeralPublic, footer, headers, id: serverId || id, @@ -43,9 +42,12 @@ export async function send(config) { profile, state, transmitKey, - connectionIdKey + destination: service, + connectionIdKeypair, + encryptConnectionId, + destinationBoxPublicKey }); - msgSent(`Packet Size ${packet.length}`, message); + msgSent(`Packet Size ${packet.length}`, message, port, ip); return promise((accept, reject) => { server.send(packet, port, ip, (error) => { if (error) { diff --git a/udsp/decodePacket.js b/udsp/decodePacket.js index bf3f1d89..125c60fa 100644 --- a/udsp/decodePacket.js +++ b/udsp/decodePacket.js @@ -4,7 +4,7 @@ import { import { decode, } from 'msgpackr'; import { assign, } from 'Acid'; import { - encrypt, nonceBox, toBase64, hashSign, decrypt, boxUnseal, sessionKeys + encrypt, nonceBox, toBase64, decrypt, boxUnseal, sessionKeys } from '#crypto'; import { createClient } from './server/clients/index.js'; export function decodePacketHeaders(config) { @@ -15,7 +15,6 @@ export function decodePacketHeaders(config) { options, packetEncoded, server, - source, state, connectionIdKeypair, keypair, @@ -34,6 +33,7 @@ export function decodePacketHeaders(config) { info(`clientId: ${toBase64(headers.id)}`); if (headers.key) { success(`Public Key is given -> Processing as create client`); + console.log(keypair); const publicKey = boxUnseal(headers.key, keypair.publicKey, keypair.privateKey); if (!publicKey) { return failed(publicKey, 'Client Key Decrypt Failed'); @@ -66,7 +66,6 @@ export async function decodePacket(config, result) { options, packetEncoded, server, - source, state, headers, client, diff --git a/udsp/encodePacket.js b/udsp/encodePacket.js index b51ddd2a..e73427a6 100644 --- a/udsp/encodePacket.js +++ b/udsp/encodePacket.js @@ -15,12 +15,9 @@ import { nonceBox, randomize, toBase64, - hashSignDetached, + signDetached, boxSeal, boxUnseal, - crypto_box_keypair, - crypto_box_PUBLICKEYBYTES, - crypto_box_SECRETKEYBYTES } from '#crypto'; export async function encodePacket(data) { const { @@ -35,13 +32,19 @@ export async function encodePacket(data) { client, keypair, profile, - ephemeralPublic, destination, - isClient + connectionIdKeypair, + encryptConnectionId, + isClient, + destinationBoxPublicKey } = data; const nonce = randomize(nonceBuffer); if (id) { - headers.id = boxSeal(id, destination.publicKey); + if (encryptConnectionId) { + headers.id = boxSeal(id, destination.publicKey); + } else { + headers.id = id; + } } else { return console.error(`ID IS'T ASSIGNED`); } @@ -51,9 +54,12 @@ export async function encodePacket(data) { if (state === 0) { console.log('DESTINATION PUBLIC KEY', destination.publicKey); headers.key = boxSeal(keypair.publicKey, destination.publicKey); - const profileKeypairSignature = hashSignDetached(Buffer.concat([nonce, keypair.publicKey]), profile.ephemeral.private); + const timeBuffer = Buffer.from(message.t.toString()); + // This can be seperated out as an authentication request to the service or it can be done here + const authenticationBuffer = Buffer.concat([timeBuffer, destination.publicKey, keypair.publicKey]); + const profileKeypairSignature = signDetached(authenticationBuffer, profile.privateKey); message.sig = profileKeypairSignature; - message.idc = ephemeralPublic; + message.idc = profile.publicKey; console.log(`Sig Size:${message.sig.length}`); console.log(`Setting ephemeral random public key to header & profile cert to message.body`); } @@ -77,7 +83,7 @@ export async function encodePacket(data) { info(`Transmit Key ${toBase64(transmitKey)}`); info(`Nonce Size: ${headers.nonce.length} ${toBase64(headers.nonce)}`); const packetSize = packet.length; - info(`encode Packet Size ${packetSize}`); + info(`encoded Packet Size ${packetSize}`); if (packetSize >= 1280) { console.log(packet); failed(`WARNING: Packet size is larger than max allowed size 1280 -> ${packetSize} over by ${packetSize - 1280}`); diff --git a/udsp/server/bind.js b/udsp/server/bind.js index fa199910..5cd77723 100644 --- a/udsp/server/bind.js +++ b/udsp/server/bind.js @@ -6,8 +6,7 @@ export async function bindServer() { port, ip, } = this; - info(`BIND SERVER`); - console.log(this); + info(`BIND SERVER`, ip, port); await promise((accept) => { server.bind(port, ip, accept); info(`SERVER BOUND: IP:${ip} - PORT:${port}`); diff --git a/udsp/server/chunkMessage.js b/udsp/server/chunkMessage.js deleted file mode 100644 index d6d94228..00000000 --- a/udsp/server/chunkMessage.js +++ /dev/null @@ -1,2 +0,0 @@ -export function chunkMessage() { -} diff --git a/udsp/server/clients/index.js b/udsp/server/clients/index.js index d5d4f8ec..e13116d3 100644 --- a/udsp/server/clients/index.js +++ b/udsp/server/clients/index.js @@ -9,9 +9,7 @@ import { success, failed, imported, msgSent, info, msgReceived } from '#logs'; import { UniqID, construct, assign } from 'Acid'; -import { - sessionKeys, keypair, toBase64, signVerifyHash -} from '#crypto'; +import { sessionKeys, keypair, toBase64 } from '#crypto'; export class Client { descriptor = 'client'; client = true; diff --git a/udsp/server/clients/initialize.js b/udsp/server/clients/initialize.js index acfd9b17..c0a761bc 100644 --- a/udsp/server/clients/initialize.js +++ b/udsp/server/clients/initialize.js @@ -1,9 +1,8 @@ import { created } from './created.js'; import { - decrypt, emptyNonce, keypair, randombytes_buf, - sessionKeys, signVerifyHash, toBase64, boxUnseal, - encodeConnectionId, randomConnectionId, - getConnectionId, + decrypt, emptyNonce, keypair, + sessionKeys, toBase64, boxUnseal, + randomConnectionId, randomBuffer } from '#crypto'; import { diff --git a/udsp/server/configure.js b/udsp/server/configure.js deleted file mode 100644 index 1974a67e..00000000 --- a/udsp/server/configure.js +++ /dev/null @@ -1,18 +0,0 @@ -import { assign } from 'Acid'; -import { - success, failed, imported, msgSent, info, msgReceived -} from '#logs'; -export function configure(source) { - info('SERVER CONFIGURATION'); - console.log('Server provided config', source.configuration); - const { - ip: certIp, - port: certPort - } = source.profile.ephemeral; - const port = source.configuration.port || certPort; - const ip = source.configuration.ip || certIp; - assign(source, { - ip, - port, - }); -} diff --git a/udsp/server/index.js b/udsp/server/index.js index ffc8d9d2..ebafc752 100644 --- a/udsp/server/index.js +++ b/udsp/server/index.js @@ -17,8 +17,6 @@ import { currentPath } from '#utilities/directory'; import dgram from 'dgram'; import { on, off } from './events.js'; import { bindServer } from './bind.js'; -import { chunkMessage } from './chunkMessage.js'; -import { configure } from './configure.js'; import { emit } from './emit.js'; import { onError } from './onError.js'; import { onListen } from './onListen.js'; @@ -90,22 +88,24 @@ export class Server { emit }); thisServer.bindActions(actions); - if (configuration.certificate) { - thisServer.certificate = await getCertificate(configuration.certificate); + if (thisServer.certificate) { + thisServer.certificate = await getCertificate(thisServer.certificate); + thisServer.publicCertificate = thisServer.certificate.certificateDecoded; thisServer.keypair = { - publicKey: thisServer.certificate.publicKey || thisServer.certificate.ephemeral.publicKey, - privateKey: thisServer.certificate.privateKey || thisServer.certificate.ephemeral.privateKey, + publicKey: thisServer.certificate.publicKey, + privateKey: thisServer.certificate.privateKey, }; } - if (configuration.connectionIdCertificate) { - thisServer.connectionIdCertificate = await getCertificate(configuration.connectionIdCertificate); - } else if (configuration.encryptConnectionId) { + if (thisServer.connectionIdCertificate) { + thisServer.connectionIdCertificate = await getCertificate(thisServer.connectionIdCertificate); + } else if (thisServer.publicCertificate.encryptConnectionId) { thisServer.connectionIdKeypair = thisServer.certificate; } if (thisServer.connectionIdKeypair) { + thisServer.encryptConnectionId = true; thisServer.connectionIdKeypair = { - publicKey: thisServer.connectionIdKeypair.publicKey || thisServer.connectionIdKeypair.ephemeral.publicKey, - privateKey: thisServer.connectionIdKeypair.privateKey || thisServer.connectionIdKeypair.ephemeral.privateKey, + publicKey: thisServer.connectionIdKeypair.publicKey, + privateKey: thisServer.connectionIdKeypair.privateKey, }; } if (configuration.randomId || !thisServer.id) { @@ -114,7 +114,17 @@ export class Server { if (isFunction(thisServer.id)) { thisServer.id = await thisServer.id(); } - configure(thisServer); + if (thisServer.publicCertificate) { + const { + ip: certIp, + port: certPort + } = thisServer.publicCertificate; + const port = configuration.port || certPort; + const ip = configuration.ip || certIp; + console.log(thisServer.certificate, ip, port); + this.ip = ip; + this.port = port; + } thisServer.server.on('error', thisServer.onError); thisServer.server.on('listening', thisServer.onListen); thisServer.server.on('message', thisServer.onPacket); diff --git a/udsp/server/onPacket.js b/udsp/server/onPacket.js index 6f3abfb1..d5236ed3 100644 --- a/udsp/server/onPacket.js +++ b/udsp/server/onPacket.js @@ -13,7 +13,8 @@ export async function onPacket(packetEncoded, connection) { const thisServer = this; const { keypair, - connectionIdKeypair + connectionIdKeypair, + encryptConnectionId } = thisServer; msgReceived('Message Received'); const config = { @@ -22,6 +23,7 @@ export async function onPacket(packetEncoded, connection) { server: thisServer, isServer: true, keypair, + encryptConnectionId, connectionIdKeypair }; const headers = await decodePacketHeaders(config); diff --git a/utilities/certificate/create.js b/utilities/certificate/create.js index 2df53144..3c4443c3 100644 --- a/utilities/certificate/create.js +++ b/utilities/certificate/create.js @@ -30,8 +30,8 @@ function certificateFactory(config, options = {}) { certificateWrapper.publicKey = publicKey; } if (options.master) { - certificate.masterSignature = signDetached(certificate.publicKey, options.master.privateKey); - certificate.masterPublicKey = options.master.certificate.publicKey; + certificate.masterSignature = signDetached(Buffer.concat([certificate.start, certificate.publicKey]), options.master.privateKey); + certificate.masterPublicKey = options.master.publicKey; } certificateWrapper.certificate = encode(certificateWrapper.certificate); if (options.master) { diff --git a/utilities/crypto.js b/utilities/crypto.js index 11a7e459..e7ff074d 100644 --- a/utilities/crypto.js +++ b/utilities/crypto.js @@ -42,7 +42,9 @@ const { crypto_secretbox_easy, crypto_secretbox_MACBYTES, crypto_secretbox_NONCEBYTES, - crypto_secretbox_KEYBYTES + crypto_secretbox_KEYBYTES, + crypto_sign_ed25519_pk_to_curve25519, + crypto_sign_ed25519_sk_to_curve25519 } = sodiumLib; import { isBuffer, assign } from 'Acid'; import { encode, decode } from 'msgpackr'; @@ -157,8 +159,6 @@ export function sessionKeys(sourcePublicKey, sourcePrivateKey, targetPublicKey) receiveKey }; } -/* console.log(crypto_kx_SECRETKEYBYTES, crypto_sign_SECRETKEYBYTES); - */ export function signKeypair() { const publicKey = bufferAlloc(crypto_sign_PUBLICKEYBYTES); const privateKey = bufferAlloc(crypto_sign_SECRETKEYBYTES); @@ -168,6 +168,15 @@ export function signKeypair() { privateKey }; } +export function boxKeypair() { + const publicKey = bufferAlloc(crypto_box_PUBLICKEYBYTES); + const privateKey = bufferAlloc(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(publicKey, privateKey); + return { + publicKey, + privateKey + }; +} export function boxSeal(message, publicKey) { const encrypted = bufferAlloc(message.length + crypto_box_SEALBYTES); crypto_box_seal(encrypted, message, publicKey); @@ -178,6 +187,26 @@ export function boxUnseal(encrypted, publicKey, privateKey) { const isValid = crypto_box_seal_open(message, encrypted, publicKey, privateKey); return isValid && message; } +export function ed25519ToCurve25519PublicKey(originalPublicKey) { + const publicKey = bufferAlloc(crypto_box_PUBLICKEYBYTES); + crypto_sign_ed25519_pk_to_curve25519(publicKey, originalPublicKey); + return publicKey; +} +export function ed25519ToCurve25519PrivateKey(originalPrivateKey) { + const privateKey = bufferAlloc(crypto_box_SECRETKEYBYTES); + crypto_sign_ed25519_sk_to_curve25519(privateKey, originalPrivateKey); + return privateKey; +} +export function ed25519ToCurve25519(originalKeypair) { + const publicKey = bufferAlloc(crypto_box_PUBLICKEYBYTES); + const privateKey = bufferAlloc(crypto_box_SECRETKEYBYTES); + crypto_sign_ed25519_pk_to_curve25519(publicKey, originalKeypair.publicKey); + crypto_sign_ed25519_sk_to_curve25519(privateKey, originalKeypair.privateKey); + return { + publicKey, + privateKey + }; +} export function toBuffer(value) { return Buffer.from(value); }