android解压带密码的zip包

网上找到的资料,还没试过,谁要是试了回复下吧。

原文出自:http://blog.alutam.com/2009/10/31/reading-password-protected-zip-files-in-java/


On a recent “fun” project, I needed my application to be able to access password-protected zip files of a particular format. It was one of these features I thought will take me no time to implement. Anyway, to my surprise, neither JDK supports password-protected ZIP files, nor I was able to find a suitable Java open source library I could use for that purpose. So, I ended up writing the utility class on my own. I wrote an implementation of java.io.InputStream that filters the ZIP file data and turns a password-protected ZIP into an unprotected one on the fly – so the stream can be nicely chained with java.util.zip.ZipInputStream. Although the class is specifically targeted at the particular type of ZIP files I had to deal with (see the limitations below), maybe other people have to deal with the same type of files, or this class can provide a good start for others to turn it into a utility that would work with any type of ZIP (maybe I will do it myself some day – for now I don’t have time).
To implement this class I used the ZIP File Format Specification as the source of information. I also used the 7-zip project (C++) as a reference during the debugging to verify my understanding of the ZIP spec. and the CRC algorithm.
So, here is the class:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import java.io.IOException;
import java.io.InputStream;
 
public class ZipDecryptInputStream extends InputStream {
     private static final int [] CRC_TABLE = new int [ 256 ];
     // compute the table
     // (could also have it pre-computed - see http://snippets.dzone.com/tag/crc32)
     static {
         for ( int i = 0 ; i < 256 ; i++) {
             int r = i;
             for ( int j = 0 ; j < 8 ; j++) {
                 if ((r & 1 ) == 1 ) {
                     r = (r >>> 1 ) ^ 0xedb88320 ;
                 } else {
                     r >>>= 1 ;
                 }
             }
             CRC_TABLE[i] = r;
         }
     }
 
     private static final int DECRYPT_HEADER_SIZE = 12 ;
     private static final int [] LFH_SIGNATURE = { 0x50 , 0x4b , 0x03 , 0x04 };
 
     private final InputStream delegate;
     private final String password;
     private final int keys[] = new int [ 3 ];
 
     private State state = State.SIGNATURE;
     private int skipBytes;
     private int compressedSize;
     private int value;
     private int valuePos;
     private int valueInc;
 
     public ZipDecryptInputStream(InputStream stream, String password) {
         this .delegate = stream;
         this .password = password;
     }
 
     @Override
     public int read() throws IOException {
         int result = delegate.read();
         if (skipBytes == 0 ) {
             switch (state) {
                 case SIGNATURE:
                     if (result != LFH_SIGNATURE[valuePos]) {
                         state = State.TAIL;
                     } else {
                         valuePos++;
                         if (valuePos >= LFH_SIGNATURE.length) {
                             skipBytes = 2 ;
                             state = State.FLAGS;
                         }
                     }
                     break ;
                 case FLAGS:
                     if ((result & 1 ) == 0 ) {
                         throw new IllegalStateException( "ZIP not password protected." );
                     }
                     if ((result & 64 ) == 64 ) {
                         throw new IllegalStateException( "Strong encryption used." );
                     }
                     if ((result & 8 ) == 8 ) {
                         throw new IllegalStateException( "Unsupported ZIP format." );
                     }
                     result -= 1 ;
                     compressedSize = 0 ;
                     valuePos = 0 ;
                     valueInc = DECRYPT_HEADER_SIZE;
                     state = State.COMPRESSED_SIZE;
                     skipBytes = 11 ;
                     break ;
                 case COMPRESSED_SIZE:
                     compressedSize += result << ( 8 * valuePos);
                     result -= valueInc;
                     if (result < 0 ) {
                         valueInc = 1 ;
                         result += 256 ;
                     } else {
                         valueInc = 0 ;
                     }
                     valuePos++;
                     if (valuePos > 3 ) {
                         valuePos = 0 ;
                         value = 0 ;
                         state = State.FN_LENGTH;
                         skipBytes = 4 ;
                     }
                     break ;
                 case FN_LENGTH:
                 case EF_LENGTH:
                     value += result << 8 * valuePos;
                     if (valuePos == 1 ) {
                         valuePos = 0 ;
                         if (state == State.FN_LENGTH) {
                             state = State.EF_LENGTH;
                         } else {
                             state = State.HEADER;
                             skipBytes = value;
                         }
                     } else {
                         valuePos = 1 ;
                     }
                     break ;
                 case HEADER:
                     initKeys(password);
                     for ( int i = 0 ; i < DECRYPT_HEADER_SIZE; i++) {
                         updateKeys(( byte ) (result ^ decryptByte()));
                         result = delegate.read();
                     }
                     compressedSize -= DECRYPT_HEADER_SIZE;
                     state = State.DATA;
                     // intentionally no break
                 case DATA:
                     result = (result ^ decryptByte()) & 0xff ;
                     updateKeys(( byte ) result);
                     compressedSize--;
                     if (compressedSize == 0 ) {
                         valuePos = 0 ;
                         state = State.SIGNATURE;
                     }
                     break ;
                 case TAIL:
                     // do nothing
             }
         } else {
             skipBytes--;
         }
         return result;
     }
 
     @Override
     public void close() throws IOException {
         delegate.close();
         super .close();
     }
 
     private void initKeys(String password) {
         keys[ 0 ] = 305419896 ;
         keys[ 1 ] = 591751049 ;
         keys[ 2 ] = 878082192 ;
         for ( int i = 0 ; i < password.length(); i++) {
             updateKeys(( byte ) (password.charAt(i) & 0xff ));
         }
     }
 
     private void updateKeys( byte charAt) {
         keys[ 0 ] = crc32(keys[ 0 ], charAt);
         keys[ 1 ] += keys[ 0 ] & 0xff ;
         keys[ 1 ] = keys[ 1 ] * 134775813 + 1 ;
         keys[ 2 ] = crc32(keys[ 2 ], ( byte ) (keys[ 1 ] >> 24 ));
     }
 
     private byte decryptByte() {
         int temp = keys[ 2 ] | 2 ;
         return ( byte ) ((temp * (temp ^ 1 )) >>> 8 );
     }
 
     private int crc32( int oldCrc, byte charAt) {
         return ((oldCrc >>> 8 ) ^ CRC_TABLE[(oldCrc ^ charAt) & 0xff ]);
     }
 
     private static enum State {
         SIGNATURE, FLAGS, COMPRESSED_SIZE, FN_LENGTH, EF_LENGTH, HEADER, DATA, TAIL
     }
}

These are the limitations:

  • Only the “Traditional PKWARE Encryption” is supported (spec. section VII)
  • Files that have the “compressed length” information at the end of the data section (rather than at the beginning) are not supported (see “general purpose bit flag”, bit 3 in section V, subsection J in the spec.)

And this is how you can use it in your code:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
 
// usage: java Main [filename] [password]
public class Main {
     public static void main(String[] args) throws IOException {
         // password-protected zip file I need to read
         FileInputStream fis = new FileInputStream(args[ 0 ]);
         // wrap it in the decrypt stream
         ZipDecryptInputStream zdis = new ZipDecryptInputStream(fis, args[ 1 ]);
         // wrap the decrypt stream by the ZIP input stream
         ZipInputStream zis = new ZipInputStream(zdis);
 
         // read all the zip entries and save them as files
         ZipEntry ze;
         while ((ze = zis.getNextEntry()) != null ) {
             FileOutputStream fos = new FileOutputStream(ze.getName());
             int b;
             while ((b = zis.read()) != - 1 ) {
                 fos.write(b);
             }
             fos.close();
             zis.closeEntry();
         }
         zis.close();
     }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值