You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RAD Studio 12 Athens如何解压加密Zip文件?求完整代码示例

加密Zip文件提取完整实现示例

Embarcadero官方的System.Zip.TZipFile.Extract示例仅提供了基础框架,缺失加密类型判断与具体解密逻辑。以下补充完整的C++和Delphi实现代码,覆盖传统ZipCrypto与AES-256两种主流Zip加密方式。


C++ 完整实现

主调用代码

#include <System.Zip.hpp>
#include <System.Cryptography.hpp>
#include <System.SysUtils.hpp>
#include <memory>

// 存储Zip密码(可根据实际场景动态传入)
UnicodeString g_ZipPassword = L"YourSecurePassword";

void ExtractEncryptedZip(const UnicodeString& ZipPath, const UnicodeString& ExtractDir)
{
    std::unique_ptr<TZipFile> myZipFile(new TZipFile);
    myZipFile->OnCreateDecompressStream = &OnCreateDecompressStream;
    myZipFile->Open(ZipPath, zmRead);
    myZipFile->ExtractAll(ExtractDir);
    myZipFile->Close();
}

解密流创建回调完整实现

TStream* __fastcall OnCreateDecompressStream(TStream* const InStream, TZipFile* const ZipFile, const TZipHeader& Item, bool IsEncrypted)
{
    if (!IsEncrypted)
        return InStream;

    try
    {
        // 通过TZipHeader的EncryptionMethod字段判断加密类型
        switch (Item.EncryptionMethod)
        {
            // 传统ZipCrypto加密(PKWARE标准)
            case 0:
                return CreateZipCryptoDecryptStream(InStream, g_ZipPassword, Item);
            // AES-256加密(WinZip兼容格式)
            case 99:
                return CreateAESDecryptStream(InStream, g_ZipPassword, Item);
            default:
                throw Exception(L"不支持的加密类型");
        }
    }
    catch (Exception& e)
    {
        ShowMessage(L"解密失败:" + e.Message);
        return InStream;
    }
}

ZipCrypto解密流实现

TStream* CreateZipCryptoDecryptStream(TStream* InStream, const UnicodeString& Password, const TZipHeader& Item)
{
    class TZipCryptoDecryptStream : public TCustomMemoryStream
    {
    private:
        TStream* FSourceStream;
        bool FOwnsSource;
        uint8_t FKeys[3];
        void UpdateKeys(uint8_t Byte);
        uint8_t DecryptByte(uint8_t Byte);
    public:
        __fastcall TZipCryptoDecryptStream(TStream* Source, bool OwnsSource, const UnicodeString& Password);
        __fastcall ~TZipCryptoDecryptStream();
        virtual int __fastcall Read(void *Buffer, int Count);
    };

    // ZipCrypto核心算法实现
    __fastcall TZipCryptoDecryptStream::TZipCryptoDecryptStream(TStream* Source, bool OwnsSource, const UnicodeString& Password)
        : FSourceStream(Source), FOwnsSource(OwnsSource)
    {
        // 初始化密钥
        FKeys[0] = 0x12;
        FKeys[1] = 0x34;
        FKeys[2] = 0x56;
        for (int i = 0; i < Password.Length(); i++)
        {
            UpdateKeys(static_cast<uint8_t>(Password[i]));
        }
        // 跳过加密文件头的12字节验证位
        uint8_t Dummy[12];
        FSourceStream->Read(Dummy, 12);
        for (int i = 0; i < 12; i++)
        {
            DecryptByte(Dummy[i]);
        }
    }

    __fastcall TZipCryptoDecryptStream::~TZipCryptoDecryptStream()
    {
        if (FOwnsSource)
            delete FSourceStream;
    }

    void TZipCryptoDecryptStream::UpdateKeys(uint8_t Byte)
    {
        FKeys[0] = static_cast<uint8_t>((FKeys[0] + FKeys[1]) * 134775813 + 1);
        FKeys[1] = static_cast<uint8_t>(FKeys[1] ^ FKeys[0]);
        FKeys[2] = static_cast<uint8_t>((FKeys[2] + FKeys[1]) * 134775813 + 1);
    }

    uint8_t TZipCryptoDecryptStream::DecryptByte(uint8_t Byte)
    {
        uint8_t Temp = static_cast<uint8_t>(FKeys[2] | 2);
        Temp = static_cast<uint8_t>((Temp * (Temp ^ 1)) >> 8);
        uint8_t Result = Byte ^ Temp;
        UpdateKeys(Result);
        return Result;
    }

    int __fastcall TZipCryptoDecryptStream::Read(void *Buffer, int Count)
    {
        int BytesRead = FSourceStream->Read(Buffer, Count);
        uint8_t* Ptr = static_cast<uint8_t*>(Buffer);
        for (int i = 0; i < BytesRead; i++)
        {
            Ptr[i] = DecryptByte(Ptr[i]);
        }
        return BytesRead;
    }

    return new TZipCryptoDecryptStream(InStream, true, Password);
}

AES-256解密流实现

TStream* CreateAESDecryptStream(TStream* InStream, const UnicodeString& Password, const TZipHeader& Item)
{
    uint8_t* ExtraField = reinterpret_cast<uint8_t*>(Item.ExtraField.c_str());
    int ExtraFieldLen = Item.ExtraField.Length();
    int KeySize = 0;
    uint8_t VerificationCode[2];

    // 遍历ExtraField查找WinZip AES标记(0x9901)
    for (int i = 0; i < ExtraFieldLen - 4; )
    {
        uint16_t Tag = *reinterpret_cast<uint16_t*>(ExtraField + i);
        uint16_t Len = *reinterpret_cast<uint16_t*>(ExtraField + i + 2);
        if (Tag == 0x9901)
        {
            KeySize = ExtraField[i + 5] * 8; // 256位对应32*8
            memcpy(VerificationCode, ExtraField + i + 6, 2);
            break;
        }
        i += 4 + Len;
    }

    if (KeySize != 256)
        throw Exception(L"仅支持AES-256加密");

    // 生成AES密钥(遵循Zip AES规范:密码+盐值迭代推导)
    TAES* AES = new TAES(TAES::ECB);
    TBytes PasswordBytes = TEncoding::UTF8::GetBytes(Password);
    TBytes SaltBytes(8);
    InStream->Read(SaltBytes.data(), 8);
    TBytes KeyBytes = AES->DeriveKeyFromPassword(PasswordBytes, SaltBytes, 1000, KeySize / 8);

    // 初始化CBC模式IV(前8字节为盐值,后8字节补0)
    TBytes IVBytes(16);
    memcpy(IVBytes.data(), SaltBytes.data(), 8);
    memset(IVBytes.data() + 8, 0, 8);
    TCryptoDecryptStream* AESStream = new TCryptoDecryptStream(InStream, true, AES, KeyBytes, IVBytes);

    // 验证解密后的校验码,确认密码正确性
    uint8_t DecryptedCode[2];
    AESStream->Read(DecryptedCode, 2);
    if (memcmp(DecryptedCode, VerificationCode, 2) != 0)
    {
        delete AESStream;
        throw Exception(L"密码错误或文件损坏");
    }

    return AESStream;
}

Delphi 完整实现

主调用代码

uses System.Zip, System.Cryptography, System.SysUtils;

var
  g_ZipPassword: string;

procedure ExtractEncryptedZip(const ZipPath, ExtractDir: string);
var
  myZipFile: TZipFile;
begin
  myZipFile := TZipFile.Create;
  try
    myZipFile.OnCreateDecompressStream := OnCreateDecompressStream;
    myZipFile.Open(ZipPath, zmRead);
    myZipFile.ExtractAll(ExtractDir);
  finally
    myZipFile.Free;
  end;
end;

解密流创建回调完整实现

function OnCreateDecompressStream(InStream: TStream; ZipFile: TZipFile; const Item: TZipHeader; IsEncrypted: Boolean): TStream;
begin
  if not IsEncrypted then
  begin
    Result := InStream;
    Exit;
  end;

  try
    case Item.EncryptionMethod of
      0: Result := CreateZipCryptoDecryptStream(InStream, g_ZipPassword, Item);
      99: Result := CreateAESDecryptStream(InStream, g_ZipPassword, Item);
    else
      raise Exception.Create('不支持的加密类型');
    end;
  except
    on E: Exception do
    begin
      ShowMessage('解密失败:' + E.Message);
      Result := InStream;
    end;
  end;
end;

ZipCrypto解密流实现

type
  TZipCryptoDecryptStream = class(TCustomMemoryStream)
  private
    FSourceStream: TStream;
    FOwnsSource: Boolean;
    FKeys: array[0..2] of Byte;
    procedure UpdateKeys(Byte: Byte);
    function DecryptByte(Byte: Byte): Byte;
  public
    constructor Create(Source: TStream; OwnsSource: Boolean; const Password: string);
    destructor Destroy; override;
    function Read(var Buffer; Count: Integer): Integer; override;
  end;

constructor TZipCryptoDecryptStream.Create(Source: TStream; OwnsSource: Boolean; const Password: string);
var
  I: Integer;
  Dummy: array[0..11] of Byte;
begin
  inherited Create;
  FSourceStream := Source;
  FOwnsSource := OwnsSource;
  // 初始化密钥
  FKeys[0] := $12;
  FKeys[1] := $34;
  FKeys[2] := $56;
  for I := 1 to Length(Password) do
    UpdateKeys(Byte(Password[I]));
  // 跳过验证头
  FSourceStream.Read(Dummy, 12);
  for I := 0 to 11 do
    DecryptByte(Dummy[I]);
end;

destructor TZipCryptoDecryptStream.Destroy;
begin
  if FOwnsSource then
    FSourceStream.Free;
  inherited;
end;

procedure TZipCryptoDecryptStream.UpdateKeys(Byte: Byte);
begin
  FKeys[0] := (FKeys[0] + FKeys[1]) * $8088405 + 1;
  FKeys[1] := FKeys[1] xor FKeys[0];
  FKeys[2] := (FKeys[2] + FKeys[1]) * $8088405 + 1;
end;

function TZipCryptoDecryptStream.DecryptByte(Byte: Byte): Byte;
var
  Temp: Byte;
begin
  Temp := FKeys[2] or 2;
  Temp := (Temp * (Temp xor 1)) shr 8;
  Result := Byte xor Temp;
  UpdateKeys(Result);
end;

function TZipCryptoDecryptStream.Read(var Buffer; Count: Integer): Integer;
var
  Ptr: PByte;
  I: Integer;
begin
  Result := FSourceStream.Read(Buffer, Count);
  Ptr := @Buffer;
  for I := 0 to Result - 1 do
    Ptr^ := DecryptByte(Ptr^);
end;

function CreateZipCryptoDecryptStream(InStream: TStream; const Password: string; const Item: TZipHeader): TStream;
begin
  Result := TZipCryptoDecryptStream.Create(InStream, True, Password);
end;

AES-256解密流实现

function CreateAESDecryptStream(InStream: TStream; const Password: string; const Item: TZipHeader): TStream;
var
  ExtraField: PByte;
  ExtraFieldLen: Integer;
  I: Integer;
  Tag, Len: Word;
  KeySize: Integer;
  VerificationCode: array[0..1] of Byte;
  AES: TAES;
  PasswordBytes, SaltBytes, KeyBytes, IVBytes: TBytes;
  AESStream: TCryptoDecryptStream;
  DecryptedCode: array[0..1] of Byte;
begin
  ExtraField := PByte(Item.ExtraField);
  ExtraFieldLen := Length(Item.ExtraField);
  KeySize := 0;
  FillChar(VerificationCode, SizeOf(VerificationCode), 0);

  // 查找WinZip AES扩展字段
  I := 0;
  while I <= ExtraFieldLen - 4 do
  begin
    Tag := PWord(ExtraField + I)^;
    Len := PWord(ExtraField + I + 2)^;
    if Tag = $9901 then
    begin
      KeySize := ExtraField[I + 5] * 8;
      Move(ExtraField[I + 6], VerificationCode, 2);
      Break;
    end;
    Inc(I, 4 + Len);
  end;

  if KeySize <> 256 then
    raise Exception.Create('仅支持AES-256加密');

  // 生成密钥
  AES := TAES.Create(TAES.ECB);
  try
    PasswordBytes := TEncoding.UTF8.GetBytes(Password);
    SetLength(SaltBytes, 8);
    InStream.ReadBuffer(SaltBytes[0], 8);
    KeyBytes := AES.DeriveKeyFromPassword(PasswordBytes, SaltBytes, 1000, KeySize div 8);

    // 初始化CBC IV
    SetLength(IVBytes, 16);
    Move(SaltBytes[0], IVBytes[0], 8);
    FillChar(IVBytes[8], 8, 0);
    AESStream := TCryptoDecryptStream.Create(InStream, True, AES, KeyBytes, IVBytes);
  except
    AES.Free;
    raise;
  end;

  // 验证校验码
  AESStream.ReadBuffer(DecryptedCode, 2);
  if not CompareMem(@DecryptedCode, @VerificationCode, 2) then
  begin
    AESStream.Free;
    raise Exception.Create('密码错误或文件损坏');
  end;

  Result := AESStream;
end;

内容的提问来源于stack exchange,提问作者Barry Andrews

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 19:32:03