WinZip AE-1 e AE-2 são os esquemas de criptografia AES utilizados dentro de arquivos .zip, substituindo a cifra de fluxo original e fraca do PKZIP 2.0. Toda função está em sgcCrypto_Zip_AE2 e opera sobre uma entrada do arquivo por vez; construir o container .zip ao redor está fora do escopo desta unit.
Layout
O material de chave vem do PBKDF2-HMAC-SHA1 sobre a senha, 1000 iterações, produzindo uma chave de criptografia, uma chave de autenticação e um verificador de senha de 2 bytes em uma única chamada. Tanto o tamanho do salt quanto o tamanho da chave dependem da força de AES escolhida para a entrada.
function sgcZipAE2_SaltLength(aStrength: TsgcZipAESStrength): Integer;
function sgcZipAE2_KeyLength(aStrength: TsgcZipAESStrength): Integer;
procedure sgcZipAE2_DeriveKeys(const aPassword, aSalt: TBytes; aStrength: TsgcZipAESStrength;
out aEncKey, aAuthKey, aVerifier: TBytes);
Criptografando e descriptografando uma entrada
function sgcZipAE2_Encrypt(const aPassword, aSalt, aPlain: TBytes; aStrength: TsgcZipAESStrength;
out aVerifier, aAuthCode: TBytes): TBytes;
function sgcZipAE2_Decrypt(const aPassword, aSalt, aCipher, aVerifier, aAuthCode: TBytes;
aStrength: TsgcZipAESStrength; out aPlain: TBytes): Boolean;
var
oSalt, oCipher, oVerifier, oAuth, oPlain: TBytes;
begin
oSalt := sgcRandomBytes(sgcZipAE2_SaltLength(zasAES256));
oCipher := sgcZipAE2_Encrypt(oPassword, oSalt, oPlain, zasAES256, oVerifier, oAuth);
if sgcZipAE2_Decrypt(oPassword, oSalt, oCipher, oVerifier, oAuth, zasAES256, oPlain) then
{ correct password, untampered data };
end;
O verificador de 2 bytes detecta a maioria das senhas erradas imediatamente, e o código de autenticação HMAC-SHA1 de 10 bytes que aAuthCode carrega detecta o restante, junto com qualquer adulteração do conteúdo criptografado.
O que o AE-2 não protege
O código de autenticação cobre apenas o conteúdo do arquivo de uma entrada. Ele não cobre o nome do arquivo, os timestamps, ou o layout do archive, de modo que um atacante que não consegue ler o conteúdo ainda assim pode renomear, reordenar ou remover entradas do archive sem ser detectado. Ele também não protege contra uma senha fraca: a derivação de chave usa apenas 1000 rounds de PBKDF2, muito menos que o Argon2id ou o scrypt usariam, porque o formato é anterior a eles. Um archive AE-2 é tão forte quanto a senha escolhida para ele.
O campo extra
Uma entrada .zip se marca como criptografada com AE definindo seu método de compressão como 99 e adicionando um pequeno campo extra (ID de cabeçalho 0x9901) que registra o método de compressão real por baixo, a versão do AE (1 ou 2) e a força do AES, que é o que um leitor precisa antes mesmo de tentar uma senha.
function sgcZipAE2_BuildExtraField(aStrength: TsgcZipAESStrength; aCompressionMethod: Word;
aVersion: TsgcZipAEVersion = zavAE2): TBytes;
function sgcZipAE2_ParseExtraField(const aData: TBytes; out aStrength: TsgcZipAESStrength;
out aCompressionMethod: Word; out aVersion: TsgcZipAEVersion): Boolean;
Duas funções de conveniência empacotam e desempacotam o layout de salt / verificador / texto cifrado / código de autenticação que segue o cabeçalho de arquivo local, para chamadores que montam ou leem uma entrada completa em vez de apenas sua criptografia:
function sgcZipAE2_PackEntry(const aSalt, aVerifier, aCipher, aAuthCode: TBytes): TBytes;
function sgcZipAE2_UnpackEntry(const aEntry: TBytes; aStrength: TsgcZipAESStrength;
out aSalt, aVerifier, aCipher, aAuthCode: TBytes): Boolean;