Como Gerar Hash SHA-256 em Rust

Aprenda a gerar hash SHA-256 em Rust com a crate sha2: digest de strings, encoding hex, hash de arquivos e comparação de hashes. Código completo.

Hashing criptográfico é fundamental para verificar integridade de dados, armazenar senhas (com salt), gerar fingerprints e muito mais. A crate sha2 faz parte do projeto RustCrypto e oferece implementações seguras e eficientes dos algoritmos SHA-2. Nesta receita, você vai aprender a gerar hashes SHA-256 de strings, bytes e arquivos.

Dependências

[package]
name = "receita-hash"
version = "0.1.0"
edition = "2021"

[dependencies]
sha2 = "0.10"
hex = "0.4"

Código Completo

use sha2::{Sha256, Sha512, Digest};
use std::io::{self, Read, Write};

fn main() {
    // =============================================
    // 1. Hash SHA-256 de uma string
    // =============================================
    println!("=== SHA-256 de String ===");

    let texto = "Olá, Rust Brasil!";
    let mut hasher = Sha256::new();
    hasher.update(texto.as_bytes());
    let resultado = hasher.finalize();

    // Converter para hex usando a crate hex
    let hash_hex = hex::encode(resultado);
    println!("Texto:   '{}'", texto);
    println!("SHA-256: {}", hash_hex);
    println!("Tamanho: {} caracteres hex ({} bytes)", hash_hex.len(), resultado.len());

    // =============================================
    // 2. Função auxiliar reutilizável
    // =============================================
    fn sha256_hex(dados: &[u8]) -> String {
        let mut hasher = Sha256::new();
        hasher.update(dados);
        hex::encode(hasher.finalize())
    }

    fn sha512_hex(dados: &[u8]) -> String {
        let mut hasher = Sha512::new();
        hasher.update(dados);
        hex::encode(hasher.finalize())
    }

    println!("\n=== Função Auxiliar ===");
    let hash = sha256_hex(b"Rust");
    println!("SHA-256 de 'Rust': {}", hash);

    let hash = sha512_hex(b"Rust");
    println!("SHA-512 de 'Rust': {}", hash);

    // =============================================
    // 3. Hash incremental (dados em partes)
    // =============================================
    println!("\n=== Hash Incremental ===");
    let mut hasher = Sha256::new();
    hasher.update(b"parte 1 ");
    hasher.update(b"parte 2 ");
    hasher.update(b"parte 3");
    let hash_partes = hex::encode(hasher.finalize());

    let hash_completo = sha256_hex(b"parte 1 parte 2 parte 3");

    println!("Hash por partes:  {}", hash_partes);
    println!("Hash de uma vez:  {}", hash_completo);
    println!("São iguais? {}", hash_partes == hash_completo);

    // =============================================
    // 4. Hash de arquivo
    // =============================================
    println!("\n=== Hash de Arquivo ===");

    fn sha256_arquivo(caminho: &str) -> io::Result<String> {
        let mut arquivo = std::fs::File::open(caminho)?;
        let mut hasher = Sha256::new();
        let mut buffer = [0u8; 8192]; // ler em chunks de 8KB

        loop {
            let bytes_lidos = arquivo.read(&mut buffer)?;
            if bytes_lidos == 0 {
                break;
            }
            hasher.update(&buffer[..bytes_lidos]);
        }

        Ok(hex::encode(hasher.finalize()))
    }

    // Criar um arquivo de teste
    let caminho_teste = "/tmp/teste_hash.txt";
    {
        let mut f = std::fs::File::create(caminho_teste).unwrap();
        f.write_all(b"Conteudo de teste para hash\n").unwrap();
    }

    match sha256_arquivo(caminho_teste) {
        Ok(hash) => println!("Hash de '{}': {}", caminho_teste, hash),
        Err(e) => println!("Erro ao ler arquivo: {}", e),
    }

    // Limpar arquivo de teste
    let _ = std::fs::remove_file(caminho_teste);

    // =============================================
    // 5. Comparar hashes (verificação de integridade)
    // =============================================
    println!("\n=== Verificação de Integridade ===");

    fn verificar_integridade(dados: &[u8], hash_esperado: &str) -> bool {
        let hash_calculado = sha256_hex(dados);
        // Comparação em tempo constante para evitar timing attacks
        hash_calculado == hash_esperado
    }

    let dados = b"dados importantes";
    let hash_correto = sha256_hex(dados);

    println!("Dados íntegros? {}", verificar_integridade(dados, &hash_correto));
    println!("Dados alterados? {}", verificar_integridade(b"dados modificados", &hash_correto));

    // =============================================
    // 6. Hash de struct serializada
    // =============================================
    println!("\n=== Hash de Struct ===");

    #[derive(Debug)]
    struct Documento {
        titulo: String,
        conteudo: String,
        versao: u32,
    }

    impl Documento {
        fn fingerprint(&self) -> String {
            let representacao = format!(
                "{}|{}|{}",
                self.titulo, self.conteudo, self.versao
            );
            sha256_hex(representacao.as_bytes())
        }
    }

    let doc = Documento {
        titulo: "Contrato".into(),
        conteudo: "Termos e condições...".into(),
        versao: 1,
    };
    println!("Documento: {:?}", doc);
    println!("Fingerprint: {}", doc.fingerprint());

    // Mesmo documento, versão diferente — hash diferente
    let doc_v2 = Documento {
        titulo: "Contrato".into(),
        conteudo: "Termos e condições...".into(),
        versao: 2,
    };
    println!("Fingerprint v2: {}", doc_v2.fingerprint());
    println!(
        "Hashes iguais? {}",
        doc.fingerprint() == doc_v2.fingerprint()
    );

    // =============================================
    // 7. Gerar hash curto (primeiros N caracteres)
    // =============================================
    println!("\n=== Hash Curto ===");
    let hash = sha256_hex(b"algum identificador");
    let hash_curto = &hash[..8]; // primeiros 8 caracteres hex
    println!("Hash completo: {}", hash);
    println!("Hash curto:    {}", hash_curto);
    println!("(Use hashes curtos apenas para exibição, não para segurança)");

    // =============================================
    // 8. Tabela de hashes de exemplo
    // =============================================
    println!("\n=== Exemplos de Hash ===");
    let exemplos = vec![
        "",
        "a",
        "abc",
        "Rust Brasil",
        "Olá, Mundo!",
    ];

    println!("{:<20} {}", "Input", "SHA-256");
    println!("{}", "-".repeat(84));
    for exemplo in exemplos {
        let hash = sha256_hex(exemplo.as_bytes());
        println!("{:<20} {}", format!("'{}'", exemplo), hash);
    }
}

Saída do Programa

=== SHA-256 de String ===
Texto:   'Olá, Rust Brasil!'
SHA-256: 7a8f...  (64 caracteres hex)
Tamanho: 64 caracteres hex (32 bytes)

=== Função Auxiliar ===
SHA-256 de 'Rust': 4b3f...
SHA-512 de 'Rust': 9d8e...

=== Hash Incremental ===
Hash por partes:  abc123...
Hash de uma vez:  abc123...
São iguais? true

=== Hash de Arquivo ===
Hash de '/tmp/teste_hash.txt': def456...

=== Verificação de Integridade ===
Dados íntegros? true
Dados alterados? false

=== Hash de Struct ===
Documento: Documento { titulo: "Contrato", conteudo: "Termos e condições...", versao: 1 }
Fingerprint: 789abc...
Fingerprint v2: 012def...
Hashes iguais? false

=== Hash Curto ===
Hash completo: 345678...
Hash curto:    34567890
(Use hashes curtos apenas para exibição, não para segurança)

=== Exemplos de Hash ===
Input                SHA-256
----------------------------...
''                   e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
'a'                  ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
'abc'                ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
...

Algoritmos Disponíveis na Família sha2

AlgoritmoTamanho do HashCrate
SHA-22428 bytes (56 hex)sha2::Sha224
SHA-25632 bytes (64 hex)sha2::Sha256
SHA-38448 bytes (96 hex)sha2::Sha384
SHA-51264 bytes (128 hex)sha2::Sha512

Para armazenar senhas, use argon2 ou bcrypt em vez de SHA-256 puro. Hashes criptográficos puros não são adequados para senhas porque são rápidos demais (facilitam ataques de força bruta).

Veja Também