KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > crypto > io > raes > Type0RaesReadOnlyFile


1 /*
2  * Copyright 2005-2006 Schlichtherle IT Services
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package de.schlichtherle.crypto.io.raes;
18
19 import de.schlichtherle.crypto.SeekableBlockCipher;
20 import de.schlichtherle.crypto.modes.SICSeekableBlockCipher;
21 import de.schlichtherle.io.rof.FilterReadOnlyFile;
22 import de.schlichtherle.io.rof.ReadOnlyFile;
23 import de.schlichtherle.util.Arrays;
24
25 import java.io.FileNotFoundException JavaDoc;
26 import java.io.IOException JavaDoc;
27
28 import org.bouncycastle.crypto.CipherParameters;
29 import org.bouncycastle.crypto.Digest;
30 import org.bouncycastle.crypto.Mac;
31 import org.bouncycastle.crypto.PBEParametersGenerator;
32 import org.bouncycastle.crypto.digests.SHA256Digest;
33 import org.bouncycastle.crypto.engines.AESFastEngine;
34 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
35 import org.bouncycastle.crypto.macs.HMac;
36 import org.bouncycastle.crypto.params.KeyParameter;
37 import org.bouncycastle.crypto.params.ParametersWithIV;
38
39 /**
40  * Reads a type 0 RAES file.
41  *
42  * @author Christian Schlichtherle
43  * @version @version@
44  * @since TrueZIP 6.0
45  */

46 class Type0RaesReadOnlyFile extends RaesReadOnlyFile {
47
48     /**
49      * The minimum delay between subsequent attempts to authenticate a key
50      * in milliseconds.
51      */

52     private static final long MIN_KEY_RETRY_DELAY = 3 * 1000;
53
54     /** The key strength. */
55     private final int keyStrength;
56
57     /**
58      * The parameters required to init the Message Authentication Code (MAC).
59      */

60     private final CipherParameters macParam;
61
62     /**
63      * The footer of the data envelope containing the authentication codes.
64      */

65     private final byte[] footer;
66
67     Type0RaesReadOnlyFile(
68             final ReadOnlyFile rof,
69             final Type0RaesParameters parameters)
70     throws NullPointerException JavaDoc,
71             FileNotFoundException JavaDoc,
72             RaesException,
73             RaesKeyException,
74             IOException JavaDoc {
75         super(rof);
76
77         assert rof != null;
78         assert parameters != null;
79
80         // Load header data.
81
final byte[] header = new byte[ENVELOPE_TYPE_0_HEADER_LEN_WO_SALT];
82         final long fileLength = rof.length();
83         rof.seek(0);
84         rof.readFully(header);
85
86         // Check key size and iteration count
87
keyStrength = parseUByte(header, 5);
88         if (keyStrength != Type0RaesParameters.KEY_STRENGTH_128
89                 && keyStrength != Type0RaesParameters.KEY_STRENGTH_192
90                 && keyStrength != Type0RaesParameters.KEY_STRENGTH_256)
91             throw new RaesException(
92                     "Unknown index for cipher key strength: "
93                     + keyStrength
94                     + "!");
95         final int keyLen = 16 + keyStrength * 8; // key strength in bytes: 16, 24 or 32
96
final int keySize = keyLen * 8; // key strength in bits
97
final int iCount = parseUShort(header, 6);
98         if (iCount < 1024)
99             throw new RaesException(
100                     "Iteration count must be 1024 or greater, but is "
101                     + iCount
102                     + "!");
103
104         // Init start of encrypted data.
105
final long start = header.length + keyLen;
106
107         // Load salt.
108
final byte[] salt = new byte[keyLen];
109         rof.readFully(salt);
110
111         // Init digest for key generation and KLAC.
112
final Digest digest = new SHA256Digest();
113
114         // Load footer data
115
footer = new byte[digest.getDigestSize()];
116         final long end = fileLength - footer.length;
117         rof.seek(end);
118         rof.readFully(footer);
119         if (this.rof.read() != -1) {
120             // This should never happen unless someone is writing to the
121
// end of the file concurrently!
122
throw new RaesException(
123                     "Expected end of file after data envelope trailer!");
124         }
125
126         // Init encrypted data length.
127
final long length = fileLength - footer.length - start;
128
129         // Init PBE parameters.
130
final PBEParametersGenerator paramGen
131                 = new PKCS12ParametersGenerator(digest);
132         ParametersWithIV cipherParam;
133         CipherParameters macParam;
134         long lastTry = 0; // don't enforce suspension on first prompt!
135
while (true) {
136             final char[] passwd = parameters.getOpenPasswd();
137             if (passwd == null) // for compatibility to old implementations
138
throw new RaesKeyException();
139             final byte[] pass
140                     = PBEParametersGenerator.PKCS12PasswordToBytes(passwd);
141             for (int i = passwd.length; --i >= 0; ) // nullify password parameter
142
passwd[i] = 0;
143
144             paramGen.init(pass, salt, iCount);
145             cipherParam
146                     = (ParametersWithIV) paramGen.generateDerivedParameters(
147                         keySize, AES_BLOCK_SIZE);
148             macParam = paramGen.generateDerivedMacParameters(keySize);
149             for (int i = pass.length; --i >= 0; ) // nullify password buffer
150
pass[i] = 0;
151
152             // Init and verify KLAC.
153
final Mac klac = new HMac(digest);
154             klac.init(macParam);
155             final byte[] cipherKey
156                     = ((KeyParameter) cipherParam.getParameters()).getKey();
157             klac.update(cipherKey, 0, cipherKey.length);
158             final byte[] buf = new byte[klac.getMacSize()];
159             RaesOutputStream.klac(klac, length, buf);
160             digest.reset(); // klac.doFinal(...) doesn't do this!
161

162             lastTry = enforceSuspensionPenalty(lastTry);
163
164             if (Arrays.equals(footer, 0, buf, 0, buf.length / 2)) {
165                 parameters.setKeyStrength(keyStrength);
166                 break;
167             }
168
169             parameters.invalidOpenPasswd();
170         }
171
172         this.macParam = macParam;
173
174         // Init cipher.
175
final SeekableBlockCipher cipher = new SICSeekableBlockCipher(new AESFastEngine());
176         cipher.init(false, cipherParam);
177
178         init(cipher, start, length);
179     }
180
181     private static long enforceSuspensionPenalty(final long last) {
182         long delay;
183         InterruptedException JavaDoc interrupted = null;
184         while ((delay = System.currentTimeMillis() - last) < MIN_KEY_RETRY_DELAY) {
185             try {
186                 Thread.sleep(MIN_KEY_RETRY_DELAY - delay);
187             } catch (InterruptedException JavaDoc ex) {
188                 interrupted = ex;
189             }
190         }
191         if (interrupted != null)
192             Thread.currentThread().interrupt();
193         return last + delay;
194     }
195
196     public int getKeySizeBits() {
197         return 128 + keyStrength * 64;
198     }
199
200     public void authenticate()
201     throws RaesAuthenticationException, IOException JavaDoc {
202         final Mac mac = new HMac(new SHA256Digest());
203         mac.init(macParam);
204
205         final byte[] buf = computeMac(mac);
206
207         if (!Arrays.equals(footer, footer.length / 2, buf, 0, buf.length / 2))
208             throw new RaesAuthenticationException();
209     }
210 }
211
Popular Tags