İçeriğe atla
HexaTransfer
Bloga dön
Sifreleme ve guvenlik

AES-GCM uygulama rehberi: doğru kimlik doğrulamalı şifreleme

AES-GCM şifrelemeyi doğru uygulayın. Nonce yönetimi, anahtar işleme ve kimlik doğrulamalı şifrelemede kaçınılması gereken hatalar.

AES-GCM (Galois/Counter Mode), kimlik doğrulamalı ilişkili veri şifrelemesi (AEAD) üretmek için AES-CTR şifrelemeyi GHASH kimlik doğrulamasıyla birleştirir. Doğru bir implementasyon; 256 bit anahtar, anahtar başına benzersiz olan 96 bit (12 bayt) nonce (asla yeniden kullanılmamalı), 128 bit kimlik doğrulama etiketi ve isteğe bağlı olarak doğrulanan ama şifrelenmeyen kimlik doğrulamalı ilişkili veri (AAD) kullanır. NIST SP 800-38D tam yapıyı belirtmektedir. Özellikle nonce yeniden kullanımı olmak üzere bunlardan herhangi biri yanlış giderse GCM'nin güvenliği çöker: tek bir tekrarlanan (anahtar, nonce) çifti, saldırganların kimlik doğrulama anahtarını kurtarmasına ve keyfi şifreli metin sahtecilik yapmasına olanak tanır. Bu rehber, tarayıcı, Node ve sunucu bağlamlarında AES-GCM'yi doğru kullanma yolunu ele alır.

GCM'nin Gerçekte Hangi Garantileri Verdiği

İki özellik:

Gizlilik: düz metin anahtar olmadan kurtarılamaz. AES-GCM'nin CTR modu şifreleme katmanı bunu sağlar.

Bütünlük ve özgünlük: şifreli metinde, nonce'da veya ilişkili veride yapılan herhangi bir değişiklik şifre çözmenin başarısız olmasına neden olur. GHASH, şifre çözme sırasında sabit zamanlı olarak doğrulanan 128 bit etiket üretir.

GCM'nin garanti etmediği: inkâr edilemezlik (simetrik olduğundan, anahtara sahip olan herkes geçerli şifreli metin üretebilir), tekrar koruma (bu daha üst katman bir kaygıdır) veya sıralama (akışlar için bir şekilde zincir kurmanız gerekir).

Temel kavrayış: GCM yalnızca nonce'lar anahtar başına benzersiz olduğunda güvende kalır. Çoğunlukla benzersiz veya genellikle benzersiz değil; gerçekten benzersiz. Güvenlik kanıtı yeniden kullanımda bozulur.

Nonce Yönetimi: En Önemli Konu

96 bit nonce iki yolla üretilebilir:

Rastgele: crypto.getRandomValues(new Uint8Array(12)). Tek bir anahtar altında rastgele 96 bit nonce'larla doğum günü sınırı çakışmaları yaklaşık 2^48 şifrelemede belirir. NIST bir güvenlik marjı önerir; bu nedenle anahtar başına 2^32 kullanımla sınırlayın.

Sayaç: 96 bit tamsayıyı artırın. 2^96 mesaja kadar benzersizliği garanti eder. Güvenilir monoton duruma ihtiyaç duyar; dağıtık sistemlerde zordur.

Her dosyanın taze bir anahtar aldığı dosya aktarımı için rastgele nonce'lar mükemmel güvenlidir — tek bir anahtarla hiçbir zaman 2^32 şifrelemeye ulaşamazsınız. Tek bir dosya anahtarı altında parçalı şifreleme için parça indeksini kodlayan nonce kullanan bir sayaç kullanın:

const nonce = new Uint8Array(12);
new DataView(nonce.buffer).setUint32(0, messageId);
new DataView(nonce.buffer).setBigUint64(4, BigInt(chunkIndex));

Felaket durumu: aynı paylaşılan anahtar altında rastgele nonce'larla saniyede milyonlarca şifreleme ölçeğine çıkan birden fazla süreç. Doğum günü çakışmaları olasılaşır. Anahtarları süreçler arasında paylaşmanız gerekiyorsa, işlem kimliği önekiyle koordineli bir sayaç kullanın.

64 Bit Nonce Kullanmayın

AES-GCM değişken nonce uzunluklarını destekler; ancak yalnızca 96 bit nonce'lar NIST 800-38D'de belirtilen optimize yapıyı kullanır. Diğer uzunluklar (genellikle 64 veya 128 bit) performansı azaltan ve karmaşıklığı artıran bir GHASH ön işleme adımını tetikler. Web Crypto API, 96 bit olmayan IV'leri kabul eder; ancak spesifikasyon 96 bit önermektedir. Sadece 96 kullanın.

Etiket Uzunluğu: Kısaltmayın

GCM'nin etiketi 128 bite kadardır. Bazı spesifikasyonlar 96, 64 hatta 32 bite kısaltmaya izin verir. Yapmayın. Kısaltılmış etiketler sahtekârlık saldırılarını kolaylaştırır; tasarruf (mesaj başına 4-12 bayt) dosya aktarımı için önemsizdir. Web Crypto'nun AES-GCM'si, tagLength parametresi aracılığıyla varsayılan olarak 128 bit etikete ayarlıdır. Olduğu gibi bırakın.

İlişkili Veri (AAD)

AAD, doğrulanan ama şifrelenmeyen veridir. Şifreli metne bağlamak istediğiniz meta veriler için kullanın: dosya adı, içerik türü, süre sonu zaman damgası, yükleyici kimliği.

await crypto.subtle.encrypt(
  {
    name: "AES-GCM",
    iv: nonce,
    additionalData: new TextEncoder().encode(JSON.stringify({
      filename: "rapor.pdf",
      contentType: "application/pdf",
      expires: 1712345678,
    })),
  },
  key,
  plaintext
);

Bir saldırgan AAD'yi değiştirirse şifre çözme başarısız olur. Bu, depolanan şifreli metin üzerindeki dosya adını algılanmadan değiştiren takas saldırılarını önler. Alıcı şifre çözmek için tam AAD'yi bilmek zorundadır; dolayısıyla şifreli metinle birlikte depolayın.

Anahtar Üretme ve Türetme

Dosya başına anahtarlar için:

const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  true,
  ["encrypt", "decrypt"]
);

256 bit, 2026'da varsayılandır. 128 bit AES hâlâ güvenlidir; ancak Grover algoritması efektif gücü yarıya indirdiğinden kuantum marjı daha azdır.

Parola türetilen anahtarlar için:

const aesKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterations: 600000,
    hash: "SHA-256",
  },
  passwordKey,
  { name: "AES-GCM", length: 256 },
  false,
  ["encrypt", "decrypt"]
);

Salt'ı şifreli metinle birlikte depolayın. Gizli değildir; yalnızca parola başına benzersiz olması gerekir.

Kritik Kod Yolu

Minimal bir şifreleme fonksiyonu:

async function encrypt(key, plaintext, aad = new Uint8Array()) {
  const nonce = crypto.getRandomValues(new Uint8Array(12));
  const ciphertext = new Uint8Array(
    await crypto.subtle.encrypt(
      { name: "AES-GCM", iv: nonce, additionalData: aad },
      key,
      plaintext
    )
  );
  return { nonce, ciphertext, aad };
}

Uygun hata işlemeyle şifre çözme:

async function decrypt(key, { nonce, ciphertext, aad }) {
  try {
    return await crypto.subtle.decrypt(
      { name: "AES-GCM", iv: nonce, additionalData: aad },
      key,
      ciphertext
    );
  } catch (e) {
    // Kimlik doğrulama hatası
    throw new Error("Şifre çözme başarısız: şifreli metin kurcalanmış veya yanlış anahtar");
  }
}

decrypt çağrısı, etiket uyuşmazlığında, kısa şifreli metinde veya yanlış anahtarda OperationError fırlatır. Herhangi bir istisnayı bütünlük hatası olarak değerlendirin; ayrım yapmaya çalışmayın.

Parçalı Büyük Dosyalar

Birkaç yüz megabaytın üzerindeki dosyalar için bellek baskısını önlemek amacıyla parçalara bölün:

async function encryptChunks(key, file, chunkSize = 1024 * 1024) {
  const chunks = [];
  let chunkIndex = 0;
  for (let offset = 0; offset < file.size; offset += chunkSize) {
    const chunk = await file.slice(offset, offset + chunkSize).arrayBuffer();
    const nonce = new Uint8Array(12);
    new DataView(nonce.buffer).setBigUint64(4, BigInt(chunkIndex++));
    const ct = await crypto.subtle.encrypt(
      { name: "AES-GCM", iv: nonce }, key, chunk
    );
    chunks.push(new Uint8Array(ct));
  }
  return chunks;
}

Uyarı: parçalı AES-GCM kesmeyi algılamaz. Bir saldırgan sondaki parçaları düşürebilir ve her sağ kalan parçanın şifresi başarıyla çözülür. Savunma olarak, her parçanın AAD'sine toplam parça sayısını dahil edin ya da bunu ele alan libsodium'un crypto_secretstream'ini kullanın.

Sunucu Taraflı Şifre Çözme (Node.js)

Node'un kripto modülü, tarayıcıda şifrelenen veriyi çözebilir:

const { createDecipheriv } = require('crypto');

function decrypt(key, nonce, ciphertextWithTag) {
  const tag = ciphertextWithTag.slice(-16);
  const ct = ciphertextWithTag.slice(0, -16);
  const decipher = createDecipheriv('aes-256-gcm', key, nonce);
  decipher.setAuthTag(tag);
  return Buffer.concat([decipher.update(ct), decipher.final()]);
}

Web Crypto 128 bit etiketi şifreli metnin sonuna ekler; Node'un API'si etiket ve şifreli metni ayrı bekler. Buna göre ayırın.

Performans Rakamları

AES-NI ile tipik 2024-2026 donanımında:

  • Yerel (OpenSSL, AES-NI): çekirdek başına 3-5 GB/s
  • Web Crypto (donanım hızlandırmalı tarayıcı): 1-2 GB/s
  • libsodium.js WASM AES-GCM: 400-800 MB/s
  • Saf JS (@noble/ciphers): 50-150 MB/s

1 GB dosya için Web Crypto şifrelemesi 0,5-1 saniyede tamamlanır. Saf JS 7-20 saniye sürer. İmplementasyonları bu gerçekliğe göre seçin; büyük dosya aktarımı UX'i için Web Crypto pratik seçimdir.

Yaygın Tuzaklar Özeti

  • Nonce yeniden kullanımı: felaket boyutunda. Tek en büyük başarısızlık modudur.
  • crypto.getRandomValues() yerine Math.random() kullanmak.
  • İlişkili meta veriyi AAD ile doğrulamayı unutmak.
  • "Alıştığımız için" CBC modu kullanmak. CBC, GCM'nin bütünlüğüyle eşleşmek için ayrı MAC gerektirir; HMAC-CBC yapısı doğru ama karmaşıktır; GCM tehlikeli durumu ortadan kaldırır.
  • Şifre çözme hatalarını sessizce yakalayıp çöp döndürmek. Her zaman gürültülü biçimde başarısız olun.
  • Kendi GCM'nizi yazmak. Web Crypto, libsodium veya node:crypto kullanın. GHASH implementasyonunun uzmanların yıllarca üzerinde çalıştığı yan kanal tuzakları vardır.

HexaTransfer, dosya başına anahtar ve ayrı depolanan AEAD korumalı meta veride dosya adı olduğundan 96 bit rastgele nonce, 128 bit etiket ve AAD olmaksızın Web Crypto'nun AES-256-GCM'sini kullanır. Basit, doğru, hızlı.

Başka Bir Şey Ne Zaman Tercih Edilmeli

AES-GCM dosya aktarımı için en uygunudur; ancak belirli durumlarda alternatifleri göz önünde bulundurun:

  • XChaCha20-Poly1305: 192 bit nonce'lar, herhangi bir ölçekte rastgele nonce güvenliğini sıradan kılar. AES-NI'lı donanımda biraz daha yavaş, AES-NI olmayan eski ARM'de daha hızlı. libsodium bunu sağlar.
  • AES-GCM-SIV: yanlış kullanıma dayanıklı; nonce yeniden kullanımı anahtarı sızdırmaz, yalnızca düz metinlerin eşit olup olmadığını ortaya çıkarır. Nonce benzersizliğini garanti edemediğinizde kullanışlıdır.

Standart bir web yığınındaki çoğu dosya aktarımı iş yükü için, dosya başına taze anahtar ve rastgele 96 bit nonce'larla AES-256-GCM doğru ve en basit biçimde uygulanabilen seçimdir.

hexatransfer.com'da deneyin — ücretsiz, hesap gerekmez, 10 GB'a kadar.

Uçtan uca şifreleme ile büyük dosyaları güvenle gönderin

Uçtan uca şifreleme ile 10 GB'a kadar dosya ücretsiz aktarın. Hesap gerekmez. Dosyalarınız yüklenmeden önce tarayıcınızda şifrelenir — başka kimse okuyamaz.

Dosya gönder