Bibliotecas de Criptografia em Zig — Segurança e Performance
A criptografia é uma das áreas onde o Zig demonstra vantagens únicas. O controle de memória, a ausência de comportamento indefinido e o modelo de execução determinístico tornam Zig uma escolha excelente para implementações criptográficas seguras. A biblioteca padrão do Zig inclui um módulo de criptografia abrangente e auditado, complementado por bibliotecas de terceiros para casos especializados.
std.crypto — A Biblioteca Padrão
O módulo std.crypto é impressionantemente completo para uma biblioteca padrão. Implementado inteiramente em Zig, sem dependências externas, ele oferece:
Funções de Hash
const std = @import("std");
const crypto = std.crypto;
pub fn main() !void {
const dados = "Mensagem secreta";
// SHA-256
var sha256_hash: [32]u8 = undefined;
crypto.hash.sha2.Sha256.hash(dados, &sha256_hash, .{});
std.debug.print("SHA-256: {s}\n", .{std.fmt.fmtSliceHexLower(&sha256_hash)});
// SHA-512
var sha512_hash: [64]u8 = undefined;
crypto.hash.sha2.Sha512.hash(dados, &sha512_hash, .{});
// BLAKE2b
var blake2_hash: [32]u8 = undefined;
crypto.hash.Blake2b256.hash(dados, &blake2_hash, .{});
// BLAKE3
var blake3_hash: [32]u8 = undefined;
crypto.hash.Blake3.hash(dados, &blake3_hash, .{});
// SHA-3 (Keccak)
var sha3_hash: [32]u8 = undefined;
crypto.hash.sha3.Sha3_256.hash(dados, &sha3_hash, .{});
}
Hash Incremental
Para dados grandes ou streaming:
var hasher = crypto.hash.sha2.Sha256.init(.{});
hasher.update("parte 1 ");
hasher.update("parte 2 ");
hasher.update("parte 3");
var resultado: [32]u8 = undefined;
hasher.final(&resultado);
HMAC
const Hmac = crypto.auth.hmac.sha2.HmacSha256;
const chave = "minha-chave-secreta";
const mensagem = "dados para autenticar";
var mac: [Hmac.mac_length]u8 = undefined;
Hmac.create(&mac, mensagem, chave);
// Verificar HMAC
const valido = Hmac.verify(mensagem, mac, chave);
Cifras Simétricas
// AES-256-GCM (Authenticated Encryption)
const aes = crypto.aead.aes_gcm;
const chave: [32]u8 = ...; // 256 bits
const nonce: [12]u8 = ...; // 96 bits
const texto_plano = "Dados confidenciais";
const dados_adicionais = "metadados"; // AAD
var cifrado: [texto_plano.len]u8 = undefined;
var tag: [16]u8 = undefined;
// Cifrar
aes.Aes256Gcm.encrypt(
&cifrado,
&tag,
texto_plano,
dados_adicionais,
nonce,
chave,
);
// Decifrar
var decifrado: [texto_plano.len]u8 = undefined;
try aes.Aes256Gcm.decrypt(
&decifrado,
cifrado,
tag,
dados_adicionais,
nonce,
chave,
);
// ChaCha20-Poly1305
const chacha = crypto.aead.chacha_poly;
chacha.ChaCha20Poly1305.encrypt(
&cifrado,
&tag,
texto_plano,
dados_adicionais,
nonce,
chave,
);
Criptografia de Chave Pública
// Ed25519 (Assinaturas Digitais)
const Ed25519 = crypto.sign.Ed25519;
// Gerar par de chaves
const par_chaves = try Ed25519.KeyPair.create(null);
// Assinar mensagem
const assinatura = try par_chaves.sign("mensagem importante", null);
// Verificar assinatura
try Ed25519.verify(
assinatura,
"mensagem importante",
par_chaves.public_key,
);
// X25519 (Diffie-Hellman)
const X25519 = crypto.dh.X25519;
const chave_privada_a = try X25519.KeyPair.create(null);
const chave_privada_b = try X25519.KeyPair.create(null);
// Derivar segredo compartilhado
const segredo_a = try X25519.scalarmult(
chave_privada_a.secret_key,
chave_privada_b.public_key,
);
const segredo_b = try X25519.scalarmult(
chave_privada_b.secret_key,
chave_privada_a.public_key,
);
// segredo_a == segredo_b (mesmo segredo compartilhado)
Derivação de Chaves
// Argon2 para hash de senhas
const argon2 = crypto.pwhash.argon2;
const senha = "senha_do_usuario";
const salt: [16]u8 = ...; // Gerado aleatoriamente
var hash_senha: [32]u8 = undefined;
try argon2.kdf(
&hash_senha,
senha,
salt,
.{
.t = 3, // iterações
.m = 65536, // memória em KB
.p = 4, // paralelismo
},
);
// HKDF (HMAC-based Key Derivation Function)
const hkdf = crypto.kdf.hkdf;
const HkdfSha256 = hkdf.HkdfSha256;
const material_chave = "material-de-entrada";
const salt_hkdf: [32]u8 = ...; // Salt opcional
const info = "contexto-de-uso";
var chave_derivada: [32]u8 = undefined;
const prk = HkdfSha256.extract(&salt_hkdf, material_chave);
HkdfSha256.expand(&chave_derivada, prk, info);
Geração de Números Aleatórios
// CSPRNG (Cryptographically Secure PRNG)
var bytes_aleatorios: [32]u8 = undefined;
std.crypto.random.bytes(&bytes_aleatorios);
// Número aleatório em range
const numero = std.crypto.random.intRangeAtMost(u32, 1, 100);
TLS na Biblioteca Padrão
O Zig inclui uma implementação TLS 1.3 na biblioteca padrão:
const std = @import("std");
const tls = std.crypto.tls;
pub fn main() !void {
const allocator = std.heap.page_allocator;
// Conectar via TLS
const stream = try std.net.tcpConnectToHost(allocator, "example.com", 443);
defer stream.close();
var tls_stream = try tls.client(stream, .{
.host = "example.com",
});
defer tls_stream.close();
// Enviar requisição HTTPS
try tls_stream.writeAll("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
// Ler resposta
var buf: [4096]u8 = undefined;
const n = try tls_stream.read(&buf);
std.debug.print("{s}\n", .{buf[0..n]});
}
Bibliotecas de Terceiros
zig-bearssl
Bindings para BearSSL, uma implementação TLS minimalista e segura:
const bearssl = @import("zig-bearssl");
var ssl_ctx = try bearssl.SslClient.init(allocator);
defer ssl_ctx.deinit();
try ssl_ctx.connect(stream, "example.com");
try ssl_ctx.writeAll("GET / HTTP/1.1\r\n\r\n");
zig-openssl
Para projetos que necessitam compatibilidade com OpenSSL:
const openssl = @import("zig-openssl");
const ctx = try openssl.SslContext.init(.tls_client);
defer ctx.deinit();
const ssl = try ctx.newSsl();
try ssl.connect(fd);
Segurança de Implementação
As implementações criptográficas em Zig seguem boas práticas de segurança:
Tempo Constante
Operações de comparação em tempo constante evitam side-channel attacks:
// Comparação segura em tempo constante
const iguais = std.crypto.utils.timingSafeEql(u8, hash_esperado, hash_calculado);
// Zerar memória sensível
std.crypto.utils.secureZero(u8, &chave_privada);
Proteção de Memória
// Usar alocador que zera memória ao liberar
const secure_allocator = std.heap.SecureAllocator.init(std.heap.page_allocator);
var chave = try secure_allocator.alloc(u8, 32);
defer {
std.crypto.utils.secureZero(u8, chave);
secure_allocator.free(chave);
}
Boas Práticas
- Use algoritmos modernos: Prefira ChaCha20-Poly1305, Ed25519, BLAKE3 e Argon2
- Nunca reutilize nonces: Cada operação de cifra deve usar um nonce único
- Zere memória sensível: Use
secureZeropara limpar chaves e senhas da memória - Use comparação em tempo constante: Para verificação de MACs e hashes
- Gere chaves com CSPRNG: Sempre use
std.crypto.randompara material criptográfico
Próximos Passos
Explore as bibliotecas de rede para comunicação segura, os frameworks web para APIs HTTPS, e as bibliotecas de serialização para formatos seguros de dados. Veja como fintechs usam criptografia Zig em produção. Para aprender mais, visite nossos tutoriais.