Skip to content

Instantly share code, notes, and snippets.

@lithdew
Created June 11, 2020 16:13
Show Gist options
  • Save lithdew/074cef3f294d7fb167f333ddc90c19c8 to your computer and use it in GitHub Desktop.
Save lithdew/074cef3f294d7fb167f333ddc90c19c8 to your computer and use it in GitHub Desktop.
Monte.
package main
import (
"encoding/hex"
"fmt"
"github.com/lithdew/monte"
"net"
)
func main() {
check := func(err error) {
if err != nil {
panic(err)
}
}
ln, err := net.Listen("tcp", ":4444")
check(err)
defer ln.Close()
conn, err := ln.Accept()
check(err)
defer conn.Close()
sess, err := monte.NewSession()
check(err)
check(sess.DoServer(conn))
fmt.Println(hex.EncodeToString(sess.SharedKey()))
sc := monte.NewSessionConn(sess.Suite(), conn)
buf := make([]byte, 1024)
for i := 0; i < 100; i++ {
n, err := sc.Read(buf)
check(err)
fmt.Println("Decrypted:", string(buf[:n]))
}
for i := 0; i < 100; i++ {
_, err = sc.Write([]byte(fmt.Sprintf("[%d] Hello from Go!", i)))
check(err)
check(sc.Flush())
}
}
import nacl from "tweetnacl";
import * as net from "net";
import blake2b from 'blake2b';
import * as crypto from "crypto";
const sized = buf => {
const scratch = Buffer.alloc(4);
scratch.writeUInt32BE(buf.byteLength);
return Buffer.concat([scratch, buf]);
}
let readNonce = 0n;
let writeNonce = 0n;
/**
*
* @param {crypto.BinaryLike} key
* @param {crypto.BinaryLike} buf
* @returns {Buffer}
*/
const encrypt = (key, buf) => {
const nonce = Buffer.alloc(12);
nonce.writeBigUInt64BE(writeNonce);
writeNonce++
const cipher = crypto.createCipheriv("aes-256-gcm", key, nonce, {authTagLength: 16});
const encrypted = cipher.update(buf);
cipher.final();
return Buffer.concat([encrypted, cipher.getAuthTag()]);
}
/**
*
* @param {crypto.BinaryLike} key
* @param {crypto.BinaryLike} buf
* @returns {Buffer}
*/
const decrypt = (key, buf) => {
if (buf.byteLength < 16) {
throw new Error("Data to be decrypted must be at least 16 bytes.");
}
const nonce = Buffer.alloc(12);
nonce.writeBigUInt64BE(readNonce);
readNonce++
const decipher = crypto.createDecipheriv("aes-256-gcm", key, nonce, {authTagLength: 16});
decipher.setAuthTag(buf.slice(buf.byteLength - 16, buf.byteLength));
const decrypted = decipher.update(buf.slice(0, buf.byteLength - 16));
decipher.final();
return decrypted;
}
/**
*
* @param {Socket} sock
* @return {Promise<crypto.BinaryLike>}
*/
const handshake = (sock) => new Promise((resolve, _) => {
const {publicKey, secretKey} = nacl.box.keyPair();
sock.write(publicKey);
sock.once('readable', () => {
const otherPublicKey = sock.read(32);
if (!otherPublicKey) sock.destroy(new Error("Peer did not provide a X25519 key to init the session."));
resolve(Buffer.from(blake2b(32).update(nacl.scalarMult(secretKey, otherPublicKey)).digest()));
});
});
/**
*
* @param {Socket} sock
* @return {Promise<Buffer>}
*/
const read = sock => new Promise((resolve, _) => {
sock.once('readable', () => {
const header = sock.read(4);
if (!header) return;
const length = header.readUInt32BE();
let frame = sock.read(length);
if (!frame) {
sock.unshift(header);
return;
}
resolve(frame);
});
});
async function main() {
const sock = new net.Socket();
sock.connect({port: 4444, host: "127.0.0.1"});
const sessionKey = await handshake(sock);
console.log("Session Key:", sessionKey.toString("hex"));
for (let i = 0; i < 100; i++) {
sock.write(sized(encrypt(sessionKey, `[${i}] Hello from NodeJS!`)));
}
for (let i = 0; i < 100; i++) {
console.log("Decrypted:", decrypt(sessionKey, await read(sock)).toString("utf8"));
}
}
main().catch(err => console.error(err));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment