KickJava   Java API By Example, From Geeks To Geeks.

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


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.generators.DigestRandom;
20 import de.schlichtherle.crypto.modes.SICSeekableBlockCipher;
21 import de.schlichtherle.io.util.LEDataOutputStream;
22
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStream JavaDoc;
25
26 import org.bouncycastle.crypto.BufferedBlockCipher;
27 import org.bouncycastle.crypto.CipherParameters;
28 import org.bouncycastle.crypto.Digest;
29 import org.bouncycastle.crypto.Mac;
30 import org.bouncycastle.crypto.PBEParametersGenerator;
31 import org.bouncycastle.crypto.digests.SHA256Digest;
32 import org.bouncycastle.crypto.engines.AESFastEngine;
33 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
34 import org.bouncycastle.crypto.io.MacOutputStream;
35 import org.bouncycastle.crypto.macs.HMac;
36 import org.bouncycastle.crypto.params.KeyParameter;
37 import org.bouncycastle.crypto.params.ParametersWithIV;
38
39 /**
40  * Writes a type 0 RAES file.
41  *
42  * @author Christian Schlichtherle
43  * @version @version@
44  * @since TrueZIP 6.0
45  */

46 class Type0RaesOutputStream extends RaesOutputStream {
47
48     /**
49      * The iteration count for the derived keys of the cipher, KLAC and MAC.
50      */

51     final static int ITERATION_COUNT = 2005; // The RAES epoch :-)
52

53     /** The actual key strength in bits. */
54     private int keyStrengthBits;
55
56     /** The Message Authentication Code (MAC). */
57     private Mac mac;
58
59     /** The cipher Key and cipher text Length Authentication Code (KLAC). */
60     private Mac klac;
61
62     /**
63      * The low level data output stream.
64      * Used for writing the header and footer.
65      **/

66     private LEDataOutputStream dos;
67
68     /** The offset where the encrypted application data starts. */
69     private long start;
70
71     /** Whether this stream has been closed or not. */
72     private boolean closed;
73     
74     Type0RaesOutputStream(
75             final OutputStream out,
76             final Type0RaesParameters parameters)
77     throws NullPointerException JavaDoc,
78             IllegalArgumentException JavaDoc,
79             RaesKeyException,
80             IOException JavaDoc{
81         super(out, null);
82
83         assert out != null;
84         assert parameters != null;
85
86         // Check parameters (fail fast).
87
final char[] passwd = parameters.getCreatePasswd();
88         if (passwd == null)
89             throw new RaesKeyException();
90         final int keyStrength = parameters.getKeyStrength();
91         if (keyStrength != Type0RaesParameters.KEY_STRENGTH_128
92                 && keyStrength != Type0RaesParameters.KEY_STRENGTH_192
93                 && keyStrength != Type0RaesParameters.KEY_STRENGTH_256)
94             throw new IllegalArgumentException JavaDoc(
95                     "Illegal cipher key strength: "
96                     + keyStrength
97                     + "!");
98
99         // Init digest for salt and key generation and KLAC.
100
final Digest digest = new SHA256Digest();
101
102         // Init key strength info and salt.
103
final int keyStrengthBytes = 16 + keyStrength * 8;
104         keyStrengthBits = keyStrengthBytes * 8; // key strength in bits
105
assert digest.getDigestSize() >= keyStrengthBytes;
106         final byte[] salt = new byte[keyStrengthBytes];
107         new DigestRandom(digest).nextBytes(salt);
108
109         // Init PBE parameters.
110
final PBEParametersGenerator paramGen
111                 = new PKCS12ParametersGenerator(digest);
112         final byte[] pass = PBEParametersGenerator.PKCS12PasswordToBytes(passwd);
113         for (int i = passwd.length; --i >= 0; ) // nullify password parameter
114
passwd[i] = 0;
115
116         paramGen.init(pass, salt, ITERATION_COUNT);
117         // Order is important here, because paramGen does not properly
118
// reset the digest object!
119
final ParametersWithIV cipherParam
120                 = (ParametersWithIV) paramGen.generateDerivedParameters(
121                     keyStrengthBits, AES_BLOCK_SIZE);
122         final CipherParameters macParam
123                 = paramGen.generateDerivedMacParameters(keyStrengthBits);
124         for (int i = pass.length; --i >= 0; ) // nullify password buffer
125
pass[i] = 0;
126
127         // Init cipher.
128
final BufferedBlockCipher cipher = new BufferedBlockCipher(
129                     new SICSeekableBlockCipher(
130                         new AESFastEngine()));
131         cipher.init(true, cipherParam);
132
133         // Init MAC.
134
mac = new HMac(new SHA256Digest());
135         mac.init(macParam);
136
137         // Init KLAC.
138
klac = new HMac(digest);
139         klac.init(macParam);
140         final byte[] cipherKey
141                 = ((KeyParameter) cipherParam.getParameters()).getKey();
142         klac.update(cipherKey, 0, cipherKey.length);
143         
144         // Init stream chain.
145
dos = new LEDataOutputStream(out);
146         this.out = new MacOutputStream(dos, mac);
147
148         // Write data envelope header.
149
dos.writeInt(RAES_SIGNATURE);
150         dos.writeByte(ENVELOPE_TYPE_0);
151         dos.writeByte(keyStrength);
152         dos.writeShort(ITERATION_COUNT);
153         dos.write(salt);
154
155         // Init start.
156
start = dos.size();
157         assert start == ENVELOPE_TYPE_0_HEADER_LEN_WO_SALT + salt.length;
158         
159         // Now that everything went OK, finally init the super class cipher.
160
this.cipher = cipher;
161     }
162
163     public int getKeySizeBits() {
164         return keyStrengthBits;
165     }
166
167     public void close() throws IOException JavaDoc {
168         // Order is important here!
169
if (!closed) {
170             closed = true;
171             try {
172                 // Flush partial block to out, if any.
173
finish();
174
175                 final long trailer = dos.size();
176
177                 assert mac.getMacSize() == klac.getMacSize();
178                 final byte[] buf = new byte[mac.getMacSize()]; // authentication code buffer
179
int bufLen;
180
181                 // Calculate and write KLAC to data envelope trailer.
182
// Please note that we will only use the first half of the
183
// authentication code for security reasons.
184
final long length = trailer - start; // message length
185
klac(klac, length, buf);
186                 dos.write(buf, 0, buf.length / 2);
187
188                 // Calculate and write MAC to data envelope trailer.
189
// Again, we will only use the first half of the
190
// authentication code for security reasons.
191
bufLen = mac.doFinal(buf, 0);
192                 assert bufLen == buf.length;
193                 dos.write(buf, 0, buf.length / 2);
194
195                 assert dos.size() - trailer == buf.length;
196             } finally {
197                 super.close();
198             }
199         }
200     }
201 }
202
Popular Tags