WinZip AE-1 en AE-2 zijn de AES-versleutelingsschema's die binnen .zip-archieven worden gebruikt, ter vervanging van het oorspronkelijke, zwakke PKZIP 2.0-stroomcijfer. Elke functie bevindt zich in sgcCrypto_Zip_AE2 en werkt op één archiefitem tegelijk; het bouwen van de omringende .zip-container zelf valt buiten het bestek van deze unit.
Indeling
Sleutelmateriaal komt van PBKDF2-HMAC-SHA1 over het wachtwoord, 1000 iteraties, en levert in één aanroep een versleutelingssleutel, een authenticatiesleutel en een wachtwoordverificator van 2 bytes op. De saltlengte en de sleutellengte hangen beide af van de AES-sterkte die voor het item is gekozen.
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);
Een item versleutelen en ontsleutelen
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;
De verificator van 2 bytes vangt de meeste onjuiste wachtwoorden onmiddellijk op, en de HMAC-SHA1-authenticatiecode van 10 bytes die aAuthCode draagt, vangt de rest op, samen met elke manipulatie van de versleutelde inhoud.
Wat AE-2 niet beschermt
De authenticatiecode dekt alleen de bestandsinhoud van één item. Ze dekt niet de bestandsnaam, de tijdstempels, of de archiefindeling, dus een aanvaller die de inhoud niet kan lezen, kan items in het archief nog steeds hernoemen, herschikken of laten vallen zonder detectie. Ze beschermt ook niet tegen een zwak wachtwoord: de sleutelafleiding gebruikt slechts 1000 PBKDF2-rondes, veel minder dan Argon2id of scrypt zouden gebruiken, omdat het formaat aan die technieken voorafgaat. Een AE-2-archief is slechts zo sterk als het wachtwoord dat ervoor is gekozen.
Het extra veld
Een .zip-item markeert zichzelf als AE-versleuteld door de compressiemethode op 99 te zetten en een klein extra veld toe te voegen (header-ID 0x9901) dat de eigenlijke onderliggende compressiemethode, de AE-versie (1 of 2) en de AES-sterkte vastlegt, wat een lezer nodig heeft voordat deze zelfs maar een wachtwoord kan proberen.
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;
Twee gemaksfuncties pakken en unpakken de indeling van salt / verificator / ciphertext / authenticatiecode die op de local file header volgt, voor aanroepers die een volledig item samenstellen of lezen in plaats van alleen de cryptografie ervan:
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;