View | Details | Raw Unified | Return to bug 55818
Collapse All | Expand All

(-)src/java/org/apache/poi/poifs/crypt/AgileDecryptor.java (-72 / +31 lines)
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
    }
(-)src/java/org/apache/poi/poifs/crypt/AgileEncryptor.java (+25 lines)
Line 0 Link Here
1
package org.apache.poi.poifs.crypt;
2
3
import java.io.IOException;
4
import java.io.OutputStream;
5
import java.security.GeneralSecurityException;
6
7
import org.apache.poi.poifs.filesystem.DirectoryNode;
8
9
public class AgileEncryptor extends Encryptor {
10
    private final EncryptionInfo _info;
11
	
12
	protected AgileEncryptor(EncryptionInfo info) {
13
		_info = info;
14
	}
15
	
16
	public void confirmPassword(String password) throws GeneralSecurityException {
17
		
18
	}
19
	
20
    public OutputStream getDataStream(DirectoryNode dir)
21
            throws IOException, GeneralSecurityException {
22
    	return null;
23
    }
24
25
}
(-)src/java/org/apache/poi/poifs/crypt/AgileFunctions.java (+96 lines)
Line 0 Link Here
1
package org.apache.poi.poifs.crypt;
2
3
import java.io.UnsupportedEncodingException;
4
import java.security.DigestException;
5
import java.security.GeneralSecurityException;
6
import java.security.MessageDigest;
7
import java.security.NoSuchAlgorithmException;
8
import java.util.Arrays;
9
10
import javax.crypto.Cipher;
11
import javax.crypto.SecretKey;
12
import javax.crypto.spec.IvParameterSpec;
13
14
import org.apache.poi.EncryptedDocumentException;
15
import org.apache.poi.util.LittleEndian;
16
import org.apache.poi.util.LittleEndianConsts;
17
18
public class AgileFunctions {
19
    public static byte[] hashPassword(String password, byte salt[], int spinCount) throws NoSuchAlgorithmException {
20
        // If no password was given, use the default
21
        if (password == null) {
22
            password = Decryptor.DEFAULT_PASSWORD;
23
        }
24
        
25
        byte[] pass;
26
        try {
27
            pass = password.getBytes("UTF-16LE");
28
        } catch (UnsupportedEncodingException e) {
29
            throw new EncryptedDocumentException("UTF16 not supported");
30
        }
31
        
32
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
33
        sha1.update(salt);
34
        byte[] hash = sha1.digest(pass);
35
        byte[] iterator = new byte[LittleEndianConsts.INT_SIZE];
36
        
37
        try {
38
            for (int i = 0; i < spinCount; i++) {
39
                LittleEndian.putInt(iterator, 0, i);
40
                sha1.reset();
41
                sha1.update(iterator);
42
                sha1.update(hash);
43
                sha1.digest(hash, 0, hash.length); // don't create hash buffer everytime new
44
            }
45
        } catch (DigestException e) {
46
            throw new EncryptedDocumentException("error in password hashing");
47
        }
48
        
49
        return hash;
50
    }    
51
52
    public static byte[] generateIv(byte[] salt, byte[] blockKey, int blockSize)
53
        throws NoSuchAlgorithmException {
54
55
        if (blockKey == null)
56
            return getBlock(salt, blockSize);
57
58
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
59
        sha1.update(salt);
60
        return getBlock(sha1.digest(blockKey), blockSize);
61
    }
62
63
    public static byte[] generateKey(byte[] passwordHash, byte[] blockKey, int keySize) throws NoSuchAlgorithmException {
64
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
65
        sha1.update(passwordHash);
66
        byte[] key = sha1.digest(blockKey);
67
        return getBlock(key, keySize);
68
    }
69
70
    public static Cipher getCipher(SecretKey key, String chain, byte[] vec)
71
    throws GeneralSecurityException {
72
        int keySizeInBytes = key.getEncoded().length;
73
        
74
        // Ensure the JCE policies files allow for this sized key
75
        if (Cipher.getMaxAllowedKeyLength(key.getAlgorithm()) < keySizeInBytes) {
76
            throw new EncryptedDocumentException("Export Restrictions in place - please install JCE Unlimited Strength Jurisdiction Policy files");
77
        }
78
        
79
        Cipher cipher = Cipher.getInstance(key.getAlgorithm() + "/" + chain + "/NoPadding");
80
        if (vec == null) {
81
            cipher.init(Cipher.DECRYPT_MODE, key);
82
        } else {
83
            IvParameterSpec iv = new IvParameterSpec(vec);
84
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
85
        }
86
        return cipher;
87
    }    
88
    
89
    public static byte[] getBlock(byte[] hash, int size) {
90
        byte[] result = new byte[size];
91
        Arrays.fill(result, (byte)0x36);
92
        System.arraycopy(hash, 0, result, 0, Math.min(result.length, hash.length));
93
        return result;
94
    }
95
96
}
(-)src/java/org/apache/poi/poifs/crypt/Decryptor.java (-44 / +3 lines)
Lines 18-34 Link Here
18
18
19
import java.io.IOException;
19
import java.io.IOException;
20
import java.io.InputStream;
20
import java.io.InputStream;
21
import java.io.UnsupportedEncodingException;
22
import java.security.DigestException;
23
import java.security.MessageDigest;
24
import java.security.GeneralSecurityException;
21
import java.security.GeneralSecurityException;
25
import java.security.NoSuchAlgorithmException;
22
23
import org.apache.poi.EncryptedDocumentException;
24
import org.apache.poi.poifs.filesystem.DirectoryNode;
26
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
25
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
27
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
26
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
28
import org.apache.poi.poifs.filesystem.DirectoryNode;
29
import org.apache.poi.EncryptedDocumentException;
30
import org.apache.poi.util.LittleEndian;
31
import org.apache.poi.util.LittleEndianConsts;
32
27
33
public abstract class Decryptor {
28
public abstract class Decryptor {
34
    public static final String DEFAULT_PASSWORD="VelvetSweatshop";
29
    public static final String DEFAULT_PASSWORD="VelvetSweatshop";
Lines 86-125 Link Here
86
    public InputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
81
    public InputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
87
        return getDataStream(fs.getRoot());
82
        return getDataStream(fs.getRoot());
88
    }
83
    }
89
90
    protected byte[] hashPassword(EncryptionInfo info,
91
                                  String password) throws NoSuchAlgorithmException {
92
        // If no password was given, use the default
93
        if (password == null) {
94
            password = DEFAULT_PASSWORD;
95
        }
96
        
97
        byte[] pass;
98
        try {
99
            pass = password.getBytes("UTF-16LE");
100
        } catch (UnsupportedEncodingException e) {
101
            throw new EncryptedDocumentException("UTF16 not supported");
102
        }
103
104
        byte[] salt = info.getVerifier().getSalt();
105
        
106
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
107
        sha1.update(salt);
108
        byte[] hash = sha1.digest(pass);
109
        byte[] iterator = new byte[LittleEndianConsts.INT_SIZE];
110
        
111
        try {
112
        for (int i = 0; i < info.getVerifier().getSpinCount(); i++) {
113
        	LittleEndian.putInt(iterator, 0, i);
114
            sha1.reset();
115
            sha1.update(iterator);
116
            sha1.update(hash);
117
            sha1.digest(hash, 0, hash.length); // don't create hash buffer everytime new
118
        }
119
        } catch (DigestException e) {
120
        	throw new EncryptedDocumentException("error in password hashing");
121
        }
122
        
123
        return hash;
124
    }
125
}
84
}
(-)src/java/org/apache/poi/poifs/crypt/EcmaDecryptor.java (-45 / +43 lines)
Lines 16-21 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.hashPassword;
20
19
import java.io.IOException;
21
import java.io.IOException;
20
import java.io.InputStream;
22
import java.io.InputStream;
21
import java.security.GeneralSecurityException;
23
import java.security.GeneralSecurityException;
Lines 36-97 Link Here
36
 */
38
 */
37
public class EcmaDecryptor extends Decryptor {
39
public class EcmaDecryptor extends Decryptor {
38
    private final EncryptionInfo info;
40
    private final EncryptionInfo info;
39
    private byte[] passwordHash;
41
    private SecretKey _secretKey;
42
    // private byte[] passwordHash;
40
    private long _length = -1;
43
    private long _length = -1;
41
44
42
    public EcmaDecryptor(EncryptionInfo info) {
45
    public EcmaDecryptor(EncryptionInfo info) {
43
        this.info = info;
46
        this.info = info;
44
    }
47
    }
45
48
46
    private byte[] generateKey(int block) throws NoSuchAlgorithmException {
49
    public boolean verifyPassword(String password) throws GeneralSecurityException {
47
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
50
        EncryptionVerifier verifier = info.getVerifier();
48
51
        byte passwordHash[] = hashPassword(password, verifier.getSalt(), verifier.getSpinCount());
49
        sha1.update(passwordHash);
50
        byte[] blockValue = new byte[4];
51
        LittleEndian.putInt(blockValue, 0, block);
52
        byte[] finalHash = sha1.digest(blockValue);
53
52
54
        int requiredKeyLength = info.getHeader().getKeySize()/8;
53
        byte[] blockKey = new byte[4];
54
        LittleEndian.putInt(blockKey, 0, 0);
55
55
56
        byte[] buff = new byte[64];
56
        byte[] finalHash = AgileFunctions.generateKey(passwordHash, blockKey, 20);
57
        byte x1[] = fillAndXor(finalHash, (byte) 0x36);
58
        byte x2[] = fillAndXor(finalHash, (byte) 0x5c);
57
59
58
        Arrays.fill(buff, (byte) 0x36);
60
        byte[] x3 = new byte[x1.length + x2.length];
61
        System.arraycopy(x1, 0, x3, 0, x1.length);
62
        System.arraycopy(x2, 0, x3, x1.length, x2.length);
59
63
60
        for (int i=0; i<finalHash.length; i++) {
64
        byte[] key = truncateOrPad(x3, getKeySizeInBytes());
61
            buff[i] = (byte) (buff[i] ^ finalHash[i]);
62
        }
63
65
64
        sha1.reset();
66
        SecretKey skey = new SecretKeySpec(key, verifier.getAlgorithmName());
65
        byte[] x1 = sha1.digest(buff);
67
        Cipher cipher = getCipher(skey);
66
68
67
        Arrays.fill(buff, (byte) 0x5c);
69
        byte[] verifierEncrypted = cipher.doFinal(verifier.getVerifier());
68
        for (int i=0; i<finalHash.length; i++) {
69
            buff[i] = (byte) (buff[i] ^ finalHash[i]);
70
        }
71
70
72
        sha1.reset();
71
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
73
        byte[] x2 = sha1.digest(buff);
72
        byte[] calcVerifierHash = sha1.digest(verifierEncrypted);
74
73
75
        byte[] x3 = new byte[x1.length + x2.length];
74
        byte[] verifierHash = truncateOrPad(cipher.doFinal(verifier.getVerifierHash()), calcVerifierHash.length);
76
        System.arraycopy(x1, 0, x3, 0, x1.length);
77
        System.arraycopy(x2, 0, x3, x1.length, x2.length);
78
75
79
        return truncateOrPad(x3, requiredKeyLength);
76
        if (Arrays.equals(calcVerifierHash, verifierHash)) {
77
            _secretKey = skey;
78
            return true;
79
        } else {
80
            return false;
81
        }
80
    }
82
    }
81
83
82
    public boolean verifyPassword(String password) throws GeneralSecurityException {
84
    private static byte[] fillAndXor(byte hash[], byte fillByte) throws NoSuchAlgorithmException {
83
        passwordHash = hashPassword(info, password);
85
        byte[] buff = new byte[64];
84
86
        Arrays.fill(buff, fillByte);
85
        Cipher cipher = getCipher();
86
87
87
        byte[] verifier = cipher.doFinal(info.getVerifier().getVerifier());
88
        for (int i=0; i<hash.length; i++) {
89
            buff[i] = (byte) (buff[i] ^ hash[i]);
90
        }
88
91
89
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
92
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
90
        byte[] calcVerifierHash = sha1.digest(verifier);
93
        return sha1.digest(buff);
91
92
        byte[] verifierHash = truncateOrPad(cipher.doFinal(info.getVerifier().getVerifierHash()), calcVerifierHash.length);
93
94
        return Arrays.equals(calcVerifierHash, verifierHash);
95
    }
94
    }
96
95
97
    /**
96
    /**
Lines 99-105 Link Here
99
     *  truncated or zero padded as needed.
98
     *  truncated or zero padded as needed.
100
     * Behaves like Arrays.copyOf in Java 1.6
99
     * Behaves like Arrays.copyOf in Java 1.6
101
     */
100
     */
102
    private byte[] truncateOrPad(byte[] source, int length) {
101
    private static byte[] truncateOrPad(byte[] source, int length) {
103
       byte[] result = new byte[length];
102
       byte[] result = new byte[length];
104
       System.arraycopy(source, 0, result, 0, Math.min(length, source.length));
103
       System.arraycopy(source, 0, result, 0, Math.min(length, source.length));
105
       if(length > source.length) {
104
       if(length > source.length) {
Lines 110-122 Link Here
110
       return result;
109
       return result;
111
    }
110
    }
112
111
113
    private Cipher getCipher() throws GeneralSecurityException {
112
    private static Cipher getCipher(SecretKey key) throws GeneralSecurityException {
114
        byte[] key = generateKey(0);
113
        return AgileFunctions.getCipher(key, "ECB", null);
115
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
116
        SecretKey skey = new SecretKeySpec(key, "AES");
117
        cipher.init(Cipher.DECRYPT_MODE, skey);
118
119
        return cipher;
120
    }
114
    }
121
115
122
    public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
116
    public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException {
Lines 124-134 Link Here
124
118
125
        _length = dis.readLong();
119
        _length = dis.readLong();
126
120
127
        return new CipherInputStream(dis, getCipher());
121
        return new CipherInputStream(dis, getCipher(_secretKey));
128
    }
122
    }
129
123
130
    public long getLength(){
124
    public long getLength(){
131
        if(_length == -1) throw new IllegalStateException("EcmaDecryptor.getDataStream() was not called");
125
        if(_length == -1) throw new IllegalStateException("EcmaDecryptor.getDataStream() was not called");
132
        return _length;
126
        return _length;
133
    }
127
    }
128
129
    protected int getKeySizeInBytes() {
130
        return info.getHeader().getKeySize()/8;
131
    }
134
}
132
}
(-)src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java (-8 / +14 lines)
Lines 35-43 Link Here
35
    private final byte[] verifier;
35
    private final byte[] verifier;
36
    private final byte[] verifierHash;
36
    private final byte[] verifierHash;
37
    private final byte[] encryptedKey;
37
    private final byte[] encryptedKey;
38
    private final int verifierHashSize;
38
    // private final int verifierHashSize;
39
    private final int spinCount;
39
    private final int spinCount;
40
    private final int algorithm;
40
    private final int algorithm;
41
    private final String algorithmName;
41
    private final int cipherMode;
42
    private final int cipherMode;
42
43
43
    public EncryptionVerifier(String descriptor) {
44
    public EncryptionVerifier(String descriptor) {
Lines 82-96 Link Here
82
                                           .getNamedItem("encryptedVerifierHashValue")
83
                                           .getNamedItem("encryptedVerifierHashValue")
83
                                           .getNodeValue().getBytes());
84
                                           .getNodeValue().getBytes());
84
85
85
        int blockSize = Integer.parseInt(keyData.getNamedItem("blockSize")
86
        // int blockSize = Integer.parseInt(keyData.getNamedItem("blockSize")
86
                                         .getNodeValue());
87
        //                                 .getNodeValue());
87
88
88
        String alg = keyData.getNamedItem("cipherAlgorithm").getNodeValue();
89
        algorithmName = keyData.getNamedItem("cipherAlgorithm").getNodeValue();
89
        
90
        
90
        int keyBits = Integer.parseInt(keyData.getNamedItem("keyBits")
91
        int keyBits = Integer.parseInt(keyData.getNamedItem("keyBits")
91
                .getNodeValue());
92
                .getNodeValue());
92
93
93
        if ("AES".equals(alg)) {
94
        if ("AES".equals(algorithmName)) {
94
        	switch (keyBits) {
95
        	switch (keyBits) {
95
              case 128: 
96
              case 128: 
96
                  algorithm = EncryptionHeader.ALGORITHM_AES_128; break;
97
                  algorithm = EncryptionHeader.ALGORITHM_AES_128; break;
Lines 113-120 Link Here
113
        else
114
        else
114
            throw new EncryptedDocumentException("Unsupported chaining mode");
115
            throw new EncryptedDocumentException("Unsupported chaining mode");
115
116
116
        verifierHashSize = Integer.parseInt(keyData.getNamedItem("hashSize")
117
        //verifierHashSize = Integer.parseInt(keyData.getNamedItem("hashSize")
117
                                            .getNodeValue());
118
        //                                    .getNodeValue());
118
    }
119
    }
119
120
120
    public EncryptionVerifier(DocumentInputStream is, int encryptedLength) {
121
    public EncryptionVerifier(DocumentInputStream is, int encryptedLength) {
Lines 129-141 Link Here
129
        verifier = new byte[16];
130
        verifier = new byte[16];
130
        is.readFully(verifier);
131
        is.readFully(verifier);
131
132
132
        verifierHashSize = is.readInt();
133
        int verifierHashSize = is.readInt();
133
134
134
        verifierHash = new byte[encryptedLength];
135
        verifierHash = new byte[encryptedLength];
135
        is.readFully(verifierHash);
136
        is.readFully(verifierHash);
136
137
137
        spinCount = 50000;
138
        spinCount = 50000;
138
        algorithm = EncryptionHeader.ALGORITHM_AES_128;
139
        algorithm = EncryptionHeader.ALGORITHM_AES_128;
140
        algorithmName = "AES";
139
        cipherMode = EncryptionHeader.MODE_ECB;
141
        cipherMode = EncryptionHeader.MODE_ECB;
140
        encryptedKey = null;
142
        encryptedKey = null;
141
    }
143
    }
Lines 164-169 Link Here
164
        return algorithm;
166
        return algorithm;
165
    }
167
    }
166
168
169
    public String getAlgorithmName() {
170
        return algorithmName;
171
    }
172
167
    public byte[] getEncryptedKey() {
173
    public byte[] getEncryptedKey() {
168
        return encryptedKey;
174
        return encryptedKey;
169
    }
175
    }
(-)src/java/org/apache/poi/poifs/crypt/Encryptor.java (+53 lines)
Line 0 Link Here
1
package org.apache.poi.poifs.crypt;
2
3
import java.io.IOException;
4
import java.io.OutputStream;
5
import java.security.GeneralSecurityException;
6
7
import org.apache.poi.EncryptedDocumentException;
8
import org.apache.poi.poifs.filesystem.DirectoryNode;
9
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
10
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
11
12
public abstract class Encryptor {
13
    /**
14
     * Return a stream for encrypted data.
15
     * <p>
16
     * Use {@link #getLength()} to get the size of that data that can be safely read from the stream.
17
     * Just reading to the end of the input stream is not sufficient because there are
18
     * normally padding bytes that must be discarded
19
     * </p>
20
     *
21
     * @param dir the node to read from
22
     * @return encrypted stream
23
     */
24
    public abstract OutputStream getDataStream(DirectoryNode dir)
25
        throws IOException, GeneralSecurityException;
26
27
    public abstract void confirmPassword(String password)
28
        throws GeneralSecurityException;
29
30
31
	
32
	public static Encryptor getInstance(EncryptionInfo info) {
33
        int major = info.getVersionMajor();
34
        int minor = info.getVersionMinor();
35
36
        if (major == 4 && minor == 4)
37
            return new AgileEncryptor(info);
38
//        else if (minor == 2 && (major == 3 || major == 4))
39
//            return new EcmaDecryptor(info);
40
        else
41
            throw new EncryptedDocumentException("Unsupported version");
42
    }
43
44
    public OutputStream getDataStream(NPOIFSFileSystem fs) throws IOException, GeneralSecurityException {
45
        return getDataStream(fs.getRoot());
46
    }
47
48
    public OutputStream getDataStream(POIFSFileSystem fs) throws IOException, GeneralSecurityException {
49
        return getDataStream(fs.getRoot());
50
    }
51
52
53
}

Return to bug 55818