Skip to content
Snippets Groups Projects
Commit 9e3b195a authored by Millicent Billette's avatar Millicent Billette
Browse files

v3.4.0

ADD: textEncrypt and textDecrypt to read and write cesium+ messages.
parent 3beece1d
No related branches found
Tags v3.4.0
No related merge requests found
Pipeline #17711 passed with warnings
......@@ -9,12 +9,15 @@ et ce projet adhère au [versionnage sémantique](https://semver.org/spec/v2.0.0
## Evolutions probable / Roadmap :
- GraphQL stuff
- @@@@ comme séparateur entre identifiant secret et mdp pour la génération de combinaison à tester (usage principal Gsper)
- supprimer automatiquement le code inutile dans les lib (Tree Shaking)
- chiffrer déchiffrer des messages
- lire et écrire des messages au format cesium+
## [Non-publié/Non-Stabilisé] (par [1000i100])
## [Version 3.4.0] - 2022-11-15 (par [1000i100])
### Ajouté
- crypto.textEncrypt(jsonMessage, senderPrivateKey, receiverPubKey) retourne un json format cesium+ avec `jsonMessage.title` et `jsonMessage.content` chiffrés.
- textDecrypt(jsonMessage, receiverPrivateKey)) retourne en json les champs `title` et `content` déchiffrés à partir d'un message chiffré format cesium+.
## [Version 3.3.3] - 2022-11-15 (par [1000i100])
### Corrections
- les versions 3.3.x antérieur à celle-ci, cherchaient à importer la lib crypto de node depuis le navigateur c'est corrigé.
......@@ -98,8 +101,9 @@ et ce projet adhère au [versionnage sémantique](https://semver.org/spec/v2.0.0
- intégration des librairies de crypto nécessaires
- calcul de la clef publique correspondant à chaque combinaison de secrets saisie, et comparaison à la clef publique de référence.
[Non-publié/Non-Stabilisé]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.3...master
[Non-publié/Non-Stabilisé]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.4.0...main
[Version 3.4.0]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.3...v3.4.0
[Version 3.3.3]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.2...v3.3.3
[Version 3.3.2]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.1...v3.3.2
[Version 3.3.1]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.0...v3.3.1
......
{
"name": "g1lib",
"version": "3.3.3",
"version": "3.4.0",
"description": "An ubiquitous static javascript toolbox lib for Ǧ1 / Duniter ecosystem with reliability in mind.",
"main": "nodejs/all.mjs",
"browser": "browser/all.mjs",
......
......@@ -5,7 +5,7 @@ import sha256 from '../node_modules/js-sha256/src/sha256.mjs';
import nacl from '../generated/vendors/nacl.mjs';
import {convertPublicKey, convertSecretKey} from '../node_modules/ed2curve/src/index.mjs';
//import {convertPublicKey} from '../node_modules/ed2curve-esm/dist-src/index.mjs';
import {b58, b64} from './basex.mjs';
import {b16, b58, b64} from './basex.mjs';
import {random, ed25519} from './context-dependant/generics.mjs';
nacl.setPRNG(random);
export const mockRandom = nacl.setPRNG;
......@@ -157,9 +157,9 @@ export async function signDocument(unsignedDocument, secretKey) {
return `${unsignedDocument.trim()}\n${signHash}`;
}
export async function sign(str, secretKey, outputFormat = 'b64') {
export function sign(str, secretKey, outputFormat = 'b64') {
const encoder = new TextEncoder();
const raw = await rawSign(encoder.encode(str), b58secretKey2bin(secretKey).slice(0, 32));
const raw = rawSign(encoder.encode(str), b58secretKey2bin(secretKey).slice(0, 32));
switch (outputFormat.toLocaleLowerCase()) {
case 'raw':
case 'array':
......@@ -174,7 +174,58 @@ export async function sign(str, secretKey, outputFormat = 'b64') {
}
}
export async function rawSign(uint8Array, rawSeed) {
const keys = await seed2keyPair(rawSeed);
export function rawSign(uint8Array, rawSeed) {
const keys = seed2keyPair(rawSeed);
return nacl.sign.detached(uint8Array, keys.secretKey);
}
const NONCE_BYTES = 24;
const PUBKEY_BYTES = 32;
export function typedStrOrBin2Bin(tStrOrBin,type2binFunc){
return (typeof tStrOrBin === 'string')?type2binFunc(tStrOrBin):tStrOrBin;
}
export function strOrBin2bin(strOrBin){
const encoder = new TextEncoder();
return (typeof strOrBin === 'string')?encoder.encode(strOrBin):strOrBin;
}
export function b64orBin2bin(b64orBin){
return typedStrOrBin2Bin(b64orBin,b64.decode);
}
export function b58orBin2bin(b58orBin){
return typedStrOrBin2Bin(b58orBin,b58.decode);
}
export function bin2str(bin){
const decoder = new TextDecoder();
return decoder.decode(bin);
}
function secKey2bin(secretKey){
return b58orBin2bin(secretKey).slice(0,PUBKEY_BYTES);
}
export function textEncrypt(jsonMessage, senderPrivateKey, receiverPubKey, nowInSecond=0, b58nonce=''){
const bNonce = b58nonce?b58.decode(b58nonce):nacl.randomBytes(NONCE_BYTES);
console.log("Défini : ", receiverPubKey)
const bReceiverPubKey = convertPublicKey(pubKey2bin(receiverPubKey));
const bSenderPrivateKey = convertSecretKey(secKey2bin(senderPrivateKey));
const encrypt = utf8text => b64.encode(nacl.box(strOrBin2bin(utf8text),bNonce,bReceiverPubKey,bSenderPrivateKey));
const b58sendPubKey = b58.encode(seed2keyPair(secKey2bin(senderPrivateKey)).publicKey);
const sTimestamp = nowInSecond || Math.trunc(Date.now()/1000);
const res = {nonce:b58.encode(bNonce),issuer:b58sendPubKey,recipient:receiverPubKey,time:sTimestamp,version:2};
if(jsonMessage.title) res.title = encrypt(jsonMessage.title);
if(jsonMessage.content) res.content = encrypt(jsonMessage.content);
res.hash = b16.encode(sha256Instance.digest(JSON.stringify(res))).toUpperCase();
res.signature = sign(res.hash,senderPrivateKey)
return res;
}
export function textDecrypt(jsonMessage, receiverPrivateKey){
const bNonce = b58.decode(jsonMessage.nonce);
const bReceiverPrivateKey = convertSecretKey(secKey2bin(receiverPrivateKey));
const bSenderPubKey = convertPublicKey(pubKey2bin(jsonMessage.issuer));
const decrypt = b64text => bin2str(nacl.box.open(b64.decode(b64text),bNonce,bSenderPubKey,bReceiverPrivateKey));
const res = {};
if(jsonMessage.content) res.content = decrypt(jsonMessage.content);
if(jsonMessage.title) res.title = decrypt(jsonMessage.title);
return res;
}
......@@ -28,7 +28,15 @@ test('b58 sign string', async t => t.is(await app.sign(unsignedDocument, secretK
test('raw sign string', async t => t.is((await app.sign(unsignedDocument, secretKey, 'raw'))[0], 27));
test('array sign string', async t => t.is((await app.sign(unsignedDocument, secretKey, 'Array'))[0], 27));
test('uint8array sign string', async t => t.is((await app.sign(unsignedDocument, secretKey, 'uint8array'))[0], 27));
test('sign throw for bad output format', async t => t.throwsAsync(() => app.sign(unsignedDocument, secretKey, 'whattt ?')));
test('sign throw for bad output format', t => t.throws(() => app.sign(unsignedDocument, secretKey, 'whattt ?')));
//test('signOnly(message, privateKey)', t => t.is(app.signOnly('a message', secretKey), 'signature'));
//test('signOnly(message, privateKey, returnFormat=uint8array)', t => t.is(app.signOnly([0,1,2,3], secretKey), [0,1,2,3]));
//test('signDocument or signMessage(message, privateKey)', t => t.is(app.sign('a message', secretKey), 'message avec sa signature'));
//test('sign(uint8array, privateKey, returnFormat=uint8array)', async t => t.is(await app.sign([0,1,2,3], secretKey,'uint8array'), [0,0,0,0]));
//test('checkSign(message, issuerPubKey) succeed', t => t.is(app.checkSign('a message', secretKey), true));
//test('checkSign(message, issuerPubKey) fail', t => t.is(app.checkSign([0,1,2,3], secretKey,'uint8array'), false));
test('b58 should decode/encode well', t => t.is(app.b58.encode(app.b58.decode(pubKey)), pubKey));
test('b58 on pubKey with leading 1', t => t.is(app.b58.encode(app.b58.decode('12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx')), '12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx'));
......@@ -127,3 +135,34 @@ test('checkKey accept valid binary pubKey', t => t.true(app.checkKey(app.b58.dec
test("isPubKey return true when checkKey return true ", (t) => t.true(app.isPubKey(pubKey)));
test("isPubKey return false when checkKey throw an error", (t) => t.false(app.isPubKey(pubKey.replace(/6/,'9'))));
app.mockRandom((u8a, n)=>{
if(!u8a && !n) return 0.5;
if(!n && typeof u8a === "number"){n = u8a;u8a = new Uint8Array(n);}
for (let i = 0; i < n; i++) u8a[i] = 5;
return u8a;
});
const user1 = await app.idSecPass2cleanKeys('1','1');
const user2 = await app.idSecPass2cleanKeys('2','2');
const timestampInSeconds = 1222111000;
const sampleMessage = {title:"Mon Titre",content:"Mon message"};
const cryptedMessage = {
content: 'G0ZAirsaoeAt/pOcsjg0milDkeBu8Uo3BgrZ',
hash: '65EC1622D2C38422EA21124397AB7A9F36A94BB6FC2C474C706ECAC33658114C',
issuer: 'BUhLyJT17bzDVXW66xxfk1F7947vytmwJVadTaWb8sJS',
nonce: 'TYPjCiGbKiwP6r12cdkmVjySbQpSHavp',
recipient: '7nge6q7F4k7FQ2q4FRMMPvt2tK7AEx8gNNRLr6LwZN38',
signature: 'u4m2YHp5nVxcXxMjQvv9H4kfSV8Q3/Jh68jHplbCjizXlA9XXksu+YuFrS9B5KuQ2HX68g9+kRdLoCspMuWtBg==',
time: timestampInSeconds,
title: 'yV5cDZCuJWqMBXsFmEm1FSlDkeBX/U02Ag==',
version: 2
};
test('textEncrypt(jsonMessage, senderPrivateKey, receiverPubKey) encrypt to cesium+ message format',
t => t.deepEqual(
app.textEncrypt(sampleMessage, user1.secretKey, user2.publicKey,timestampInSeconds),
cryptedMessage)
);
test('textDecrypt(jsonMessage, receiverPrivateKey)', t => t.deepEqual(app.textDecrypt(cryptedMessage, user2.secretKey),
{title:"Mon Titre",content:"Mon message"}));
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment