Outils pour utilisateurs

Outils du site


notes:webcrypto

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
notes:webcrypto [2020/02/26 16:21]
etienne [WebCrypto]
notes:webcrypto [2021/05/28 15:12] (Version actuelle)
etienne
Ligne 1: Ligne 1:
 ====== WebCrypto ====== ====== WebCrypto ======
  
-Cette page résume des opérations similaires entre WebCrypto et d'autres outils+Comme il est parfois difficile de faire le lien entre les formats, les algorithmes et les divers paramètres, cette page à pour but de montrer le lien qu'il existe entre des opérations avec l'API WebCrypto et d'autres outils et langages. 
 +Elle ne reflète en aucun cas des méthodes devant être appliquée mais bien des exemples comme générer un clé privée avec OpenSSL et l'utiliser avec WebCrypto. 
 ===== RSA-PSS pour signature ===== ===== RSA-PSS pour signature =====
 +
 +[[https://artnum.ch/code/demos/webcrypto/sign.html|Démonstration]]
  
 ==== Conversion de clés ==== ==== Conversion de clés ====
 +
 +==== Clé publique de PEM vers DER ====
 +<code shell>
 +$ openssl pkey  -pubin -in rsapub.pem -out rsapub.der -outform DER
 +</code>
 +
 +
 +=== OpenSSH ===
 +
 +Pour convertir une clé SSH vers RSA (pour ensuite être utilisée avec OpenSSL)
 +<code shell>
 +$ ssh-keygen -p -m PEM -f ssh-rsa.key
 +</code>
 +
 +Ensuite on extrait sa clé publique et on la converti en PKCS#8
 +<code shell>
 +$ openssl rsa -in ssh-rsa.key -pubout > ssh-rsa.pub
 +$ openssl pkcs8 -topk8 -nocrypt -in ssh-rsa.key -out ssh-rsa.pkcs8
 +</code>
  
 === OpenSSL === === OpenSSL ===
Ligne 21: Ligne 44:
  
 <code javascript> <code javascript>
-  function b64Decode (text) {                                                                                                                                                                                      +  function b64Decode (text) { 
-     let s = atob(text.trim().replace(/\r?\n|\r/g, ''))                                                                                                                                                             +     let s = atob(text.trim().replace(/\r?\n|\r/g, '')) 
-     const buffer = new ArrayBuffer(s.length)                                                                                                                                                                       +     const buffer = new ArrayBuffer(s.length) 
-     const bview = new Uint8Array(buffer)                                                                                                                                                                           +     const bview = new Uint8Array(buffer) 
-     for (let i = 0; i < s.length; i++) {                                                                                                                                                                           +     for (let i = 0; i < s.length; i++) { 
-       bview[i] = s.charCodeAt(i)                                                                                                                                                                                   +       bview[i] = s.charCodeAt(i) 
-                                                                                                                                                                                                                  +     } 
-     return buffer                                                                                                                                                                                                  +     return buffer 
-                                                                                                                                                                                                                  +   } 
-                                                                                                                                                                                                                    + 
-   function readPEM (text) {                                                                                                                                                                                        +   function readPEM (text) { 
-     const pemRegex = /^-----BEGIN (?:PRIVATE|PUBLIC) KEY-----$([a-zA-Z0-9\/\+=\r\n]*)^-----END (?:PRIVATE|PUBLIC) KEY-----$/mg                                                                                     +     const pemRegex = /^-----BEGIN (?:PRIVATE|PUBLIC) KEY-----$([a-zA-Z0-9\/\+=\r\n]*)^-----END (?:PRIVATE|PUBLIC) KEY-----$/mg 
-     let m = pemRegex.exec(text)                                                                                                                                                                                    +     let m = pemRegex.exec(text) 
-     if (m && m.length > 1) {                                                                                                                                                                                       +     if (m && m.length > 1) { 
-       return b64Decode(m[1])                                                                                                                                                                                       +       return b64Decode(m[1]) 
-                                                                                                                                                                                                                  +     } 
-     return undefined                                                                                                                                                                                               +     return undefined 
-          +   }
 </code> </code>
  
Ligne 44: Ligne 67:
  
 <code javascript> <code javascript>
-   function b64Encode (buffer) {                                                                                                                                                                                    +   function b64Encode (buffer) { 
-     let txt = ''                                                                                                                                                                                                   +     let txt = '' 
-     let b64 = btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)))                                                                                                                                        +     let b64 = btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))) 
-     for (let i = 0; i < (Math.ceil(b64.length / 64)); i++) {                                                                                                                                                       +     for (let i = 0; i < (Math.ceil(b64.length / 64)); i++) { 
-       txt += b64.substring(i * 64, (i + 1) * 64) + "\n"                                                                                                                                                            +       txt += b64.substring(i * 64, (i + 1) * 64) + "\n" 
-                                                                                                                                                                                                                  +     } 
-     return txt                                                                                                                                                                                                     +     return txt 
-                                                                                                                                                                                                                  +   } 
-                                                                                                                                                                                                                    + 
-   function writePEM (buffer, priv = false) {                                                                                                                                                                                                                                                                                                                                                                                       +   function writePEM (buffer, priv = false) { 
-     let txt = `-----BEGIN ${priv ? 'PRIVATE' : 'PUBLIC'} KEY-----` + "\n"                                                                                                                                          +     let txt = `-----BEGIN ${priv ? 'PRIVATE' : 'PUBLIC'} KEY-----` + "\n" 
-     txt += b64Encode(buffer)                                                                                                                                                                                       +     txt += b64Encode(buffer) 
-     return txt + `-----END ${priv ? 'PRIVATE' : 'PUBLIC'} KEY-----`                                                                                                                                                +     return txt + `-----END ${priv ? 'PRIVATE' : 'PUBLIC'} KEY-----` 
-               +   }
 </code> </code>
  
 ==== Génération de clés ==== ==== Génération de clés ====
 +
 +
  
 === OpenSSL === === OpenSSL ===
Ligne 70: Ligne 95:
 $ openssl rsa -in rsakey.pem -pubout > rsapub.pem # clé publique $ openssl rsa -in rsakey.pem -pubout > rsapub.pem # clé publique
 </code> </code>
 +
 +=== SSH ===
 +
 +OpenSSH génère des clé au format RFC4716.
 +<code shell>
 +$ ssh-keygen -t rsa -b 2048 -f ssh-rsa.key
 +</code>
 +
 +Avec l'option "-m PEM" on peut avoir directement une clé PKCS#1
  
 === JavaScript === === JavaScript ===
  
 <code javascript> <code javascript>
-   function genKeyPair() {                                                                                                                                                                                          +   function genKeyPair() { 
-     return new Promise((resolve, reject) => {                                                                                                                                                                      +     return new Promise((resolve, reject) => { 
-       /* same as openssl genrsa -F4 2048 */                                                                                                                                                                        +       /* same as openssl genrsa -F4 2048 */ 
-       crypto.subtle.generateKey(                                                                                                                                                                                   +       crypto.subtle.generateKey( 
-                                                                                                                                                                                                                  +         { 
-           name: 'RSA-PSS',                                                                                                                                                                                         +           name: 'RSA-PSS', 
-           hash: 'SHA-256',                                                                                                                                                                                         +           hash: 'SHA-256', 
-           modulusLength: 2048,                                                                                                                                                                                     +           modulusLength: 2048, 
-           publicExponent: new Uint8Array([1, 0, 1])                                                                                                                                                                +           publicExponent: new Uint8Array([1, 0, 1]) 
-         },                                                                                                                                                                                                         +         }, 
-         true,                                                                                                                                                                                                      +         true, 
-         ['sign', 'verify']).then((key) => {                                                                                                                                                                        +         ['sign', 'verify']).then((key) => { 
-           Promise.all([                                                                                                                                                                                            +           Promise.all([ 
-             crypto.subtle.exportKey('pkcs8', key.privateKey),                                                                                                                                                      +             crypto.subtle.exportKey('pkcs8', key.privateKey), 
-             crypto.subtle.exportKey('spki', key.publicKey)                                                                                                                                                         +             crypto.subtle.exportKey('spki', key.publicKey) 
-           ]).then((keys) => {                                                                                                                                                                                      +           ]).then((keys) => { 
-             resolve([writePEM(keys[0], true), writePEM(keys[1], false)])                                                                                                                                           +             resolve([writePEM(keys[0], true), writePEM(keys[1], false)]) 
-           })                                                                                                                                                                                                       +           }) 
-         })                                                                                                                                                                                                         +         }) 
-     })                                                                                                                                                                                                            +     })
    }    }
 </code> </code>
 +
 +==== Création de signature ====
 +=== OpenSSL ===
 +
 +<code shell>
 +echo -n "Texte à signer" | openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -sign fromjs.key  -out - - | base64
 +</code>
 +
 +=== JavaScript ===
 +<code javascript>
 +   function signFromPKCS8 (text, privkey) {
 +     return new Promise((resolve, reject) => {
 +       const key = readPEM(privkey)
 +       if (key) {
 +         crypto.subtle.importKey(
 +           'pkcs8',
 +           key,
 +           {
 +             name: 'RSA-PSS',
 +             hash: { name: 'SHA-256' }
 +           },
 +           false,
 +           [ 'sign' ]
 +         ).then((key) => {
 +           crypto.subtle.sign(
 +             {
 +               name: 'RSA-PSS', saltLength: 0
 +             },
 +             key,
 +             (new TextEncoder).encode(text)
 +           ).then((signed) => {
 +             resolve(b64Encode(signed))
 +           })
 +         })
 +       }
 +     })
 +   }
 +</code>
 +
 +=== PHP/phpseclib 2 ===
 +
 +Signature avec [[http://phpseclib.sourceforge.net/|phpseclib]]
 +
 +<code php>
 +<?PHP
 +require('phpseclib/autoload.php');
 +use phpseclib\Crypt\RSA;
 +
 +$rsa = new RSA();
 +$rsa->loadKey(file_get_contents('fromjs.key'));
 +$rsa->setHash('sha256');
 +$rsa->setMGFHash('sha256');
 +$rsa->setSaltLength(0);
 +$rsa->setSignatureMode(RSA::SIGNATURE_PSS);
 +$text = 'Texte à signer';
 +$signature = $rsa->sign($text);
 +echo base64_encode($signature);
 +?>
 +</code>
 +
 +=== C/OpenSSL EVP ===
 +
 +<code c>
 +/* Pour lire la clé :
 + 
 + * FILE * fp = fopen("pkey.pem", "r");
 + * sign(PEM_read_PrivateKey(fp, NULL, NULL, NULL), ...);
 + */
 +
 +void sign (EVP_PKEY * pkey, const char * text, unsigned char ** stext, size_t * slen) {
 +  size_t siglen = 0;
 +  EVP_PKEY_CTX * kctx = NULL;
 +  EVP_MD_CTX * mctx = NULL;
 +
 +  mctx = EVP_MD_CTX_new();
 +  if (!mctx) { return; }
 +  
 +  kctx = EVP_PKEY_CTX_new(pkey, NULL);
 +  if (kctx) {
 +    /* ordre important ici */
 +    EVP_MD_CTX_set_pkey_ctx(mctx, kctx);
 +    EVP_DigestSignInit(mctx, NULL, EVP_sha256(), NULL, NULL);
 +
 +    EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PSS_PADDING);
 +    EVP_PKEY_CTX_set_signature_md(kctx, EVP_sha256());
 +    EVP_PKEY_CTX_set_rsa_mgf1_md(kctx, EVP_sha256());
 +    EVP_PKEY_CTX_set_rsa_pss_saltlen(kctx, 0);
 +
 +    EVP_DigestSignUpdate(mctx, text, strlen(text));
 +    EVP_DigestSignFinal(mctx, NULL, &siglen);
 +    
 +    *stext = calloc(siglen, sizeof(**stext));
 +    if (*stext == NULL) {
 +      EVP_MD_CTX_free(mctx);
 +      return;
 +    }
 +    EVP_DigestSignFinal(mctx, *stext, &siglen);
 +    *slen = siglen;
 +  }
 +  EVP_MD_CTX_free(mctx);
 +  
 +  return;
 +}
 +</code>
 +
 +==== Vérification de signature ====
 +
 +=== OpenSSL ===
 +<code shell>
 +$ base64 -d < fromjs.sig - > fromjs.bin.sig
 +$ echo -n "Texte à signer" | openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify fromjs.pem -signature fromjs.bin.sig -
 +</code>
 +
 +=== JavaScript ===
 +<code javascript>
 +   function verifyFromPKCS8 (text, signature, pubkey) {
 +     return new Promise((resolve, reject) => {
 +       const cert = readPEM(pubkey)
 +       if (cert) {
 +         crypto.subtle.importKey(
 +           'spki',
 +           cert,
 +           {
 +             name: 'RSA-PSS',
 +             hash: { name: 'SHA-256' }
 +           },
 +           false,
 +           [ 'verify' ]
 +         ).then((key) => {
 +           crypto.subtle.verify(
 +             {
 +               name: 'RSA-PSS', saltLength: 0
 +             },
 +             key,
 +             b64Decode(signature),
 +             (new TextEncoder).encode(text)
 +           ).then((verified) => {
 +             resolve(verified)
 +           })
 +         })
 +       }
 +     })
 +   }
 +</code>
 +
 +=== PHP/phpseclib 2 ===
 +
 +L'ordre des opérations (setHash, setMGFHash, loadKey, ...) n'est pas déterminant.
 +
 +<code php>
 +<?PHP
 +$rsa = new RSA();
 +$rsa->loadKey(file_get_contents('fromjs.pem'));
 +$rsa->setHash('sha256');
 +$rsa->setMGFHash('sha256');
 +$rsa->setSaltLength(0);
 +$rsa->setSignatureMode(RSA::SIGNATURE_PSS);
 +$text = 'Texte à signer';
 +echo $rsa->verify($text, base64_decode(file_get_contents('fromjs.sig'))) ? 'Valide' : 'Invalide';
 +?>
 +</code>
 +
notes/webcrypto.1582730482.txt.gz · Dernière modification: 2020/02/26 16:21 de etienne