2
votes

Comment puis-je hacher une chaîne avec SHA256 dans JS?

La description

Je cherche à hacher une chaîne localement avec SHA256 en Javascript. J'ai regardé autour de moi en pensant qu'il y aurait une sorte de bibliothèque ou de fonction officielle, mais tout ce que j'ai trouvé était des tas de projets différents, chacun avec des scripts différents, et je ne suis pas sûr de faire confiance aux scripts (car je ne suis pas un expert et certainement pas qualifié pour les évaluer) ou comment les mettre en œuvre. EDIT: J'ai besoin de la sortie sous forme de texte, pas d'hexagones, désolé si je ne l'ai pas expliqué lors de la publication de la question originale.

Code

Voici ce que j'ai essayé jusqu'à présent:

async function sha256(message) {
  // encode as UTF-8
  const msgBuffer = new TextEncoder('utf-8').encode(message);

  // hash the message
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);

  // convert ArrayBuffer to Array
  const hashArray = Array.from(new Uint8Array(hashBuffer));

  // convert bytes to hex string
  const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
  console.log(hashHex);
  return hashHex;
}
sha256(passwordInput); 

Sortie de la console:

Uncaught (in promise) TypeError: Impossible de lire la propriété 'digest' de undefined

Je suis nouveau sur javascript et je suis ouvert à toutes les suggestions, alors oui.


2 commentaires

Quel navigateur (y compris la version) utilisez-vous?


@Amy J'utilise la version 79.0.3945.130 de Google Chrome (64 bits), j'espère que cela vous aidera


4 Réponses :


3
votes

Vérifiez ceci: https://github.com/brix/crypto-js

Vous pouvez utiliser les éléments suivants:

<script type="text/javascript" src="path-to/bower_components/crypto-js/crypto-js.js"></script>
<script type="text/javascript">
    var encrypted = CryptoJS.AES(...);
    var encrypted = CryptoJS.SHA256(...);
</script>

ou sans exiger:

require(["crypto-js/aes", "crypto-js/sha256"], function (AES, SHA256)
{
    console.log(SHA256("Message")); 
});


2 commentaires

Merci pour la réponse (cela fonctionne), mais j'ai besoin que la sortie soit au format texte, pas au format hexadécimal, désolé si je ne l'ai pas précisé dans la description du problème.


Je pense que c'est un format de texte (il ressemble juste à hexadécimal).



9
votes

Hellow là: D c'est tout à fait une fonction. Si vous êtes un universitaire, vous souhaitez consulter cet article: https://www.movable-type.co.uk/scripts/sha256.html

JavaScript pur, aucune dépendance nécessaire:

var sha256 = function sha256(ascii) {
    function rightRotate(value, amount) {
        return (value>>>amount) | (value<<(32 - amount));
    };
    
    var mathPow = Math.pow;
    var maxWord = mathPow(2, 32);
    var lengthProperty = 'length'
    var i, j; // Used as a counter across the whole file
    var result = ''

    var words = [];
    var asciiBitLength = ascii[lengthProperty]*8;
    
    //* caching results is optional - remove/add slash from front of this line to toggle
    // Initial hash value: first 32 bits of the fractional parts of the square roots of the first 8 primes
    // (we actually calculate the first 64, but extra values are just ignored)
    var hash = sha256.h = sha256.h || [];
    // Round constants: first 32 bits of the fractional parts of the cube roots of the first 64 primes
    var k = sha256.k = sha256.k || [];
    var primeCounter = k[lengthProperty];
    /*/
    var hash = [], k = [];
    var primeCounter = 0;
    //*/

    var isComposite = {};
    for (var candidate = 2; primeCounter < 64; candidate++) {
        if (!isComposite[candidate]) {
            for (i = 0; i < 313; i += candidate) {
                isComposite[i] = candidate;
            }
            hash[primeCounter] = (mathPow(candidate, .5)*maxWord)|0;
            k[primeCounter++] = (mathPow(candidate, 1/3)*maxWord)|0;
        }
    }
    
    ascii += '\x80' // Append Ƈ' bit (plus zero padding)
    while (ascii[lengthProperty]%64 - 56) ascii += '\x00' // More zero padding
    for (i = 0; i < ascii[lengthProperty]; i++) {
        j = ascii.charCodeAt(i);
        if (j>>8) return; // ASCII check: only accept characters in range 0-255
        words[i>>2] |= j << ((3 - i)%4)*8;
    }
    words[words[lengthProperty]] = ((asciiBitLength/maxWord)|0);
    words[words[lengthProperty]] = (asciiBitLength)
    
    // process each chunk
    for (j = 0; j < words[lengthProperty];) {
        var w = words.slice(j, j += 16); // The message is expanded into 64 words as part of the iteration
        var oldHash = hash;
        // This is now the undefinedworking hash", often labelled as variables a...g
        // (we have to truncate as well, otherwise extra entries at the end accumulate
        hash = hash.slice(0, 8);
        
        for (i = 0; i < 64; i++) {
            var i2 = i + j;
            // Expand the message into 64 words
            // Used below if 
            var w15 = w[i - 15], w2 = w[i - 2];

            // Iterate
            var a = hash[0], e = hash[4];
            var temp1 = hash[7]
                + (rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25)) // S1
                + ((e&hash[5])^((~e)&hash[6])) // ch
                + k[i]
                // Expand the message schedule if needed
                + (w[i] = (i < 16) ? w[i] : (
                        w[i - 16]
                        + (rightRotate(w15, 7) ^ rightRotate(w15, 18) ^ (w15>>>3)) // s0
                        + w[i - 7]
                        + (rightRotate(w2, 17) ^ rightRotate(w2, 19) ^ (w2>>>10)) // s1
                    )|0
                );
            // This is only used once, so *could* be moved below, but it only saves 4 bytes and makes things unreadble
            var temp2 = (rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22)) // S0
                + ((a&hash[1])^(a&hash[2])^(hash[1]&hash[2])); // maj
            
            hash = [(temp1 + temp2)|0].concat(hash); // We don't bother trimming off the extra ones, they're harmless as long as we're truncating when we do the slice()
            hash[4] = (hash[4] + temp1)|0;
        }
        
        for (i = 0; i < 8; i++) {
            hash[i] = (hash[i] + oldHash[i])|0;
        }
    }
    
    for (i = 0; i < 8; i++) {
        for (j = 3; j + 1; j--) {
            var b = (hash[i]>>(j*8))&255;
            result += ((b < 16) ? 0 : '') + b.toString(16);
        }
    }
    return result;
};

Source: https://geraintluff.github.io/sha256/


3 commentaires

Je ne peux pas comprendre pourquoi les gens vous votent contre vous? Votre fonction fonctionne et sans dépendances


Je n'ai pas voté contre, mais je pense qu'il a été rejeté parce que dans le monde de la cryptographie, il est fortement conseillé de ne pas «lancer votre propre» crypto car il n'est pas vérifié et pourrait avoir des problèmes de sécurité. Il est généralement préférable d'utiliser une bibliothèque bien connue car elle vous offre la meilleure sécurité et, généralement, des mises à jour constantes.


Je pense que c'est génial à des fins éducatives , merci beaucoup.



1
votes

Cannot read property 'digest' of undefined lors de l'appel de crypto.subtle.digest implique que subtle n'est pas disponible dans crypto ; par conséquent, digest ne peut pas exister, car son module contenant n'existe pas.
Logiquement donc, crypto.subtle ne doit pas être disponible dans cette étendue, et en fait, cela est vrai dans le navigateur n'importe où en dehors d'un contexte sécurisé .

Quand un contexte est-il considéré comme sécurisé? - developer.mozilla.org

Un contexte sera considéré comme sécurisé lorsqu'il est fourni de manière sécurisée (ou localement) et lorsqu'il ne peut pas être utilisé pour fournir un accès à des API sécurisées à un contexte qui n'est pas sécurisé. En pratique, cela signifie que pour qu'une page ait un contexte sécurisé, elle et toutes les pages le long de sa chaîne parent et ouvrante doivent avoir été livrées en toute sécurité.

Par exemple, une page livrée en toute sécurité via TLS n'est pas considérée comme un contexte sécurisé si elle contient un document parent ou ancêtre qui n'a pas été livré de manière sécurisée; sinon, la page serait alors en mesure d'exposer des API sensibles à l'ancêtre livré de manière non sécurisée via des messages postMessage . De même, si un document livré par TLS est ouvert dans une nouvelle fenêtre par un contexte non sécurisé sans qu'aucune ouverture ne soit spécifiée, alors la fenêtre ouverte n'est pas considérée comme un contexte sécurisé (puisque l'ouvreur et la fenêtre ouverte pourraient communiquer via postMessage).

Les fichiers livrés localement tels que les chemins http: // localhost * et file: // sont considérés comme ayant été livrés en toute sécurité.

¦ ¦ ¦ ¦ ¦ Les contextes qui ne sont pas locaux doivent être servis via https: // ou wss: // et où les protocoles utilisés ne doivent pas être considérés comme obsolètes.

Dans un contexte sécurisé, votre code fonctionne parfaitement 😄


1: Contextes sécurisés - Sécurité Web | MDN
2: Quand un contexte est-il considéré comme sécurisé? - Contexte sécurisé - Sécurité Web | MDN
3: Window.postMessage () - API Web | MDN
4: Fonctionnalités de la fenêtre - Window.open () - API Web | MDN


0 commentaires

0
votes

Le code est bien. La dernière ligne devrait ressembler à ceci:

var vDigest = await sha256(passwordInput);


0 commentaires