New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@consento/crypto

Package Overview
Dependencies
Maintainers
2
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@consento/crypto - npm Package Compare versions

Comparing version 0.0.12 to 0.1.0

108

core/friends.js

@@ -12,4 +12,5 @@ "use strict";

const buffer_1 = require("../util/buffer");
const types_1 = require("./types");
/* eslint @typescript-eslint/camelcase: "off" */
const { crypto_kdf_derive_from_key, randombytes_buf, crypto_scalarmult_base, crypto_scalarmult, crypto_scalarmult_ed25519_BYTES, crypto_kdf_BYTES_MAX, crypto_kdf_CONTEXTBYTES, crypto_box_SEALBYTES, crypto_box_SECRETKEYBYTES, crypto_box_PUBLICKEYBYTES, crypto_sign_PUBLICKEYBYTES, crypto_sign_SECRETKEYBYTES, crypto_sign_BYTES, crypto_sign_ed25519_sk_to_curve25519, crypto_sign_ed25519_pk_to_curve25519, crypto_sign_seed_keypair, crypto_sign_detached, crypto_sign_verify_detached, crypto_sign_ed25519_sk_to_pk, crypto_box_seal, crypto_box_seal_open, crypto_sign_keypair, crypto_secretbox_easy, crypto_secretbox_open_easy, crypto_secretbox_NONCEBYTES, crypto_secretbox_MACBYTES, crypto_secretbox_KEYBYTES, sodium_malloc } = sodium.default;
const { randombytes_buf, crypto_scalarmult_base, crypto_scalarmult, crypto_scalarmult_BYTES, crypto_kdf_CONTEXTBYTES, crypto_box_seal, crypto_box_seal_open, crypto_box_keypair, crypto_box_SEALBYTES, crypto_box_SECRETKEYBYTES, crypto_box_PUBLICKEYBYTES, crypto_sign_PUBLICKEYBYTES, crypto_sign_SECRETKEYBYTES, crypto_sign_BYTES, crypto_sign_detached, crypto_sign_verify_detached, crypto_sign_keypair, crypto_secretbox_easy, crypto_secretbox_open_easy, crypto_secretbox_NONCEBYTES, crypto_secretbox_MACBYTES, crypto_secretbox_KEYBYTES, sodium_malloc } = sodium.default;
function randomBuffer(size) {

@@ -31,25 +32,2 @@ const buffer = sodium_malloc(size);

}
function boxSecretFromSignSecret(signSecretKey) {
const encryptSecretKey = sodium_malloc(crypto_box_SECRETKEYBYTES);
crypto_sign_ed25519_sk_to_curve25519(encryptSecretKey, signSecretKey);
return encryptSecretKey;
}
function boxPublicFromSignPublic(signPublicKey) {
const encryptPublicKey = sodium_malloc(crypto_box_PUBLICKEYBYTES);
crypto_sign_ed25519_pk_to_curve25519(encryptPublicKey, signPublicKey);
return encryptPublicKey;
}
function decrypt(encryptPublicKey, encryptSecretKey, messageEncrypted) {
const messageDecrypted = sodium_malloc(messageEncrypted.length - crypto_box_SEALBYTES);
const successful = crypto_box_seal_open(messageDecrypted, messageEncrypted, encryptPublicKey, encryptSecretKey);
if (!successful) {
return null;
}
return messageDecrypted;
}
function encrypt(encryptPublicKey, message) {
const messageEncrypted = sodium_malloc(message.length + crypto_box_SEALBYTES);
crypto_box_seal(messageEncrypted, message, encryptPublicKey);
return messageEncrypted;
}
function sign(signSecretKey, body) {

@@ -65,7 +43,2 @@ const signature = sodium_malloc(crypto_sign_BYTES);

/* eslint @typescript-eslint/require-await: "off" */
async deriveKdfKey(key) {
const derivedKey = sodium_malloc(crypto_kdf_BYTES_MAX);
crypto_kdf_derive_from_key(derivedKey, 1, deriveContext, key);
return derivedKey;
},
async sign(signSecretKey, body) {

@@ -77,16 +50,2 @@ return sign(signSecretKey, body);

},
async deriveAnnonymousKeys(readKey) {
const sign = {
annonymous: true,
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES),
write: sodium_malloc(crypto_sign_SECRETKEYBYTES)
};
crypto_sign_seed_keypair(sign.read, sign.write, readKey);
return sign;
},
async deriveReadKey(writeKey) {
const readKey = sodium_malloc(crypto_sign_PUBLICKEYBYTES);
crypto_sign_ed25519_sk_to_pk(readKey, writeKey);
return readKey;
},
async createSecretKey() {

@@ -111,34 +70,25 @@ return randomBuffer(crypto_secretbox_KEYBYTES);

},
async decryptMessage(signReadKey, signWriteKey, readKey, message) {
if (!verify(signReadKey, message.signature, message.body)) {
async decryptMessage(verifyKey, writeKey, readKey, message) {
if (!verify(verifyKey, message.signature, message.body)) {
return {
error: 'invalid-channel'
error: types_1.EDecryptionError.invalidSignature
};
}
const encryptPublicKey = boxPublicFromSignPublic(signReadKey);
const encryptSecretKey = boxSecretFromSignSecret(signWriteKey);
const decrypted = decrypt(encryptPublicKey, encryptSecretKey, message.body);
if (decrypted === null) {
const messageDecrypted = sodium_malloc(message.body.length - crypto_box_SEALBYTES);
const successful = crypto_box_seal_open(messageDecrypted, message.body, writeKey, readKey);
if (!successful) {
return {
error: 'invalid-encryption'
error: types_1.EDecryptionError.invalidEncryption
};
}
const [signature, body] = split(decrypted, crypto_sign_BYTES);
if (!verify(readKey, signature, body)) {
return {
error: 'invalid-owner'
};
}
return {
body: buffer_1.bufferToAny(body)
body: buffer_1.bufferToAny(messageDecrypted)
};
},
async encryptMessage(annonymousReadKey, annonymousWriteKey, writeKey, message) {
async encryptMessage(signKey, writeKey, message) {
const msgBuffer = buffer_1.anyToBuffer(message);
const signedStandardized = sign(writeKey, msgBuffer);
const secret = buffer_1.Buffer.concat([signedStandardized, msgBuffer]);
const encryptPublicKey = boxPublicFromSignPublic(annonymousReadKey);
const body = encrypt(encryptPublicKey, secret);
const body = sodium_malloc(msgBuffer.length + crypto_box_SEALBYTES);
crypto_box_seal(body, msgBuffer, writeKey);
return {
signature: sign(annonymousWriteKey, body),
signature: sign(signKey, body),
body

@@ -148,21 +98,29 @@ };

async initHandshake() {
const pri = randomBuffer(crypto_scalarmult_ed25519_BYTES);
const pub = sodium_malloc(crypto_scalarmult_ed25519_BYTES);
crypto_scalarmult_base(pub, pri);
return { write: pri, read: pub };
const privateKey = randomBuffer(crypto_scalarmult_BYTES);
const publicKey = sodium_malloc(crypto_scalarmult_BYTES);
crypto_scalarmult_base(publicKey, privateKey);
return { privateKey, publicKey };
},
async computeSecret(pri, remotePublic) {
const secret = sodium_malloc(crypto_scalarmult_ed25519_BYTES);
crypto_scalarmult(secret, pri, remotePublic);
async computeSecret(privateKey, remotePublic) {
const secret = sodium_malloc(crypto_scalarmult_BYTES);
crypto_scalarmult(secret, privateKey, remotePublic);
return secret;
},
async createKeys() {
async createEncryptionKeys() {
const keys = {
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES),
write: sodium_malloc(crypto_sign_SECRETKEYBYTES)
publicKey: sodium_malloc(crypto_box_PUBLICKEYBYTES),
privateKey: sodium_malloc(crypto_box_SECRETKEYBYTES)
};
crypto_sign_keypair(keys.read, keys.write);
crypto_box_keypair(keys.publicKey, keys.privateKey);
return keys;
},
async createSignKeys() {
const keys = {
publicKey: sodium_malloc(crypto_sign_PUBLICKEYBYTES),
privateKey: sodium_malloc(crypto_sign_SECRETKEYBYTES)
};
crypto_sign_keypair(keys.publicKey, keys.privateKey);
return keys;
}
};
//# sourceMappingURL=friends.js.map

@@ -6,4 +6,6 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/camelcase */
const libsodium_wrappers_sumo_1 = __importDefault(require("@consento/libsodium-wrappers-sumo"));
const buffer_1 = require("../util/buffer");
const types_1 = require("./types");
const _global = global;

@@ -20,23 +22,2 @@ if (_global.document === null || _global.document === undefined) {

}
const deriveContext = 'conotify';
/* eslint @typescript-eslint/camelcase: "off" */
async function boxSecretFromSignSecret(signSecretKey) {
const { crypto_sign_ed25519_sk_to_curve25519 } = await libsodium;
return crypto_sign_ed25519_sk_to_curve25519(assertUint8(signSecretKey));
}
async function boxPublicFromSignPublic(signPublicKey) {
const { crypto_sign_ed25519_pk_to_curve25519 } = await libsodium;
return crypto_sign_ed25519_pk_to_curve25519(assertUint8(signPublicKey));
}
async function decrypt(signReadKey, signWriteKey, messageEncrypted) {
const encryptPublicKey = await boxPublicFromSignPublic(signReadKey);
const encryptSecretKey = await boxSecretFromSignSecret(signWriteKey);
const { crypto_box_seal_open } = await libsodium;
return crypto_box_seal_open(assertUint8(messageEncrypted), encryptPublicKey, encryptSecretKey);
}
async function encrypt(signPublicKey, message) {
const { crypto_box_seal: seal } = await libsodium;
const encryptPublicKey = await boxPublicFromSignPublic(assertUint8(signPublicKey));
return seal(assertUint8(message), encryptPublicKey);
}
function assertUint8(input) {

@@ -57,44 +38,20 @@ if (!('Buffer' in global) || input instanceof buffer_1.Buffer) {

exports.sodium = {
async deriveKdfKey(key) {
const { crypto_kdf_derive_from_key, crypto_kdf_BYTES_MAX } = await libsodium;
return crypto_kdf_derive_from_key(crypto_kdf_BYTES_MAX, 1, deriveContext, assertUint8(key));
},
sign,
verify,
async deriveAnnonymousKeys(readKey) {
const { crypto_sign_seed_keypair } = await libsodium;
const pair = crypto_sign_seed_keypair(assertUint8(readKey));
return {
annonymous: true,
read: pair.publicKey,
write: pair.privateKey
};
},
async deriveReadKey(writeKey) {
const { crypto_sign_ed25519_sk_to_pk } = await libsodium;
return crypto_sign_ed25519_sk_to_pk(assertUint8(writeKey));
},
async decryptMessage(signReadKey, signWriteKey, readKey, message) {
signReadKey = assertUint8(signReadKey);
async decryptMessage(verifyKey, writeKey, readKey, message) {
const bodyIn = assertUint8(message.body);
if (!await verify(signReadKey, message.signature, bodyIn)) {
if (!await verify(verifyKey, message.signature, bodyIn)) {
return {
error: 'invalid-channel'
error: types_1.EDecryptionError.invalidSignature
};
}
const decrypted = await decrypt(signReadKey, assertUint8(signWriteKey), bodyIn);
if (decrypted === null) {
const { crypto_box_seal_open } = await libsodium;
const messageDecrypted = crypto_box_seal_open(message.body, writeKey, readKey);
if (messageDecrypted === null) {
return {
error: 'invalid-encryption'
error: types_1.EDecryptionError.invalidEncryption
};
}
const { crypto_sign_BYTES } = await libsodium;
const [signature, body] = split(decrypted, crypto_sign_BYTES);
if (!await verify(assertUint8(readKey), signature, body)) {
return {
error: 'invalid-owner'
};
}
return {
body: buffer_1.bufferToAny(body)
body: buffer_1.bufferToAny(messageDecrypted)
};

@@ -119,9 +76,8 @@ },

},
async encryptMessage(annonymousReadKey, annonymousWriteKey, writeKey, message) {
const msgBuffer = assertUint8(buffer_1.anyToBuffer(message));
const signedStandardized = await sign(assertUint8(writeKey), msgBuffer);
const secret = buffer_1.concatUint8Arrays([signedStandardized, msgBuffer]);
const body = await encrypt(assertUint8(annonymousReadKey), secret);
async encryptMessage(signKey, writeKey, message) {
const { crypto_box_seal } = await libsodium;
const msgBuffer = buffer_1.anyToBuffer(message);
const body = crypto_box_seal(msgBuffer, writeKey);
return {
signature: await sign(assertUint8(annonymousWriteKey), body),
signature: await sign(signKey, body),
body

@@ -132,5 +88,7 @@ };

const { randombytes_buf, crypto_scalarmult_BYTES, crypto_scalarmult_base } = await libsodium;
const pri = randombytes_buf(crypto_scalarmult_BYTES);
const pub = crypto_scalarmult_base(pri);
return { write: pri, read: pub };
const privateKey = randombytes_buf(crypto_scalarmult_BYTES);
return {
privateKey,
publicKey: crypto_scalarmult_base(privateKey)
};
},

@@ -141,11 +99,11 @@ async computeSecret(pri, remotePublic) {

},
async createKeys() {
async createEncryptionKeys() {
const { crypto_box_keypair } = await libsodium;
return crypto_box_keypair();
},
async createSignKeys() {
const { crypto_sign_keypair } = await libsodium;
const keyPair = crypto_sign_keypair();
return {
write: keyPair.privateKey,
read: keyPair.publicKey
};
return crypto_sign_keypair();
}
};
//# sourceMappingURL=sodium.js.map

@@ -7,16 +7,13 @@ import { IEncodable } from '../util/buffer';

}
export interface IKeyPair {
read: Uint8Array;
write?: Uint8Array;
export interface IRawKeys {
privateKey: Uint8Array;
publicKey: Uint8Array;
}
export interface IKeys extends IKeyPair {
write: Uint8Array;
export declare enum EDecryptionError {
invalidEncryption = "invalid-encryption",
invalidSignature = "invalid-signature"
}
export interface IAnnonymousKeys extends IKeys {
annonymous: true;
write: Uint8Array;
}
export interface IDecryption {
body?: IEncodable;
error?: 'invalid-channel' | 'invalid-encryption' | 'invalid-owner';
error?: EDecryptionError;
}

@@ -26,16 +23,14 @@ export interface ICryptoCore {

verify(signPublicKey: Uint8Array, signature: Uint8Array, body: Uint8Array): Promise<boolean>;
deriveKdfKey(key: Uint8Array): Promise<Uint8Array>;
deriveAnnonymousKeys(readKey: Uint8Array): Promise<IAnnonymousKeys>;
deriveReadKey(writeKey: Uint8Array): Promise<Uint8Array>;
decryptMessage(signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption>;
decryptMessage(verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption>;
createSecretKey(): Promise<Uint8Array>;
decrypt(secretKey: Uint8Array, encrypted: IEncodable): Promise<IEncodable>;
createEncryptionKeys(): Promise<IRawKeys>;
createSignKeys(): Promise<IRawKeys>;
decrypt(secretKey: Uint8Array, encrypted: Uint8Array): Promise<IEncodable>;
encrypt(secretKey: Uint8Array, body: IEncodable): Promise<Uint8Array>;
encryptMessage(annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{
encryptMessage(signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{
signature: Uint8Array;
body: Uint8Array;
}>;
initHandshake(): Promise<IKeys>;
computeSecret(pri: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array>;
createKeys(): Promise<IKeys>;
initHandshake(): Promise<IRawKeys>;
computeSecret(privateKey: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var EDecryptionError;
(function (EDecryptionError) {
EDecryptionError["invalidEncryption"] = "invalid-encryption";
EDecryptionError["invalidSignature"] = "invalid-signature";
})(EDecryptionError = exports.EDecryptionError || (exports.EDecryptionError = {}));
//# sourceMappingURL=types.js.map

@@ -5,2 +5,2 @@ import { ICryptoCore } from '../core/types';

export declare const HANDSHAKE_MSG_VERSION: Buffer;
export declare function setupHandshake(crypto: ICryptoCore, { createSender, createSenderFromSendKey, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake;
export declare function setupHandshake(crypto: ICryptoCore, { createReceiver, Sender, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake;

@@ -11,3 +11,3 @@ "use strict";

}
if (msg.length !== 97) {
if (msg.length !== 161) {
throw Object.assign(new Error(`Error while processing handshake: Invalid handshake size: ${msg.length}`), { code: 'invalid-size', size: msg.length });

@@ -20,7 +20,7 @@ }

}
function setupHandshake(crypto, { createSender, createSenderFromSendKey, Receiver, Connection }) {
function setupHandshake(crypto, { createReceiver, Sender, Receiver, Connection }) {
class HandshakeInit {
constructor({ receiver, confirmKey, firstMessage }) {
constructor({ receiver, handshakeSecret, firstMessage }) {
this.receiver = isReceiver_1.isReceiver(receiver) ? receiver : new Receiver(receiver);
this.confirmKey = buffer_1.toBuffer(confirmKey);
this.handshakeSecret = buffer_1.toBuffer(handshakeSecret);
this.firstMessage = buffer_1.toBuffer(firstMessage);

@@ -32,3 +32,3 @@ }

firstMessage: buffer_1.bufferToString(this.firstMessage, 'base64'),
confirmKey: buffer_1.bufferToString(this.confirmKey, 'base64')
handshakeSecret: buffer_1.bufferToString(this.handshakeSecret, 'base64')
};

@@ -38,5 +38,6 @@ }

confirm(accept) {
// eslint-disable-next-line @typescript-eslint/return-await
return cancelable_1.cancelable(function* () {
const secretKey = (yield crypto.computeSecret(this.confirmKey, buffer_1.Buffer.from(accept.token, 'base64')));
const bob = (yield createSender());
const secretKey = (yield crypto.computeSecret(this.handshakeSecret, buffer_1.Buffer.from(accept.token, 'base64')));
const bob = (yield createReceiver());
const sendKey = (yield crypto.decrypt(secretKey, buffer_1.Buffer.from(accept.secret, 'base64')));

@@ -46,11 +47,13 @@ if (!(sendKey instanceof Uint8Array)) {

}
const sender = (yield createSenderFromSendKey(sendKey));
const aliceSender = (yield new Sender({ sendKey }));
return yield new HandshakeConfirmation({
connection: new Connection({
sender,
receiver: bob.newReceiver()
sender: aliceSender,
receiver: bob.receiver
}),
// In case you are wondering why we not just simply return "bob" as sender
// but instead pass it in two messages: the reason is that without this step
finalMessage: bob.sendKey
// the API is clearer.
// TODO: rethink
finalMessage: bob.sender.sendKey
});

@@ -71,3 +74,3 @@ }, this);

receiver: this.receiver,
sender: await createSenderFromSendKey(message)
sender: new Sender({ sendKey: message })
});

@@ -90,12 +93,11 @@ }

async initHandshake() {
const tempChannel = await createSender();
const receiver = tempChannel.newReceiver();
const { write: confirmKey, read: receiveKey } = await crypto.initHandshake();
const { receiver, sender } = await createReceiver();
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake();
return new HandshakeInit({
receiver,
confirmKey,
handshakeSecret,
firstMessage: buffer_1.Buffer.concat([
exports.HANDSHAKE_MSG_VERSION,
receiveKey,
tempChannel.sendKey
handshakePublic,
sender.sendKey
])

@@ -107,10 +109,10 @@ });

const { token, sendKey } = processHandshake(firstMessage);
const keys = await crypto.initHandshake();
const secretKey = await crypto.computeSecret(keys.write, token);
const sender = await createSender();
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake();
const secretKey = await crypto.computeSecret(handshakeSecret, token);
const { receiver, sender } = await createReceiver();
return new HandshakeAccept({
sender: await createSenderFromSendKey(sendKey),
receiver: sender.newReceiver(),
sender: new Sender({ sendKey }),
receiver,
acceptMessage: {
token: buffer_1.bufferToString(keys.read, 'base64'),
token: buffer_1.bufferToString(handshakePublic, 'base64'),
secret: buffer_1.bufferToString(await crypto.encrypt(secretKey, sender.sendKey), 'base64')

@@ -117,0 +119,0 @@ }

{
"name": "@consento/crypto",
"version": "0.0.12",
"version": "0.1.0",
"description": "Crypto functionality used in Consento",

@@ -11,3 +11,3 @@ "main": "index.js",

"@consento/libsodium-wrappers-sumo": "^0.7.7",
"buffer": "^5.4.3",
"buffer": "^5.6.0",
"sodium-universal": "^2.0.0"

@@ -14,0 +14,0 @@ },

@@ -6,2 +6,29 @@ "use strict";

const buffer_1 = require("../util/buffer");
const isReceiver_1 = require("../util/isReceiver");
const isSender_1 = require("../util/isSender");
const VERIFY_KEY_SIZE = 32;
const VERIFY_KEY_START = 0;
const VERIFY_KEY_END = VERIFY_KEY_SIZE;
const SIGN_KEY_SIZE = 64;
const SIGN_KEY_START = VERIFY_KEY_END;
const SIGN_KEY_END = SIGN_KEY_START + SIGN_KEY_SIZE;
const ENCRYPT_KEY_SIZE = 32;
const ENCRYPT_KEY_START = SIGN_KEY_END;
const ENCRYPT_KEY_END = ENCRYPT_KEY_START + ENCRYPT_KEY_SIZE;
const DECRYPT_KEY_START = ENCRYPT_KEY_END;
function signKeyFromSendKey(receiveKey) {
return receiveKey.slice(SIGN_KEY_START, SIGN_KEY_END);
}
function encryptKeyFromSendKey(sendKey) {
return sendKey.slice(ENCRYPT_KEY_START, ENCRYPT_KEY_END);
}
function decryptKeyFromReceiveKey(receiveKey) {
return receiveKey.slice(DECRYPT_KEY_START);
}
function verifyKeyFromSendKey(sendKey) {
return sendKey.slice(VERIFY_KEY_START, VERIFY_KEY_END);
}
function sendKeyFromReceiveKey(receiveKey) {
return receiveKey.slice(VERIFY_KEY_START, ENCRYPT_KEY_END);
}
function setupPrimitives(crypto) {

@@ -29,10 +56,7 @@ class Annonymous {

}
compare(other, force = false) {
if (!(other instanceof Annonymous)) {
compare(other) {
if (isSender_1.isSender(other) || isReceiver_1.isReceiver(other)) {
return 1;
}
if (force) {
return buffer_1.bufferCompare(other.id, this.id);
}
return other.compare(this, true);
return buffer_1.bufferCompare(other.id, this.id);
}

@@ -48,91 +72,141 @@ toJSON() {

async verify(signature, body) {
return crypto.verify(this.id, signature, body);
return await crypto.verify(this.id, signature, body);
}
// eslint-disable-next-line @typescript-eslint/require-await
async verifyMessage(message) {
return this.verify(message.signature, message.body);
return await this.verify(message.signature, message.body);
}
}
class Receiver extends Annonymous {
constructor(opts) {
super({ id: opts.id });
this[types_1.receiverFlag] = true;
this.receiveKey = buffer_1.toBuffer(opts.receiveKey);
this.signKey = crypto.deriveAnnonymousKeys(this.receiveKey).then(keys => keys.write);
class Sender {
constructor({ id, sendKey }) {
this[types_1.senderFlag] = true;
this.sendKey = buffer_1.toBuffer(sendKey);
if (id !== undefined) {
this._annonymous = new Annonymous({ id });
}
}
get receiveKeyBase64() {
if (this._receiveKeyBase64 === undefined) {
this._receiveKeyBase64 = buffer_1.bufferToString(this.receiveKey, 'base64');
get signKey() {
if (this._signKey === undefined) {
this._signKey = signKeyFromSendKey(this.sendKey);
}
return this._receiveKeyBase64;
return this._signKey;
}
newAnnonymous() {
return new Annonymous(this);
get encryptKey() {
if (this._encryptKey === undefined) {
this._encryptKey = encryptKeyFromSendKey(this.sendKey);
}
return this._encryptKey;
}
compare(other, force = false) {
if (!(other instanceof Receiver)) {
return (force ? -1 : 1);
get sendKeyBase64() {
if (this._sendKeyBase64 === undefined) {
this._sendKeyBase64 = buffer_1.bufferToString(this.sendKey, 'base64');
}
if (force) {
return buffer_1.bufferCompare(other.receiveKey, this.receiveKey);
return this._sendKeyBase64;
}
get sender() {
return this;
}
get id() {
return this.annonymous.id;
}
get idHex() {
return this.annonymous.idHex;
}
get idBase64() {
return this.annonymous.idBase64;
}
get annonymous() {
if (this._annonymous === undefined) {
this._annonymous = new Annonymous({ id: verifyKeyFromSendKey(this.sendKey) });
}
return other.compare(this, true);
return this._annonymous;
}
equals(other) {
return this.compare(other) === 0;
}
compare(other) {
if (isReceiver_1.isReceiver(other)) {
return 1;
}
if (!isSender_1.isSender(other)) {
return -1;
}
return buffer_1.bufferCompare(other.sendKey, this.sendKey);
}
toJSON() {
return {
id: this.idBase64,
receiveKey: this.receiveKeyBase64
};
return { sendKey: this.sendKeyBase64 };
}
toString() {
return `Receiver[receiveKey=${this.receiveKeyBase64}]`;
return `Sender[sendKey=${this.sendKeyBase64}]`;
}
async sign(data) {
return crypto.sign(await this.signKey, data);
return await crypto.sign(this.signKey, data);
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
decrypt(encrypted) {
encrypt(message) {
// eslint-disable-next-line @typescript-eslint/return-await
return cancelable_1.cancelable(function* () {
return yield crypto.decryptMessage(this.id, yield this.signKey, this.receiveKey, encrypted);
// eslint-disable-next-line @typescript-eslint/return-await
return yield crypto.encryptMessage(this.signKey, this.encryptKey, message);
}, this);
}
}
class Sender extends Receiver {
class Receiver {
constructor({ id, sendKey, receiveKey }) {
super({ id, receiveKey });
this[types_1.senderFlag] = true;
this.sendKey = buffer_1.toBuffer(sendKey);
this[types_1.receiverFlag] = true;
this.receiveKey = buffer_1.toBuffer(receiveKey);
if (sendKey !== undefined) {
this._sender = new Sender({ id, sendKey });
}
}
get sendKeyBase64() {
if (this._sendKeyBase64 === undefined) {
this._sendKeyBase64 = buffer_1.bufferToString(this.sendKey, 'base64');
get sender() {
if (this._sender === undefined) {
this._sender = new Sender({ sendKey: sendKeyFromReceiveKey(this.receiveKey) });
}
return this._sendKeyBase64;
return this._sender;
}
newReceiver() {
return new Receiver(this);
get id() {
return this.sender.id;
}
compare(other, force = false) {
if (!(other instanceof Sender)) {
return (force ? -1 : 1);
get idHex() {
return this.sender.idHex;
}
get idBase64() {
return this.sender.idBase64;
}
get receiver() {
return this;
}
get annonymous() {
return this.sender.annonymous;
}
get decryptKey() {
return decryptKeyFromReceiveKey(this.receiveKey);
}
get receiveKeyBase64() {
if (this._receiveKeyBase64 === undefined) {
this._receiveKeyBase64 = buffer_1.bufferToString(this.receiveKey, 'base64');
}
if (force) {
return buffer_1.bufferCompare(other.sendKey, this.sendKey);
return this._receiveKeyBase64;
}
equals(other) {
return this.compare(other) === 0;
}
compare(other) {
if (!isReceiver_1.isReceiver(other)) {
return -1;
}
return other.compare(this, true);
return buffer_1.bufferCompare(other.receiveKey, this.receiveKey);
}
toJSON() {
return {
id: this.idBase64,
sendKey: this.sendKeyBase64,
receiveKey: this.receiveKeyBase64
};
return { receiveKey: this.receiveKeyBase64 };
}
toString() {
return `Sender[sendKey=${this.sendKeyBase64}]`;
return `Receiver[receiveKey=${this.receiveKeyBase64}]`;
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
encrypt(message) {
decrypt(encrypted) {
// eslint-disable-next-line @typescript-eslint/return-await
return cancelable_1.cancelable(function* () {
return yield crypto.encryptMessage(this.id, yield this.signKey, this.sendKey, message);
return yield crypto.decryptMessage(this.annonymous.id, this.sender.encryptKey, this.decryptKey, encrypted);
}, this);

@@ -143,4 +217,4 @@ }

constructor(opts) {
this.receiver = new Receiver(opts.receiver);
this.sender = new Sender(opts.sender);
this.receiver = (opts.receiver instanceof Receiver) ? opts.receiver : new Receiver(opts.receiver);
this.sender = (opts.sender instanceof Sender) ? opts.sender : new Sender(opts.sender);
}

@@ -155,22 +229,15 @@ toJSON() {

return {
async createReceiverFromReceiveKey(receiveKey) {
const syncReceiveKey = buffer_1.toBuffer(receiveKey);
const { read: id } = await crypto.deriveAnnonymousKeys(syncReceiveKey);
return new Receiver({ receiveKey: syncReceiveKey, id });
async createReceiver() {
const [encrypt, sign] = await Promise.all([
crypto.createEncryptionKeys(),
crypto.createSignKeys()
]);
const sendKey = buffer_1.Buffer.concat([sign.publicKey, sign.privateKey, encrypt.publicKey]);
const receiver = new Receiver({
id: sign.publicKey,
sendKey,
receiveKey: buffer_1.Buffer.concat([sendKey, encrypt.privateKey])
});
return receiver;
},
async createSenderFromSendKey(sendKey) {
const sendKeySync = buffer_1.toBuffer(sendKey);
const receiveKey = await crypto.deriveReadKey(sendKeySync);
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey);
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
const signKey = Promise.resolve(signKeyValue);
return new Sender({ id, signKey, receiveKey, sendKey: sendKeySync });
},
async createSender() {
const { read: receiveKey, write: sendKey } = await crypto.createKeys();
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey);
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
const signKey = Promise.resolve(signKeyValue);
return new Sender({ id, signKey, receiveKey, sendKey });
},
Annonymous,

@@ -177,0 +244,0 @@ Receiver,

@@ -42,12 +42,14 @@ # @consento/crypto

```javascript
const { createSender } = setup(sodium)
const { createReceiver } = setup(sodium)
```
You can create a new communication channel by creating a new sender:
You can create a new communication channel by creating a new receiver:
```javascript
const sender = await createSender()
sender.id // public channel id - can be shared with other people - also used to verify if a message was properly sent.
sender.receiveKey // channel reader id - to be used for decrypting sent messages
sender.sendKey // encryption key for messages
const receiver = await createReceiver()
receiver.receiveKey // allows decryption of messages
receiver.sender.sendKey // encryption key for sending messages
receiver.sender.annonymous.id // public channel id - can be shared with other people - also used to verify if a message was properly sent.
receiver.sender.id // shortcut on the sender for the channel id
receiver.id // shortcut on the receiver for the channel id
```

@@ -57,12 +59,16 @@

A `Sender` &gt; `Receiver` &gt; `Annonymous` and there are methods to create a receiver/annonymous
A `Receiver` &gt; `Sender` &gt; `Annonymous` and there are methods to create a receiver/annonymous
instance out of a sender instance:
```javascript
const { createSender, toReceiver, toAnnonymous } = setup(sodium)
const sender = await createSender()
const receiver = toReceiver(sender)
const annonymous = toAnnonymous(sender)
const { createReceiver } = setup(sodium)
const receiver = await createReceiver()
```
you can also destruct each instance:
```javascript
const { receiver, sender, annonymous } = await createReceiver()
```
Every instance can verify a given message for a channel:

@@ -99,5 +105,5 @@

```javascript
const { Sender } = setup(sodium)
const senderJson = sender.toJSON()
const restoredSender = new Sender(json)
const { Receiver } = setup(sodium)
const receiverJson = receiver.toJSON()
const restoredReceiver = new Receiver(json)
```

@@ -144,3 +150,3 @@

```javascript
const decryptedAcceptMessage = (await decrypt(alice.receiver, acceptMessage)).body
const decryptedAcceptMessage = (await alice.receiver.decryptMessage(acceptMessage)).body
const package = await confirmHandshake(alice, decryptedAcceptMessage)

@@ -165,3 +171,3 @@ const {

```javascript
const { sender: bobToAliceSender, receiver: aliceToBobReceiver } = await finalize(bob, finalMessage)
const { sender: bobToAliceSender, receiver: aliceToBobReceiver } = await bob.finalize(finalMessage)
```

@@ -168,0 +174,0 @@

@@ -10,3 +10,3 @@ import * as sodium from 'sodium-universal'

import {
ICryptoCore, IAnnonymousKeys, IEncryptedMessage, IDecryption, IKeys
ICryptoCore, IEncryptedMessage, IDecryption, EDecryptionError, IRawKeys
} from './types'

@@ -16,9 +16,10 @@

const {
crypto_kdf_derive_from_key,
randombytes_buf,
crypto_scalarmult_base,
crypto_scalarmult,
crypto_scalarmult_ed25519_BYTES,
crypto_kdf_BYTES_MAX,
crypto_scalarmult_BYTES,
crypto_kdf_CONTEXTBYTES,
crypto_box_seal,
crypto_box_seal_open,
crypto_box_keypair,
crypto_box_SEALBYTES,

@@ -30,10 +31,4 @@ crypto_box_SECRETKEYBYTES,

crypto_sign_BYTES,
crypto_sign_ed25519_sk_to_curve25519,
crypto_sign_ed25519_pk_to_curve25519,
crypto_sign_seed_keypair,
crypto_sign_detached,
crypto_sign_verify_detached,
crypto_sign_ed25519_sk_to_pk,
crypto_box_seal,
crypto_box_seal_open,
crypto_sign_keypair,

@@ -68,28 +63,2 @@ crypto_secretbox_easy,

function boxSecretFromSignSecret (signSecretKey: Uint8Array): Uint8Array {
const encryptSecretKey = sodium_malloc(crypto_box_SECRETKEYBYTES)
crypto_sign_ed25519_sk_to_curve25519(encryptSecretKey, signSecretKey)
return encryptSecretKey
}
function boxPublicFromSignPublic (signPublicKey: Uint8Array): Uint8Array {
const encryptPublicKey = sodium_malloc(crypto_box_PUBLICKEYBYTES)
crypto_sign_ed25519_pk_to_curve25519(encryptPublicKey, signPublicKey)
return encryptPublicKey
}
function decrypt (encryptPublicKey: Uint8Array, encryptSecretKey: Uint8Array, messageEncrypted: Uint8Array): Uint8Array {
const messageDecrypted = sodium_malloc(messageEncrypted.length - crypto_box_SEALBYTES)
const successful = crypto_box_seal_open(messageDecrypted, messageEncrypted, encryptPublicKey, encryptSecretKey)
if (!successful) {
return null
}
return messageDecrypted
}
function encrypt (encryptPublicKey: Uint8Array, message: Uint8Array): Uint8Array {
const messageEncrypted = sodium_malloc(message.length + crypto_box_SEALBYTES)
crypto_box_seal(messageEncrypted, message, encryptPublicKey)
return messageEncrypted
}
function sign (signSecretKey: Uint8Array, body: Uint8Array): Uint8Array {

@@ -106,7 +75,2 @@ const signature = sodium_malloc(crypto_sign_BYTES)

/* eslint @typescript-eslint/require-await: "off" */
async deriveKdfKey (key: Uint8Array) {
const derivedKey = sodium_malloc(crypto_kdf_BYTES_MAX)
crypto_kdf_derive_from_key(derivedKey, 1, deriveContext, key)
return derivedKey
},
async sign (signSecretKey: Uint8Array, body: Uint8Array) {

@@ -118,16 +82,2 @@ return sign(signSecretKey, body)

},
async deriveAnnonymousKeys (readKey: Uint8Array) {
const sign: IAnnonymousKeys = {
annonymous: true,
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES),
write: sodium_malloc(crypto_sign_SECRETKEYBYTES)
}
crypto_sign_seed_keypair(sign.read, sign.write, readKey)
return sign
},
async deriveReadKey (writeKey: Uint8Array) {
const readKey = sodium_malloc(crypto_sign_PUBLICKEYBYTES)
crypto_sign_ed25519_sk_to_pk(readKey, writeKey)
return readKey
},
async createSecretKey () {

@@ -152,56 +102,55 @@ return randomBuffer(crypto_secretbox_KEYBYTES)

},
async decryptMessage (signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> {
if (!verify(signReadKey, message.signature, message.body)) {
async decryptMessage (verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> {
if (!verify(verifyKey, message.signature, message.body)) {
return {
error: 'invalid-channel'
error: EDecryptionError.invalidSignature
}
}
const encryptPublicKey = boxPublicFromSignPublic(signReadKey)
const encryptSecretKey = boxSecretFromSignSecret(signWriteKey)
const decrypted = decrypt(encryptPublicKey, encryptSecretKey, message.body)
if (decrypted === null) {
const messageDecrypted = sodium_malloc(message.body.length - crypto_box_SEALBYTES)
const successful = crypto_box_seal_open(messageDecrypted, message.body, writeKey, readKey)
if (!successful) {
return {
error: 'invalid-encryption'
error: EDecryptionError.invalidEncryption
}
}
const [signature, body] = split(decrypted, crypto_sign_BYTES)
if (!verify(readKey, signature, body)) {
return {
error: 'invalid-owner'
}
}
return {
body: bufferToAny(body)
body: bufferToAny(messageDecrypted)
}
},
async encryptMessage (annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable) {
async encryptMessage (signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable) {
const msgBuffer = anyToBuffer(message)
const signedStandardized = sign(writeKey, msgBuffer)
const secret = Buffer.concat([signedStandardized, msgBuffer])
const encryptPublicKey = boxPublicFromSignPublic(annonymousReadKey)
const body = encrypt(encryptPublicKey, secret)
const body = sodium_malloc(msgBuffer.length + crypto_box_SEALBYTES)
crypto_box_seal(body, msgBuffer, writeKey)
return {
signature: sign(annonymousWriteKey, body),
signature: sign(signKey, body),
body
}
},
async initHandshake (): Promise<IKeys> {
const pri = randomBuffer(crypto_scalarmult_ed25519_BYTES)
const pub = sodium_malloc(crypto_scalarmult_ed25519_BYTES)
crypto_scalarmult_base(pub, pri)
return { write: pri, read: pub }
async initHandshake (): Promise<IRawKeys> {
const privateKey = randomBuffer(crypto_scalarmult_BYTES)
const publicKey = sodium_malloc(crypto_scalarmult_BYTES)
crypto_scalarmult_base(publicKey, privateKey)
return { privateKey, publicKey }
},
async computeSecret (pri: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array> {
const secret = sodium_malloc(crypto_scalarmult_ed25519_BYTES)
crypto_scalarmult(secret, pri, remotePublic)
async computeSecret (privateKey: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array> {
const secret = sodium_malloc(crypto_scalarmult_BYTES)
crypto_scalarmult(secret, privateKey, remotePublic)
return secret
},
async createKeys (): Promise<IKeys> {
async createEncryptionKeys (): Promise<IRawKeys> {
const keys = {
read: sodium_malloc(crypto_sign_PUBLICKEYBYTES),
write: sodium_malloc(crypto_sign_SECRETKEYBYTES)
publicKey: sodium_malloc(crypto_box_PUBLICKEYBYTES),
privateKey: sodium_malloc(crypto_box_SECRETKEYBYTES)
}
crypto_sign_keypair(keys.read, keys.write)
crypto_box_keypair(keys.publicKey, keys.privateKey)
return keys
},
async createSignKeys (): Promise<IRawKeys> {
const keys = {
publicKey: sodium_malloc(crypto_sign_PUBLICKEYBYTES),
privateKey: sodium_malloc(crypto_sign_SECRETKEYBYTES)
}
crypto_sign_keypair(keys.publicKey, keys.privateKey)
return keys
}
}

@@ -0,1 +1,2 @@

/* eslint-disable @typescript-eslint/camelcase */
import _libsodium from '@consento/libsodium-wrappers-sumo'

@@ -6,3 +7,2 @@

bufferToAny,
concatUint8Arrays,
IEncodable,

@@ -13,3 +13,3 @@ Buffer

import {
ICryptoCore, IEncryptedMessage, IDecryption
ICryptoCore, IEncryptedMessage, IDecryption, EDecryptionError
} from './types'

@@ -31,28 +31,2 @@

const deriveContext = 'conotify'
/* eslint @typescript-eslint/camelcase: "off" */
async function boxSecretFromSignSecret (signSecretKey: Uint8Array): Promise<Uint8Array> {
const { crypto_sign_ed25519_sk_to_curve25519 } = await libsodium
return crypto_sign_ed25519_sk_to_curve25519(assertUint8(signSecretKey))
}
async function boxPublicFromSignPublic (signPublicKey: Uint8Array): Promise<Uint8Array> {
const { crypto_sign_ed25519_pk_to_curve25519 } = await libsodium
return crypto_sign_ed25519_pk_to_curve25519(assertUint8(signPublicKey))
}
async function decrypt (signReadKey: Uint8Array, signWriteKey: Uint8Array, messageEncrypted: Uint8Array): Promise<Uint8Array> {
const encryptPublicKey = await boxPublicFromSignPublic(signReadKey)
const encryptSecretKey = await boxSecretFromSignSecret(signWriteKey)
const { crypto_box_seal_open } = await libsodium
return crypto_box_seal_open(assertUint8(messageEncrypted), encryptPublicKey, encryptSecretKey)
}
async function encrypt (signPublicKey: Uint8Array, message: Uint8Array): Promise<Uint8Array> {
const { crypto_box_seal: seal } = await libsodium
const encryptPublicKey = await boxPublicFromSignPublic(assertUint8(signPublicKey))
return seal(assertUint8(message), encryptPublicKey)
}
function assertUint8 (input: Uint8Array | Buffer): Uint8Array {

@@ -75,44 +49,20 @@ if (!('Buffer' in global) || input instanceof Buffer) {

export const sodium: ICryptoCore = {
async deriveKdfKey (key: Uint8Array) {
const { crypto_kdf_derive_from_key, crypto_kdf_BYTES_MAX } = await libsodium
return crypto_kdf_derive_from_key(crypto_kdf_BYTES_MAX, 1, deriveContext, assertUint8(key))
},
sign,
verify,
async deriveAnnonymousKeys (readKey: Uint8Array) {
const { crypto_sign_seed_keypair } = await libsodium
const pair = crypto_sign_seed_keypair(assertUint8(readKey))
return {
annonymous: true,
read: pair.publicKey,
write: pair.privateKey
}
},
async deriveReadKey (writeKey: Uint8Array) {
const { crypto_sign_ed25519_sk_to_pk } = await libsodium
return crypto_sign_ed25519_sk_to_pk(assertUint8(writeKey))
},
async decryptMessage (signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> {
signReadKey = assertUint8(signReadKey)
async decryptMessage (verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption> {
const bodyIn = assertUint8(message.body)
if (!await verify(signReadKey, message.signature, bodyIn)) {
if (!await verify(verifyKey, message.signature, bodyIn)) {
return {
error: 'invalid-channel'
error: EDecryptionError.invalidSignature
}
}
const decrypted = await decrypt(signReadKey, assertUint8(signWriteKey), bodyIn)
if (decrypted === null) {
const { crypto_box_seal_open } = await libsodium
const messageDecrypted = crypto_box_seal_open(message.body, writeKey, readKey)
if (messageDecrypted === null) {
return {
error: 'invalid-encryption'
error: EDecryptionError.invalidEncryption
}
}
const { crypto_sign_BYTES } = await libsodium
const [signature, body] = split(decrypted, crypto_sign_BYTES)
if (!await verify(assertUint8(readKey), signature, body)) {
return {
error: 'invalid-owner'
}
}
return {
body: bufferToAny(body)
body: bufferToAny(messageDecrypted)
}

@@ -137,9 +87,8 @@ },

},
async encryptMessage (annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable) {
const msgBuffer = assertUint8(anyToBuffer(message))
const signedStandardized = await sign(assertUint8(writeKey), msgBuffer)
const secret = concatUint8Arrays([signedStandardized, msgBuffer])
const body = await encrypt(assertUint8(annonymousReadKey), secret)
async encryptMessage (signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<IEncryptedMessage> {
const { crypto_box_seal } = await libsodium
const msgBuffer = anyToBuffer(message)
const body = crypto_box_seal(msgBuffer, writeKey)
return {
signature: await sign(assertUint8(annonymousWriteKey), body),
signature: await sign(signKey, body),
body

@@ -150,5 +99,7 @@ }

const { randombytes_buf, crypto_scalarmult_BYTES, crypto_scalarmult_base } = await libsodium
const pri = randombytes_buf(crypto_scalarmult_BYTES)
const pub = crypto_scalarmult_base(pri)
return { write: pri, read: pub }
const privateKey = randombytes_buf(crypto_scalarmult_BYTES)
return {
privateKey,
publicKey: crypto_scalarmult_base(privateKey)
}
},

@@ -159,10 +110,10 @@ async computeSecret (pri: Uint8Array, remotePublic: Uint8Array) {

},
async createKeys () {
async createEncryptionKeys () {
const { crypto_box_keypair } = await libsodium
return crypto_box_keypair()
},
async createSignKeys () {
const { crypto_sign_keypair } = await libsodium
const keyPair = crypto_sign_keypair()
return {
write: keyPair.privateKey,
read: keyPair.publicKey
}
return crypto_sign_keypair()
}
}

@@ -10,19 +10,15 @@ import { IEncodable } from '../util/buffer'

export interface IKeyPair {
read: Uint8Array
write?: Uint8Array
export interface IRawKeys {
privateKey: Uint8Array
publicKey: Uint8Array
}
export interface IKeys extends IKeyPair {
write: Uint8Array
export enum EDecryptionError {
invalidEncryption = 'invalid-encryption',
invalidSignature = 'invalid-signature'
}
export interface IAnnonymousKeys extends IKeys {
annonymous: true
write: Uint8Array
}
export interface IDecryption {
body?: IEncodable
error?: 'invalid-channel' | 'invalid-encryption' | 'invalid-owner'
error?: EDecryptionError
}

@@ -33,16 +29,14 @@

verify (signPublicKey: Uint8Array, signature: Uint8Array, body: Uint8Array): Promise<boolean>
deriveKdfKey (key: Uint8Array): Promise<Uint8Array>
deriveAnnonymousKeys (readKey: Uint8Array): Promise<IAnnonymousKeys>
deriveReadKey (writeKey: Uint8Array): Promise<Uint8Array>
decryptMessage (signReadKey: Uint8Array, signWriteKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption>
decryptMessage (verifyKey: Uint8Array, writeKey: Uint8Array, readKey: Uint8Array, message: IEncryptedMessage): Promise<IDecryption>
createSecretKey(): Promise<Uint8Array>
decrypt(secretKey: Uint8Array, encrypted: IEncodable): Promise<IEncodable>
createEncryptionKeys (): Promise<IRawKeys>
createSignKeys (): Promise<IRawKeys>
decrypt(secretKey: Uint8Array, encrypted: Uint8Array): Promise<IEncodable>
encrypt(secretKey: Uint8Array, body: IEncodable): Promise<Uint8Array>
encryptMessage (annonymousReadKey: Uint8Array, annonymousWriteKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{
encryptMessage (signKey: Uint8Array, writeKey: Uint8Array, message: IEncodable): Promise<{
signature: Uint8Array
body: Uint8Array
}>
initHandshake (): Promise<IKeys>
computeSecret (pri: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array>
createKeys (): Promise<IKeys>
initHandshake (): Promise<IRawKeys>
computeSecret (privateKey: Uint8Array, remotePublic: Uint8Array): Promise<Uint8Array>
}

@@ -0,4 +1,6 @@

/* eslint-disable @typescript-eslint/no-throw-literal */
// ↑ https://github.com/typescript-eslint/typescript-eslint/issues/1841
import { ICryptoCore } from '../core/types'
import { Buffer, toBuffer, bufferToString, IEncodable } from '../util/buffer'
import { ICryptoHandshake, IHandshakeInit, IReceiver, ICryptoPrimitives, IHandshakeInitOptions, IHandshakeAccept, ISender, IHandshakeAcceptMessage, IHandshakeAcceptOptions, IHandshakeConfirmation, IHandshakeAcceptJSON, IHandshakeConfirmationOptions, IHandshakeConfirmationJSON, IConnection } from '../types'
import { ICryptoHandshake, IHandshakeInit, IReceiver, ICryptoPrimitives, IHandshakeInitOptions, IHandshakeAccept, ISender, IHandshakeAcceptMessage, IHandshakeAcceptOptions, IHandshakeConfirmation, IHandshakeAcceptJSON, IHandshakeConfirmationOptions, IHandshakeConfirmationJSON, IConnection, IHandshakeInitJSON } from '../types'
import { isReceiver } from '../util/isReceiver'

@@ -16,3 +18,3 @@ import { cancelable, ICancelable } from '../util/cancelable'

}
if (msg.length !== 97) {
if (msg.length !== 161) {
throw Object.assign(new Error(`Error while processing handshake: Invalid handshake size: ${msg.length}`), { code: 'invalid-size', size: msg.length })

@@ -26,19 +28,19 @@ }

export function setupHandshake (crypto: ICryptoCore, { createSender, createSenderFromSendKey, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake {
export function setupHandshake (crypto: ICryptoCore, { createReceiver, Sender, Receiver, Connection }: ICryptoPrimitives): ICryptoHandshake {
class HandshakeInit implements IHandshakeInit {
receiver: IReceiver
firstMessage: Uint8Array
confirmKey: Uint8Array
handshakeSecret: Uint8Array
constructor ({ receiver, confirmKey, firstMessage }: IHandshakeInitOptions) {
constructor ({ receiver, handshakeSecret, firstMessage }: IHandshakeInitOptions) {
this.receiver = isReceiver(receiver) ? receiver : new Receiver(receiver)
this.confirmKey = toBuffer(confirmKey)
this.handshakeSecret = toBuffer(handshakeSecret)
this.firstMessage = toBuffer(firstMessage)
}
toJSON (): any {
toJSON (): IHandshakeInitJSON {
return {
receiver: this.receiver.toJSON(),
firstMessage: bufferToString(this.firstMessage, 'base64'),
confirmKey: bufferToString(this.confirmKey, 'base64')
handshakeSecret: bufferToString(this.handshakeSecret, 'base64')
}

@@ -49,5 +51,6 @@ }

confirm (accept: IHandshakeAcceptMessage): ICancelable<IHandshakeConfirmation> {
// eslint-disable-next-line @typescript-eslint/return-await
return cancelable<IHandshakeConfirmation, HandshakeInit>(function * () {
const secretKey = (yield crypto.computeSecret(this.confirmKey, Buffer.from(accept.token, 'base64'))) as Uint8Array
const bob = (yield createSender()) as ISender
const secretKey = (yield crypto.computeSecret(this.handshakeSecret, Buffer.from(accept.token, 'base64'))) as Uint8Array
const bob = (yield createReceiver()) as IReceiver
const sendKey = (yield crypto.decrypt(secretKey, Buffer.from(accept.secret, 'base64'))) as IEncodable

@@ -57,11 +60,13 @@ if (!(sendKey instanceof Uint8Array)) {

}
const sender = (yield createSenderFromSendKey(sendKey)) as ISender
const aliceSender = (yield new Sender({ sendKey })) as ISender
return yield new HandshakeConfirmation({
connection: new Connection({
sender,
receiver: bob.newReceiver()
sender: aliceSender,
receiver: bob.receiver
}),
// In case you are wondering why we not just simply return "bob" as sender
// but instead pass it in two messages: the reason is that without this step
finalMessage: bob.sendKey
// the API is clearer.
// TODO: rethink
finalMessage: bob.sender.sendKey
})

@@ -90,3 +95,3 @@ }, this)

receiver: this.receiver,
sender: await createSenderFromSendKey(message)
sender: new Sender({ sendKey: message })
})

@@ -115,12 +120,11 @@ }

async initHandshake (): Promise<HandshakeInit> {
const tempChannel = await createSender()
const receiver = tempChannel.newReceiver()
const { write: confirmKey, read: receiveKey } = await crypto.initHandshake()
const { receiver, sender } = await createReceiver()
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake()
return new HandshakeInit({
receiver,
confirmKey,
handshakeSecret,
firstMessage: Buffer.concat([
HANDSHAKE_MSG_VERSION,
receiveKey,
tempChannel.sendKey
handshakePublic,
sender.sendKey
])

@@ -135,10 +139,10 @@ })

} = processHandshake(firstMessage)
const keys = await crypto.initHandshake()
const secretKey = await crypto.computeSecret(keys.write, token)
const sender = await createSender()
const { privateKey: handshakeSecret, publicKey: handshakePublic } = await crypto.initHandshake()
const secretKey = await crypto.computeSecret(handshakeSecret, token)
const { receiver, sender } = await createReceiver()
return new HandshakeAccept({
sender: await createSenderFromSendKey(sendKey),
receiver: sender.newReceiver(),
sender: new Sender({ sendKey }),
receiver,
acceptMessage: {
token: bufferToString(keys.read, 'base64'),
token: bufferToString(handshakePublic, 'base64'),
secret: bufferToString(await crypto.encrypt(secretKey, sender.sendKey), 'base64')

@@ -145,0 +149,0 @@ }

import { ICryptoCore, IDecryption, IEncryptedMessage } from '../core/types'
import {
IAnnonymous, IAnnonymousOptions, IAnnonymousJSON, annonymousFlag,
IReceiver, IReceiverOptions, IReceiverJSON, receiverFlag,
ISender, ISenderOptions, ISenderJSON, senderFlag,
IReceiver, IReceiverOptions, receiverFlag,
ISender, ISenderOptions, senderFlag,
ICryptoPrimitives,
IConnectionOptions,
IConnectionJSON
IConnectionJSON,
ISenderJSON,
IReceiverJSON
} from '../types'
import { ICancelable, cancelable } from '../util/cancelable'
import { Buffer, bufferToString, bufferCompare, toBuffer, IStringOrBuffer, IEncodable } from '../util/buffer'
import { Buffer, bufferToString, bufferCompare, toBuffer, IEncodable } from '../util/buffer'
import { isReceiver } from '../util/isReceiver'
import { isSender } from '../util/isSender'
const VERIFY_KEY_SIZE = 32
const VERIFY_KEY_START = 0
const VERIFY_KEY_END = VERIFY_KEY_SIZE
const SIGN_KEY_SIZE = 64
const SIGN_KEY_START = VERIFY_KEY_END
const SIGN_KEY_END = SIGN_KEY_START + SIGN_KEY_SIZE
const ENCRYPT_KEY_SIZE = 32
const ENCRYPT_KEY_START = SIGN_KEY_END
const ENCRYPT_KEY_END = ENCRYPT_KEY_START + ENCRYPT_KEY_SIZE
const DECRYPT_KEY_START = ENCRYPT_KEY_END
function signKeyFromSendKey (receiveKey: Uint8Array): Uint8Array {
return receiveKey.slice(SIGN_KEY_START, SIGN_KEY_END)
}
function encryptKeyFromSendKey (sendKey: Uint8Array): Uint8Array {
return sendKey.slice(ENCRYPT_KEY_START, ENCRYPT_KEY_END)
}
function decryptKeyFromReceiveKey (receiveKey: Uint8Array): Uint8Array {
return receiveKey.slice(DECRYPT_KEY_START)
}
function verifyKeyFromSendKey (sendKey: Uint8Array): Uint8Array {
return sendKey.slice(VERIFY_KEY_START, VERIFY_KEY_END)
}
function sendKeyFromReceiveKey (receiveKey: Uint8Array): Uint8Array {
return receiveKey.slice(VERIFY_KEY_START, ENCRYPT_KEY_END)
}
export function setupPrimitives (crypto: ICryptoCore): ICryptoPrimitives {

@@ -39,14 +74,11 @@ class Annonymous implements IAnnonymous {

equals (other: IAnnonymous): boolean {
equals (other: IAnnonymous | ISender | IReceiver): boolean {
return this.compare(other) === 0
}
compare (other: IAnnonymous, force: boolean = false): number {
if (!(other instanceof Annonymous)) {
compare (other: IAnnonymous | ISender | IReceiver): number {
if (isSender(other) || isReceiver(other)) {
return 1
}
if (force) {
return bufferCompare(other.id, this.id)
}
return other.compare(this, true)
return bufferCompare(other.id, this.id)
}

@@ -65,3 +97,3 @@

async verify (signature: Uint8Array, body: Uint8Array): Promise<boolean> {
return crypto.verify(this.id, signature, body)
return await crypto.verify(this.id, signature, body)
}

@@ -71,63 +103,102 @@

async verifyMessage (message: IEncryptedMessage): Promise<boolean> {
return this.verify(message.signature, message.body)
return await this.verify(message.signature, message.body)
}
}
class Receiver extends Annonymous implements IReceiver {
[receiverFlag]: true
receiveKey: Uint8Array
signKey: Promise<Uint8Array>
_receiveKeyBase64: string
class Sender implements ISender {
[senderFlag]: true
sendKey: Uint8Array
_sendKeyBase64: string
receiveKeyBase64: any
_annonymous: IAnnonymous
_signKey: Uint8Array
_encryptKey: Uint8Array
constructor (opts: IReceiverOptions) {
super({ id: opts.id })
this[receiverFlag] = true
this.receiveKey = toBuffer(opts.receiveKey)
this.signKey = crypto.deriveAnnonymousKeys(this.receiveKey).then(keys => keys.write)
constructor ({ id, sendKey }: ISenderOptions) {
this[senderFlag] = true
this.sendKey = toBuffer(sendKey)
if (id !== undefined) {
this._annonymous = new Annonymous({ id })
}
}
get receiveKeyBase64 (): string {
if (this._receiveKeyBase64 === undefined) {
this._receiveKeyBase64 = bufferToString(this.receiveKey, 'base64')
get signKey (): Uint8Array {
if (this._signKey === undefined) {
this._signKey = signKeyFromSendKey(this.sendKey)
}
return this._receiveKeyBase64
return this._signKey
}
newAnnonymous (): IAnnonymous {
return new Annonymous(this)
get encryptKey (): Uint8Array {
if (this._encryptKey === undefined) {
this._encryptKey = encryptKeyFromSendKey(this.sendKey)
}
return this._encryptKey
}
compare (other: IAnnonymous, force: boolean = false): number {
if (!(other instanceof Receiver)) {
return (force ? -1 : 1)
get sendKeyBase64 (): string {
if (this._sendKeyBase64 === undefined) {
this._sendKeyBase64 = bufferToString(this.sendKey, 'base64')
}
if (force) {
return bufferCompare(other.receiveKey, this.receiveKey)
return this._sendKeyBase64
}
get sender (): this {
return this
}
get id (): Uint8Array {
return this.annonymous.id
}
get idHex (): string {
return this.annonymous.idHex
}
get idBase64 (): string {
return this.annonymous.idBase64
}
get annonymous (): IAnnonymous {
if (this._annonymous === undefined) {
this._annonymous = new Annonymous({ id: verifyKeyFromSendKey(this.sendKey) })
}
return other.compare(this, true)
return this._annonymous
}
toJSON (): IReceiverJSON {
return {
id: this.idBase64,
receiveKey: this.receiveKeyBase64
equals (other: IAnnonymous | ISender | IReceiver): boolean {
return this.compare(other) === 0
}
compare (other: IAnnonymous | ISender | IReceiver): number {
if (isReceiver(other)) {
return 1
}
if (!isSender(other)) {
return -1
}
return bufferCompare(other.sendKey, this.sendKey)
}
toJSON (): ISenderJSON {
return { sendKey: this.sendKeyBase64 }
}
toString (): string {
return `Receiver[receiveKey=${this.receiveKeyBase64}]`
return `Sender[sendKey=${this.sendKeyBase64}]`
}
async sign (data: Uint8Array): Promise<Uint8Array> {
return crypto.sign(await this.signKey, data)
return await crypto.sign(this.signKey, data)
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
decrypt (encrypted: IEncryptedMessage): ICancelable<IDecryption> {
return cancelable<IDecryption, Receiver>(function * () {
return yield crypto.decryptMessage(
this.id,
yield this.signKey,
this.receiveKey,
encrypted
encrypt (message: IEncodable): ICancelable<IEncryptedMessage> {
// eslint-disable-next-line @typescript-eslint/return-await
return cancelable<IEncryptedMessage, Sender>(function * () {
// eslint-disable-next-line @typescript-eslint/return-await
return yield crypto.encryptMessage(
this.signKey,
this.encryptKey,
message
)

@@ -138,55 +209,83 @@ }, this)

class Sender extends Receiver implements ISender {
[senderFlag]: true
sendKey: Uint8Array
_sendKeyBase64: string
receiveKeyBase64: any
class Receiver implements IReceiver {
[receiverFlag]: true
receiveKey: Uint8Array
_receiveKeyBase64: string
_sender: ISender
_annonymous: IAnnonymous
constructor ({ id, sendKey, receiveKey }: ISenderOptions) {
super({ id, receiveKey })
this[senderFlag] = true
this.sendKey = toBuffer(sendKey)
constructor ({ id, sendKey, receiveKey }: IReceiverOptions) {
this[receiverFlag] = true
this.receiveKey = toBuffer(receiveKey)
if (sendKey !== undefined) {
this._sender = new Sender({ id, sendKey })
}
}
get sendKeyBase64 (): string {
if (this._sendKeyBase64 === undefined) {
this._sendKeyBase64 = bufferToString(this.sendKey, 'base64')
get sender (): ISender {
if (this._sender === undefined) {
this._sender = new Sender({ sendKey: sendKeyFromReceiveKey(this.receiveKey) })
}
return this._sendKeyBase64
return this._sender
}
newReceiver (): IReceiver {
return new Receiver(this)
get id (): Uint8Array {
return this.sender.id
}
compare (other: any, force: boolean = false): number {
if (!(other instanceof Sender)) {
return (force ? -1 : 1)
get idHex (): string {
return this.sender.idHex
}
get idBase64 (): string {
return this.sender.idBase64
}
get receiver (): this {
return this
}
get annonymous (): IAnnonymous {
return this.sender.annonymous
}
get decryptKey (): Uint8Array {
return decryptKeyFromReceiveKey(this.receiveKey)
}
get receiveKeyBase64 (): string {
if (this._receiveKeyBase64 === undefined) {
this._receiveKeyBase64 = bufferToString(this.receiveKey, 'base64')
}
if (force) {
return bufferCompare(other.sendKey, this.sendKey)
}
return other.compare(this, true)
return this._receiveKeyBase64
}
toJSON (): ISenderJSON {
return {
id: this.idBase64,
sendKey: this.sendKeyBase64,
receiveKey: this.receiveKeyBase64
equals (other: IReceiver | ISender | IAnnonymous): boolean {
return this.compare(other) === 0
}
compare (other: IReceiver | ISender | IAnnonymous): number {
if (!isReceiver(other)) {
return -1
}
return bufferCompare(other.receiveKey, this.receiveKey)
}
toJSON (): IReceiverJSON {
return { receiveKey: this.receiveKeyBase64 }
}
toString (): string {
return `Sender[sendKey=${this.sendKeyBase64}]`
return `Receiver[receiveKey=${this.receiveKeyBase64}]`
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
encrypt (message: IEncodable): ICancelable<IEncryptedMessage> {
return cancelable<IEncryptedMessage, Sender>(function * () {
return yield crypto.encryptMessage(
this.id,
yield this.signKey,
this.sendKey,
message
decrypt (encrypted: IEncryptedMessage): ICancelable<IDecryption> {
// eslint-disable-next-line @typescript-eslint/return-await
return cancelable<IDecryption, Receiver>(function * () {
return yield crypto.decryptMessage(
this.annonymous.id,
this.sender.encryptKey,
this.decryptKey,
encrypted
)

@@ -202,4 +301,4 @@ }, this)

constructor (opts: IConnectionOptions) {
this.receiver = new Receiver(opts.receiver)
this.sender = new Sender(opts.sender)
this.receiver = (opts.receiver instanceof Receiver) ? opts.receiver : new Receiver(opts.receiver)
this.sender = (opts.sender instanceof Sender) ? opts.sender : new Sender(opts.sender)
}

@@ -215,22 +314,15 @@

return {
async createReceiverFromReceiveKey (receiveKey: IStringOrBuffer): Promise<IReceiver> {
const syncReceiveKey = toBuffer(receiveKey)
const { read: id } = await crypto.deriveAnnonymousKeys(syncReceiveKey)
return new Receiver({ receiveKey: syncReceiveKey, id })
async createReceiver (): Promise<IReceiver> {
const [encrypt, sign] = await Promise.all([
crypto.createEncryptionKeys(),
crypto.createSignKeys()
])
const sendKey = Buffer.concat([sign.publicKey, sign.privateKey, encrypt.publicKey])
const receiver = new Receiver({
id: sign.publicKey,
sendKey,
receiveKey: Buffer.concat([sendKey, encrypt.privateKey])
})
return receiver
},
async createSenderFromSendKey (sendKey: IStringOrBuffer): Promise<ISender> {
const sendKeySync = toBuffer(sendKey)
const receiveKey = await crypto.deriveReadKey(sendKeySync)
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey)
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
const signKey = Promise.resolve(signKeyValue)
return new Sender({ id, signKey, receiveKey, sendKey: sendKeySync })
},
async createSender (): Promise<ISender> {
const { read: receiveKey, write: sendKey } = await crypto.createKeys()
const { read: id, write: signKeyValue } = await crypto.deriveAnnonymousKeys(receiveKey)
// @ts-ignore - some Typescript versions forgot to declare/define the resolve property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
const signKey = Promise.resolve(signKeyValue)
return new Sender({ id, signKey, receiveKey, sendKey })
},
Annonymous,

@@ -237,0 +329,0 @@ Receiver,

@@ -21,9 +21,15 @@ import { IEncryptedMessage, IDecryption } from './core/types'

export interface IAnnonymous {
export interface IComparable<Base> {
equals(other: Base): boolean
compare(other: Base): number
}
export interface IChannelId {
readonly id: Uint8Array
readonly idBase64: string
readonly idHex: string
}
export interface IAnnonymous extends IComparable<IAnnonymous>, IChannelId {
[annonymousFlag]: true
id: Uint8Array
idBase64: string
readonly idHex: string
equals(other: IAnnonymous): boolean
compare(other: IAnnonymous, _?: boolean): number
toJSON(): IAnnonymousJSON

@@ -34,35 +40,41 @@ verify(signature: Uint8Array, body: Uint8Array): Promise<boolean>

export interface IReceiverJSON extends IAnnonymousJSON {
receiveKey: string
export interface ISenderJSON {
sendKey: string
}
export interface IReceiverOptions extends IAnnonymousOptions {
receiveKey: IStringOrBuffer
signKey?: Promise<Uint8Array>
export interface ISenderOptions {
id?: IStringOrBuffer
sendKey: IStringOrBuffer
}
export interface IReceiver extends IAnnonymous {
[receiverFlag]: true
receiveKey: Uint8Array
signKey: Promise<Uint8Array>
toJSON(): IReceiverJSON
newAnnonymous(): IAnnonymous
export interface ISender extends IComparable<ISender>, IChannelId {
[senderFlag]: true
toJSON(): ISenderJSON
readonly sendKey: Uint8Array
readonly encryptKey: Uint8Array
readonly signKey: Uint8Array
readonly sender: this
readonly annonymous: IAnnonymous
sign(data: Uint8Array): Promise<Uint8Array>
decrypt(encrypted: IEncryptedMessage): ICancelable<IDecryption>
encrypt(message: IEncodable): ICancelable<IEncryptedMessage>
}
export interface ISenderJSON extends IReceiverJSON {
sendKey: string
export interface IReceiverJSON {
receiveKey: string
}
export interface ISenderOptions extends IReceiverOptions {
sendKey: IStringOrBuffer
export interface IReceiverOptions {
id?: IStringOrBuffer
sendKey?: IStringOrBuffer
receiveKey: IStringOrBuffer
}
export interface ISender extends IReceiver {
[senderFlag]: true
sendKey: Uint8Array
toJSON(): ISenderJSON
newReceiver(): IReceiver
encrypt(message: IEncodable): ICancelable<IEncryptedMessage>
export interface IReceiver extends IComparable<IReceiver>, IChannelId {
[receiverFlag]: true
readonly receiveKey: Uint8Array
readonly receiver: this
readonly sender: ISender
readonly annonymous: IAnnonymous
toJSON(): IReceiverJSON
decrypt(encrypted: IEncryptedMessage): ICancelable<IDecryption>
}

@@ -89,3 +101,3 @@

firstMessage: string
confirmKey: string
handshakeSecret: string
}

@@ -96,3 +108,3 @@

firstMessage: IStringOrBuffer
confirmKey: IStringOrBuffer
handshakeSecret: IStringOrBuffer
}

@@ -103,3 +115,3 @@

firstMessage: Uint8Array
confirmKey: Uint8Array
handshakeSecret: Uint8Array
toJSON(): IHandshakeInitJSON

@@ -145,5 +157,3 @@ confirm(acceptMessage: IHandshakeAcceptMessage): ICancelable<IHandshakeConfirmation>

export interface ICryptoPrimitives {
createReceiverFromReceiveKey (receiveKey: IStringOrBuffer): Promise<IReceiver>
createSenderFromSendKey (sendKey: IStringOrBuffer): Promise<ISender>
createSender(): Promise<ISender>
createReceiver(): Promise<IReceiver>
Annonymous: new (opts: IAnnonymousOptions) => IAnnonymous

@@ -150,0 +160,0 @@ Receiver: new (opts: IReceiverOptions) => IReceiver

@@ -13,18 +13,16 @@ declare module 'sodium-universal' {

readonly crypto_sign_BYTES: number
readonly crypto_scalarmult_ed25519_BYTES: number
readonly crypto_secretbox_NONCEBYTES: number
readonly crypto_secretbox_KEYBYTES: number
readonly crypto_secretbox_MACBYTES: number
readonly crypto_scalarmult_BYTES: number
crypto_kdf_derive_from_key(derivedKey: Uint8Array, index: number, deriveContext: Uint8Array, key: Uint8Array): void
crypto_scalarmult_base(pk: Uint8Array, sk: Uint8Array): void
crypto_scalarmult(secret: Uint8Array, sk: Uint8Array, remotePk: Uint8Array): void
crypto_sign_ed25519_sk_to_curve25519(sk: Uint8Array, pk: Uint8Array): void
crypto_sign_ed25519_pk_to_curve25519(pk: Uint8Array, sk: Uint8Array): void
crypto_sign_seed_keypair(pk: Uint8Array, sk: Uint8Array, readKey: Uint8Array): void
crypto_sign_detached(signature: Uint8Array, body: Uint8Array, signSecretKey: Uint8Array): void
crypto_sign_verify_detached(signature: Uint8Array, body: Uint8Array, signPublicKey: Uint8Array): boolean
crypto_sign_ed25519_sk_to_pk(sk: Uint8Array, pk: Uint8Array): void
crypto_box_seal(messageEncrypted: Uint8Array, message: Uint8Array, pk: Uint8Array): void
crypto_box_seal_open(messageDecrypted: Uint8Array, messageEncrypted: Uint8Array, pk: Uint8Array, sk: Uint8Array): boolean
crypto_sign_keypair(pk: Uint8Array, sk: Uint8Array): void
crypto_box_keypair(pk: Uint8Array, sk: Uint8Array): void
randombytes_buf(buffer: Buffer): void

@@ -31,0 +29,0 @@ crypto_secretbox_easy(ciphertext: Uint8Array, message: Uint8Array, nonce: Uint8Array, secretKey: Uint8Array): void

@@ -0,1 +1,3 @@

/* eslint-disable @typescript-eslint/no-throw-literal */
// ↑ https://github.com/typescript-eslint/typescript-eslint/issues/1841
import { Buffer } from 'buffer'

@@ -2,0 +4,0 @@ export { Buffer } from 'buffer'

@@ -0,1 +1,3 @@

/* eslint-disable @typescript-eslint/promise-function-async */
/* eslint-disable @typescript-eslint/return-await */
export interface ICancelable <T = any> extends Promise<T> {

@@ -128,3 +130,2 @@ name?: string

// eslint-disable-next-line @typescript-eslint/promise-function-async
then <TResult3 = TReturn, TResult4 = never> (onfulfilled?: ((value: TReturn) => TResult3 | PromiseLike<TResult3>) | undefined | null, onrejected?: ((reason: any) => TResult4 | PromiseLike<TResult4>) | undefined | null): ICancelable<TResult3 | TResult4> {

@@ -143,3 +144,3 @@ const next = new CancelableWrap(onfulfilled, onrejected)

}
next.cancel = async (): Promise<void> => this.cancel()
next.cancel = (): Promise<void> => this.cancel()
} else if (this._done === TDone.ok) {

@@ -153,9 +154,6 @@ next._receiveData(this._data)

// eslint-disable-next-line @typescript-eslint/promise-function-async
catch <TResult3> (onrejected?: ((reason: any) => TResult3 | PromiseLike<TResult3>) | undefined | null): ICancelable<TResult3> {
// @ts-ignore TS2322
return this.then(null, onrejected)
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
finally (onfinally?: (() => void | PromiseLike<void>) | undefined | null): ICancelable<TReturn> {

@@ -182,5 +180,3 @@ if (typeof onfinally !== 'function') {

return res.then(
// @ts-ignore
async () => Promise.reject(error),
// @ts-ignore
async () => Promise.reject(error)

@@ -268,3 +264,2 @@ )

// eslint-disable-next-line @typescript-eslint/promise-function-async
export function cancelable <TReturn = any, TScope = undefined, T = any> (generator: TCancelable<TReturn, TScope, T>, scope?: TScope, name?: string): ICancelable<TReturn> {

@@ -279,3 +274,2 @@ return new Cancelable(generator, scope, name)

try {
// eslint-disable-next-line @typescript-eslint/promise-function-async
iter = generator.call(scope, (child: ICancelable): ICancelable => {

@@ -300,3 +294,2 @@ if (this._done !== TDone.not) {

if (this._done !== TDone.not) return
// @ts-ignore TS2314
let data: IteratorResult<T, TReturn>

@@ -328,7 +321,5 @@ try {

// eslint-disable-next-line @typescript-eslint/promise-function-async
export function abortCancelable <T> (template: (signal: AbortSignal) => Promise<T>, name?: string): ICancelable<T> {
const controller = new AbortController()
return new SplitCancelable({
// eslint-disable-next-line @typescript-eslint/require-await
cancel: async (): Promise<void> => controller.abort(),

@@ -340,3 +331,2 @@ promise: template(controller.signal),

// eslint-disable-next-line @typescript-eslint/promise-function-async
export function splitCancelable <T> (split: ISplitCancelable<T>): ICancelable<T> {

@@ -343,0 +333,0 @@ return new SplitCancelable(split)

@@ -16,3 +16,4 @@ export interface IExtPromise<T> extends Promise<T> {

result._reject = _reject
// eslint-disable-next-line @typescript-eslint/return-await
return result
}

@@ -0,1 +1,2 @@

/* eslint-disable @typescript-eslint/return-await */
import { isPromiseLike } from './isPromiseLike'

@@ -6,5 +7,14 @@ import { isObject } from './isObject'

export function toPromise<T> (input: T | PromiseLike<T>): PromiseLike<T> {
// eslint-disable-next-line @typescript-eslint/promise-function-async
export function toPromise<T> (input: T | PromiseLike<T>): Promise<T> {
if (isPromiseLike(input)) {
return input
if (input instanceof Promise) {
return input
}
let promise = cache.get(input)
if (promise === undefined) {
promise = new Promise((resolve, reject) => { input.then(resolve, reject) })
cache.set(input, promise)
}
return promise
}

@@ -11,0 +21,0 @@ if (isObject(input)) {

@@ -15,9 +15,13 @@ import { IEncryptedMessage, IDecryption } from './core/types';

}
export interface IAnnonymous {
export interface IComparable<Base> {
equals(other: Base): boolean;
compare(other: Base): number;
}
export interface IChannelId {
readonly id: Uint8Array;
readonly idBase64: string;
readonly idHex: string;
}
export interface IAnnonymous extends IComparable<IAnnonymous>, IChannelId {
[annonymousFlag]: true;
id: Uint8Array;
idBase64: string;
readonly idHex: string;
equals(other: IAnnonymous): boolean;
compare(other: IAnnonymous, _?: boolean): number;
toJSON(): IAnnonymousJSON;

@@ -27,31 +31,37 @@ verify(signature: Uint8Array, body: Uint8Array): Promise<boolean>;

}
export interface IReceiverJSON extends IAnnonymousJSON {
export interface ISenderJSON {
sendKey: string;
}
export interface ISenderOptions {
id?: IStringOrBuffer;
sendKey: IStringOrBuffer;
}
export interface ISender extends IComparable<ISender>, IChannelId {
[senderFlag]: true;
toJSON(): ISenderJSON;
readonly sendKey: Uint8Array;
readonly encryptKey: Uint8Array;
readonly signKey: Uint8Array;
readonly sender: this;
readonly annonymous: IAnnonymous;
sign(data: Uint8Array): Promise<Uint8Array>;
encrypt(message: IEncodable): ICancelable<IEncryptedMessage>;
}
export interface IReceiverJSON {
receiveKey: string;
}
export interface IReceiverOptions extends IAnnonymousOptions {
export interface IReceiverOptions {
id?: IStringOrBuffer;
sendKey?: IStringOrBuffer;
receiveKey: IStringOrBuffer;
signKey?: Promise<Uint8Array>;
}
export interface IReceiver extends IAnnonymous {
export interface IReceiver extends IComparable<IReceiver>, IChannelId {
[receiverFlag]: true;
receiveKey: Uint8Array;
signKey: Promise<Uint8Array>;
readonly receiveKey: Uint8Array;
readonly receiver: this;
readonly sender: ISender;
readonly annonymous: IAnnonymous;
toJSON(): IReceiverJSON;
newAnnonymous(): IAnnonymous;
sign(data: Uint8Array): Promise<Uint8Array>;
decrypt(encrypted: IEncryptedMessage): ICancelable<IDecryption>;
}
export interface ISenderJSON extends IReceiverJSON {
sendKey: string;
}
export interface ISenderOptions extends IReceiverOptions {
sendKey: IStringOrBuffer;
}
export interface ISender extends IReceiver {
[senderFlag]: true;
sendKey: Uint8Array;
toJSON(): ISenderJSON;
newReceiver(): IReceiver;
encrypt(message: IEncodable): ICancelable<IEncryptedMessage>;
}
export interface IConnectionJSON {

@@ -73,3 +83,3 @@ receiver: IReceiverJSON;

firstMessage: string;
confirmKey: string;
handshakeSecret: string;
}

@@ -79,3 +89,3 @@ export interface IHandshakeInitOptions {

firstMessage: IStringOrBuffer;
confirmKey: IStringOrBuffer;
handshakeSecret: IStringOrBuffer;
}

@@ -85,3 +95,3 @@ export interface IHandshakeInit {

firstMessage: Uint8Array;
confirmKey: Uint8Array;
handshakeSecret: Uint8Array;
toJSON(): IHandshakeInitJSON;

@@ -119,5 +129,3 @@ confirm(acceptMessage: IHandshakeAcceptMessage): ICancelable<IHandshakeConfirmation>;

export interface ICryptoPrimitives {
createReceiverFromReceiveKey(receiveKey: IStringOrBuffer): Promise<IReceiver>;
createSenderFromSendKey(sendKey: IStringOrBuffer): Promise<ISender>;
createSender(): Promise<ISender>;
createReceiver(): Promise<IReceiver>;
Annonymous: new (opts: IAnnonymousOptions) => IAnnonymous;

@@ -124,0 +132,0 @@ Receiver: new (opts: IReceiverOptions) => IReceiver;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/no-throw-literal */
// ↑ https://github.com/typescript-eslint/typescript-eslint/issues/1841
const buffer_1 = require("buffer");

@@ -4,0 +6,0 @@ var buffer_2 = require("buffer");

@@ -102,3 +102,2 @@ "use strict";

}
// eslint-disable-next-line @typescript-eslint/promise-function-async
then(onfulfilled, onrejected) {

@@ -119,3 +118,3 @@ const next = new CancelableWrap(onfulfilled, onrejected);

}
next.cancel = async () => this.cancel();
next.cancel = () => this.cancel();
}

@@ -130,8 +129,5 @@ else if (this._done === TDone.ok) {

}
// eslint-disable-next-line @typescript-eslint/promise-function-async
catch(onrejected) {
// @ts-ignore TS2322
return this.then(null, onrejected);
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
finally(onfinally) {

@@ -156,7 +152,3 @@ if (typeof onfinally !== 'function') {

if (isPromiseLike(res)) {
return res.then(
// @ts-ignore
async () => Promise.reject(error),
// @ts-ignore
async () => Promise.reject(error));
return res.then(async () => Promise.reject(error), async () => Promise.reject(error));
}

@@ -235,3 +227,2 @@ throw error;

}
// eslint-disable-next-line @typescript-eslint/promise-function-async
function cancelable(generator, scope, name) {

@@ -246,3 +237,2 @@ return new Cancelable(generator, scope, name);

try {
// eslint-disable-next-line @typescript-eslint/promise-function-async
iter = generator.call(scope, (child) => {

@@ -269,3 +259,2 @@ if (this._done !== TDone.not) {

return;
// @ts-ignore TS2314
let data;

@@ -297,7 +286,5 @@ try {

}
// eslint-disable-next-line @typescript-eslint/promise-function-async
function abortCancelable(template, name) {
const controller = new AbortController();
return new SplitCancelable({
// eslint-disable-next-line @typescript-eslint/require-await
cancel: async () => controller.abort(),

@@ -309,3 +296,2 @@ promise: template(controller.signal),

exports.abortCancelable = abortCancelable;
// eslint-disable-next-line @typescript-eslint/promise-function-async
function splitCancelable(split) {

@@ -312,0 +298,0 @@ return new SplitCancelable(split);

@@ -13,2 +13,3 @@ "use strict";

result._reject = _reject;
// eslint-disable-next-line @typescript-eslint/return-await
return result;

@@ -15,0 +16,0 @@ }

@@ -1,1 +0,1 @@

export declare function toPromise<T>(input: T | PromiseLike<T>): PromiseLike<T>;
export declare function toPromise<T>(input: T | PromiseLike<T>): Promise<T>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/return-await */
const isPromiseLike_1 = require("./isPromiseLike");
const isObject_1 = require("./isObject");
const cache = new WeakMap();
// eslint-disable-next-line @typescript-eslint/promise-function-async
function toPromise(input) {
if (isPromiseLike_1.isPromiseLike(input)) {
return input;
if (input instanceof Promise) {
return input;
}
let promise = cache.get(input);
if (promise === undefined) {
promise = new Promise((resolve, reject) => { input.then(resolve, reject); });
cache.set(input, promise);
}
return promise;
}

@@ -10,0 +20,0 @@ if (isObject_1.isObject(input)) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc