Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/cryptoapi/CryptoAPIEncryptor.java
 Wed Aug  3 23:54:01 2016
@@ -18,7 +18,7 @@
 package org.apache.poi.poifs.crypt.cryptoapi;
 
 import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.security.GeneralSecurityException;
@@ -36,6 +36,7 @@ import org.apache.poi.hpsf.DocumentSumma
 import org.apache.poi.hpsf.PropertySetFactory;
 import org.apache.poi.hpsf.SummaryInformation;
 import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.poifs.crypt.ChunkedCipherOutputStream;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.DataSpaceMapUtils;
 import org.apache.poi.poifs.crypt.EncryptionInfo;
@@ -50,13 +51,14 @@ import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayOutputStream;
 import org.apache.poi.util.StringUtil;
 
-public class CryptoAPIEncryptor extends Encryptor {
-    private final CryptoAPIEncryptionInfoBuilder builder;
-
-    protected CryptoAPIEncryptor(CryptoAPIEncryptionInfoBuilder builder) {
-        this.builder = builder;
+public class CryptoAPIEncryptor extends Encryptor implements Cloneable {
+    
+    private int _chunkSize = 512;
+    
+    protected CryptoAPIEncryptor() {
     }
 
+    @Override
     public void confirmPassword(String password) {
         Random r = new SecureRandom();
         byte salt[] = new byte[16];
@@ -66,11 +68,12 @@ public class CryptoAPIEncryptor extends
         confirmPassword(password, null, null, verifier, salt, null);
     }
 
+    @Override
     public void confirmPassword(String password, byte keySpec[],
             byte keySalt[], byte verifier[], byte verifierSalt[],
             byte integritySalt[]) {
         assert(verifier != null && verifierSalt != null);
-        CryptoAPIEncryptionVerifier ver = builder.getVerifier();
+        CryptoAPIEncryptionVerifier ver = 
(CryptoAPIEncryptionVerifier)getEncryptionInfo().getVerifier();
         ver.setSalt(verifierSalt);
         SecretKey skey = CryptoAPIDecryptor.generateSecretKey(password, ver);
         setSecretKey(skey);
@@ -99,8 +102,19 @@ public class CryptoAPIEncryptor extends
      */
     public Cipher initCipherForBlock(Cipher cipher, int block)
     throws GeneralSecurityException {
-        return CryptoAPIDecryptor.initCipherForBlock(cipher, block, builder, 
getSecretKey(), Cipher.ENCRYPT_MODE);
+        return CryptoAPIDecryptor.initCipherForBlock(cipher, block, 
getEncryptionInfo(), getSecretKey(), Cipher.ENCRYPT_MODE);
     }    
+
+    @Override
+    public ChunkedCipherOutputStream getDataStream(DirectoryNode dir)
+    throws IOException, GeneralSecurityException {
+        throw new IOException("not supported");
+    }
+    
+    public CryptoAPICipherOutputStream getDataStream(OutputStream stream)
+    throws IOException, GeneralSecurityException {
+        return new CryptoAPICipherOutputStream(stream);
+    }
     
     /**
      * Encrypt the Document-/SummaryInformation and other optionally streams.
@@ -109,9 +123,9 @@ public class CryptoAPIEncryptor extends
      * 
      * @see <a 
href="http://msdn.microsoft.com/en-us/library/dd943321(v=office.12).aspx">2.3.5.4
 RC4 CryptoAPI Encrypted Summary Stream</a>
      */
-    public OutputStream getDataStream(DirectoryNode dir)
+    public OutputStream getSummaryEntries(DirectoryNode dir)
     throws IOException, GeneralSecurityException {
-        CipherByteArrayOutputStream bos = new CipherByteArrayOutputStream();
+        CryptoAPIDocumentOutputStream bos = new 
CryptoAPIDocumentOutputStream(this);
         byte buf[] = new byte[8];
         
         bos.write(buf, 0, 8); // skip header
@@ -124,7 +138,9 @@ public class CryptoAPIEncryptor extends
 
         int block = 0;
         for (String entryName : entryNames) {
-            if (!dir.hasEntry(entryName)) continue;
+            if (!dir.hasEntry(entryName)) {
+                continue;
+            }
             StreamDescriptorEntry descEntry = new StreamDescriptorEntry();
             descEntry.block = block;
             descEntry.streamOffset = bos.size();
@@ -193,15 +209,20 @@ public class CryptoAPIEncryptor extends
     }
 
     protected int getKeySizeInBytes() {
-        return builder.getHeader().getKeySize() / 8;
+        return getEncryptionInfo().getHeader().getKeySize() / 8;
     }
 
+    public void setChunkSize(int chunkSize) {
+        _chunkSize = chunkSize;
+    }
+    
     protected void createEncryptionInfoEntry(DirectoryNode dir) throws 
IOException {
         DataSpaceMapUtils.addDefaultDataSpace(dir);
-        final EncryptionInfo info = builder.getEncryptionInfo();
-        final CryptoAPIEncryptionHeader header = builder.getHeader();
-        final CryptoAPIEncryptionVerifier verifier = builder.getVerifier();
+        final EncryptionInfo info = getEncryptionInfo();
+        final CryptoAPIEncryptionHeader header = 
(CryptoAPIEncryptionHeader)getEncryptionInfo().getHeader();
+        final CryptoAPIEncryptionVerifier verifier = 
(CryptoAPIEncryptionVerifier)getEncryptionInfo().getVerifier();
         EncryptionRecord er = new EncryptionRecord() {
+            @Override
             public void write(LittleEndianByteArrayOutputStream bos) {
                 bos.writeShort(info.getVersionMajor());
                 bos.writeShort(info.getVersionMinor());
@@ -212,44 +233,42 @@ public class CryptoAPIEncryptor extends
         DataSpaceMapUtils.createEncryptionEntry(dir, "EncryptionInfo", er);
     }
 
-    private class CipherByteArrayOutputStream extends ByteArrayOutputStream {
-        Cipher cipher;
-        byte oneByte[] = { 0 };
 
-        public CipherByteArrayOutputStream() throws GeneralSecurityException {
-            setBlock(0);
-        }
-        
-        public byte[] getBuf() {
-            return buf;
-        }
-        
-        public void setSize(int count) {
-            this.count = count;
+    @Override
+    public CryptoAPIEncryptor clone() throws CloneNotSupportedException {
+        return (CryptoAPIEncryptor)super.clone();
+    }
+
+    protected class CryptoAPICipherOutputStream extends 
ChunkedCipherOutputStream {
+
+        @Override
+        protected Cipher initCipherForBlock(Cipher cipher, int block, boolean 
lastChunk)
+        throws IOException, GeneralSecurityException {
+            flush();
+            EncryptionInfo ei = getEncryptionInfo();
+            SecretKey sk = getSecretKey();
+            return CryptoAPIDecryptor.initCipherForBlock(cipher, block, ei, 
sk, Cipher.ENCRYPT_MODE);
         }
-        
-        public void setBlock(int block) throws GeneralSecurityException {
-            cipher = initCipherForBlock(cipher, block);
+
+        @Override
+        protected void calculateChecksum(File file, int i) {
         }
-        
-        public void write(int b) {
-            try {
-                oneByte[0] = (byte)b;
-                cipher.update(oneByte, 0, 1, oneByte, 0);
-                super.write(oneByte);
-            } catch (Exception e) {
-                throw new EncryptedDocumentException(e);
-            }
+
+        @Override
+        protected void createEncryptionInfoEntry(DirectoryNode dir, File 
tmpFile)
+        throws IOException, GeneralSecurityException {
+            throw new RuntimeException("createEncryptionInfoEntry not 
supported");
         }
 
-        public void write(byte[] b, int off, int len) {
-            try {
-                cipher.update(b, off, len, b, off);
-                super.write(b, off, len);
-            } catch (Exception e) {
-                throw new EncryptedDocumentException(e);
-            }
+        public CryptoAPICipherOutputStream(OutputStream stream)
+        throws IOException, GeneralSecurityException {
+            super(stream, CryptoAPIEncryptor.this._chunkSize);
         }
 
+        @Override
+        public void flush() throws IOException {
+            writeChunk(false);
+        }
     }
+
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardDecryptor.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardDecryptor.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardDecryptor.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardDecryptor.java
 Wed Aug  3 23:54:01 2016
@@ -34,7 +34,6 @@ import org.apache.poi.poifs.crypt.Chaini
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.crypt.EncryptionHeader;
-import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
 import org.apache.poi.poifs.crypt.EncryptionVerifier;
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
@@ -44,15 +43,15 @@ import org.apache.poi.util.LittleEndian;
 
 /**
  */
-public class StandardDecryptor extends Decryptor {
+public class StandardDecryptor extends Decryptor implements Cloneable {
     private long _length = -1;
 
-    protected StandardDecryptor(EncryptionInfoBuilder builder) {
-        super(builder);
+    protected StandardDecryptor() {
     }
 
+    @Override
     public boolean verifyPassword(String password) {
-        EncryptionVerifier ver = builder.getVerifier();
+        EncryptionVerifier ver = getEncryptionInfo().getVerifier();
         SecretKey skey = generateSecretKey(password, ver, getKeySizeInBytes());
         Cipher cipher = getCipher(skey);
 
@@ -116,12 +115,13 @@ public class StandardDecryptor extends D
     }
 
     private Cipher getCipher(SecretKey key) {
-        EncryptionHeader em = builder.getHeader();
+        EncryptionHeader em = getEncryptionInfo().getHeader();
         ChainingMode cm = em.getChainingMode();
         assert(cm == ChainingMode.ecb);
         return CryptoFunctions.getCipher(key, em.getCipherAlgorithm(), cm, 
null, Cipher.DECRYPT_MODE);
     }
 
+    @Override
     @SuppressWarnings("resource")
     public InputStream getDataStream(DirectoryNode dir) throws IOException {
         DocumentInputStream dis = 
dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY);
@@ -134,7 +134,7 @@ public class StandardDecryptor extends D
         // limit wrong calculated ole entries - (bug #57080)
         // standard encryption always uses aes encoding, so blockSize is 
always 16 
         // 
http://stackoverflow.com/questions/3283787/size-of-data-after-aes-encryption
-        int blockSize = builder.getHeader().getCipherAlgorithm().blockSize;
+        int blockSize = 
getEncryptionInfo().getHeader().getCipherAlgorithm().blockSize;
         long cipherLen = (_length/blockSize + 1) * blockSize;
         Cipher cipher = getCipher(getSecretKey());
         
@@ -145,8 +145,16 @@ public class StandardDecryptor extends D
     /**
      * @return the length of the stream returned by {@link 
#getDataStream(DirectoryNode)}
      */
+    @Override
     public long getLength(){
-        if(_length == -1) throw new 
IllegalStateException("Decryptor.getDataStream() was not called");
+        if(_length == -1) {
+            throw new IllegalStateException("Decryptor.getDataStream() was not 
called");
+        }
         return _length;
     }
+
+    @Override
+    public StandardDecryptor clone() throws CloneNotSupportedException {
+        return (StandardDecryptor)super.clone();
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java
 Wed Aug  3 23:54:01 2016
@@ -22,6 +22,7 @@ import static org.apache.poi.poifs.crypt
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.poifs.crypt.ChainingMode;
 import org.apache.poi.poifs.crypt.CipherAlgorithm;
 import org.apache.poi.poifs.crypt.CipherProvider;
@@ -33,7 +34,7 @@ import org.apache.poi.util.LittleEndianI
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.StringUtil;
 
-public class StandardEncryptionHeader extends EncryptionHeader implements 
EncryptionRecord {
+public class StandardEncryptionHeader extends EncryptionHeader implements 
EncryptionRecord, Cloneable {
 
     protected StandardEncryptionHeader(LittleEndianInput is) throws 
IOException {
         setFlags(is.readInt());
@@ -55,9 +56,17 @@ public class StandardEncryptionHeader ex
 
         // CSPName may not always be specified
         // In some cases, the salt value of the EncryptionVerifier is the next 
chunk of data
-        ((InputStream)is).mark(LittleEndianConsts.INT_SIZE+1);
+        if (is instanceof RecordInputStream) {
+            ((RecordInputStream)is).mark(LittleEndianConsts.INT_SIZE+1);
+        } else {
+            ((InputStream)is).mark(LittleEndianConsts.INT_SIZE+1);
+        }
         int checkForSalt = is.readInt();
-        ((InputStream)is).reset();
+        if (is instanceof RecordInputStream) {
+            ((RecordInputStream)is).reset();
+        } else {
+            ((InputStream)is).reset();
+        }
         
         if (checkForSalt == 16) {
             setCspName("");
@@ -65,7 +74,9 @@ public class StandardEncryptionHeader ex
             StringBuilder builder = new StringBuilder();
             while (true) {
                 char c = (char) is.readShort();
-                if (c == 0) break;
+                if (c == 0) {
+                    break;
+                }
                 builder.append(c);
             }
             setCspName(builder.toString());
@@ -90,6 +101,7 @@ public class StandardEncryptionHeader ex
     /**
      * serializes the header 
      */
+    @Override
     public void write(LittleEndianByteArrayOutputStream bos) {
         int startIdx = bos.getWriteIndex();
         LittleEndianOutput sizeOutput = 
bos.createDelayedOutput(LittleEndianConsts.INT_SIZE);
@@ -102,10 +114,17 @@ public class StandardEncryptionHeader ex
         bos.writeInt(0); // reserved1
         bos.writeInt(0); // reserved2
         String cspName = getCspName();
-        if (cspName == null) cspName = getCipherProvider().cipherProviderName;
+        if (cspName == null) {
+            cspName = getCipherProvider().cipherProviderName;
+        }
         bos.write(StringUtil.getToUnicodeLE(cspName));
         bos.writeShort(0);
         int headerSize = 
bos.getWriteIndex()-startIdx-LittleEndianConsts.INT_SIZE;
         sizeOutput.writeInt(headerSize);        
     }
+
+    @Override
+    public StandardEncryptionHeader clone() throws CloneNotSupportedException {
+        return (StandardEncryptionHeader)super.clone();
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionInfoBuilder.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionInfoBuilder.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionInfoBuilder.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionInfoBuilder.java
 Wed Aug  3 23:54:01 2016
@@ -27,34 +27,29 @@ import org.apache.poi.poifs.crypt.HashAl
 import org.apache.poi.util.LittleEndianInput;
 
 public class StandardEncryptionInfoBuilder implements EncryptionInfoBuilder {
-    
-    EncryptionInfo info;
-    StandardEncryptionHeader header;
-    StandardEncryptionVerifier verifier;
-    StandardDecryptor decryptor;
-    StandardEncryptor encryptor;
 
     /**
      * initialize the builder from a stream
      */
+    @Override
     public void initialize(EncryptionInfo info, LittleEndianInput dis) throws 
IOException {
-        this.info = info;
-        
         /* int hSize = */ dis.readInt();
-        header = new StandardEncryptionHeader(dis);
-        verifier = new StandardEncryptionVerifier(dis, header);
+        StandardEncryptionHeader header = new StandardEncryptionHeader(dis);
+        info.setHeader(header);
+        info.setVerifier(new StandardEncryptionVerifier(dis, header));
 
         if (info.getVersionMinor() == 2 && (info.getVersionMajor() == 3 || 
info.getVersionMajor() == 4)) {
-            decryptor = new StandardDecryptor(this);
+            StandardDecryptor dec = new StandardDecryptor();
+            dec.setEncryptionInfo(info);
+            info.setDecryptor(dec);
         }
     }
     
     /**
      * initialize the builder from scratch
      */
+    @Override
     public void initialize(EncryptionInfo info, CipherAlgorithm 
cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, 
ChainingMode chainingMode) {
-        this.info = info;
-
         if (cipherAlgorithm == null) {
             cipherAlgorithm = CipherAlgorithm.aes128;
         }
@@ -89,29 +84,13 @@ public class StandardEncryptionInfoBuild
         if (!found) {
             throw new EncryptedDocumentException("KeySize "+keyBits+" not 
allowed for Cipher "+cipherAlgorithm.toString());
         }
-        header = new StandardEncryptionHeader(cipherAlgorithm, hashAlgorithm, 
keyBits, blockSize, chainingMode);
-        verifier = new StandardEncryptionVerifier(cipherAlgorithm, 
hashAlgorithm, keyBits, blockSize, chainingMode);
-        decryptor = new StandardDecryptor(this);
-        encryptor = new StandardEncryptor(this);
-    }
-
-    public StandardEncryptionHeader getHeader() {
-        return header;
-    }
-
-    public StandardEncryptionVerifier getVerifier() {
-        return verifier;
-    }
-
-    public StandardDecryptor getDecryptor() {
-        return decryptor;
-    }
-
-    public StandardEncryptor getEncryptor() {
-        return encryptor;
-    }
-    
-    public EncryptionInfo getEncryptionInfo() {
-        return info;
+        info.setHeader(new StandardEncryptionHeader(cipherAlgorithm, 
hashAlgorithm, keyBits, blockSize, chainingMode));
+        info.setVerifier(new StandardEncryptionVerifier(cipherAlgorithm, 
hashAlgorithm, keyBits, blockSize, chainingMode));
+        StandardDecryptor dec = new StandardDecryptor();
+        dec.setEncryptionInfo(info);
+        info.setDecryptor(dec);
+        StandardEncryptor enc = new StandardEncryptor();
+        enc.setEncryptionInfo(info);
+        info.setEncryptor(enc);
     }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java
 Wed Aug  3 23:54:01 2016
@@ -27,7 +27,7 @@ import org.apache.poi.util.LittleEndianI
 /**
  * Used when checking if a key is valid for a document 
  */
-public class StandardEncryptionVerifier extends EncryptionVerifier implements 
EncryptionRecord {
+public class StandardEncryptionVerifier extends EncryptionVerifier implements 
EncryptionRecord, Cloneable {
     private static final int SPIN_COUNT = 50000;
     private final int verifierHashSize;
     
@@ -68,6 +68,7 @@ public class StandardEncryptionVerifier
     }
 
     // make method visible for this package
+    @Override
     protected void setSalt(byte salt[]) {
         if (salt == null || salt.length != 16) {
             throw new EncryptedDocumentException("invalid verifier salt");
@@ -76,15 +77,18 @@ public class StandardEncryptionVerifier
     }
     
     // make method visible for this package
+    @Override
     protected void setEncryptedVerifier(byte encryptedVerifier[]) {
         super.setEncryptedVerifier(encryptedVerifier);
     }
 
     // make method visible for this package
+    @Override
     protected void setEncryptedVerifierHash(byte encryptedVerifierHash[]) {
         super.setEncryptedVerifierHash(encryptedVerifierHash);
     }
     
+    @Override
     public void write(LittleEndianByteArrayOutputStream bos) {
         // see [MS-OFFCRYPTO] - 2.3.4.9
         byte salt[] = getSalt();
@@ -115,4 +119,9 @@ public class StandardEncryptionVerifier
     protected int getVerifierHashSize() {
         return verifierHashSize;
     }
+
+    @Override
+    public StandardEncryptionVerifier clone() throws 
CloneNotSupportedException {
+        return (StandardEncryptionVerifier)super.clone();
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptor.java
 Wed Aug  3 23:54:01 2016
@@ -53,15 +53,13 @@ import org.apache.poi.util.POILogFactory
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.TempFile;
 
-public class StandardEncryptor extends Encryptor {
+public class StandardEncryptor extends Encryptor implements Cloneable {
     private static final POILogger logger = 
POILogFactory.getLogger(StandardEncryptor.class);
 
-    private final StandardEncryptionInfoBuilder builder;
-    
-    protected StandardEncryptor(StandardEncryptionInfoBuilder builder) {
-        this.builder = builder;
+    protected StandardEncryptor() {
     }    
 
+    @Override
     public void confirmPassword(String password) {
         // see [MS-OFFCRYPTO] - 2.3.3 EncryptionVerifier
         Random r = new SecureRandom();
@@ -79,8 +77,9 @@ public class StandardEncryptor extends E
      * 
      * see [MS-OFFCRYPTO] - 2.3.4.7 ECMA-376 Document Encryption Key Generation
      */
+    @Override
     public void confirmPassword(String password, byte keySpec[], byte 
keySalt[], byte verifier[], byte verifierSalt[], byte integritySalt[]) {
-        StandardEncryptionVerifier ver = builder.getVerifier();
+        StandardEncryptionVerifier ver = 
(StandardEncryptionVerifier)getEncryptionInfo().getVerifier();
 
         ver.setSalt(verifierSalt);
         SecretKey secretKey = generateSecretKey(password, ver, 
getKeySizeInBytes());
@@ -111,10 +110,11 @@ public class StandardEncryptor extends E
     }
 
     private Cipher getCipher(SecretKey key, String padding) {
-        EncryptionVerifier ver = builder.getVerifier();
+        EncryptionVerifier ver = getEncryptionInfo().getVerifier();
         return CryptoFunctions.getCipher(key, ver.getCipherAlgorithm(), 
ver.getChainingMode(), null, Cipher.ENCRYPT_MODE, padding);
     }
     
+    @Override
     public OutputStream getDataStream(final DirectoryNode dir)
     throws IOException, GeneralSecurityException {
         createEncryptionInfoEntry(dir);
@@ -163,6 +163,7 @@ public class StandardEncryptor extends E
             countBytes++;
         }
     
+        @Override
         public void close() throws IOException {
             // the CipherOutputStream adds the padding bytes on close()
             super.close(); 
@@ -175,6 +176,7 @@ public class StandardEncryptor extends E
             // TODO: any properties???
         }
     
+        @Override
         public void processPOIFSWriterEvent(POIFSWriterEvent event) {
             try {
                 LittleEndianOutputStream leos = new 
LittleEndianOutputStream(event.getStream());
@@ -200,15 +202,16 @@ public class StandardEncryptor extends E
     }
     
     protected int getKeySizeInBytes() {
-        return builder.getHeader().getKeySize()/8;
+        return getEncryptionInfo().getHeader().getKeySize()/8;
     }
     
     protected void createEncryptionInfoEntry(DirectoryNode dir) throws 
IOException {
-        final EncryptionInfo info = builder.getEncryptionInfo();
-        final StandardEncryptionHeader header = builder.getHeader();
-        final StandardEncryptionVerifier verifier = builder.getVerifier();
+        final EncryptionInfo info = getEncryptionInfo();
+        final StandardEncryptionHeader header = 
(StandardEncryptionHeader)info.getHeader();
+        final StandardEncryptionVerifier verifier = 
(StandardEncryptionVerifier)info.getVerifier();
         
         EncryptionRecord er = new EncryptionRecord(){
+            @Override
             public void write(LittleEndianByteArrayOutputStream bos) {
                 bos.writeShort(info.getVersionMajor());
                 bos.writeShort(info.getVersionMinor());
@@ -222,4 +225,9 @@ public class StandardEncryptor extends E
         
         // TODO: any properties???
     }
+
+    @Override
+    public StandardEncryptor clone() throws CloneNotSupportedException {
+        return (StandardEncryptor)super.clone();
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
 Wed Aug  3 23:54:01 2016
@@ -17,103 +17,91 @@
 
 package org.apache.poi.util;
 
+import java.io.ByteArrayInputStream;
+
 /**
  * Adapts a plain byte array to {@link LittleEndianInput}
- *
- * @author Josh Micich
  */
-public final class LittleEndianByteArrayInputStream implements 
LittleEndianInput {
-       private final byte[] _buf;
-       private final int _endIndex;
-       private int _readIndex;
-
+public final class LittleEndianByteArrayInputStream extends 
ByteArrayInputStream implements LittleEndianInput {
        public LittleEndianByteArrayInputStream(byte[] buf, int startOffset, 
int maxReadLen) { // NOSONAR
-               _buf = buf;
-               _readIndex = startOffset;
-               _endIndex = startOffset + maxReadLen;
+           super(buf, startOffset, maxReadLen);
        }
+       
        public LittleEndianByteArrayInputStream(byte[] buf, int startOffset) {
-               this(buf, startOffset, buf.length - startOffset);
+           super(buf, startOffset, buf.length - startOffset);
        }
+       
        public LittleEndianByteArrayInputStream(byte[] buf) {
-               this(buf, 0, buf.length);
+           super(buf);
        }
 
-       public int available() {
-               return _endIndex - _readIndex;
-       }
        private void checkPosition(int i) {
-               if (i > _endIndex - _readIndex) {
+               if (i > count - pos) {
                        throw new RuntimeException("Buffer overrun");
                }
        }
 
        public int getReadIndex() {
-               return _readIndex;
+               return pos;
        }
-       public byte readByte() {
+
+       @Override
+    public byte readByte() {
                checkPosition(1);
-               return _buf[_readIndex++];
+               return (byte)read();
        }
 
-       public int readInt() {
-               checkPosition(4);
-               int i = _readIndex;
-
-               int b0 = _buf[i++] & 0xFF;
-               int b1 = _buf[i++] & 0xFF;
-               int b2 = _buf[i++] & 0xFF;
-               int b3 = _buf[i++] & 0xFF;
-               _readIndex = i;
-               return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
-       }
-       public long readLong() {
-               checkPosition(8);
-               int i = _readIndex;
-
-               int b0 = _buf[i++] & 0xFF;
-               int b1 = _buf[i++] & 0xFF;
-               int b2 = _buf[i++] & 0xFF;
-               int b3 = _buf[i++] & 0xFF;
-               int b4 = _buf[i++] & 0xFF;
-               int b5 = _buf[i++] & 0xFF;
-               int b6 = _buf[i++] & 0xFF;
-               int b7 = _buf[i++] & 0xFF;
-               _readIndex = i;
-               return (((long)b7 << 56) +
-                               ((long)b6 << 48) +
-                               ((long)b5 << 40) +
-                               ((long)b4 << 32) +
-                               ((long)b3 << 24) +
-                               (b2 << 16) +
-                               (b1 <<  8) +
-                               (b0 <<  0));
+       @Override
+    public int readInt() {
+           final int size = LittleEndianConsts.INT_SIZE;
+               checkPosition(size);
+               int le = LittleEndian.getInt(buf, pos);
+               super.skip(size);
+               return le;
        }
-       public short readShort() {
-               return (short)readUShort();
-       }
-       public int readUByte() {
-               checkPosition(1);
-               return _buf[_readIndex++] & 0xFF;
+
+       @Override
+    public long readLong() {
+           final int size = LittleEndianConsts.LONG_SIZE;
+               checkPosition(size);
+               long le = LittleEndian.getLong(buf, pos);
+               super.skip(size);
+               return le;
        }
-       public int readUShort() {
-               checkPosition(2);
-               int i = _readIndex;
-
-               int b0 = _buf[i++] & 0xFF;
-               int b1 = _buf[i++] & 0xFF;
-               _readIndex = i;
-               return (b1 << 8) + (b0 << 0);
+
+       @Override
+    public short readShort() {
+               return (short)readUShort();
        }
-       public void readFully(byte[] buf, int off, int len) {
+
+       @Override
+    public int readUByte() {
+           return readByte() & 0xFF;
+       }
+
+       @Override
+    public int readUShort() {
+        final int size = LittleEndianConsts.SHORT_SIZE;
+        checkPosition(size);
+        int le = LittleEndian.getUShort(buf, pos);
+        super.skip(size);
+        return le;
+       }
+
+    @Override
+    public double readDouble() {
+        return Double.longBitsToDouble(readLong());
+    }
+       
+       @Override
+    public void readFully(byte[] buffer, int off, int len) {
                checkPosition(len);
-               System.arraycopy(_buf, _readIndex, buf, off, len);
-               _readIndex+=len;
-       }
-       public void readFully(byte[] buf) {
-               readFully(buf, 0, buf.length);
+               read(buffer, off, len);
        }
-       public double readDouble() {
-               return Double.longBitsToDouble(readLong());
+
+       @Override
+    public void readFully(byte[] buffer) {
+        checkPosition(buffer.length);
+        read(buffer, 0, buffer.length);
        }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
 Wed Aug  3 23:54:01 2016
@@ -17,28 +17,26 @@
 
 package org.apache.poi.util;
 
+import java.io.OutputStream;
 
 /**
- * Adapts a plain byte array to {@link LittleEndianOutput} 
- * 
- * 
- * @author Josh Micich
+ * Adapts a plain byte array to {@link LittleEndianOutput}
  */
-public final class LittleEndianByteArrayOutputStream implements 
LittleEndianOutput, DelayableLittleEndianOutput {
+public final class LittleEndianByteArrayOutputStream extends OutputStream 
implements LittleEndianOutput, DelayableLittleEndianOutput {
        private final byte[] _buf;
        private final int _endIndex;
        private int _writeIndex;
 
        public LittleEndianByteArrayOutputStream(byte[] buf, int startOffset, 
int maxWriteLen) { // NOSONAR
                if (startOffset < 0 || startOffset > buf.length) {
-                       throw new IllegalArgumentException("Specified 
startOffset (" + startOffset 
+                       throw new IllegalArgumentException("Specified 
startOffset (" + startOffset
                                        + ") is out of allowable range (0.." + 
buf.length + ")");
                }
                _buf = buf;
                _writeIndex = startOffset;
                _endIndex = startOffset + maxWriteLen;
                if (_endIndex < startOffset ||  _endIndex > buf.length) {
-                       throw new IllegalArgumentException("calculated end 
index (" + _endIndex 
+                       throw new IllegalArgumentException("calculated end 
index (" + _endIndex
                                        + ") is out of allowable range (" + 
_writeIndex + ".." + buf.length + ")");
                }
        }
@@ -52,16 +50,19 @@ public final class LittleEndianByteArray
                }
        }
 
-       public void writeByte(int v) {
+       @Override
+    public void writeByte(int v) {
                checkPosition(1);
                _buf[_writeIndex++] = (byte)v;
        }
 
-       public void writeDouble(double v) {
+       @Override
+    public void writeDouble(double v) {
                writeLong(Double.doubleToLongBits(v));
        }
 
-       public void writeInt(int v) {
+       @Override
+    public void writeInt(int v) {
                checkPosition(4);
                int i = _writeIndex;
                _buf[i++] = (byte)((v >>>  0) & 0xFF);
@@ -71,33 +72,47 @@ public final class LittleEndianByteArray
                _writeIndex = i;
        }
 
-       public void writeLong(long v) {
+       @Override
+    public void writeLong(long v) {
                writeInt((int)(v >>  0));
                writeInt((int)(v >> 32));
        }
 
-       public void writeShort(int v) {
+       @Override
+    public void writeShort(int v) {
                checkPosition(2);
                int i = _writeIndex;
                _buf[i++] = (byte)((v >>>  0) & 0xFF);
                _buf[i++] = (byte)((v >>>  8) & 0xFF);
                _writeIndex = i;
        }
-       public void write(byte[] b) {
+
+       @Override
+    public void write(int b) {
+           writeByte(b);
+    }
+
+       @Override
+    public void write(byte[] b) {
                int len = b.length;
                checkPosition(len);
                System.arraycopy(b, 0, _buf, _writeIndex, len);
                _writeIndex += len;
        }
-       public void write(byte[] b, int offset, int len) {
+
+       @Override
+    public void write(byte[] b, int offset, int len) {
                checkPosition(len);
                System.arraycopy(b, offset, _buf, _writeIndex, len);
                _writeIndex += len;
        }
+
        public int getWriteIndex() {
                return _writeIndex;
        }
-       public LittleEndianOutput createDelayedOutput(int size) {
+
+       @Override
+    public LittleEndianOutput createDelayedOutput(int size) {
                checkPosition(size);
                LittleEndianOutput result = new 
LittleEndianByteArrayOutputStream(_buf, _writeIndex, size);
                _writeIndex += size;

Modified: 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java
 Wed Aug  3 23:54:01 2016
@@ -45,7 +45,7 @@ import org.apache.poi.poifs.crypt.Cipher
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.crypt.EncryptionHeader;
-import org.apache.poi.poifs.crypt.EncryptionInfoBuilder;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
 import org.apache.poi.poifs.crypt.EncryptionVerifier;
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import 
org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry;
@@ -56,14 +56,14 @@ import org.apache.poi.util.LittleEndian;
 /**
  * Decryptor implementation for Agile Encryption
  */
-public class AgileDecryptor extends Decryptor {
+public class AgileDecryptor extends Decryptor implements Cloneable {
     private long _length = -1;
 
-    protected static final byte[] kVerifierInputBlock;
-    protected static final byte[] kHashedVerifierBlock;
-    protected static final byte[] kCryptoKeyBlock;
-    protected static final byte[] kIntegrityKeyBlock;
-    protected static final byte[] kIntegrityValueBlock;
+    /* package */ static final byte[] kVerifierInputBlock;
+    /* package */ static final byte[] kHashedVerifierBlock;
+    /* package */ static final byte[] kCryptoKeyBlock;
+    /* package */ static final byte[] kIntegrityKeyBlock;
+    /* package */ static final byte[] kIntegrityValueBlock;
 
     static {
         kVerifierInputBlock =
@@ -83,16 +83,16 @@ public class AgileDecryptor extends Decr
                          (byte)0xb2, (byte)0x2c, (byte)0x84, (byte)0x33 };
     }
 
-    protected AgileDecryptor(AgileEncryptionInfoBuilder builder) {
-        super(builder);
+    protected AgileDecryptor() {
     }
     
     /**
      * set decryption password
      */
+    @Override
     public boolean verifyPassword(String password) throws 
GeneralSecurityException {
-        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)builder.getVerifier();
-        AgileEncryptionHeader header = 
(AgileEncryptionHeader)builder.getHeader(); 
+        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
+        AgileEncryptionHeader header = 
(AgileEncryptionHeader)getEncryptionInfo().getHeader(); 
         HashAlgorithm hashAlgo = header.getHashAlgorithmEx();
         CipherAlgorithm cipherAlgo = header.getCipherAlgorithm();
         int blockSize = header.getBlockSize();
@@ -113,7 +113,7 @@ public class AgileDecryptor extends Decr
          *    blockSize bytes.
          * 4. Use base64 to encode the result of step 3.
          */
-        byte verfierInputEnc[] = hashInput(builder, pwHash, 
kVerifierInputBlock, ver.getEncryptedVerifier(), Cipher.DECRYPT_MODE);
+        byte verfierInputEnc[] = hashInput(getEncryptionInfo(), pwHash, 
kVerifierInputBlock, ver.getEncryptedVerifier(), Cipher.DECRYPT_MODE);
         setVerifier(verfierInputEnc);
         MessageDigest hashMD = getMessageDigest(hashAlgo);
         byte[] verifierHash = hashMD.digest(verfierInputEnc);
@@ -130,7 +130,7 @@ public class AgileDecryptor extends Decr
          *    blockSize bytes, pad the hash value with 0x00 to an integral 
multiple of blockSize bytes.
          * 4. Use base64 to encode the result of step 3.
          */
-        byte verifierHashDec[] = hashInput(builder, pwHash, 
kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE);
+        byte verifierHashDec[] = hashInput(getEncryptionInfo(), pwHash, 
kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE);
         verifierHashDec = getBlock0(verifierHashDec, hashAlgo.hashSize);
         
         /**
@@ -146,7 +146,7 @@ public class AgileDecryptor extends Decr
          *    blockSize bytes.
          * 4. Use base64 to encode the result of step 3.
          */
-        byte keyspec[] = hashInput(builder, pwHash, kCryptoKeyBlock, 
ver.getEncryptedKey(), Cipher.DECRYPT_MODE);
+        byte keyspec[] = hashInput(getEncryptionInfo(), pwHash, 
kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE);
         keyspec = getBlock0(keyspec, keySize);
         SecretKeySpec secretKey = new SecretKeySpec(keyspec, 
ver.getCipherAlgorithm().jceId);
 
@@ -204,8 +204,8 @@ public class AgileDecryptor extends Decr
      * @throws GeneralSecurityException
      */
     public boolean verifyPassword(KeyPair keyPair, X509Certificate x509) 
throws GeneralSecurityException {
-        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)builder.getVerifier();
-        AgileEncryptionHeader header = 
(AgileEncryptionHeader)builder.getHeader();
+        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
+        AgileEncryptionHeader header = 
(AgileEncryptionHeader)getEncryptionInfo().getHeader();
         HashAlgorithm hashAlgo = header.getHashAlgorithmEx();
         CipherAlgorithm cipherAlgo = header.getCipherAlgorithm();
         int blockSize = header.getBlockSize();
@@ -217,7 +217,9 @@ public class AgileDecryptor extends Decr
                 break;
             }
         }
-        if (ace == null) return false;
+        if (ace == null) {
+            return false;
+        }
         
         Cipher cipher = Cipher.getInstance("RSA");
         cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
@@ -255,9 +257,9 @@ public class AgileDecryptor extends Decr
         return fillSize;
     }
 
-    protected static byte[] hashInput(EncryptionInfoBuilder builder, byte 
pwHash[], byte blockKey[], byte inputKey[], int cipherMode) {
-        EncryptionVerifier ver = builder.getVerifier();
-        AgileDecryptor dec = (AgileDecryptor)builder.getDecryptor();
+    protected static byte[] hashInput(EncryptionInfo encryptionInfo, byte 
pwHash[], byte blockKey[], byte inputKey[], int cipherMode) {
+        EncryptionVerifier ver = encryptionInfo.getVerifier();
+        AgileDecryptor dec = (AgileDecryptor)encryptionInfo.getDecryptor();
         int keySize = dec.getKeySizeInBytes();
         int blockSize = dec.getBlockSizeInBytes();
         HashAlgorithm hashAlgo = ver.getHashAlgorithm();
@@ -278,6 +280,7 @@ public class AgileDecryptor extends Decr
         }
     }
 
+    @Override
     @SuppressWarnings("resource")
     public InputStream getDataStream(DirectoryNode dir) throws IOException, 
GeneralSecurityException {
         DocumentInputStream dis = 
dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY);
@@ -285,17 +288,20 @@ public class AgileDecryptor extends Decr
         return new AgileCipherInputStream(dis, _length);
     }
 
+    @Override
     public long getLength(){
-        if(_length == -1) throw new 
IllegalStateException("EcmaDecryptor.getDataStream() was not called");
+        if(_length == -1) {
+            throw new IllegalStateException("EcmaDecryptor.getDataStream() was 
not called");
+        }
         return _length;
     }
 
 
-    protected static Cipher initCipherForBlock(Cipher existing, int block, 
boolean lastChunk, EncryptionInfoBuilder builder, SecretKey skey, int 
encryptionMode)
+    protected static Cipher initCipherForBlock(Cipher existing, int block, 
boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int 
encryptionMode)
     throws GeneralSecurityException {
-        EncryptionHeader header = builder.getHeader();
-        if (existing == null || lastChunk) {
-            String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
+        EncryptionHeader header = encryptionInfo.getHeader();
+        String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
+        if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
             existing = getCipher(skey, header.getCipherAlgorithm(), 
header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
         }
 
@@ -339,9 +345,15 @@ public class AgileDecryptor extends Decr
         // TODO: calculate integrity hmac while reading the stream
         // for a post-validation of the data
         
+        @Override
         protected Cipher initCipherForBlock(Cipher cipher, int block)
         throws GeneralSecurityException {
-            return AgileDecryptor.initCipherForBlock(cipher, block, false, 
builder, getSecretKey(), Cipher.DECRYPT_MODE);
+            return AgileDecryptor.initCipherForBlock(cipher, block, false, 
getEncryptionInfo(), getSecretKey(), Cipher.DECRYPT_MODE);
         }
     }
+    
+    @Override
+    public AgileDecryptor clone() throws CloneNotSupportedException {
+        return (AgileDecryptor)super.clone();
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java
 Wed Aug  3 23:54:01 2016
@@ -27,7 +27,7 @@ import com.microsoft.schemas.office.x200
 import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
 import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
 
-public class AgileEncryptionHeader extends EncryptionHeader {
+public class AgileEncryptionHeader extends EncryptionHeader implements 
Cloneable {
     private byte encryptedHmacKey[], encryptedHmacValue[];
     
     public AgileEncryptionHeader(String descriptor) {
@@ -99,6 +99,7 @@ public class AgileEncryptionHeader exten
     }
 
     // make method visible for this package
+    @Override
     protected void setKeySalt(byte salt[]) {
         if (salt == null || salt.length != getBlockSize()) {
             throw new EncryptedDocumentException("invalid verifier salt");
@@ -121,4 +122,13 @@ public class AgileEncryptionHeader exten
     protected void setEncryptedHmacValue(byte[] encryptedHmacValue) {
         this.encryptedHmacValue = (encryptedHmacValue == null) ? null : 
encryptedHmacValue.clone();
     }
+
+    @Override
+    public AgileEncryptionHeader clone() throws CloneNotSupportedException {
+        AgileEncryptionHeader other = (AgileEncryptionHeader)super.clone();
+        other.encryptedHmacKey = (encryptedHmacKey == null) ? null : 
encryptedHmacKey.clone();
+        other.encryptedHmacValue = (encryptedHmacValue == null) ? null : 
encryptedHmacValue.clone();
+        return other;
+    }
+
 }

Modified: 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionInfoBuilder.java
 Wed Aug  3 23:54:01 2016
@@ -35,30 +35,24 @@ import com.microsoft.schemas.office.x200
 
 public class AgileEncryptionInfoBuilder implements EncryptionInfoBuilder {
     
-    EncryptionInfo info;
-    AgileEncryptionHeader header;
-    AgileEncryptionVerifier verifier;
-    AgileDecryptor decryptor;
-    AgileEncryptor encryptor;
-
     @Override
-    public void initialize(EncryptionInfo ei, LittleEndianInput dis) throws 
IOException {
-        this.info = ei;
-        
+    public void initialize(EncryptionInfo info, LittleEndianInput dis) throws 
IOException {
         EncryptionDocument ed = parseDescriptor((InputStream)dis);
-        header = new AgileEncryptionHeader(ed);
-        verifier = new AgileEncryptionVerifier(ed);
-        if (ei.getVersionMajor() == EncryptionMode.agile.versionMajor
-            && ei.getVersionMinor() == EncryptionMode.agile.versionMinor) {
-            decryptor = new AgileDecryptor(this);
-            encryptor = new AgileEncryptor(this);
+        info.setHeader(new AgileEncryptionHeader(ed));
+        info.setVerifier(new AgileEncryptionVerifier(ed));
+        if (info.getVersionMajor() == EncryptionMode.agile.versionMajor
+            && info.getVersionMinor() == EncryptionMode.agile.versionMinor) {
+            AgileDecryptor dec = new AgileDecryptor();
+            dec.setEncryptionInfo(info);
+            info.setDecryptor(dec);
+            AgileEncryptor enc = new AgileEncryptor();
+            enc.setEncryptionInfo(info);
+            info.setEncryptor(enc);
         }
     }
 
     @Override
-    public void initialize(EncryptionInfo ei, CipherAlgorithm cipherAlgorithm, 
HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode 
chainingMode) {
-        this.info = ei;
-
+    public void initialize(EncryptionInfo info, CipherAlgorithm 
cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, 
ChainingMode chainingMode) {
         if (cipherAlgorithm == null) {
             cipherAlgorithm = CipherAlgorithm.aes128;
         }
@@ -87,30 +81,14 @@ public class AgileEncryptionInfoBuilder
         if (!found) {
             throw new EncryptedDocumentException("KeySize "+keyBits+" not 
allowed for Cipher "+cipherAlgorithm.toString());
         }
-        header = new AgileEncryptionHeader(cipherAlgorithm, hashAlgorithm, 
keyBits, blockSize, chainingMode);
-        verifier = new AgileEncryptionVerifier(cipherAlgorithm, hashAlgorithm, 
keyBits, blockSize, chainingMode);
-        decryptor = new AgileDecryptor(this);
-        encryptor = new AgileEncryptor(this);
-    }
-    
-    public AgileEncryptionHeader getHeader() {
-        return header;
-    }
-
-    public AgileEncryptionVerifier getVerifier() {
-        return verifier;
-    }
-
-    public AgileDecryptor getDecryptor() {
-        return decryptor;
-    }
-
-    public AgileEncryptor getEncryptor() {
-        return encryptor;
-    }
-
-    protected EncryptionInfo getInfo() {
-        return info;
+        info.setHeader(new AgileEncryptionHeader(cipherAlgorithm, 
hashAlgorithm, keyBits, blockSize, chainingMode));
+        info.setVerifier(new AgileEncryptionVerifier(cipherAlgorithm, 
hashAlgorithm, keyBits, blockSize, chainingMode));
+        AgileDecryptor dec = new AgileDecryptor();
+        dec.setEncryptionInfo(info);
+        info.setDecryptor(dec);
+        AgileEncryptor enc = new AgileEncryptor();
+        enc.setEncryptionInfo(info);
+        info.setEncryptor(enc);
     }
     
     protected static EncryptionDocument parseDescriptor(String descriptor) {

Modified: 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java
 Wed Aug  3 23:54:01 2016
@@ -39,7 +39,7 @@ import com.microsoft.schemas.office.x200
 /**
  * Used when checking if a key is valid for a document 
  */
-public class AgileEncryptionVerifier extends EncryptionVerifier {
+public class AgileEncryptionVerifier extends EncryptionVerifier implements 
Cloneable {
 
     public static class AgileCertificateEntry {
         X509Certificate x509;
@@ -87,8 +87,9 @@ public class AgileEncryptionVerifier ext
         setEncryptedVerifierHash(keyData.getEncryptedVerifierHashValue());
 
         int saltSize = keyData.getSaltSize();
-        if (saltSize != getSalt().length)
+        if (saltSize != getSalt().length) {
             throw new EncryptedDocumentException("Invalid salt size");
+        }
         
         switch (keyData.getCipherChaining().intValue()) {
             case STCipherChaining.INT_CHAINING_MODE_CBC:
@@ -101,7 +102,9 @@ public class AgileEncryptionVerifier ext
                 throw new EncryptedDocumentException("Unsupported chaining 
mode - "+keyData.getCipherChaining().toString());
         }
         
-        if (!encList.hasNext()) return;
+        if (!encList.hasNext()) {
+            return;
+        }
         
         try {
             CertificateFactory cf = CertificateFactory.getInstance("X.509");
@@ -125,6 +128,7 @@ public class AgileEncryptionVerifier ext
         setSpinCount(100000); // TODO: use parameter
     }
     
+    @Override
     protected void setSalt(byte salt[]) {
         if (salt == null || salt.length != getCipherAlgorithm().blockSize) {
             throw new EncryptedDocumentException("invalid verifier salt");
@@ -133,16 +137,19 @@ public class AgileEncryptionVerifier ext
     }
     
     // make method visible for this package
+    @Override
     protected void setEncryptedVerifier(byte encryptedVerifier[]) {
         super.setEncryptedVerifier(encryptedVerifier);
     }
 
     // make method visible for this package
+    @Override
     protected void setEncryptedVerifierHash(byte encryptedVerifierHash[]) {
         super.setEncryptedVerifierHash(encryptedVerifierHash);
     }
 
     // make method visible for this package
+    @Override
     protected void setEncryptedKey(byte[] encryptedKey) {
         super.setEncryptedKey(encryptedKey);
     }
@@ -156,4 +163,12 @@ public class AgileEncryptionVerifier ext
     public List<AgileCertificateEntry> getCertificates() {
         return certList;
     }
+
+    @Override
+    public AgileEncryptionVerifier clone() throws CloneNotSupportedException {
+        AgileEncryptionVerifier other = (AgileEncryptionVerifier)super.clone();
+        // TODO: deep copy of certList
+        other.certList = new ArrayList<AgileCertificateEntry>(certList);
+        return other;
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
 Wed Aug  3 23:54:01 2016
@@ -60,6 +60,7 @@ import org.apache.poi.poifs.crypt.standa
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianConsts;
 import org.apache.xmlbeans.XmlOptions;
 
 import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
@@ -74,21 +75,20 @@ import com.microsoft.schemas.office.x200
 import 
com.microsoft.schemas.office.x2006.keyEncryptor.certificate.CTCertificateKeyEncryptor;
 import 
com.microsoft.schemas.office.x2006.keyEncryptor.password.CTPasswordKeyEncryptor;
 
-public class AgileEncryptor extends Encryptor {
-    private final AgileEncryptionInfoBuilder builder;
+public class AgileEncryptor extends Encryptor implements Cloneable {
     private byte integritySalt[];
        private byte pwHash[];
     
-       protected AgileEncryptor(AgileEncryptionInfoBuilder builder) {
-               this.builder = builder;
+       protected AgileEncryptor() {
        }
 
+    @Override
     public void confirmPassword(String password) {
         // see [MS-OFFCRYPTO] - 2.3.3 EncryptionVerifier
         Random r = new SecureRandom();
-        int blockSize = builder.getHeader().getBlockSize();
-        int keySize = builder.getHeader().getKeySize()/8;
-        int hashSize = builder.getHeader().getHashAlgorithmEx().hashSize;
+        int blockSize = getEncryptionInfo().getHeader().getBlockSize();
+        int keySize = getEncryptionInfo().getHeader().getKeySize()/8;
+        int hashSize = 
getEncryptionInfo().getHeader().getHashAlgorithmEx().hashSize;
         
         byte[] newVerifierSalt = new byte[blockSize]
              , newVerifier = new byte[blockSize]
@@ -104,10 +104,11 @@ public class AgileEncryptor extends Encr
         confirmPassword(password, newKeySpec, newKeySalt, newVerifierSalt, 
newVerifier, newIntegritySalt);
     }
        
-       public void confirmPassword(String password, byte keySpec[], byte 
keySalt[], byte verifier[], byte verifierSalt[], byte integritySalt[]) {
-        AgileEncryptionVerifier ver = builder.getVerifier();
+       @Override
+    public void confirmPassword(String password, byte keySpec[], byte 
keySalt[], byte verifier[], byte verifierSalt[], byte integritySalt[]) {
+        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
         ver.setSalt(verifierSalt);
-        AgileEncryptionHeader header = builder.getHeader();
+        AgileEncryptionHeader header = 
(AgileEncryptionHeader)getEncryptionInfo().getHeader();
         header.setKeySalt(keySalt);
         HashAlgorithm hashAlgo = ver.getHashAlgorithm();
 
@@ -128,7 +129,7 @@ public class AgileEncryptor extends Encr
          *    blockSize bytes.
          * 4. Use base64 to encode the result of step 3.
          */
-        byte encryptedVerifier[] = hashInput(builder, pwHash, 
kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
+        byte encryptedVerifier[] = hashInput(getEncryptionInfo(), pwHash, 
kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
         ver.setEncryptedVerifier(encryptedVerifier);
            
 
@@ -146,7 +147,7 @@ public class AgileEncryptor extends Encr
          */
         MessageDigest hashMD = getMessageDigest(hashAlgo);
         byte[] hashedVerifier = hashMD.digest(verifier);
-        byte encryptedVerifierHash[] = hashInput(builder, pwHash, 
kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
+        byte encryptedVerifierHash[] = hashInput(getEncryptionInfo(), pwHash, 
kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
         ver.setEncryptedVerifierHash(encryptedVerifierHash);
         
         /**
@@ -162,7 +163,7 @@ public class AgileEncryptor extends Encr
          *    blockSize bytes.
          * 4. Use base64 to encode the result of step 3.
          */
-        byte encryptedKey[] = hashInput(builder, pwHash, kCryptoKeyBlock, 
keySpec, Cipher.ENCRYPT_MODE);
+        byte encryptedKey[] = hashInput(getEncryptionInfo(), pwHash, 
kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
         ver.setEncryptedKey(encryptedKey);
         
         SecretKey secretKey = new SecretKeySpec(keySpec, 
ver.getCipherAlgorithm().jceId);
@@ -214,6 +215,7 @@ public class AgileEncryptor extends Encr
         }
        }
        
+    @Override
     public OutputStream getDataStream(DirectoryNode dir)
             throws IOException, GeneralSecurityException {
         // TODO: initialize headers
@@ -234,14 +236,14 @@ public class AgileEncryptor extends Encr
         // as the integrity hmac needs to contain the StreamSize,
         // it's not possible to calculate it on-the-fly while buffering
         // TODO: add stream size parameter to getDataStream()
-        AgileEncryptionVerifier ver = builder.getVerifier();
+        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
         HashAlgorithm hashAlgo = ver.getHashAlgorithm();
         Mac integrityMD = CryptoFunctions.getMac(hashAlgo);
         integrityMD.init(new SecretKeySpec(integritySalt, hashAlgo.jceHmacId));
 
         byte buf[] = new byte[1024];
         LittleEndian.putLong(buf, 0, oleStreamSize);
-        integrityMD.update(buf, 0, LittleEndian.LONG_SIZE);
+        integrityMD.update(buf, 0, LittleEndianConsts.LONG_SIZE);
         
         InputStream fis = new FileInputStream(tmpFile);
         try {
@@ -255,7 +257,7 @@ public class AgileEncryptor extends Encr
         
         byte hmacValue[] = integrityMD.doFinal();
         
-        AgileEncryptionHeader header = builder.getHeader();
+        AgileEncryptionHeader header = 
(AgileEncryptionHeader)getEncryptionInfo().getHeader();
         int blockSize = header.getBlockSize();
         byte iv[] = CryptoFunctions.generateIv(header.getHashAlgorithmEx(), 
header.getKeySalt(), kIntegrityValueBlock, blockSize);
         Cipher cipher = CryptoFunctions.getCipher(getSecretKey(), 
header.getCipherAlgorithm(), header.getChainingMode(), iv, Cipher.ENCRYPT_MODE);
@@ -271,8 +273,8 @@ public class AgileEncryptor extends Encr
         
CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE;
     
     protected EncryptionDocument createEncryptionDocument() {
-        AgileEncryptionVerifier ver = builder.getVerifier();
-        AgileEncryptionHeader header = builder.getHeader(); 
+        AgileEncryptionVerifier ver = 
(AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
+        AgileEncryptionHeader header = 
(AgileEncryptionHeader)getEncryptionInfo().getHeader(); 
         
         EncryptionDocument ed = EncryptionDocument.Factory.newInstance();
         CTEncryption edRoot = ed.addNewEncryption();
@@ -379,9 +381,10 @@ public class AgileEncryptor extends Encr
     throws IOException, GeneralSecurityException {
         DataSpaceMapUtils.addDefaultDataSpace(dir);
 
-        final EncryptionInfo info = builder.getInfo();
+        final EncryptionInfo info = getEncryptionInfo();
 
         EncryptionRecord er = new EncryptionRecord(){
+            @Override
             public void write(LittleEndianByteArrayOutputStream bos) {
                 // EncryptionVersionInfo (4 bytes): A Version structure 
(section 2.1.4), where 
                 // Version.vMajor MUST be 0x0004 and Version.vMinor MUST be 
0x0004
@@ -422,7 +425,7 @@ public class AgileEncryptor extends Encr
         @Override
         protected Cipher initCipherForBlock(Cipher existing, int block, 
boolean lastChunk)
         throws GeneralSecurityException {
-            return AgileDecryptor.initCipherForBlock(existing, block, 
lastChunk, builder, getSecretKey(), Cipher.ENCRYPT_MODE);
+            return AgileDecryptor.initCipherForBlock(existing, block, 
lastChunk, getEncryptionInfo(), getSecretKey(), Cipher.ENCRYPT_MODE);
         }
 
         @Override
@@ -439,4 +442,11 @@ public class AgileEncryptor extends Encr
         }
     }
 
+    @Override
+    public AgileEncryptor clone() throws CloneNotSupportedException {
+        AgileEncryptor other = (AgileEncryptor)super.clone();
+        other.integritySalt = (integritySalt == null) ? null : 
integritySalt.clone();
+        other.pwHash = (pwHash == null) ? null : pwHash.clone();
+        return other;
+    }
 }

Modified: 
poi/branches/hssf_cryptoapi/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java
URL: 
http://svn.apache.org/viewvc/poi/branches/hssf_cryptoapi/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java?rev=1755127&r1=1755126&r2=1755127&view=diff
==============================================================================
--- 
poi/branches/hssf_cryptoapi/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java
 (original)
+++ 
poi/branches/hssf_cryptoapi/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java
 Wed Aug  3 23:54:01 2016
@@ -16,8 +16,7 @@
 ==================================================================== */
 package org.apache.poi.poifs.crypt;
 
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
@@ -94,6 +93,7 @@ public class TestAgileEncryptionParamete
         os.close();
         bos.reset();
         fsEnc.writeFilesystem(bos);
+        fsEnc.close();
         
         POIFSFileSystem fsDec = new POIFSFileSystem(new 
ByteArrayInputStream(bos.toByteArray()));
         EncryptionInfo infoDec = new EncryptionInfo(fsDec);
@@ -103,6 +103,7 @@ public class TestAgileEncryptionParamete
         InputStream is = dec.getDataStream(fsDec);
         byte actualData[] = IOUtils.toByteArray(is);
         is.close();
-        assertThat("Failed roundtrip - "+ca+"-"+ha+"-"+cm, testData, 
equalTo(actualData));
+        fsDec.close();
+        assertArrayEquals("Failed roundtrip - "+ca+"-"+ha+"-"+cm, testData, 
actualData);
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to