欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

golang解壓帶密碼的zip包的方法詳解

 更新時(shí)間:2024年07月22日 09:47:15   作者:Generalzy  
ZIP 文件格式是一種常用的壓縮和歸檔格式,用于將多個(gè)文件和目錄打包到一個(gè)單獨(dú)的文件中,同時(shí)對其內(nèi)容進(jìn)行壓縮以減少文件大小,golang zip包的解壓有官方的zip包(archive/zip),但是官方給的zip解壓包代碼只有解壓不帶密碼的zip包,下面給出解壓操作的封裝

Zip文件詳解

ZIP 文件格式是一種常用的壓縮和歸檔格式,用于將多個(gè)文件和目錄打包到一個(gè)單獨(dú)的文件中,同時(shí)對其內(nèi)容進(jìn)行壓縮以減少文件大小。ZIP 文件格式的設(shè)計(jì)旨在支持多種壓縮算法、加密和數(shù)據(jù)完整性校驗(yàn)。以下是 ZIP 文件格式的主要特性和常用算法:

ZIP 文件格式主要特性

文件頭

每個(gè)文件都有一個(gè)本地文件頭和一個(gè)中央目錄文件頭。文件頭包含文件名、壓縮方法、時(shí)間戳、CRC-32 校驗(yàn)和、壓縮前后的大小等信息。

數(shù)據(jù)描述符

可選的后綴結(jié)構(gòu),包含文件的 CRC-32 校驗(yàn)和、壓縮大小和未壓縮大小。

中央目錄

ZIP 文件的末尾包含一個(gè)中央目錄記錄,列出了 ZIP 文件中的所有文件和目錄的文件頭信息,用于快速定位和訪問。

結(jié)束記錄

ZIP 文件末尾的“中央目錄結(jié)束記錄”標(biāo)識了中央目錄的結(jié)束,包含中央目錄的偏移量和大小等信息。

一個(gè)簡單的 ZIP 文件可以包含多個(gè)文件的本地文件頭、壓縮數(shù)據(jù)、中央目錄和結(jié)束記錄。解壓工具通過讀取中央目錄找到各個(gè)文件的偏移量和大小,然后根據(jù)這些信息讀取和解壓文件數(shù)據(jù)。

以下是一個(gè) ZIP 文件結(jié)構(gòu)的簡化示例:

[本地文件頭1] [文件數(shù)據(jù)1] [本地文件頭2] [文件數(shù)據(jù)2] ... [中央目錄] [中央目錄結(jié)束記錄]

ZIP 文件格式因其廣泛的支持和高效的壓縮性能,廣泛應(yīng)用于文件歸檔和傳輸。DEFLATE 算法是其最常用的壓縮算法,提供了良好的平衡點(diǎn)。

常用算法

壓縮算法

  • DEFLATE:這是 ZIP 文件中最常用的壓縮算法,由 Phil Katz 發(fā)明。它結(jié)合了 LZ77 算法和 Huffman 編碼,提供了良好的壓縮比和解壓速度。
  • STORE:不進(jìn)行任何壓縮,僅用于存儲數(shù)據(jù)。適用于已經(jīng)被壓縮過的數(shù)據(jù),如 JPEG 圖像或 MP3 音頻文件。
  • 其他壓縮方法:ZIP 規(guī)范還支持其他壓縮方法,如 BZIP2、LZMA 和 PPMd,但這些方法在實(shí)際使用中較為少見。

加密算法

  • 傳統(tǒng) ZIP 加密:早期的 ZIP 文件使用一種相對簡單的對稱加密方法,但這種方法的安全性較弱。
  • AES 加密:一些現(xiàn)代的 ZIP 工具支持使用高級加密標(biāo)準(zhǔn) (AES) 進(jìn)行加密,提供了更強(qiáng)的安全性。

校驗(yàn)算法

  • CRC-32:用于每個(gè)文件的數(shù)據(jù)完整性校驗(yàn)。每個(gè)文件都有一個(gè) CRC-32 校驗(yàn)和,用于檢測數(shù)據(jù)傳輸或存儲過程中的錯(cuò)誤。

Zip格式結(jié)構(gòu)圖總覽

在這里插入圖片描述

Zip文件結(jié)構(gòu)詳解

zip格式壓縮包主要由三大部分組成:數(shù)據(jù)區(qū)、中央目錄記錄區(qū)(也有叫核心目錄記錄)、中央目錄記錄尾部區(qū)。

數(shù)據(jù)區(qū)

數(shù)據(jù)區(qū)是由一系列本地文件記錄組成,本地文件記錄主要是記錄了壓縮前后文件的元數(shù)據(jù)以及存放壓縮后的文件,組成部分也分為三大部分:本地文件頭文件數(shù)據(jù)、文件描述

本地文件頭

在這里插入圖片描述

local file header signature     4 bytes  (0x04034b50)
version needed to extract       2 bytes
general purpose bit flag        2 bytes
compression method              2 bytes
last mod file time              2 bytes
last mod file date              2 bytes
crc-32                          4 bytes
compressed size                 4 bytes
uncompressed size               4 bytes
file name length                2 bytes
extra field length              2 bytes

file name (variable size)
extra field (variable size)

本地文件頭主要是記錄了壓縮文件的元數(shù)據(jù):

  • loca file header signature:0~3,4個(gè)字節(jié),用來存放本地文件頭標(biāo)識,一般為固定值0x04034b50,用于解壓時(shí)候,讀取判斷文件頭的開始;
  • version needed to extract:4~5,2個(gè)字節(jié),記錄解壓縮文件所需的最低支持的ZIP規(guī)范版本,apk壓縮版本默認(rèn)是20, 即Deflate壓縮方式。該字段值=解壓所需的最低ZIP規(guī)范版本*10,比如,最低支持的ZIP規(guī)范版本是2.0,那么該字段的值就是20。每個(gè)版本定義如下。
當(dāng)前最低功能版本定義如下:(壓縮包記錄的解壓版本都是需要版本*10,比如:2.0 * 10 = 20)
1.0 – 默認(rèn)值
1.1 – 文件是卷標(biāo)
2.0 – 文件是一個(gè)文件夾(目錄)
2.0 – 使用 Deflate 壓縮來壓縮文件
2.0 – 使用傳統(tǒng)的 PKWARE 加密對文件進(jìn)行加密
2.1 – 使用 Deflate64? 壓縮文件
2.5 – 使用 PKWARE DCL Implode 壓縮文件
2.7 – 文件是補(bǔ)丁數(shù)據(jù)集
4.5 – 文件使用 ZIP64 格式擴(kuò)展
4.6 – 使用 BZIP2 壓縮文件壓縮
5.0 – 文件使用 DES 加密
5.0 – 文件使用 3DES 加密
5.0 – 使用原始 RC2 加密對文件進(jìn)行加密
5.0 – 使用 RC4 加密對文件進(jìn)行加密
5.1 – 文件使用 AES 加密進(jìn)行加密
5.1 – 使用更正的 RC2 加密對文件進(jìn)行加密
5.2 – 使用更正的 RC2-64 加密對文件進(jìn)行加密
6.1 – 使用非 OAEP 密鑰包裝對文件進(jìn)行加密
6.2 – 中央目錄加密
  • genaral purpose bit flag:6~7,2個(gè)字節(jié),記錄通用標(biāo)志位,第0位為1時(shí)(即二進(jìn)制:00000000 00000001),表示文件被加密,解壓時(shí)候需要解密;第3位為1時(shí)候(即二進(jìn)制:00000000 00000100),表示有數(shù)據(jù)描述部分,本地文件頭中的 CRC-32、壓縮大小和未壓縮大小字段都被設(shè)置為0(雖然zip規(guī)范是這么定義,但是發(fā)現(xiàn)有些壓縮包即使聲明有數(shù)據(jù)描述部分,但是本地文件頭的CRC-32、壓縮大小和未壓縮大小依然還是設(shè)置為真實(shí)值) , 正確的值被放在緊跟在壓縮數(shù)據(jù)之后的數(shù)據(jù)描述部分,apk的通用標(biāo)志位默認(rèn)傳0即可,也有傳2048、2056,目前第15位是PKWARE保留位。
  • compression method:8~9,2個(gè)字節(jié),記錄壓縮包所用到的壓縮方式,apk默認(rèn)Deflate壓縮,傳8即可, 要是傳0 ,則是不壓縮,各種壓縮方式對應(yīng)數(shù)值如下:
0 – The file is stored (no compression)
1 – The file is Shrunk
2 – The file is Reduced with compression factor 1
3 – The file is Reduced with compression factor 2
4 – The file is Reduced with compression factor 3
5 – The file is Reduced with compression factor 4
6 – The file is Imploded
7 – Reserved for Tokenizing compression algorithm
8 – The file is Deflated
9 – Enhanced Deflating using Deflate64?
10 – PKWARE Data Compression Library Imploding
11 – Reserved by PKWARE
12 – File is compressed using BZIP2 algorithm
  • last mod file time:10~11,2個(gè)字節(jié),記錄文件最后修改時(shí)間,是MS-DOS格式編碼的時(shí)間

在這里插入圖片描述

  • last mod date time:12~13,2個(gè)字節(jié),記錄文件最后修改日期,是MS-DOS格式編碼的日期
  • crc-32:14~17,4個(gè)字節(jié),記錄文件未壓縮時(shí)的CRC-32校驗(yàn)碼
  • compressed size:18~21,4個(gè)字節(jié),記錄文件壓縮后的大小
  • uncompressed size:22~25,4個(gè)字節(jié),記錄文件未壓縮的大小
  • file name length:26~27,2個(gè)字節(jié),記錄文件名的長度(假設(shè)文件名長度為n)
  • extra field length:28~29,2個(gè)字節(jié),記錄擴(kuò)展區(qū)的長度(假設(shè)擴(kuò)展區(qū)長度為m)
  • file name:30~30+n,n個(gè)字節(jié),記錄文件名
  • extral field:30+n~30+n+m,m個(gè)字節(jié),記錄擴(kuò)展數(shù)據(jù)

文件數(shù)據(jù)

文件數(shù)據(jù)緊跟在本地文件頭之后,一般是壓縮后的文件數(shù)據(jù)或壓縮方式選擇不壓縮時(shí)候,用來存儲未壓縮文件數(shù)據(jù)。

文件描述

文件描述符僅在通用位標(biāo)志的第 3 位被設(shè)置為1時(shí)才存在。 它是字節(jié)對齊的,緊跟在文件數(shù)據(jù)的最后一個(gè)字節(jié)之后。當(dāng)且僅當(dāng)無法在 .ZIP 文件中查找時(shí)才使用此描述符,例如:當(dāng)輸出 的.ZIP 文件是標(biāo)準(zhǔn)輸出或不可查找設(shè)備時(shí)使用文件描述,換句話說,正常情況下都不需要使用。

在這里插入圖片描述

( 數(shù)據(jù)描述符標(biāo)識不一定有,因?yàn)橐婚_始規(guī)范是沒有的,后面才加上去的)

中央目錄記錄區(qū)(核心目錄記錄區(qū) )

中心目錄區(qū)的結(jié)構(gòu)如下。

[file header 1]
.
.
. 
[file header n]
[digital signature]
central file header signature   4 bytes  (0x02014b50)
version made by                 2 bytes
version needed to extract       2 bytes
general purpose bit flag        2 bytes
compression method              2 bytes
last mod file time              2 bytes
last mod file date              2 bytes
crc-32                          4 bytes
compressed size                 4 bytes
uncompressed size               4 bytes
file name length                2 bytes
extra field length              2 bytes
file comment length             2 bytes
disk number start               2 bytes
internal file attributes        2 bytes
external file attributes        4 bytes
relative offset of local header 4 bytes

file name (variable size)
extra field (variable size)
file comment (variable size)

中央目錄記錄區(qū)是有一系列中央目錄記錄所組成,一條中央目錄記錄對應(yīng)數(shù)據(jù)區(qū)中的一個(gè)壓縮文件記錄,中央目錄記錄由以下部分構(gòu)成:(中央目錄區(qū)通常由多個(gè)文件頭(file header)組成,每一個(gè)被壓縮的文件都有一個(gè)對應(yīng)的file header(注意,這里不是local file header),用于標(biāo)識和定位該文件在ZIP文件中的位置。這個(gè)文件頭和本地文件頭類似,記錄了被壓縮文件的元數(shù)據(jù)信息,包括文件原始大小,壓縮之后的大小,文件注釋等。)

在這里插入圖片描述

  1. central file header signature:0~3,4個(gè)字節(jié),記錄核心目錄文件頭標(biāo)識,固定值:0x02014b50,用于解壓時(shí)候,查找判斷是否是中央目錄的開始位置
  2. version made by:4~5,2個(gè)字節(jié),記錄壓縮所用的版本,同數(shù)據(jù)區(qū)本地文件頭的解壓所需版本,apk設(shè)置20
  3. 6~7:2個(gè)字節(jié),記錄解壓所需的最小版本,同數(shù)據(jù)區(qū)本地文件頭的解壓所需版本,apk設(shè)置20
  4. 8~9:2個(gè)字節(jié),通用位標(biāo)記,同數(shù)據(jù)區(qū)本地文件頭的通用位標(biāo)記
  5. 壓縮方法、文件最后修改時(shí)間、文件最后修改日期、CRC-32校驗(yàn)碼、壓縮后大小、未壓縮大小、文件名長度、擴(kuò)展區(qū)長度,這幾個(gè)字段的含義都等同于數(shù)據(jù)區(qū)本地文件頭對應(yīng)字段的含義
  6. file comment length:32~33,2個(gè)字節(jié),記錄文件注釋的長度
  7. disk number start:34~35,2個(gè)字節(jié),記錄文件開始位置的磁盤編號,一般傳0即可
  8. 36~41:內(nèi)部文件屬性、外部文件屬性,一般也是傳0即可
  9. 42~45:4個(gè)字節(jié),記錄數(shù)據(jù)區(qū)本地文件頭相對于壓縮包開始位置的偏移量

數(shù)據(jù)簽名(digital signature):

header signature                4 bytes  (0x05054b50)
size of data                    2 bytes
signature data (variable size)
  • header signature:數(shù)字簽名起始標(biāo)識,固定值為0x05054b50。
  • size of data:數(shù)字簽名數(shù)據(jù)大小。
  • signature data :簽名數(shù)據(jù)

中央目錄記錄尾部區(qū)

中央目錄記錄尾部主要作用是用來定位中央目錄記錄區(qū)的開始位置,同時(shí)記錄壓縮包的注釋內(nèi)容:

在這里插入圖片描述

end of central dir signature    4 bytes  (0x06054b50)
number of this disk             2 bytes
number of the disk with the
start of the central directory  2 bytes
total number of entries in the
central directory on this disk  2 bytes
total number of entries in
the central directory           2 bytes
size of the central directory   4 bytes
offset of start of central
directory with respect to
the starting disk number        4 bytes
.ZIP file comment length        2 bytes
.ZIP file comment       (variable size)
  1. end of central dir signature:0~3,4個(gè)字節(jié),中央目錄記錄尾部開頭標(biāo)記,固定值:0x06054b50,用于解壓時(shí),查找判斷中央目錄尾部的起始位置
  2. number of this disk:4~5,2個(gè)字節(jié),記錄中央目錄記錄尾部區(qū)所在磁盤編號
  3. number of the disk with the start of the central directory:6~7,2個(gè)字節(jié),記錄中央目錄開始位置所在的磁盤編號
  4. total number of entries in the central directory on this disk:8~9,2個(gè)字節(jié),該磁盤上所記錄的核心目錄數(shù)量
  5. total number of entries in the central directory:10~11,2個(gè)字節(jié),zip壓縮包中的文件總數(shù)
  6. size of the central directory:12~15,4個(gè)字節(jié),整個(gè)中央目錄的大小(以字節(jié)為單位)
  7. offset of start of central directory with respect to the starting disk number:16~19,4個(gè)字節(jié),中央目錄開始位置相對位移
  8. ZIP file comment length:20~21,2個(gè)字節(jié),注釋內(nèi)容的長度(假設(shè)長度為n)
  9. ZIP file comment:22~22+n,n個(gè)字節(jié),注釋內(nèi)容

中央目錄結(jié)束標(biāo)識是ZIP文件解壓的入口。通過讀取中央目錄結(jié)束標(biāo)識,解壓縮軟件可以快速地找到中央目錄,并據(jù)此解析整個(gè)ZIP文件的結(jié)構(gòu)和內(nèi)容。通過里面的中央核心目錄區(qū)的大小可以找到對應(yīng)的中央目錄模塊,然后根據(jù)中央目錄文件頭中的本地文件頭偏移(relative offset of local header)可以尋址到對應(yīng)的文件,并進(jìn)行解壓。

每個(gè)壓縮文件都必須且僅有一個(gè)中央目錄結(jié)束標(biāo)識。如果ZIP文件損壞或結(jié)構(gòu)不正確,可能會導(dǎo)致中央目錄結(jié)束標(biāo)識丟失或損壞,從而使得解壓縮軟件無法正確讀取和解析ZIP文件。

壓縮包解壓過程

方式1 通過解析中央目錄區(qū)來解壓

通過ZIP文件的結(jié)構(gòu)我們發(fā)現(xiàn),ZIP文件的中央目錄區(qū)保存了所有的文件信息。所以,可以通過中央目錄區(qū)拿到所有的文件信息并進(jìn)行解壓,步驟如下所示。

在這里插入圖片描述

  1. 首先在 ZIP 文件末尾通過中央目錄結(jié)束標(biāo)識 (0x06054b50)找到中央目錄結(jié)束標(biāo)識數(shù)據(jù)塊。
  2. 通過中央目錄結(jié)束標(biāo)識中的中央目錄區(qū)開始位置偏移找到中央目錄區(qū)數(shù)據(jù)塊。
  3. 根據(jù)中央目錄區(qū)的File Header中的 local file header的偏移量找到對應(yīng)的local file header。
  4. 根據(jù) local file header找到對應(yīng)的file data
  5. 解密 file data(如果需要);
  6. 解壓 file data;

方式2 通過讀取本地文件頭來解壓

根據(jù) ZIP 文件格式標(biāo)準(zhǔn)可知,除了 中央目錄區(qū), 本地文件頭中也包含了每個(gè)文件的相關(guān)信息。因此,可以基于本地文件頭去解壓文件數(shù)據(jù),其解壓流程就可以變?yōu)椋?/p>

  • 從頭開始,通過本地文件頭標(biāo)識搜索對應(yīng)的 local file header
  • 讀取 local file header并找到file data;
  • 解密 file data(如果需要);
  • 解壓 file data;

兩種解壓方式對比

通過兩種解壓方式可以明顯看出,兩種解壓方式適用的場景不同。

方式1適用場景:

  • 適用于在解壓文件已經(jīng)存在于磁盤上,并且需要解壓壓縮包中所有的文件。

方式2適用場景:

  • 當(dāng)文件不在磁盤上,比如從網(wǎng)絡(luò)接收的數(shù)據(jù),想邊接收邊解壓;
  • 需要順序解壓ZIP文件前面的一小部分文件,可以使用這種方式,因?yàn)榉绞?讀中央目錄區(qū)會帶來額外的耗時(shí);
  • ZIP文件中的中央目錄區(qū)遭到損壞;

golang解壓zip包

官方archive/zip

golang zip包的解壓有官方的zip包(archive/zip),但是官方給的zip解壓包代碼只有解壓不帶密碼的zip包。

下面給出解壓操作的封裝:

func Unzip(src, dst string) error {
	// zip.NewReader() 適合從stream中讀取字節(jié)序列
	zf, err := zip.OpenReader(src)
	if err != nil {
		return err
	}
	defer zf.Close()

	for _, file := range zf.File {
		// fmt.Println(file.Name)
		path := filepath.Join(dst, file.Name)
		// 如果是目錄則創(chuàng)建目錄
		if file.FileInfo().IsDir() {
			if err = os.MkdirAll(path, 0o644); err != nil {
				return err
			}
			continue
		}
		f, err := os.Create(path)
		if err != nil {
			return err
		}
		reader, err := file.Open()
		if err != nil {
			return err
		}
		_, err = io.Copy(f, reader)
		if err != nil {
			return err
		}
		_ = f.Close()
		_ = reader.Close()
	}
	return nil
}

func main() {
	log.Println(Unzip("Go.zip", "./static"))
}

在這里插入圖片描述

通常情況下,目錄權(quán)限設(shè)為 0755,文件權(quán)限設(shè)為 0644 更為合適。

在 Unix 和 Unix-like 操作系統(tǒng)(如 Linux)中,文件權(quán)限使用三位八進(jìn)制數(shù)來表示,每一位分別表示所有者(Owner)、組(Group)和其他人(Others)的權(quán)限。每一位的權(quán)限可以是 1(執(zhí)行權(quán)限),2(寫入權(quán)限),4(讀取權(quán)限)的組合。它們的組合值表示特定的權(quán)限設(shè)置。

權(quán)限位的含義:

  • 1:執(zhí)行權(quán)限 (Execute)
  • 2:寫入權(quán)限 (Write)
  • 4:讀取權(quán)限 (Read)

這些權(quán)限可以相加來組合權(quán)限。例如:

  • 7 (4+2+1):讀取、寫入和執(zhí)行權(quán)限 (Read + Write + Execute)
  • 6 (4+2):讀取和寫入權(quán)限 (Read + Write)
  • 5 (4+1):讀取和執(zhí)行權(quán)限 (Read + Execute)
  • 4:讀取權(quán)限 (Read)
  • 3 (2+1):寫入和執(zhí)行權(quán)限 (Write + Execute)
  • 2:寫入權(quán)限 (Write)
  • 1:執(zhí)行權(quán)限 (Execute)
  • 0:無權(quán)限 (No permissions)

權(quán)限設(shè)置示例:

權(quán)限設(shè)置通常以三位八進(jìn)制數(shù)表示,例如 0755,每一位代表不同用戶類別的權(quán)限:

  • 第一位(Owner 權(quán)限):7,表示所有者有讀取、寫入和執(zhí)行權(quán)限。
  • 第二位(Group 權(quán)限):5,表示組用戶有讀取和執(zhí)行權(quán)限。
  • 第三位(Others 權(quán)限):5,表示其他用戶有讀取和執(zhí)行權(quán)限。
rwxr-xr-x
  • r 代表讀取權(quán)限
  • w 代表寫入權(quán)限
  • x 代表執(zhí)行權(quán)限
  • - 代表沒有該權(quán)限

示例解釋:

0755:

  • 所有者(Owner)權(quán)限:7 (rwx) 讀取、寫入和執(zhí)行
  • 組(Group)權(quán)限:5 (r-x) 讀取和執(zhí)行
  • 其他人(Others)權(quán)限:5 (r-x) 讀取和執(zhí)行

0644:

  • 所有者(Owner)權(quán)限:6 (rw-) 讀取和寫入
  • 組(Group)權(quán)限:4 (r–) 讀取
  • 其他人(Others)權(quán)限:4 (r–) 讀取

第三方包github.com/yeka/zip

使用go get github.com/yeka/zip安裝后,代碼都不需要改變,只是導(dǎo)入的zip包替換為第三方即可:

在這里插入圖片描述

在這里插入圖片描述

https://github.com/yeka/zip,關(guān)于這個(gè)庫里面的整個(gè)代碼是在官方的zip庫的基礎(chǔ)上做了一些修改,并且這個(gè)庫里面的代碼拋棄了注冊的功能,直接把解密代碼寫在了open文件里,廢棄了一個(gè)很好用的功能。

在這里插入圖片描述

在這里插入圖片描述

自己實(shí)現(xiàn)解壓加密的zip包

golang官方的zip代碼庫,https://golang.google.cn/pkg/archive/zip/#pkg-examples有兩個(gè)注冊接口,一個(gè)是壓縮和一個(gè)是解壓的:

在這里插入圖片描述

在這里插入圖片描述

官方注冊壓縮器方法示例:

package main

import (
	"archive/zip"
	"bytes"
	"compress/flate"
	"io"
)

func main() {
	// Override the default Deflate compressor with a higher compression level.

	// Create a buffer to write our archive to.
	buf := new(bytes.Buffer)

	// Create a new zip archive.
	w := zip.NewWriter(buf)

	// Register a custom Deflate compressor.
	w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
		return flate.NewWriter(out, flate.BestCompression)
	})

	// Proceed to add files to w.
}

類比這個(gè)案例可以寫出:

func main() {
	zf, _ := zip.OpenReader("")
	zf.RegisterDecompressor(zip.Deflate, func(r io.Reader) io.ReadCloser {
		
		// TODO:解密算法實(shí)現(xiàn)

		return flate.NewReader(r)
	})
}

接下來實(shí)現(xiàn)解密算法(官方鏈接:https://support.pkware.com/pkzip/appnote):

在這里插入圖片描述

zip標(biāo)準(zhǔn)文件:https://pkwaredownloads.blob.core.windows.net/pem/APPNOTE.txt,溫馨提示:不要機(jī)器翻譯成中文。

在這里插入圖片描述

ZIP 文件加密算法通常使用一種簡單的流加密方法,稱為 ZipCrypto。解密過程包括初始化三個(gè) 32 位整數(shù) key0, key1, 和 key2,并根據(jù)密碼和加密的字節(jié)數(shù)據(jù)更新這些值。加密和解密使用同樣的邏輯,只是加密是將明文轉(zhuǎn)換為密文,而解密是將密文轉(zhuǎn)換為明文。

type ZipCrypto struct {
    password []byte
    Keys     [3]uint32
}
 
func NewZipCrypto(passphrase []byte) *ZipCrypto {
    z := &ZipCrypto{}
    z.password = passphrase
    z.init()
    return z
}
 
func (z *ZipCrypto) init() {
    z.Keys[0] = 0x12345678
    z.Keys[1] = 0x23456789
    z.Keys[2] = 0x34567890
 
    for i := 0; i < len(z.password); i++ {
        z.updateKeys(z.password[i])
    }
}
 
func (z *ZipCrypto) updateKeys(byteValue byte) {
    z.Keys[0] = crc32update(z.Keys[0], byteValue)
    z.Keys[1] += z.Keys[0] & 0xff
    z.Keys[1] = z.Keys[1]*134775813 + 1
    z.Keys[2] = crc32update(z.Keys[2], (byte)(z.Keys[1]>>24))
}
 
func (z *ZipCrypto) magicByte() byte {
    var t uint32 = z.Keys[2] | 2
    return byte((t * (t ^ 1)) >> 8)
}
 
func (z *ZipCrypto) Encrypt(data []byte) []byte {
    length := len(data)
    chiper := make([]byte, length)
    for i := 0; i < length; i++ {
        v := data[i]
        chiper[i] = v ^ z.magicByte()
        z.updateKeys(v)
    }
    return chiper
}
 
func (z *ZipCrypto) Decrypt(chiper []byte) []byte {
    length := len(chiper)
    plain := make([]byte, length)
    for i, c := range chiper {
        v := c ^ z.magicByte()
        z.updateKeys(v)
        plain[i] = v
    }
    return plain
}
 
func crc32update(pCrc32 uint32, bval byte) uint32 {
    return crc32.IEEETable[(pCrc32^uint32(bval))&0xff] ^ (pCrc32 >> 8)
}

實(shí)現(xiàn)加密解密算法后寫一個(gè)小例子來測試下:

func main() {
	password := "generalzy"
	zc := NewZipCrypto(password)

	// 示例數(shù)據(jù)
	data := []byte("Hello, ZipCrypto!")
	fmt.Printf("Original: %s\n", data)

	// 加密數(shù)據(jù)
	encrypted := zc.Encrypt(data)
	fmt.Printf("Encrypted: %x\n", encrypted)

	// 初始化解密器
	zcDecrypt := NewZipCrypto(password)

	// 解密數(shù)據(jù)
	decrypted := zcDecrypt.Decrypt(encrypted)
	fmt.Printf("Decrypted: %s\n", decrypted)
}

在這里插入圖片描述

要利用 zip 包提供的注冊方法來注冊解密函數(shù),可以使用 RegisterDecompressor 方法。首先,需要擴(kuò)展之前的 ZipCrypto 實(shí)現(xiàn),使其能夠解密壓縮數(shù)據(jù)流。然后,可以將這個(gè)解密流注冊到 zip 包中。

最后給出整體代碼:

package main

import (
	"archive/zip"
	"bytes"
	"compress/flate"
	"fmt"
	"hash/crc32"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

type ZipCrypto struct {
	password []byte
	Keys     [3]uint32
}

func NewZipCrypto(passphrase []byte) *ZipCrypto {
	z := &ZipCrypto{}
	z.password = passphrase
	z.init()
	return z
}

func (z *ZipCrypto) init() {
	z.Keys[0] = 0x12345678
	z.Keys[1] = 0x23456789
	z.Keys[2] = 0x34567890

	for i := 0; i < len(z.password); i++ {
		z.updateKeys(z.password[i])
	}
}

func (z *ZipCrypto) updateKeys(byteValue byte) {
	z.Keys[0] = crc32update(z.Keys[0], byteValue)
	z.Keys[1] += z.Keys[0] & 0xff
	z.Keys[1] = z.Keys[1]*134775813 + 1
	z.Keys[2] = crc32update(z.Keys[2], (byte)(z.Keys[1]>>24))
}

func (z *ZipCrypto) magicByte() byte {
	var t uint32 = z.Keys[2] | 2
	return byte((t * (t ^ 1)) >> 8)
}

func (z *ZipCrypto) Encrypt(data []byte) []byte {
	length := len(data)
	chiper := make([]byte, length)
	for i := 0; i < length; i++ {
		v := data[i]
		chiper[i] = v ^ z.magicByte()
		z.updateKeys(v)
	}
	return chiper
}

func (z *ZipCrypto) Decrypt(chiper []byte) []byte {
	length := len(chiper)
	plain := make([]byte, length)
	for i, c := range chiper {
		v := c ^ z.magicByte()
		z.updateKeys(v)
		plain[i] = v
	}
	return plain
}

func crc32update(pCrc32 uint32, bval byte) uint32 {
	return crc32.IEEETable[(pCrc32^uint32(bval))&0xff] ^ (pCrc32 >> 8)
}

func ZipCryptoDecryptor(r *io.SectionReader, password []byte) (*io.SectionReader, error) {
	z := NewZipCrypto(password)
	b := make([]byte, r.Size())

	r.Read(b)

	m := z.Decrypt(b)
	return io.NewSectionReader(bytes.NewReader(m), 12, int64(len(m))), nil
}

type unzip struct {
	offset int64
	fp     *os.File
	name   string
}

func (uz *unzip) init() (err error) {
	uz.fp, err = os.Open(uz.name)
	return err
}

func (uz *unzip) close() {
	if uz.fp != nil {
		uz.fp.Close()
	}
}

func (uz *unzip) Size() int64 {
	if uz.fp == nil {
		if err := uz.init(); err != nil {
			return -1
		}
	}

	fi, err := uz.fp.Stat()
	if err != nil {
		return -1
	}

	return fi.Size() - uz.offset
}

func (uz *unzip) ReadAt(p []byte, off int64) (int, error) {
	if uz.fp == nil {
		if err := uz.init(); err != nil {
			return 0, err
		}
	}

	return uz.fp.ReadAt(p, off+uz.offset)
}


// DeCompressZip 解壓zip包
func DeCompressZip(zipFile, dest, passwd string, offset int64) error {
	uz := &unzip{offset: offset, name: zipFile}
	defer uz.close()

	zr, err := zip.NewReader(uz, uz.Size())
	if err != nil {
		return err
	}

	if passwd != "" {
		// Register a custom Deflate compressor.
		zr.RegisterDecompressor(zip.Deflate, func(r io.Reader) io.ReadCloser {
			rs := r.(*io.SectionReader)
			r, _ = ZipCryptoDecryptor(rs, []byte(passwd))
			return flate.NewReader(r)
		})

		zr.RegisterDecompressor(zip.Store, func(r io.Reader) io.ReadCloser {
			rs := r.(*io.SectionReader)
			r, _ = ZipCryptoDecryptor(rs, []byte(passwd))
			return ioutil.NopCloser(r)
		})
	}

	for _, f := range zr.File {
		fpath := filepath.Join(dest, f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, os.ModePerm)
			continue
		}

		if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
			return err
		}

		inFile, err := f.Open()
		if err != nil {
			return err
		}

		outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
		if err != nil {
			inFile.Close()
			return err
		}

		_, err = io.Copy(outFile, inFile)
		inFile.Close()
		outFile.Close()
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {
	err := DeCompressZip("Go.zip", "./tmp", "123456", 0)
	if err != nil {
		fmt.Println(err)
	}
	return
}

以上就是golang解壓帶密碼的zip包的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于golang解壓zip包的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang簡介與基本語法的學(xué)習(xí)

    Golang簡介與基本語法的學(xué)習(xí)

    這篇文章主要介紹了Golang簡介與基本語法的學(xué)習(xí),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • golang抓取tcp包的實(shí)現(xiàn)方式

    golang抓取tcp包的實(shí)現(xiàn)方式

    使用`golang`的`packet`和`pcap`庫可以抓取TCP數(shù)據(jù)包,首先,確保安裝了`pcap`庫,然后使用以下代碼打開網(wǎng)絡(luò)接口,設(shè)置過濾規(guī)則為“tcp”,開始捕獲并解析TCP數(shù)據(jù)包,運(yùn)行代碼時(shí)需要管理員權(quán)限
    2024-12-12
  • Go語言基礎(chǔ)變量的聲明及初始化示例詳解

    Go語言基礎(chǔ)變量的聲明及初始化示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)變量的聲明及初始化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步,早日升職加薪
    2021-11-11
  • golang?gorm的Callbacks事務(wù)回滾對象操作示例

    golang?gorm的Callbacks事務(wù)回滾對象操作示例

    這篇文章主要為大家介紹了golang?gorm的Callbacks事務(wù)回滾對象操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go基礎(chǔ)教程系列之?dāng)?shù)據(jù)類型詳細(xì)說明

    Go基礎(chǔ)教程系列之?dāng)?shù)據(jù)類型詳細(xì)說明

    這篇文章主要介紹了Go基礎(chǔ)教程系列之?dāng)?shù)據(jù)類型詳細(xì)說明,需要的朋友可以參考下
    2022-04-04
  • Go語言基礎(chǔ)go doc命令用法及示例詳解

    Go語言基礎(chǔ)go doc命令用法及示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)go doc命令的用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步
    2021-11-11
  • 使用go進(jìn)行云存儲上傳實(shí)現(xiàn)實(shí)例

    使用go進(jìn)行云存儲上傳實(shí)現(xiàn)實(shí)例

    這篇文章主要為大家介紹了使用go進(jìn)行云存儲上傳實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>
    2024-01-01
  • 基于Go語言實(shí)現(xiàn)應(yīng)用IP防火墻

    基于Go語言實(shí)現(xiàn)應(yīng)用IP防火墻

    在公司里面經(jīng)常會聽到某應(yīng)用有安全漏洞問題,沒有做安全加固,IP防火墻就是一個(gè)典型的安全加固解決方案,下面我們就來學(xué)習(xí)一下如何使用go語言實(shí)現(xiàn)IP防火墻吧
    2023-11-11
  • 一篇文章說清楚?go?get?使用私有庫的方法

    一篇文章說清楚?go?get?使用私有庫的方法

    這篇文章主要介紹了go?get?如何使用私有庫,本文會明確指出Git?、golang的配置項(xiàng),附送TortoiseGit?+?Git混合配置,需要的朋友可以參考下
    2022-09-09
  • Golang自定義開發(fā)Prometheus?exporter詳解

    Golang自定義開發(fā)Prometheus?exporter詳解

    Exporter是基于Prometheus實(shí)施的監(jiān)控系統(tǒng)中重要的組成部分,承擔(dān)數(shù)據(jù)指標(biāo)的采集工作,這篇文章主要為大家介紹了如何自定義編寫開發(fā)?Prometheus?exporter,感興趣的可以了解一下
    2023-06-06

最新評論