Voir le flux RSS

danielhagnoul

Cryptographie asymétrique (à clé publique et privée)

Noter ce billet
par , 03/06/2016 à 12h43 (476 Affichages)
Découverte du sujet et premiers essais.

  • Niveau du billet : élevé.
  • Prérequis : ES2015.
  • Couverture du sujet : faible. Pour la théorie, on renvoie le lecteur à ES2015 et à "Web Cryptography API".
  • Navigateurs compatibles avec "crypto" : Firefox 40+ et Chrome 44+.
  • Exemples testés (2016-06-02) avec Chrome 51b (compatible à 98 % avec ES2015).


La cryptographie rend un message inintelligible à autre que qui de droit. Elle est utilisée depuis l'Antiquité, mais la cryptographie asymétrique date de la fin du vingtième siècle.

Elle utilise deux clés :
  • une publique, permettant le chiffrement ;
  • une privée, permettant le déchiffrement.


La clé publique est mise à la disposition de quiconque désire chiffrer un message. Ce dernier ne pourra être déchiffré qu'avec la clé privée, qui doit rester confidentielle.

Web Cryptography API fournit des interfaces JavaScript pour effectuer des opérations de cryptographie. "window.crypto" est l'objet principal, il expose toutes les propriétés et fonctions requises pour utiliser la cryptographie dans le navigateur. "window.crypto.subtle" est la propriété la plus importante de l'objet "window.crypto". La dénomination "SubtleCrypto" reflète le fait que beaucoup de ces algorithmes ont des exigences d'utilisation subtiles afin de fournir les garanties requises de sécurité algorithmiques.

Web Cryptography API utilise les opérations suivantes : encrypt, decrypt, sign, verify, deriveBits, wrapKey, unwrapKey, generateKey, importKey, exportKey, getLength. Mais les opérations réellement utilisables dépendent des algorithmes de cryptographie (voir le tableau).

Pour construire notre exemple de cryptographie asymétrique nous utiliserons l'algorithme RSA-OAEP et les opérations : generateKey, importKey, exportKey, encrypt et decrypt.

Nota bene : les codes utilisant "crypto" fonctionnent uniquement si l' URL de la page web est sur un hôte (host) "localhost" ou "https". Ne disposant pas d'un site "https", il m'est donc impossible de vous donner un lien vers mes exemples.

1. Génération d'une paire de clés (publique et privée)

Voir les explications dans la page web générée par le code ci-dessous.

La clé publique doit-être copier-coller dans la page web de l'étape 2 : Chiffrer un message avec la clé publique.
La clé privée doit être copier-coller dans la page web de l'étape 3 : Déchiffrer le message avec la clé privée.

Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<!DOCTYPE html>
<html lang="fr" dir="ltr">
<head>
  <meta http-equiv="cache-control" content="public, max-age=60">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="author" content="Daniel Hagnoul">
  <title>Crypto : générer les clés</title>
  <style>
    
    h1 { text-align: center; }
    
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
  <script src="dvjhUtilities.js"></script>
  <script>
    'use strict';
    
    document.addEventListener( 'DOMContentLoaded', function( ev ){
      console.log( `DOM ready   : ${ new kDvjhDate() }` );  
            
    });
    
    window.addEventListener( 'load', function( ev ){
      console.log( `Window load : ${ new kDvjhDate() }` );
 
      crypto
        .subtle
        .generateKey(
          {
            'name' : "RSA-OAEP",
            'modulusLength' : 2048,
            'publicExponent' : new Uint8Array( [ 0x01, 0x00, 0x01 ] ),
            'hash' : {
              'name' : 'SHA-256'
            }
          },
          true,
          [ 'encrypt', 'decrypt' ]
        )
        .then( key => {
          
          // export public key
          crypto
            .subtle
            .exportKey( 'jwk', key.publicKey )
            .then( r => {
              document.querySelector( '#publicKey' ).textContent = JSON.stringify( r );
            })
            .catch( er => console.log( er ) );
          
          // export private key
          crypto
            .subtle
            .exportKey( 'jwk', key.privateKey )
            .then( r => {
              document.querySelector( '#privateKey' ).textContent = JSON.stringify( r );
            })
            .catch( er => console.log( er ) );
            
        })
        .catch( er => console.log( er ) );
        
    });
    
  </script>
</head>
<body>
 
  <h1>Crypto : générer les clés</h1>
 
  <h2>Clé publique</h2>
  <h3>Cette clé peut être diffusée sans risque, elle servira à vos correspondants pour crypter leurs messages.</h3>
  <article id="publicKey"></article>
 
  <h2>Clé privée</h2>
  <h3>Cette clé doit être conservée au secret. Elle servira à décrypter les messages de vos correspondants.</h3>
  <article id="privateKey"></article>
 
</body>
</html>

2. Chiffrer un message avec la clé publique

Voir les explications dans la page web générée par le code ci-dessous.

Pour un usage personnel, il suffit de remplacer la clé publique de notre exemple par celle qui a été générée à l'étape 1 et d'envoyer ce code à votre correspondant par email.

Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<!DOCTYPE html>
<html lang="fr" dir="ltr">
<head>
  <meta http-equiv="cache-control" content="public, max-age=60">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="author" content="Daniel Hagnoul">
  <title>Crypto : crypter un message</title>
  <style>
    
    h1 { text-align: center; }
 
    [contenteditable] {
      margin: 12px;
      padding: 6px;
      min-height: 100px;
      max-height: 200px;
      overflow-y: scroll;
      border: 1px dotted red;
    }
 
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
  <script src="dvjhUtilities.js"></script>
  <script>
    'use strict';
    
    
    document.addEventListener( 'DOMContentLoaded', function( ev ){
      console.log( `DOM ready   : ${ new kDvjhDate() }` );
      
    }, false );
    
    window.addEventListener( 'load', function( ev ){
      console.log( `Window load : ${ new kDvjhDate() }` )
 
      let
        data = 'Un texte',
        ObjTextEncoder = new TextEncoder(),
        vector = crypto.getRandomValues( new Uint8Array( 16 ) ),
        encrypt_data = () => {
          
          // importer la clé publique
          crypto
            .subtle
            .importKey(
              'jwk',
              JSON.parse( document.querySelector( '#publicKey' ).textContent.trim() ),
              {
                'name' : 'RSA-OAEP',
                'modulusLength' : 2048,
                'publicExponent' : new Uint8Array( [ 0x01, 0x00, 0x01 ] ),
                'hash' : { 'name' : 'SHA-256' }
              },
              false,
              [ 'encrypt' ]
            )
            .then( r => {
              
              // crypter le message
              crypto
                .subtle
                .encrypt(
                  {
                    'name' : "RSA-OAEP",
                    'iv' : vector
                  },
                  r,
                  ObjTextEncoder.encode( document.querySelector( '#messageClair' ).textContent.trim() )
                )
                .then( result => {
                  let encrypted_data = new Uint8Array( result );
                    
                  document.querySelector( '#messageCrypter' ).textContent = '[ [' + vector + '], [' + encrypted_data + '] ]';
                })
                .catch( er => console.log( er ) );
                
            })
            .catch( er => console.log( er ) );
        };
        
        document.querySelector( '#crypterMessage' ).addEventListener( 'click', function( ev ){
          encrypt_data();
        }, false );
        
    }, false );
  </script>
</head>
<body>
 
  <h1>Crypto : crypter un message</h1>
 
  <h2>Clé publique</h2>
  <h3>Cette clé sert à crypter les messages destinés à la personne qui vous a donné cette clé.</h3>
  <article id="publicKey" contenteditable>{"alg":"RSA-OAEP-256","e":"AQAB","ext":true,"key_ops":["encrypt"],"kty":"RSA","n":"35rlXst4C2OxY8vXPbVApWXbmRDl4ehmZX1WcNxNeb0Jd_SFul8JCeFehSl7ChmvQcf9kgE_ABbvnLxP2Ft5S0q97hwvZ9S5OcnUdkTKmX0aN9aX9KaYuyJp5Q4fo3upcfbEW3y49AXp19HAXZlHzZ_8m8s1T9rU3wUXMqr0UTH139RAf9pIe10dcH5aPWI5g6Tx4iCsSevnAGiOhcukm3L0ECqMHqkbMKkwEc9jK0pIRcWh1ILH3BmauOzyzgizX7n8UZFYb6HOmHxk7hPfz0D-MOOpikzEHvJCLeVjQgC07aUxB4oXYEgyXLfUA8iTs1VcEAB5BDqmRXl0VE37DQ"}</article>
 
  <h2>Votre message</h2>
  <h3>Taper votre message ci-dessous puis cliquer sur le bouton "Crypter".</h3>
  <article id="messageClair" contenteditable>Un texte</article>
  <button id="crypterMessage">Crypter</button>
 
  <h2>Message crypté</h2>
  <h3>Voici le message à transmettre à votre correspondant.</h3>
  <article id="messageCrypter"></article>
 
</body>
</html>

3. Déchiffrer le message avec la clé privée

Voir les explications dans la page web générée par le code ci-dessous.

Pour un usage personnel, il suffit de remplacer la clé privée de notre exemple par celle qui a été générée à l'étape 1.

Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<!DOCTYPE html>
<html lang="fr" dir="ltr">
<head>
  <meta http-equiv="cache-control" content="public, max-age=60">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="author" content="Daniel Hagnoul">
  <title>Crypto : decrypter le message</title>
  <style>
    
    h1 { text-align: center; }
    
    [contenteditable] {
      margin: 12px;
      padding: 6px;
      min-height: 100px;
      max-height: 200px;
      overflow-y: scroll;
      border: 1px dotted red;
    }
 
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
  <script src="dvjhUtilities.js"></script>
  <script>
    'use strict';
    
    document.addEventListener( 'DOMContentLoaded', function( ev ){
      console.log( `DOM ready   : ${ new kDvjhDate() }` );
      
    }, false );
    
    window.addEventListener( 'load', function( ev ){
      console.log( `Window load : ${ new kDvjhDate() }` );
      
      let
        ObjTextDecoder = new TextDecoder(),
        decrypt_data = () => {
          
          // importer la clé privée
          crypto
            .subtle
            .importKey(
              'jwk',
              JSON.parse( document.querySelector( '#privateKey' ).textContent.trim() ),
              {
                'name' : 'RSA-OAEP',
                'modulusLength' : 2048,
                'publicExponent' : new Uint8Array( [ 0x01, 0x00, 0x01 ] ),
                'hash' : { 'name' : 'SHA-256' }
              },
              false,
              [ 'decrypt' ]
            )
            .then( r => {
              
              let
                data = JSON.parse( document.querySelector( '#messageCrypter' ).textContent.trim() ),
                vector = Uint8Array.from( data[ 0 ] ),
                encrypted_data = Uint8Array.from( data[ 1 ] );
                
              // décrypter le message
              crypto
                .subtle
                .decrypt(
                  {
                    'name' : 'RSA-OAEP',
                    'iv' : vector
                  },
                  r,
                  encrypted_data
                )
                .then( result => {
                  let decrypted_data = new Uint8Array( result );
                  
                  document.querySelector( '#messageClair' ).textContent = ObjTextDecoder.decode( decrypted_data );
                })
                .catch( er => console.log( er ) );
              
            })
            .catch( er => console.log( er ) );
            
        };
          
        document.querySelector( '#decrypterMessage' ).addEventListener( 'click', function( ev ){
          decrypt_data();
        }, false );
      
    }, false );
  </script>
</head>
<body>
 
  <h1>Crypto : decrypter le message</h1>
 
  <h2>Clé privée</h2>
  <h3>Votre clé secrete sert à décrypter les messages envoyés par vos correspondants.</h3>
  <article id="privateKey" contenteditable>{"alg":"RSA-OAEP-256","d":"ty11acrVdL8eutpqYaryYoym8SXerMpt2AZtoddXwLsT3qj6REtGZEmz3PK2UPfpksH7AHj022XutT-vSVbmbr-0CDQewbiKZMTqwFhqgILzz3qE0W8I_4SZq4N-d7b-gNXe1fO-sGmHv72dERBYuiKuFhLKgbiLWogZEPDrZPc4YTzMw5nJuJetgyTppYSh6YT24kYnKDFK5Der-4Ie5j6K14m67hsaos2P56cRNpn5GkikvLb6oi1_xJ_sSW4s-sI0cq1hwg0iBmXW-spLczgau1ADC1CCM7UzyE5pj-e8qEpNtF9ZSj7wcW3ktsqS-cSInCkjIPLPmXchWk4dIQ","dp":"MFG4a5BHb8lGRKrr2LX-qudyiKeo3qKNvqhbjSaxTGHQgYyQqN5zIXn5oyEejIkvukBwsolT3GHYSdGJhAeWG5CEwOK-Q3gv0onMfRVB4sQ4E8l7LbWMtG5spkK5dgo5X6C0gZaHIgj1DD2HDo2uVt7MWkyhjjVuo8DMspngapk","dq":"h_42njRSZOKx-k6rTNVdK9ktGxuW2eQeFtnGAKJQWCU2QXJcHdM8w6vRjNFoiPhFxK13g8_zkBL3TbzjhPZnduoXrk9TdaOc_gIAOPKS5pe9YFiJGtOXRfk8agW-3bQevlYM0r3dmn5Y_zZz7K8UxNu2cVbrPxXiszXIHHGbF68","e":"AQAB","ext":true,"key_ops":["decrypt"],"kty":"RSA","n":"35rlXst4C2OxY8vXPbVApWXbmRDl4ehmZX1WcNxNeb0Jd_SFul8JCeFehSl7ChmvQcf9kgE_ABbvnLxP2Ft5S0q97hwvZ9S5OcnUdkTKmX0aN9aX9KaYuyJp5Q4fo3upcfbEW3y49AXp19HAXZlHzZ_8m8s1T9rU3wUXMqr0UTH139RAf9pIe10dcH5aPWI5g6Tx4iCsSevnAGiOhcukm3L0ECqMHqkbMKkwEc9jK0pIRcWh1ILH3BmauOzyzgizX7n8UZFYb6HOmHxk7hPfz0D-MOOpikzEHvJCLeVjQgC07aUxB4oXYEgyXLfUA8iTs1VcEAB5BDqmRXl0VE37DQ","p":"-LgxfRQWMwFUAU-Ni2rgFqSAr4lR680Y4FqbA4DkzAaxfXzyrYtMznqiPneMdZRQLLiPOGuUV56dtgsqf0IS4iJEto9N5ekQYavaf5e-2rlckmiyDLje0shJH0YL6ym63qobOwOiO63I7nAukasqzGN5EKsQ3cxNZRX3OKwszrs","q":"5iaBPgV243SctQF1V_JeZVTUEtu9bTjYbZQNea-ATBYfQoO1gvyxIjAYLEjwOQQi9rhZA-CAnkb7VLRSfM9QnPmjR98rbqMu38QfJIruCH4NjXLsdgupdny7ytZxvYd2kPOqW1aVNMyqF0C7qMjsKSy657bxNjw1gEwf4NyVVNc","qi":"JuxRn6DED7MeBikP3ielo7LCJxai-bGRlsYnchRxE4LssexkVmY9hp-eihPTw0_6RpZz1t2qR_rMDL14FRBSLw3e8WbkFot8C0RcLCWvkCmltSComsw228aXaSZvSiLyfQSA5ADY1-bi5b4ZbFhn0queQe8ryeuAHhEQKDmlCWA"}
</article>
 
  <h2>Message crypté</h2>
  <h3>Le message transmis par votre correspondant.</h3>
  <article id="messageCrypter" contenteditable>[ [128,78,229,225,75,103,108,45,139,125,73,209,190,155,182,7], [153,54,171,92,81,94,227,71,105,142,144,205,165,110,101,74,37,230,111,184,170,207,199,32,127,10,229,1,161,131,116,97,116,171,115,26,249,218,131,91,7,16,35,147,170,122,18,60,206,61,20,208,39,185,44,203,74,38,218,7,6,68,99,213,246,107,96,217,161,72,139,245,135,163,103,203,226,152,234,88,239,4,147,7,250,195,242,171,186,165,234,35,206,141,201,6,163,103,66,54,70,61,142,31,251,22,229,156,155,137,209,162,73,189,184,140,31,28,116,230,236,67,209,232,246,82,245,128,167,63,188,206,197,133,144,239,82,209,200,203,82,197,126,180,222,151,214,183,197,78,157,151,28,103,149,59,255,32,105,136,228,232,44,241,22,126,231,21,178,153,189,106,211,235,163,184,84,210,205,5,84,47,126,85,37,216,203,15,75,31,177,61,242,181,178,176,85,83,62,66,126,158,172,72,70,85,73,65,168,165,212,246,245,163,61,105,169,243,152,46,223,132,47,26,240,45,144,189,98,76,191,254,15,27,192,188,19,103,239,212,159,39,17,115,251,31,104,173,187,237,155,4,206,127,142,113] ]</article>
 
  <button id="decrypterMessage">Décrypter</button>
 
  <h2>Le message</h2>
  <h3>Cliquer sur le bouton "Décrypter".</h3>
  <article id="messageClair"></article>
 
</body>
</html>

Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Viadeo Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Twitter Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Google Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Facebook Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Digg Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Delicious Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog MySpace Envoyer le billet « Cryptographie asymétrique (à clé publique et privée) » dans le blog Yahoo

Commentaires