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]
