mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-14 11:05:41 +05:00
Curve Encryptor added hybrid (support only working with ml_dsa so far)
This commit is contained in:
parent
71f4e69be0
commit
6b01d64da5
@ -19,6 +19,10 @@ Core.isValidPublicKey = function (owner) {
|
||||
return typeof(owner) === 'string' && owner.length === 44;
|
||||
};
|
||||
|
||||
Core.isValidKemPublicKey = function (kemPublic) {
|
||||
return typeof(kemPublic) === 'string' && kemPublic.length === 800;
|
||||
};
|
||||
|
||||
var makeToken = Core.makeToken = function () {
|
||||
return Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
|
||||
.toString(16);
|
||||
|
||||
@ -264,14 +264,16 @@ commands.DISABLE_APPS = function (Env, args) {
|
||||
commands.SET_SUPPORT_KEYS = function (Env, args) {
|
||||
const curvePublic = args[0]; // Support mailbox key
|
||||
const edPublic = args[1]; // Support pin log
|
||||
const kemPublic = args[2]; // Support KEM key
|
||||
let validated = typeof(curvePublic) === "string" &&
|
||||
(Core.isValidPublicKey(curvePublic) || !curvePublic) &&
|
||||
typeof(edPublic) === "string" &&
|
||||
(Core.isValidPublicKey(edPublic) || !edPublic);
|
||||
if (!validated) { throw new Error('INVALID_ARGS'); }
|
||||
if (Env.supportMailboxKey === curvePublic && Env.supportPinKey === edPublic) { return false; }
|
||||
if (Env.supportMailboxKey === curvePublic && Env.supportPinKey === edPublic && Env.supportMailboxKemKey === kemPublic) { return false; }
|
||||
Env.supportMailboxKey = curvePublic;
|
||||
Env.supportPinKey = edPublic;
|
||||
Env.supportMailboxKemKey = kemPublic;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@ -156,6 +156,7 @@ module.exports.create = function (config) {
|
||||
adminEmail: config.adminEmail,
|
||||
supportMailbox: config.supportMailboxPublicKey,
|
||||
supportMailboxKey: undefined,
|
||||
supportMailboxKemKey: undefined,
|
||||
|
||||
metadata_cache: {},
|
||||
channel_cache: {},
|
||||
|
||||
@ -620,6 +620,7 @@ var serveConfig = makeRouteCache(function () {
|
||||
inactiveTime: Env.inactiveTime,
|
||||
supportMailbox: Env.supportMailbox,
|
||||
supportMailboxKey: Env.supportMailboxKey,
|
||||
supportMailboxKemKey: Env.supportMailboxKemKey,
|
||||
defaultStorageLimit: Env.defaultStorageLimit,
|
||||
maxUploadSize: Env.maxUploadSize,
|
||||
premiumUploadSize: Env.premiumUploadSize,
|
||||
|
||||
@ -45,6 +45,7 @@ Stats.instanceData = function (Env) {
|
||||
// we expect that you enable your support mailbox
|
||||
data.supportMailbox = Boolean(Env.supportMailbox);
|
||||
data.supportMailboxKey = Boolean(Env.supportMailboxKey);
|
||||
data.supportMailboxKemKey = Boolean(Env.supportMailboxKemKey);
|
||||
|
||||
// do you allow registration?
|
||||
data.restrictRegistration = Boolean(Env.restrictRegistration);
|
||||
|
||||
@ -297,7 +297,7 @@ const factory = (Feedback, Hash, Util,
|
||||
* 3.b. No ==> post our mailbox data to the messenger channel
|
||||
*/
|
||||
network.join(friend.channel).then(function (wc) {
|
||||
var keys = Crypto.Curve.deriveKeys(friend.curvePublic, userObject.curvePrivate);
|
||||
var keys = Crypto.Curve.deriveKeys(friend.curvePublic, userObject.curvePrivate, friend.kemPublic, userObject.kemPublic);
|
||||
var encryptor = Crypto.Curve.createEncryptor(keys);
|
||||
channels[friend.channel] = {
|
||||
wc: wc,
|
||||
|
||||
@ -721,7 +721,7 @@ const factory = (Crypto, Hash, Util, Realtime, Messaging,
|
||||
}
|
||||
|
||||
var proxy = ctx.store.proxy;
|
||||
var keys = Curve.deriveKeys(friend.curvePublic, proxy.curvePrivate);
|
||||
var keys = Curve.deriveKeys(friend.curvePublic, proxy.curvePrivate, friend.kemPublic, proxy.kemPublic);
|
||||
var data = {
|
||||
keys: keys,
|
||||
channel: friend.channel,
|
||||
|
||||
@ -39,13 +39,18 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
return void cb('EFORBIDDEN');
|
||||
}
|
||||
|
||||
var supportKemKey = NewConfig.supportMailboxKemKey;
|
||||
|
||||
if (isAdmin) {
|
||||
return ctx.adminRdyEvt.reg(() => {
|
||||
cb(null, {
|
||||
supportKey: supportKey,
|
||||
supportKemKey: supportKemKey,
|
||||
myCurve: data.adminCurvePrivate || Util.find(ctx.store.proxy, [
|
||||
'mailboxes', 'supportteam', 'keys', 'curvePrivate']),
|
||||
theirPublic: data.curvePublic,
|
||||
myKem: ctx.store.proxy.kemPublic,
|
||||
theirKem: data.kemPublic,
|
||||
notifKey: data.curvePublic
|
||||
});
|
||||
});
|
||||
@ -53,8 +58,11 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
|
||||
cb(null, {
|
||||
supportKey: supportKey,
|
||||
supportKemKey: supportKemKey,
|
||||
myCurve: ctx.store.proxy.curvePrivate,
|
||||
theirPublic: data.curvePublic || supportKey, // old tickets may use deprecated key
|
||||
myKem: ctx.store.proxy.kemPublic,
|
||||
theirKem: data.kemPublic, // || supportKemKey, // Needed for PQC, currently making messages unreadable
|
||||
notifKey: supportKey
|
||||
});
|
||||
});
|
||||
@ -63,7 +71,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
// Get the content of a ticket mailbox and close it
|
||||
var getContent = function (ctx, data, isAdmin, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
var theirPublic, myCurve;
|
||||
var theirPublic, myCurve, theirKem, myKem;
|
||||
nThen((waitFor) => {
|
||||
getKeys(ctx, isAdmin, data, waitFor((err, obj) => {
|
||||
if (err) {
|
||||
@ -72,9 +80,11 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
}
|
||||
theirPublic = obj.theirPublic;
|
||||
myCurve = obj.myCurve;
|
||||
theirKem = obj.theirKem;
|
||||
myKem = obj.myKem;
|
||||
}));
|
||||
}).nThen(() => {
|
||||
var keys = Crypto.Curve.deriveKeys(theirPublic, myCurve);
|
||||
var keys = Crypto.Curve.deriveKeys(theirPublic, myCurve, theirKem, myKem);
|
||||
var crypto = Crypto.Curve.createEncryptor(keys);
|
||||
var cfg = {
|
||||
network: ctx.store.network,
|
||||
@ -121,7 +131,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
var channel = data.channel;
|
||||
var title = data.title;
|
||||
var ticket = data.ticket;
|
||||
var supportKey, theirPublic, myCurve;
|
||||
var supportKey, theirPublic, myCurve, theirKem, myKem;
|
||||
var time = +new Date();
|
||||
nThen((waitFor) => {
|
||||
// Send ticket to the admins and call back
|
||||
@ -132,13 +142,15 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
}
|
||||
supportKey = obj.supportKey;
|
||||
theirPublic = obj.theirPublic;
|
||||
theirKem = obj.theirKem;
|
||||
myKem = obj.myKem;
|
||||
myCurve = obj.myCurve;
|
||||
// No need for notifKey here: users can only create tickets for the
|
||||
// currently used key
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
// Create ticket mailbox
|
||||
var keys = Crypto.Curve.deriveKeys(theirPublic, myCurve);
|
||||
var keys = Crypto.Curve.deriveKeys(theirPublic, myCurve, theirKem, myKem);
|
||||
var crypto = Crypto.Curve.createEncryptor(keys);
|
||||
var text = JSON.stringify(ticket);
|
||||
var ciphertext = crypto.encrypt(text);
|
||||
@ -227,7 +239,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
if (!mailbox) { return void cb('E_NOT_READY'); }
|
||||
if (!anonRpc) { return void cb("anonymous rpc session not ready"); }
|
||||
if (!data?.ticket) { return void cb('E_NO_DATA'); }
|
||||
var theirPublic, myCurve, notifKey;
|
||||
var theirPublic, myCurve, notifKey, myKem, theirKem;
|
||||
var time;
|
||||
nThen((waitFor) => {
|
||||
// Get correct keys
|
||||
@ -238,11 +250,13 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
}
|
||||
theirPublic = obj.theirPublic;
|
||||
myCurve = obj.myCurve;
|
||||
theirKem = obj.theirKem;
|
||||
myKem = obj.myKem;
|
||||
notifKey = obj.notifKey;
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
// Send message
|
||||
var keys = Crypto.Curve.deriveKeys(theirPublic, myCurve);
|
||||
var keys = Crypto.Curve.deriveKeys(theirPublic, myCurve, theirKem, myKem);
|
||||
var crypto = Crypto.Curve.createEncryptor(keys);
|
||||
var text = JSON.stringify(data.ticket);
|
||||
var ciphertext = crypto.encrypt(text);
|
||||
@ -417,7 +431,8 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
var t = Util.clone(ctx.supportData[ticket]);
|
||||
getContent(ctx, {
|
||||
channel: ticket,
|
||||
curvePublic: t.curvePublic
|
||||
curvePublic: t.curvePublic,
|
||||
kemPublic: t.kemPublic
|
||||
}, false, waitFor((err, messages) => {
|
||||
if (err) {
|
||||
if (err.type === 'EDELETED') {
|
||||
@ -829,6 +844,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
name: Util.find(first, ['sender', 'name']),
|
||||
notifications: Util.find(first, ['sender', 'notifications']),
|
||||
curvePublic: Util.find(first, ['sender', 'curvePublic']),
|
||||
kemPublic: Util.find(first, ['sender', 'kemPublic']),
|
||||
channel: Hash.createChannelId(),
|
||||
title: first.title,
|
||||
time: last.time,
|
||||
@ -995,7 +1011,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
|
||||
// ADMIN COMMANDS
|
||||
|
||||
let updateServerKey = (ctx, curvePublic, curvePrivate, cb) => {
|
||||
let updateServerKey = (ctx, curvePublic, curvePrivate, kemPublic, cb) => {
|
||||
let edPublic;
|
||||
try {
|
||||
let pair = Crypto.CryptoAgility.signKeyPairFromSeed(Util.decodeBase64(curvePrivate));
|
||||
@ -1005,7 +1021,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
}
|
||||
ctx.Store.adminRpc(null, {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['SET_SUPPORT_KEYS', [curvePublic, edPublic]]
|
||||
data: ['SET_SUPPORT_KEYS', [curvePublic, edPublic, kemPublic]]
|
||||
}, cb);
|
||||
};
|
||||
let getModerators = (ctx, data, cId, cb) => {
|
||||
@ -1021,11 +1037,14 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
let edPublic = proxy.edPublic;
|
||||
|
||||
const keyPair = Crypto.CryptoAgility.curveKeyPair();
|
||||
const kemPair = Crypto.PQC.ml_kem.ml_kem512.keygen();
|
||||
const newKeyPub = Util.encodeBase64(keyPair.publicKey);
|
||||
const newKey = Util.encodeBase64(keyPair.secretKey);
|
||||
const newKemPublic = Util.encodeBase64(kemPair.publicKey);
|
||||
|
||||
const oldKey = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'curvePrivate']);
|
||||
const oldKeyPub = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'curvePublic']);
|
||||
const oldKemPublic = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'kemPublic']);
|
||||
|
||||
if (!newKey || !newKeyPub) { return void cb({ error: 'INVALID_KEY' }); }
|
||||
let oldAdminChan;
|
||||
@ -1091,7 +1110,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
});
|
||||
}).nThen((waitFor) => {
|
||||
// Send new key to server
|
||||
updateServerKey(ctx, newKeyPub, newKey, waitFor((obj) => {
|
||||
updateServerKey(ctx, newKeyPub, newKey, newKemPublic, waitFor((obj) => {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
@ -1122,7 +1141,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
waitFor.abort();
|
||||
if (oldSupportKey) {
|
||||
// If we weren't able to store the new key, abort and restore old keys
|
||||
return updateServerKey(ctx, oldKeyPub, oldKey, () => {
|
||||
return updateServerKey(ctx, oldKeyPub, oldKey, oldKemPublic,() => {
|
||||
return void cb(obj);
|
||||
});
|
||||
}
|
||||
@ -1204,7 +1223,7 @@ const factory = (Util, Hash, Realtime, Pinpad, Crypt,
|
||||
}).nThen((waitFor) => {
|
||||
ctx.Store.adminRpc(null, {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['SET_SUPPORT_KEYS', ['', '']]
|
||||
data: ['SET_SUPPORT_KEYS', ['', '', '']]
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
|
||||
@ -1681,6 +1681,10 @@ const factory = (Util, Hash, Constants, Realtime, ProxyManager,
|
||||
edPrivate: ephemeralKeys.edPrivate,
|
||||
curvePublic: ephemeralKeys.curvePublic,
|
||||
curvePrivate: ephemeralKeys.curvePrivate,
|
||||
kemPublic: ephemeralKeys.kemPublic,
|
||||
kemPrivate: ephemeralKeys.kemPrivate,
|
||||
dsaPublic: ephemeralKeys.dsaPublic,
|
||||
dsaPrivate: ephemeralKeys.dsaPrivate,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -105,6 +105,7 @@ define([
|
||||
APP.supportModule.execCommand('CLOSE_TICKET', {
|
||||
channel: channel,
|
||||
curvePublic: data.curvePublic, // Support curve public for this ticket
|
||||
kemPublic: data.kemPublic, // Support kem public for this ticket
|
||||
ticket: APP.support.getDebuggingData({ close: true })
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { return void UI.warn(Messages.error); }
|
||||
@ -116,6 +117,7 @@ define([
|
||||
APP.supportModule.execCommand('REPLY_TICKET', {
|
||||
channel: channel,
|
||||
curvePublic: data.curvePublic, // Support curve public for this ticket
|
||||
kemPublic: data.kemPublic, // Support kem public for this ticket
|
||||
ticket: formData
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { return void UI.warn(Messages.error); }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user