Skip to content

Hacher une chaîne avec SHA-256 snippet

SHA-256 transforme n'importe quelle entrée en une empreinte fixe de 32 octets — à sens unique, déterministe, et PAS du chiffrement.

SHA-256 transforme n'importe quelle entrée en une empreinte fixe de 32 octets — à sens unique, déterministe, et PAS du chiffrement. Deux pièges reviennent : tu haches les octets UTF-8, pas la chaîne ; et la sortie hex exige des paires d'octets complétées par des zéros (b.toString(16) laisse tomber silencieusement les zéros de tête et corrompt le digest). Et la règle permanente : SHA-256 sert aux checksums et aux clés, jamais aux mots de passe — ceux-ci exigent des hachages lents comme bcrypt ou argon2. SQL a besoin de l'extension pgcrypto, donc il est omis ; C et C++ n'ont pas de crypto en stdlib.

Recette exécutable · 12 langagesOpen the hash tool →
Crypto & Encodingsha256hashchecksumdigesthex

Every language

12 langages, copy-ready. One at a time with syntax highlighting, or all inline.

JSJavaScript
// crypto.subtle is async — the Web Crypto API, secure contexts only
const digest = await crypto.subtle.digest('SHA-256',
  new TextEncoder().encode('hello world'));

const hex = [...new Uint8Array(digest)]
  .map((b) => b.toString(16).padStart(2, '0'))
  .join('');
console.log(hex);

Node has the sync one-liner: crypto.createHash('sha256').update(s).digest('hex').

TSTypeScript
async function sha256Hex(input: string): Promise<string> {
  const digest = await crypto.subtle.digest(
    'SHA-256',
    new TextEncoder().encode(input),
  );
  return [...new Uint8Array(digest)]
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
}

padStart(2, '0') is load-bearing — toString(16) drops the leading zero on bytes under 0x10 and silently breaks the hex string.

GoGo
sum := sha256.Sum256([]byte("hello world"))

fmt.Println(hex.EncodeToString(sum[:])) // or just fmt.Printf("%x\n", sum)

Sum256 returns a [32]byte array — sum[:] slices it into the []byte hex.EncodeToString wants.

RsRust
use sha2::{Digest, Sha256};

let hex = format!("{:x}", Sha256::digest(b"hello world"));
println!("{hex}");

sha2 is the RustCrypto canonical crate. {:x} on the generic-array output renders lowercase hex directly — no manual byte loop.

PHPPHP
$hex = hash('sha256', 'hello world');      // 64-char hex string
$raw = hash('sha256', 'hello world', true); // 32 raw bytes

echo $hex, PHP_EOL;

hash() is encoding-agnostic because PHP strings are byte strings. The third parameter true switches hex → raw output.

PyPython
import hashlib

hexdigest = hashlib.sha256(b'hello world').hexdigest()
raw = hashlib.sha256(b'hello world').digest()  # bytes, len 32

print(hexdigest)

The b'' literal is UTF-8 already; for runtime strings hash(s.encode()). hexdigest() and digest() are the same bytes, two renderings.

C#C#
using System.Security.Cryptography;

byte[] hash = SHA256.HashData("hello world"u8);
string hex = Convert.ToHexString(hash).ToLowerInvariant();

Console.WriteLine(hex);

SHA256.HashData (.NET 5+) replaced the Create()/TransformFinalBlock dance. Convert.ToHexString returns UPPERCASE — lower it if your consumer expects the common lowercase.

JvJava
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HexFormat;

byte[] hash = MessageDigest.getInstance("SHA-256")
        .digest("hello world".getBytes(StandardCharsets.UTF_8));

String hex = HexFormat.of().formatHex(hash);

Java 17+ HexFormat killed the hand-rolled %02x StringBuilder loop that haunted every older example.

SwSwift
import CryptoKit

let hex = SHA256.hash(data: Data("hello world".utf8))
    .map { String(format: "%02x", $0) }
    .joined()
print(hex)

CryptoKit is Apple-platform; swift-crypto is the same API as a cross-platform Swift package. %02x — the zero-padding is what keeps the hex length at 64.

KtKotlin
import java.security.MessageDigest
import java.util.HexFormat

val hex = HexFormat.of().formatHex(
    MessageDigest.getInstance("SHA-256")
        .digest("hello world".toByteArray()),
)

Same JVM MessageDigest; toByteArray() is UTF-8 by default in Kotlin.

RbRuby
require 'digest'

hex = Digest::SHA256.hexdigest('hello world')
puts hex

Digest::SHA256.digest gives the 32 raw bytes; .hexdigest is the convention everyone else matches.

ZigZig
const std = @import("std");

pub fn main() !void {
    var out: [std.crypto.hash.sha2.Sha256.digest_length]u8 = undefined;
    std.crypto.hash.sha2.Sha256.hash("hello world", &out, .{});

    std.debug.print("{s}\n", .{std.fmt.fmtSliceHexLower(&out)});
}

The .{} options arg enables streaming mode for large inputs; init/update/final is the incremental API. fmtSliceHexLower formats without allocating.

Keep going

Try the interactive hash tool →