Lines 16-26
Link Here
|
16 |
==================================================================== */ |
16 |
==================================================================== */ |
17 |
package org.apache.poi.poifs.crypt; |
17 |
package org.apache.poi.poifs.crypt; |
18 |
|
18 |
|
|
|
19 |
import static org.apache.poi.poifs.crypt.AgileFunctions.generateIv; |
20 |
import static org.apache.poi.poifs.crypt.AgileFunctions.generateKey; |
21 |
import static org.apache.poi.poifs.crypt.AgileFunctions.hashPassword; |
22 |
|
19 |
import java.io.IOException; |
23 |
import java.io.IOException; |
20 |
import java.io.InputStream; |
24 |
import java.io.InputStream; |
21 |
import java.security.GeneralSecurityException; |
25 |
import java.security.GeneralSecurityException; |
22 |
import java.security.MessageDigest; |
26 |
import java.security.MessageDigest; |
23 |
import java.security.NoSuchAlgorithmException; |
|
|
24 |
import java.util.Arrays; |
27 |
import java.util.Arrays; |
25 |
|
28 |
|
26 |
import javax.crypto.Cipher; |
29 |
import javax.crypto.Cipher; |
Lines 62-100
Link Here
|
62 |
EncryptionVerifier verifier = _info.getVerifier(); |
65 |
EncryptionVerifier verifier = _info.getVerifier(); |
63 |
byte[] salt = verifier.getSalt(); |
66 |
byte[] salt = verifier.getSalt(); |
64 |
|
67 |
|
65 |
byte[] pwHash = hashPassword(_info, password); |
68 |
byte[] pwHash = hashPassword(password, verifier.getSalt(), verifier.getSpinCount()); |
66 |
byte[] iv = generateIv(salt, null); |
|
|
67 |
|
68 |
SecretKey skey; |
69 |
skey = new SecretKeySpec(generateKey(pwHash, kVerifierInputBlock), "AES"); |
70 |
Cipher cipher = getCipher(skey, iv); |
71 |
byte[] verifierHashInput = cipher.doFinal(verifier.getVerifier()); |
72 |
|
69 |
|
|
|
70 |
byte verfierInputEnc[] = hashInput(pwHash, kVerifierInputBlock, verifier.getVerifier(), salt.length); |
73 |
MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); |
71 |
MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); |
74 |
byte[] trimmed = new byte[salt.length]; |
72 |
byte[] hashedVerifier = sha1.digest(verfierInputEnc); |
75 |
System.arraycopy(verifierHashInput, 0, trimmed, 0, trimmed.length); |
|
|
76 |
byte[] hashedVerifier = sha1.digest(trimmed); |
77 |
|
78 |
skey = new SecretKeySpec(generateKey(pwHash, kHashedVerifierBlock), "AES"); |
79 |
iv = generateIv(salt, null); |
80 |
cipher = getCipher(skey, iv); |
81 |
byte[] verifierHash = cipher.doFinal(verifier.getVerifierHash()); |
82 |
trimmed = new byte[hashedVerifier.length]; |
83 |
System.arraycopy(verifierHash, 0, trimmed, 0, trimmed.length); |
84 |
|
73 |
|
|
|
74 |
byte trimmed[] = hashInput(pwHash, kHashedVerifierBlock, verifier.getVerifierHash(), hashedVerifier.length); |
75 |
|
85 |
if (Arrays.equals(trimmed, hashedVerifier)) { |
76 |
if (Arrays.equals(trimmed, hashedVerifier)) { |
86 |
skey = new SecretKeySpec(generateKey(pwHash, kCryptoKeyBlock), "AES"); |
77 |
byte keyspec[] = hashInput(pwHash, kCryptoKeyBlock, verifier.getEncryptedKey(), getKeySizeInBytes()); |
87 |
iv = generateIv(salt, null); |
78 |
_secretKey = new SecretKeySpec(keyspec, verifier.getAlgorithmName()); |
88 |
cipher = getCipher(skey, iv); |
|
|
89 |
byte[] inter = cipher.doFinal(verifier.getEncryptedKey()); |
90 |
byte[] keyspec = new byte[getKeySizeInBytes()]; |
91 |
System.arraycopy(inter, 0, keyspec, 0, keyspec.length); |
92 |
_secretKey = new SecretKeySpec(keyspec, "AES"); |
93 |
return true; |
79 |
return true; |
94 |
} else { |
80 |
} else { |
95 |
return false; |
81 |
return false; |
96 |
} |
82 |
} |
97 |
} |
83 |
} |
|
|
84 |
|
85 |
protected byte[] hashInput(byte pwHash[], byte blockKey[], byte inputKey[], int trimLength) |
86 |
throws GeneralSecurityException { |
87 |
EncryptionVerifier verifier = _info.getVerifier(); |
88 |
byte[] salt = verifier.getSalt(); |
89 |
|
90 |
byte key[] = generateKey(pwHash, blockKey, getKeySizeInBytes()); |
91 |
SecretKey skey = new SecretKeySpec(key, verifier.getAlgorithmName()); |
92 |
byte[] iv = generateIv(salt, null, getBlockSizeInBytes()); |
93 |
Cipher cipher = getCipher(skey, iv); |
94 |
byte[] verifierHashInput = cipher.doFinal(inputKey); |
95 |
|
96 |
byte[] trimmed = new byte[trimLength]; |
97 |
System.arraycopy(verifierHashInput, 0, trimmed, 0, trimLength); |
98 |
return trimmed; |
99 |
} |
98 |
|
100 |
|
99 |
public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { |
101 |
public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { |
100 |
DocumentInputStream dis = dir.createDocumentInputStream("EncryptedPackage"); |
102 |
DocumentInputStream dis = dir.createDocumentInputStream("EncryptedPackage"); |
Lines 180-186
Link Here
|
180 |
int index = (int)(_pos >> 12); |
182 |
int index = (int)(_pos >> 12); |
181 |
byte[] blockKey = new byte[4]; |
183 |
byte[] blockKey = new byte[4]; |
182 |
LittleEndian.putInt(blockKey, 0, index); |
184 |
LittleEndian.putInt(blockKey, 0, index); |
183 |
byte[] iv = generateIv(_info.getHeader().getKeySalt(), blockKey); |
185 |
byte[] iv = generateIv(_info.getHeader().getKeySalt(), blockKey, getBlockSizeInBytes()); |
184 |
_cipher.init(Cipher.DECRYPT_MODE, _secretKey, new IvParameterSpec(iv)); |
186 |
_cipher.init(Cipher.DECRYPT_MODE, _secretKey, new IvParameterSpec(iv)); |
185 |
if (_lastIndex != index) |
187 |
if (_lastIndex != index) |
186 |
_stream.skip((index - _lastIndex) << 12); |
188 |
_stream.skip((index - _lastIndex) << 12); |
Lines 193-220
Link Here
|
193 |
} |
195 |
} |
194 |
|
196 |
|
195 |
private Cipher getCipher(SecretKey key, byte[] vec) |
197 |
private Cipher getCipher(SecretKey key, byte[] vec) |
196 |
throws GeneralSecurityException { |
198 |
throws GeneralSecurityException { |
|
|
199 |
EncryptionVerifier verifier = _info.getVerifier(); |
197 |
|
200 |
|
198 |
String name = null; |
|
|
199 |
String chain = null; |
201 |
String chain = null; |
200 |
|
|
|
201 |
EncryptionVerifier verifier = _info.getVerifier(); |
202 |
|
203 |
switch (verifier.getAlgorithm()) { |
204 |
case EncryptionHeader.ALGORITHM_AES_128: |
205 |
case EncryptionHeader.ALGORITHM_AES_192: |
206 |
case EncryptionHeader.ALGORITHM_AES_256: |
207 |
name = "AES"; |
208 |
break; |
209 |
default: |
210 |
throw new EncryptedDocumentException("Unsupported algorithm"); |
211 |
} |
212 |
|
213 |
// Ensure the JCE policies files allow for this sized key |
214 |
if (Cipher.getMaxAllowedKeyLength(name) < _info.getHeader().getKeySize()) { |
215 |
throw new EncryptedDocumentException("Export Restrictions in place - please install JCE Unlimited Strength Jurisdiction Policy files"); |
216 |
} |
217 |
|
218 |
switch (verifier.getCipherMode()) { |
202 |
switch (verifier.getCipherMode()) { |
219 |
case EncryptionHeader.MODE_CBC: |
203 |
case EncryptionHeader.MODE_CBC: |
220 |
chain = "CBC"; |
204 |
chain = "CBC"; |
Lines 226-263
Link Here
|
226 |
throw new EncryptedDocumentException("Unsupported chain mode"); |
210 |
throw new EncryptedDocumentException("Unsupported chain mode"); |
227 |
} |
211 |
} |
228 |
|
212 |
|
|
|
213 |
String name = verifier.getAlgorithmName(); |
229 |
Cipher cipher = Cipher.getInstance(name + "/" + chain + "/NoPadding"); |
214 |
Cipher cipher = Cipher.getInstance(name + "/" + chain + "/NoPadding"); |
230 |
IvParameterSpec iv = new IvParameterSpec(vec); |
215 |
IvParameterSpec iv = new IvParameterSpec(vec); |
231 |
cipher.init(Cipher.DECRYPT_MODE, key, iv); |
216 |
cipher.init(Cipher.DECRYPT_MODE, key, iv); |
232 |
return cipher; |
217 |
return cipher; |
233 |
} |
218 |
} |
234 |
|
219 |
|
235 |
private byte[] getBlock(byte[] hash, int size) { |
|
|
236 |
byte[] result = new byte[size]; |
237 |
Arrays.fill(result, (byte)0x36); |
238 |
System.arraycopy(hash, 0, result, 0, Math.min(result.length, hash.length)); |
239 |
return result; |
240 |
} |
241 |
|
242 |
private byte[] generateKey(byte[] hash, byte[] blockKey) throws NoSuchAlgorithmException { |
243 |
MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); |
244 |
sha1.update(hash); |
245 |
byte[] key = sha1.digest(blockKey); |
246 |
return getBlock(key, getKeySizeInBytes()); |
247 |
} |
248 |
|
249 |
protected byte[] generateIv(byte[] salt, byte[] blockKey) |
250 |
throws NoSuchAlgorithmException { |
251 |
|
252 |
|
253 |
if (blockKey == null) |
254 |
return getBlock(salt, getBlockSizeInBytes()); |
255 |
|
256 |
MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); |
257 |
sha1.update(salt); |
258 |
return getBlock(sha1.digest(blockKey), getBlockSizeInBytes()); |
259 |
} |
260 |
|
261 |
protected int getBlockSizeInBytes() { |
220 |
protected int getBlockSizeInBytes() { |
262 |
return _info.getHeader().getBlockSize(); |
221 |
return _info.getHeader().getBlockSize(); |
263 |
} |
222 |
} |