WinZip AE-1 i AE-2 to schematy szyfrowania AES stosowane wewnątrz archiwów .zip, zastępujące oryginalny, słaby szyfr strumieniowy PKZIP 2.0. Każda funkcja znajduje się w jednostce sgcCrypto_Zip_AE2 i działa na jednym wpisie archiwum naraz; budowanie samego kontenera .zip wykracza poza zakres tej jednostki.
Układ
Materiał kluczowy pochodzi z PBKDF2-HMAC-SHA1 zastosowanego do hasła, 1000 iteracji, dających w jednym wywołaniu klucz szyfrujący, klucz uwierzytelniający oraz 2-bajtowy weryfikator hasła. Długość soli i długość klucza zależą obie od siły AES wybranej dla danego wpisu.
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);
Szyfrowanie i odszyfrowywanie wpisu
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;
2-bajtowy weryfikator wychwytuje natychmiast większość błędnych haseł, a 10-bajtowy kod uwierzytelniający HMAC-SHA1 przenoszony przez aAuthCode wychwytuje resztę, wraz z jakąkolwiek manipulacją zaszyfrowaną zawartością.
Czego AE-2 nie chroni
Kod uwierzytelniający obejmuje wyłącznie zawartość pliku jednego wpisu. Nie obejmuje nazwy pliku, znaczników czasu ani układu archiwum, więc atakujący, który nie może odczytać zawartości, wciąż może bez wykrycia zmienić nazwę, zmienić kolejność albo usunąć wpisy w archiwum. Nie chroni też przed słabym hasłem: wyprowadzanie klucza używa tylko 1000 rund PBKDF2, znacznie mniej niż użyłby Argon2id lub scrypt, ponieważ format powstał, zanim one istniały. Archiwum AE-2 jest tak bezpieczne, jak silne jest wybrane dla niego hasło.
Pole dodatkowe (extra field)
Wpis .zip oznacza się jako zaszyfrowany AE, ustawiając swoją metodę kompresji na 99 i dodając niewielkie pole dodatkowe (identyfikator nagłówka 0x9901), które zapisuje rzeczywistą metodę kompresji ukrytą pod spodem, wersję AE (1 lub 2) oraz siłę AES, czego czytnik potrzebuje, zanim w ogóle będzie mógł spróbować hasła.
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;
Dwie funkcje pomocnicze pakują i rozpakowują układ sól / weryfikator / szyfrogram / kod uwierzytelniający, który następuje po nagłówku lokalnego pliku, dla wywołujących składających lub odczytujących cały wpis, a nie tylko jego część kryptograficzną:
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;