Aide pour utiliser Ğ1lib.js

Je voudrai arriver à utiliser l’outil comme keygen et jaklis en “CLI”
et aussi dans la page du “navigateur”

Une version javascript est prévue ?

Moi, je n’ai toujours pas réussi à utiliser g1lib.js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Duniter and IPFS Key Generator</title>
    <script src="https://cdn.jsdelivr.net/npm/g1lib@latest"></script>
</head>
<body>
    <h1>Duniter and IPFS Key Generator</h1>
    
    <label for="latitude">Latitude:</label>
    <input type="text" id="latitude" name="latitude"><br>
    
    <label for="longitude">Longitude:</label>
    <input type="text" id="longitude" name="longitude"><br>
    
    <button onclick="generateKeys()">Generate Keys</button>
    
    <h2>Duniter (G1) Public Key:</h2>
    <p id="duniterPubkey"></p>
    
    <h2>IPFS Public Key:</h2>
    <p id="ipfsPubkey"></p>
    
    <script>
        async function generateKeys() {
            const latitude = document.getElementById('latitude').value;
            const longitude = document.getElementById('longitude').value;
            
            const credentials = `_${latitude}_${longitude}`;
            const keyPair = await g1lib.keyPair.fromCredentials(credentials);
            const publicKey = keyPair.publicKey;
            
            // Duniter (G1) Public Key
            const duniterPubkey = publicKey;
            document.getElementById('duniterPubkey').textContent = duniterPubkey;
            
            // IPFS Public Key
            const ipfsPrefix = new Uint8Array([0x00, 0x24, 0x08, 0x01, 0x12, 0x20]);
            const ipfsPubkey = g1lib.b58.encode(new Uint8Array([...ipfsPrefix, ...publicKey]));
            document.getElementById('ipfsPubkey').textContent = ipfsPubkey;
        }
    </script>
</body>
</html>

Toujours ce bordel entre les versions pour node et pour browser des librairies ja
export declarations may only appear at top level of a module

Je déplace ça dans un nouveau fil parce que ce sera plus facile à retrouver.

Pour générer des clés dans le navigateur, le mieux est d’utiliser une extension navigateur et de lui déléguer la partie crypto.

merci @HugoTrentesaux
peut être que @1000i100 peut apporter son aide?

Voici une démo d’utilisation de Ğ1lib en javascript dans une application vue :

Hugo Trentesaux / g1lib demo · GitLab

Et voici une version servie sur IPFS : https://bafybeiee3qwcg5q74ulb4rqbif6esm3mjedubi4b754hprggfb2mgeu53a.ipfs.pagu.re/

merci. superbe.
pas habitué aux framework vue.js

J’en suis au niveau “ajax”… je charge des librairies et exécute les fonctions dans la page…

ipfs ls /ipfs/bafybeiee3qwcg5q74ulb4rqbif6esm3mjedubi4b754hprggfb2mgeu53a
QmXj1TmR2wAw6pKxQJGLh6hCGNtykenUuhV3Bmzu84ozWt -    assets/
QmaSyMrhp7Y1bgw5hRDCzwLMgf6piNhawkkVpwUgZ94d3Q 4286 favicon.ico
QmW4YD35ttfDcATej5s9ZSZxbwETJ6GmL9SfaMce4PuWCj 430  index.html
ipfs cat /ipfs/bafybeiee3qwcg5q74ulb4rqbif6esm3mjedubi4b754hprggfb2mgeu53a/assets/index-qu9fWtog.js

“rétro ingénierie” difficile…

Bah si tu veux que je t’aide, tu peux t’y mettre c’est facile.

Bah oui, tu choisis le chemin le plus difficile alors que je t’ai fourni les sources :

voici la page de l’appli : src/App.vue · master · Hugo Trentesaux / g1lib demo · GitLab

<script setup lang="ts">
import { ref } from 'vue'
import * as g1lib from 'g1lib'

const id = ref('')
const passwd = ref('')
const res = ref('')

function compute() {
  g1lib.crypto.idSecPass2cleanKeys(id.value, passwd.value).then((v: any) => (res.value = v.pubKey))
}
</script>

<template>
  <h1>G1lib</h1>
  <div style="min-width: 40em">
    id <input v-model="id" @input="compute" /> <br />
    passwd <input v-model="passwd" @input="compute" /> <br />
    <span class="mono">{{ res }}</span>
  </div>
</template>

<style scoped>
.mono {
  font-family: monospace;
}
</style>

C’est pas plus compliqué que ça. Le reste n’est qu’emballage généré par la commande pnpm create vue@latest. Donc pour reproduire chez toi, c’est git clone puis pnpm install puis pnpm run dev. C’est tout (enfin bien sûr il faut installer pnpm et node).

Je sais, mais un peu comme un aveugle, je dois toucher à tout et suivre tous la “tuyauterie” pour comprendre les fonctions de la machine que j’ai sous les yeux. Bien isoler où sont chaque parties, celles exécutées dans le navigateur et sur le serveur…

search
#!/bin/bash
MY_PATH="`dirname \"$0\"`"              # relative
MY_PATH="`( cd \"$MY_PATH\" && pwd )`"  # absolutized and normalized
ME="${0##*/}"
## THIS IS A GREAT RETRO ENGINEERING AND CODE SNIFFING TOOLS
clear
[[ ! -s ~/.local/bin/${ME} ]] && cp ${MY_PATH}/${ME} ~/.local/bin/ && echo "Auto Install into ~/.local/bin/${ME}"
echo "------------------------------------------------------------------------------"
if [ "$1" == "" ]; then
    echo "  Nothing to search for!"
else
    echo "  Searching for "$1" recursively. Please Wait..."
    echo "------------------------------------------------------------------------------"
    grep -h -r --exclude-dir='.git*' -H --colour=always "$1" ./
fi
echo "------------------------------------------------------------------------------"
if [ "$2" != "" ]; then
    echo "  To replace \"$1\" whith \"$2\", please run"
    echo "  grep -rl --exclude-dir='.git*' '$1' ./  | xargs sed -i 's~$1~$2~g'"
fi
exit 0

search est mon outil favori pour explorer les variables et les fonctions
Je code avec du bois et de l’argile. Un peu comme je fais mes cabanes, avec les matériaux du coin, légères, démontables, cousu ou cloué … :hut: plutôt que vissé et cimenté…
“nodejs” et ses framework js c’est du BTP pour faire des immeubles :building_construction:


Essayons vue.js

ça à l’air simple… mais ça utilise plein de balises que je ne connais pas.

et ça commence pas top…

sudo apt install pnpm
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances       
Lecture des informations d'état... Fait
E: Impossible de trouver le paquet pnpm

L’UX recherchée…

Avoir les “5 outils du Web3” et pratiquer le partage de secrets ala Diffie-Hellman

Soit disposer dans le navigateur des outils pour fabriquer et utiliser une clefs publique et privée adressée en 2D (salt/pepper) et exprimée dans l’espace “G1” et “IPFS”, pour m’en servir comme avec keygen et natools et ipfs pour hasher, (dé)chiffrer, signer, vérifier…

Tu crois pouvoir m’y aider ?
En fait, je ne suis pas sûr qu’on puisse forcer la création de sa clef “ipns” avec https://helia.io/ Si ce n’est pas possible, il y a cette double “DHT” ipfs à informer entre les ipfs navigateurs (éphémère) et serveur (online), ce qui peut nécessiter de développer une API //

Un des usages premier serait de publier des data sur la clef IPNS de la G1Pub connectée afin d’informer le réseau qu’un “sign on” a eu lieu. Puis enrichir le protocole de communication inter “clients” et “serveurs”… comme c’est le cas entre les serveurs d’un essaim Astroport. Pour la messagerie, pubsub (et le gossip p2p) a des limites… J’explore aussi le protocole webRTC (avec vdo.ninja)

NB

Quand on charge https://cdn.jsdelivr.net/npm/g1lib@latest/browser/all.mjs directement dans une page, il y a toujours cette erreur…
Uncaught SyntaxError: export declarations may only appear at top level of a module all.mjs:5:8507 ça ne devrait pas dans la version browser ?

Faut que j’essaye https://browserify.org/

Sur le dépot g1lib les liens vers “Packages” sont cassés

avec nacl.min.js et scrypt.min.js
J’ai réussi à progresser en arrivant à générer une clef pour “duniter” et “ipfs”
et j’ai pu chiffrer… mais pas déchiffrer

code
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>Générateur de clés Duniter/IPFS et Chiffrement/Déchiffrement</title>
    <script src="nacl.min.js"></script>
    <script src="scrypt.min.js"></script>
</head>
<body>
    <h1>Générateur de clés Duniter/IPFS</h1>
    <form id="keygenForm">
        <label for="username">Username:</label>
        <input type="text" id="username" required><br><br>
        <label for="password">Password:</label>
        <input type="text" id="password" required><br><br>
        <button type="submit">Générer les clés</button>
    </form>
    <div id="output"></div>

    <h2>Chiffrement avec la clé publique</h2>
    <form id="encryptForm">
        <label for="publicKey">Clé publique:</label>
        <input type="text" id="publicKey" required><br><br>
        <label for="message">Message à chiffrer:</label>
        <textarea id="message" required></textarea><br><br>
        <button type="submit">Chiffrer</button>
    </form>
    <div id="encryptedOutput"></div>

    <h2>Déchiffrement avec la clé privée</h2>
    <form id="decryptForm">
        <label for="privateKeySelect">Sélectionner une clé privée:</label>
        <select id="privateKeySelect"></select><br><br>
        <label for="encryptedMessage">Message chiffré:</label>
        <textarea id="encryptedMessage" required></textarea><br><br>
        <button type="submit">Déchiffrer</button>
    </form>
    <div id="decryptedOutput"></div>

    <script>
    const BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    let generatedKeys = [];

    function to_b58(B, A = BASE58) {
        var d = [], s = "", i, j, c, n;
        for (i in B) {
            j = 0, c = B[i];
            s += c || s.length ^ i ? "" : 1;
            while (j in d || c) {
                n = d[j];
                n = n ? n * 256 + c : c;
                c = n / 58 | 0;
                d[j] = n % 58;
                j++
            }
        }
        while (j--) s += A[d[j]];
        return s;
    }

    function from_b58(S, A = BASE58) {
        var d = [], b = [], i, j, c, n;
        for (i in S) {
            j = 0, c = A.indexOf(S[i]);
            if (c < 0) return undefined;
            c || b.length ^ i ? i : b.push(0);
            while (j in d || c) {
                n = d[j];
                n = n ? n * 58 + c : c;
                c = n >> 8;
                d[j] = n % 256;
                j++
            }
        }
        while (j--) b.push(d[j]);
        return new Uint8Array(b);
    }

    async function generateDuniterKey(username, password) {
        const scryptParams = {
            N: 4096,
            r: 16,
            p: 1,
            dkLen: 32
        };

        const salt = new TextEncoder().encode(username);
        const passwordBytes = new TextEncoder().encode(password);

        const derivedKey = await scrypt.scrypt(passwordBytes, salt, scryptParams.N, scryptParams.r, scryptParams.p, scryptParams.dkLen);

        const keyPair = nacl.sign.keyPair.fromSeed(new Uint8Array(derivedKey));

        const publicKey = to_b58(keyPair.publicKey);
        const privateKey = to_b58(keyPair.secretKey);

        return { publicKey, privateKey };
    }

    function formatDuniterKey(publicKey, privateKey) {
        return `PubSec:${publicKey}:${privateKey}`;
    }

    function formatIPFSKey(publicKey, privateKey) {
        const publicKeyBytes = from_b58(publicKey);
        const privateKeyBytes = from_b58(privateKey);
        const publicProtobuf = new Uint8Array([0, 36, 8, 1, 18, 32, ...publicKeyBytes]);
        const privateProtobuf = new Uint8Array([8, 1, 18, 64, ...privateKeyBytes]);

        return {
            id: to_b58(publicProtobuf),
            privKey: btoa(String.fromCharCode.apply(null, privateProtobuf))
        };
    }

function encryptMessage(publicKey, message) {
    const publicKeyUint8 = from_b58(publicKey);
    const messageUint8 = new TextEncoder().encode(message);
    const ephemeralKeyPair = nacl.box.keyPair();
    const nonce = nacl.randomBytes(nacl.box.nonceLength);
    const sharedKey = nacl.box.before(publicKeyUint8, ephemeralKeyPair.secretKey);
    const encrypted = nacl.secretbox(messageUint8, nonce, sharedKey);

    const fullMessage = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
    fullMessage.set(ephemeralKeyPair.publicKey);
    fullMessage.set(nonce, ephemeralKeyPair.publicKey.length);
    fullMessage.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);

    return to_b58(fullMessage);
}


function decryptMessage(privateKey, encryptedMessage) {
    try {
        const privateKeyUint8 = from_b58(privateKey);
        const fullMessageUint8 = from_b58(encryptedMessage);

        const ephemeralPublicKey = fullMessageUint8.slice(0, nacl.box.publicKeyLength);
        const nonce = fullMessageUint8.slice(nacl.box.publicKeyLength, nacl.box.publicKeyLength + nacl.box.nonceLength);
        const ciphertext = fullMessageUint8.slice(nacl.box.publicKeyLength + nacl.box.nonceLength);

        const sharedKey = nacl.box.before(ephemeralPublicKey, privateKeyUint8);
        const decrypted = nacl.secretbox.open(ciphertext, nonce, sharedKey);

        if (decrypted === null) {
            throw new Error("Déchiffrement échoué");
        }

        return new TextDecoder().decode(decrypted);
    } catch (error) {
        throw new Error("Erreur de déchiffrement : " + error.message);
    }
}




    async function generateKeys() {
        const username = document.getElementById('username').value;
        const password = document.getElementById('password').value;

        try {
            const keys = await generateDuniterKey(username, password);
            const duniterKey = formatDuniterKey(keys.publicKey, keys.privateKey);
            const ipfsKey = formatIPFSKey(keys.publicKey, keys.privateKey);

            generatedKeys.push(keys);
            updatePrivateKeySelect();

            const output = document.getElementById('output');
            output.innerHTML = `
                <h2>Clé Duniter :</h2>
                <pre>${duniterKey}</pre>
                <h2>Clé IPFS :</h2>
                <pre>${JSON.stringify(ipfsKey, null, 2)}</pre>
            `;

            document.getElementById('publicKey').value = keys.publicKey;
        } catch (error) {
            console.error('Erreur lors de la génération des clés:', error);
            document.getElementById('output').innerHTML = `<p>Erreur : ${error.message}</p>`;
        }
    }

    function updatePrivateKeySelect() {
        const select = document.getElementById('privateKeySelect');
        select.innerHTML = '';
        generatedKeys.forEach((keys, index) => {
            const option = document.createElement('option');
            option.value = keys.privateKey;
            option.textContent = `Clé ${index + 1} (Publique: ${keys.publicKey.substr(0, 10)}...)`;
            select.appendChild(option);
        });
    }

    document.getElementById('keygenForm').addEventListener('submit', function(e) {
        e.preventDefault();
        generateKeys();
    });

    document.getElementById('encryptForm').addEventListener('submit', function(e) {
        e.preventDefault();
        const publicKey = document.getElementById('publicKey').value;
        const message = document.getElementById('message').value;
        const encryptedMessage = encryptMessage(publicKey, message);

        const encryptedOutput = document.getElementById('encryptedOutput');
        encryptedOutput.innerHTML = `
            <h3>Message chiffré :</h3>
            <pre>${encryptedMessage}</pre>
        `;

        document.getElementById('encryptedMessage').value = encryptedMessage;
    });

    document.getElementById('decryptForm').addEventListener('submit', function(e) {
        e.preventDefault();
        const privateKey = document.getElementById('privateKeySelect').value;
        const encryptedMessage = document.getElementById('encryptedMessage').value;

        try {
            const decryptedMessage = decryptMessage(privateKey, encryptedMessage);
            const decryptedOutput = document.getElementById('decryptedOutput');
            decryptedOutput.innerHTML = `
                <h3>Message déchiffré :</h3>
                <pre>${decryptedMessage}</pre>
            `;
        } catch (error) {
            console.error('Erreur lors du déchiffrement:', error);
            document.getElementById('decryptedOutput').innerHTML = `<p>Erreur de déchiffrement : ${error.message}</p>`;
        }
    });
    </script>
</body>
</html>

online: /ipfs/QmQZyqA6heDkz4SJmw2NHxnwEJKKqwBZnGbwAZh75tJjdZ

Pas mal cette petite appli :slight_smile:

Effectivement quand je tente de déchiffrer j’ai

Erreur de déchiffrement : Erreur de déchiffrement : bad secret key size

Le test qui couvre le déchiffrement est ici : src/crypto.test.mjs · main · libs / G1lib.js · GitLab. Est-ce que ça t’aide ? Sinon ça peut être bien de demander de l’aide à @1000i100 (et aussi pour réparer les liens cassés suite à l’abandon de duniter.io).

J’ai repris le proto d’ @HugoTrentesaux et j’y ai ajouter de quoi chiffrer et déchiffré :

2 Likes

Et tu as même mis une version en ligne : https://1000i100.pages.duniter.org/g1lib-webui-demo/