{"id":25026007,"url":"https://github.com/979st/smp25519-typescript","last_synced_at":"2025-04-13T11:51:16.731Z","repository":{"id":273770079,"uuid":"920821117","full_name":"979st/smp25519-typescript","owner":"979st","description":"Secure Messaging Protocol 25519","archived":false,"fork":false,"pushed_at":"2025-01-22T20:49:03.000Z","size":102,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-03-27T03:01:32.194Z","etag":null,"topics":["javascript","messaging","network-programming","protocol","secure","sockets","typescript","udp","x25519"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/979st.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-22T20:37:24.000Z","updated_at":"2025-01-27T12:02:12.000Z","dependencies_parsed_at":"2025-01-22T21:30:17.951Z","dependency_job_id":null,"html_url":"https://github.com/979st/smp25519-typescript","commit_stats":null,"previous_names":["979st/smp25519-typescript"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/979st%2Fsmp25519-typescript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/979st%2Fsmp25519-typescript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/979st%2Fsmp25519-typescript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/979st%2Fsmp25519-typescript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/979st","download_url":"https://codeload.github.com/979st/smp25519-typescript/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248710438,"owners_count":21149188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","messaging","network-programming","protocol","secure","sockets","typescript","udp","x25519"],"created_at":"2025-02-05T17:18:34.660Z","updated_at":"2025-04-13T11:51:16.708Z","avatar_url":"https://github.com/979st.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SMP25519 | Secure Messaging Protocol 25519 | TypeScript \u0026 JavaScript\n![SMP25519 Flow Chart](./svg/smp25519_flow_chart.svg)\n## Overview\nSMP25519 is designed to facilitate secure communication using the X25519 key exchange, BLAKE3 hashing, and ChaCha20 encryption. It provides a straightforward interface for generating secure identities, creating handshake messages, deriving shared secrets, and encrypting/decrypting data.\n## Installation\n```\nnpm install smp25519\n```\n## Dependencies\nSMP25519 uses the following dependencies:\n- [@noble/ciphers](https://www.npmjs.com/package/@noble/ciphers)\n- [@noble/curves](https://www.npmjs.com/package/@noble/curves)\n- [@noble/hashes](https://www.npmjs.com/package/@noble/hashes)\n## License\nThis package is distributed under the [Unlicense](https://choosealicense.com/licenses/unlicense/).\n## Contact\nFor support or inquiries, contact truebreaker@proton.me.\n# Examples\n## Client\n```typescript\nimport * as smp25519 from \"smp25519\";\nimport dgram from \"dgram\";\nimport { exit } from \"process\";\nimport * as base64 from \"js-base64\"\n\nfunction stringToUint8Array(input: string): Uint8Array {\n    const encoder = new TextEncoder();\n    return encoder.encode(input);\n}\n\nfunction uint8ArrayToString(input: Uint8Array): string {\n    const decoder = new TextDecoder();\n    return decoder.decode(input);\n}\n\n/*\n * Secure UDP client example using the smp25519 package.\n * This script demonstrates how to establish a secure communication channel with a server using key exchange and encryption.\n */\nfunction main() {\n    // Step 1: Generate client identity (private key, public key, and connection ID).\n    const { privateKey, publicKey, connectionId } = smp25519.generateIdentity();\n\n    // Step 2 (RECOMMENDED): Define the server's known public key (Base64 encoded).\n    let knownServerPublicKey = base64.toUint8Array(\"Vh4DBTYyDbwTqg1eZzTnuTxThscIoNQgLpxgsBCOFCU=\");\n\n    // Step 3: Create a UDP socket.\n    const socket = dgram.createSocket(\"udp4\");\n    const SERVER_HOST = \"localhost\";\n    const SERVER_PORT = 12000;\n\n    console.log(`Secure UDP Client: Attempting connection to ${SERVER_HOST}:${SERVER_PORT}.`);\n\n    // Variables to store server-specific connection data.\n    let serverPublicKey: Uint8Array;\n    let sharedSecret: Uint8Array;\n\n    // Message handler\n    socket.on(\"message\", (msg, rinfo) =\u003e {\n        // Step 5: Receive and validate handshake response from the server.\n        if (smp25519.isHandshakeMessage(msg) == true) {\n            // Extract the server's public key from the handshake message.\n            serverPublicKey = smp25519.extractPublicKeyFromHandshake(msg);\n\n            // (RECOMMENDED) Verify the server's public key.\n            if (serverPublicKey.every((val, index) =\u003e val !== knownServerPublicKey[index])) {\n                console.error(\"Error: Known server public key mismatch. Aborting connection.\");\n                exit(-1);\n            }\n\n            // Step 6: Derive the shared secret using the server's public key and a salt.\n            // sharedSecret = smp25519.deriveSharedSecret(privateKey, serverPublicKey, \"examplesalt\");\n            sharedSecret = smp25519.deriveSharedSecret(privateKey, serverPublicKey);\n\n            // Send something.\n            socket.send(smp25519.encryptAndSendData(connectionId, stringToUint8Array(\"Hello from Client!\"), sharedSecret), SERVER_PORT, SERVER_HOST, (err) =\u003e {\n                if (err) {\n                    console.error(`Error: Unable to send message for reason: ${err}`)\n                    exit(-1);\n                }\n            });\n\n            return;\n        }\n\n        // Receive and decrypt the server's response.\n        if (smp25519.isValidData(msg) == true \u0026\u0026 sharedSecret.length \u003e 0) {\n            const decryptedMessage = smp25519.decryptReceivedData(msg, sharedSecret);\n            console.log(`Server response from ${rinfo.address}:${rinfo.port}: ${uint8ArrayToString(decryptedMessage)}`);\n\n            return;\n        }\n\n        console.error(`Error: Unknown message from ${rinfo.address}:${rinfo.port}`)\n        exit(-1);\n    });\n\n    // Step 4: Send handshake message containing the client's public key.\n    socket.send(smp25519.createHandshakeMessage(publicKey), SERVER_PORT, SERVER_HOST, (err) =\u003e {\n        if (err) {\n            console.error(`Error: Unable to send handshake message for reason: ${err}`)\n            exit(-1);\n        }\n    });\n}\n\nmain();\n```\n## Server\n```typescript\nimport * as smp25519 from \"smp25519\";\nimport dgram from \"dgram\";\nimport { exit } from \"process\";\nimport * as base64 from \"js-base64\"\n\nfunction stringToUint8Array(input: string): Uint8Array {\n    const encoder = new TextEncoder();\n    return encoder.encode(input);\n}\n\nfunction uint8ArrayToString(input: Uint8Array): string {\n    const decoder = new TextDecoder();\n    return decoder.decode(input);\n}\n\n/*\n * Secure UDP server example using the smp25519 package.\n * This script demonstrates how to establish a secure communication channel with a single\n * client at a time using key exchange and encryption.\n */\nfunction main() {\n    // Step 1: Generate the server's identity.\n    // const { privateKey, publicKey, connectionId } = smp25519.generateIdentity();\n\n    // Or use a pre-existing private key (Base64 encoded) and derive the public key.\n    const privateKey = base64.toUint8Array(\"4Pe2QvF6zk41OWkMTqVR8e9nvwhbOEaDRti6oykaG18=\");\n    const publicKey = smp25519.getPublicKeyFromPrivate(privateKey);\n    console.log(`Server public key (Base64): ${base64.fromUint8Array(publicKey)}`);\n\n    // Step 2: Set up the UDP socket.\n    const socket = dgram.createSocket(\"udp4\");\n    const SERVER_PORT = 12000;\n\n    console.log(`Secure UDP Server: Listening on port ${SERVER_PORT}`);\n\n    // Variables to store client-specific connection data.\n    let clientConnectionId: Uint8Array;\n    let clientSharedSecret: Uint8Array;\n\n    // Step 3: Main server loop.\n    socket.on(\"message\", (msg, rinfo) =\u003e {\n        // Step 4: Handle handshake messages.\n        if (smp25519.isHandshakeMessage(msg) == true) {\n            console.log(`Handshake received from ${rinfo.address}:${rinfo.port}`);\n\n            // Extract the client's public key and generate a connection ID.\n            const clientPublicKey = smp25519.extractPublicKeyFromHandshake(msg);\n            clientConnectionId = smp25519.generateConnectionIdFromPublicKey(clientPublicKey);\n\n            // Derive a shared secret using the client's public key and a salt.\n            // clientSharedSecret = smp25519.deriveSharedSecret(privateKey, clientPublicKey, \"examplesalt\");\n            clientSharedSecret = smp25519.deriveSharedSecret(privateKey, clientPublicKey);\n\n            // Respond with the server's handshake message.\n            socket.send(smp25519.createHandshakeMessage(publicKey), rinfo.port, rinfo.address, (err) =\u003e {\n                if (err) {\n                    console.error(`Error: Unable to send handshake message for reason: ${err}`)\n                    exit(-1);\n                }\n            });\n\n            return;\n        }\n\n        // Step 5: Handle encrypted messages.\n        if (smp25519.isValidData(msg) == true \u0026\u0026 clientSharedSecret.length \u003e 0) {\n            // Verify the connection ID matches the client.\n            if (smp25519.extractConnectionIdFromData(msg).every((val, index) =\u003e val !== clientConnectionId[index])) {\n                console.log(`Notice: Unknown client ID from ${rinfo.address}:${rinfo.port}. Ignoring message.`);\n                return;\n            }\n\n            // Decrypt the received message.\n            const decryptedMessage = smp25519.decryptReceivedData(msg, clientSharedSecret);\n            console.log(`Message from ${rinfo.address}:${rinfo.port}: ${uint8ArrayToString(decryptedMessage)}`);\n\n            // Send an encrypted response back to the client.\n            const responseMessage = \"Hello from Server!\";\n            const encryptedMessage = smp25519.encryptAndSendData(clientConnectionId, stringToUint8Array(responseMessage), clientSharedSecret);\n            socket.send(encryptedMessage, rinfo.port, rinfo.address, (err) =\u003e {\n                if (err) {\n                    console.error(`Error: Unable to send handshake message for reason: ${err}`)\n                    exit(-1);\n                }\n            });\n            console.log(\"Response sent.\");\n\n            return;\n        }\n\n        // Step 6: Handle unrecognized data.\n        console.log(`Notice: Received unknown data from ${rinfo.address}:${rinfo.port}`);\n    });\n\n    // Bind to port\n    socket.bind(SERVER_PORT);\n}\n\nmain();\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F979st%2Fsmp25519-typescript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F979st%2Fsmp25519-typescript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F979st%2Fsmp25519-typescript/lists"}