You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2013/12/25 00:13:22 UTC

svn commit: r1553336 [3/4] - in /poi: site/src/documentation/content/xdocs/ trunk/ trunk/src/java/org/apache/poi/ trunk/src/java/org/apache/poi/poifs/crypt/ trunk/src/java/org/apache/poi/poifs/crypt/standard/ trunk/src/ooxml/java/org/apache/poi/ trunk/...

Copied: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java (from r1541255, poi/trunk/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java)
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java?p2=poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java&p1=poi/trunk/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java&r1=1541255&r2=1553336&rev=1553336&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java Tue Dec 24 23:13:21 2013
@@ -14,157 +14,151 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-package org.apache.poi.poifs.crypt;
+package org.apache.poi.poifs.crypt.agile;
 
 import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.commons.codec.binary.Base64;
 import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.poifs.filesystem.DocumentInputStream;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.EncryptionVerifier;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.xmlbeans.XmlException;
+
+import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor;
+import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
+import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
+import com.microsoft.schemas.office.x2006.keyEncryptor.certificate.CTCertificateKeyEncryptor;
+import com.microsoft.schemas.office.x2006.keyEncryptor.password.CTPasswordKeyEncryptor;
 
 /**
  * Used when checking if a key is valid for a document 
  */
-public class EncryptionVerifier {
-    private final byte[] salt;
-    private final byte[] verifier;
-    private final byte[] verifierHash;
-    private final byte[] encryptedKey;
-    private final int verifierHashSize;
-    private final int spinCount;
-    private final int algorithm;
-    private final int cipherMode;
+public class AgileEncryptionVerifier extends EncryptionVerifier {
+
+    public static class AgileCertificateEntry {
+        X509Certificate x509;
+        byte encryptedKey[];
+        byte certVerifier[];
+    }
+    
+    private List<AgileCertificateEntry> certList = new ArrayList<AgileCertificateEntry>();
+
+    
+    public AgileEncryptionVerifier(String descriptor) {
+        EncryptionDocument ed;
+        try {
+            ed = EncryptionDocument.Factory.parse(descriptor);
+        } catch (XmlException e) {
+            throw new EncryptedDocumentException("Unable to parse encryption descriptor", e);
+        }
 
-    public EncryptionVerifier(String descriptor) {
-        NamedNodeMap keyData = null;
+        Iterator<CTKeyEncryptor> encList = ed.getEncryption().getKeyEncryptors().getKeyEncryptorList().iterator();
+        CTPasswordKeyEncryptor keyData;
         try {
-            ByteArrayInputStream is;
-            is = new ByteArrayInputStream(descriptor.getBytes());
-            NodeList keyEncryptor = DocumentBuilderFactory.newInstance()
-                .newDocumentBuilder().parse(is)
-                .getElementsByTagName("keyEncryptor").item(0).getChildNodes();
-            for (int i = 0; i < keyEncryptor.getLength(); i++) {
-                Node node = keyEncryptor.item(i);
-                if (node.getNodeName().equals("p:encryptedKey")) {
-                    keyData = node.getAttributes();
-                    break;
-                }
+            keyData = encList.next().getEncryptedPasswordKey();
+            if (keyData == null) {
+                throw new NullPointerException("encryptedKey not set");
             }
-            if (keyData == null)
-                throw new EncryptedDocumentException("");
         } catch (Exception e) {
-            throw new EncryptedDocumentException("Unable to parse keyEncryptor");
+            throw new EncryptedDocumentException("Unable to parse keyData", e);
         }
-
-        spinCount = Integer.parseInt(keyData.getNamedItem("spinCount")
-                                     .getNodeValue());
-        verifier = Base64.decodeBase64(keyData
-                                       .getNamedItem("encryptedVerifierHashInput")
-                                       .getNodeValue().getBytes());
-        salt = Base64.decodeBase64(keyData.getNamedItem("saltValue")
-                                   .getNodeValue().getBytes());
-
-        encryptedKey = Base64.decodeBase64(keyData
-                                           .getNamedItem("encryptedKeyValue")
-                                           .getNodeValue().getBytes());
-
-        int saltSize = Integer.parseInt(keyData.getNamedItem("saltSize")
-                                        .getNodeValue());
-        if (saltSize != salt.length)
-            throw new EncryptedDocumentException("Invalid salt size");
-
-        verifierHash = Base64.decodeBase64(keyData
-                                           .getNamedItem("encryptedVerifierHashValue")
-                                           .getNodeValue().getBytes());
-
-        int blockSize = Integer.parseInt(keyData.getNamedItem("blockSize")
-                                         .getNodeValue());
-
-        String alg = keyData.getNamedItem("cipherAlgorithm").getNodeValue();
         
-        int keyBits = Integer.parseInt(keyData.getNamedItem("keyBits")
-                .getNodeValue());
-
-        if ("AES".equals(alg)) {
-        	switch (keyBits) {
-              case 128: 
-                  algorithm = EncryptionHeader.ALGORITHM_AES_128; break;
-              case 192: 
-                  algorithm = EncryptionHeader.ALGORITHM_AES_192; break;
-              case 256: 
-                  algorithm = EncryptionHeader.ALGORITHM_AES_256; break;
-              default: 
-                  throw new EncryptedDocumentException("Unsupported key size");
-        	}
-        } else {
-            throw new EncryptedDocumentException("Unsupported cipher");
-        }
-
-        String chain = keyData.getNamedItem("cipherChaining").getNodeValue();
-        if ("ChainingModeCBC".equals(chain))
-            cipherMode = EncryptionHeader.MODE_CBC;
-        else if ("ChainingModeCFB".equals(chain))
-            cipherMode = EncryptionHeader.MODE_CFB;
-        else
-            throw new EncryptedDocumentException("Unsupported chaining mode");
+        int keyBits = (int)keyData.getKeyBits();
+        
+        CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), keyBits);
+        setCipherAlgorithm(ca);
 
-        verifierHashSize = Integer.parseInt(keyData.getNamedItem("hashSize")
-                                            .getNodeValue());
-    }
+        int hashSize = keyData.getHashSize();
 
-    public EncryptionVerifier(DocumentInputStream is, int encryptedLength) {
-        int saltSize = is.readInt();
+        HashAlgorithm ha = HashAlgorithm.fromEcmaId(keyData.getHashAlgorithm().toString());
+        setHashAlgorithm(ha);
 
-        if (saltSize!=16) {
-            throw new RuntimeException("Salt size != 16 !?");
+        if (getHashAlgorithm().hashSize != hashSize) {
+            throw new EncryptedDocumentException("Unsupported hash algorithm: " + 
+                    keyData.getHashAlgorithm() + " @ " + hashSize + " bytes");
         }
 
-        salt = new byte[16];
-        is.readFully(salt);
-        verifier = new byte[16];
-        is.readFully(verifier);
-
-        verifierHashSize = is.readInt();
-
-        verifierHash = new byte[encryptedLength];
-        is.readFully(verifierHash);
+        setSpinCount(keyData.getSpinCount());
+        setEncryptedVerifier(keyData.getEncryptedVerifierHashInput());
+        setSalt(keyData.getSaltValue());
+        setEncryptedKey(keyData.getEncryptedKeyValue()); 
+        setEncryptedVerifierHash(keyData.getEncryptedVerifierHashValue());
 
-        spinCount = 50000;
-        algorithm = EncryptionHeader.ALGORITHM_AES_128;
-        cipherMode = EncryptionHeader.MODE_ECB;
-        encryptedKey = null;
-    }
-
-    public byte[] getSalt() {
-        return salt;
+        int saltSize = keyData.getSaltSize();
+        if (saltSize != getSalt().length)
+            throw new EncryptedDocumentException("Invalid salt size");
+        
+        switch (keyData.getCipherChaining().intValue()) {
+            case STCipherChaining.INT_CHAINING_MODE_CBC:
+                setChainingMode(ChainingMode.cbc);
+                break;
+            case STCipherChaining.INT_CHAINING_MODE_CFB:
+                setChainingMode(ChainingMode.cfb);
+                break;
+            default:
+                throw new EncryptedDocumentException("Unsupported chaining mode - "+keyData.getCipherChaining().toString());
+        }
+        
+        if (!encList.hasNext()) return;
+        
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            while (encList.hasNext()) {
+                CTCertificateKeyEncryptor certKey = encList.next().getEncryptedCertificateKey();
+                AgileCertificateEntry ace = new AgileCertificateEntry();
+                ace.certVerifier = certKey.getCertVerifier();
+                ace.encryptedKey = certKey.getEncryptedKeyValue();
+                ace.x509 = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(certKey.getX509Certificate()));
+                certList.add(ace);
+            }
+        } catch (GeneralSecurityException e) {
+            throw new EncryptedDocumentException("can't parse X509 certificate", e);
+        }
     }
-
-    public byte[] getVerifier() {
-        return verifier;
+    
+    public AgileEncryptionVerifier(CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) {
+        setCipherAlgorithm(cipherAlgorithm);
+        setHashAlgorithm(hashAlgorithm);
+        setChainingMode(chainingMode);
+        setSpinCount(100000); // TODO: use parameter
+    }
+    
+    protected void setSalt(byte salt[]) {
+        if (salt == null || salt.length != getCipherAlgorithm().blockSize) {
+            throw new EncryptedDocumentException("invalid verifier salt");
+        }
+        super.setSalt(salt);
     }
-
-    public byte[] getVerifierHash() {
-        return verifierHash;
+    
+    // make method visible for this package
+    protected void setEncryptedVerifier(byte encryptedVerifier[]) {
+        super.setEncryptedVerifier(encryptedVerifier);
     }
 
-    public int getSpinCount() {
-        return spinCount;
+    // make method visible for this package
+    protected void setEncryptedVerifierHash(byte encryptedVerifierHash[]) {
+        super.setEncryptedVerifierHash(encryptedVerifierHash);
     }
 
-    public int getCipherMode() {
-        return cipherMode;
+    // make method visible for this package
+    protected void setEncryptedKey(byte[] encryptedKey) {
+        super.setEncryptedKey(encryptedKey);
     }
-
-    public int getAlgorithm() {
-        return algorithm;
+    
+    public void addCertificate(X509Certificate x509) {
+        AgileCertificateEntry ace = new AgileCertificateEntry();
+        ace.x509 = x509;
+        certList.add(ace);
     }
-
-    public byte[] getEncryptedKey() {
-        return encryptedKey;
+    
+    public List<AgileCertificateEntry> getCertificates() {
+        return certList;
     }
 }

Added: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java Tue Dec 24 23:13:21 2013
@@ -0,0 +1,511 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.poifs.crypt.agile;
+
+import static org.apache.poi.poifs.crypt.CryptoFunctions.generateIv;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getCipher;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest;
+import static org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.getNextBlockSize;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.hashInput;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kCryptoKeyBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kHashedVerifierBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kIntegrityKeyBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kIntegrityValueBlock;
+import static org.apache.poi.poifs.crypt.agile.AgileDecryptor.kVerifierInputBlock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.DataSpaceMapUtils;
+import org.apache.poi.poifs.crypt.EncryptionHeader;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.Encryptor;
+import org.apache.poi.poifs.crypt.HashAlgorithm;
+import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.POIFSWriterEvent;
+import org.apache.poi.poifs.filesystem.POIFSWriterListener;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianOutputStream;
+import org.apache.poi.util.TempFile;
+import org.apache.xmlbeans.XmlOptions;
+
+import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
+import com.microsoft.schemas.office.x2006.encryption.CTEncryption;
+import com.microsoft.schemas.office.x2006.encryption.CTKeyData;
+import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor;
+import com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptors;
+import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
+import com.microsoft.schemas.office.x2006.encryption.STCipherAlgorithm;
+import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
+import com.microsoft.schemas.office.x2006.encryption.STHashAlgorithm;
+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;
+    @SuppressWarnings("unused")
+    private byte integritySalt[];
+    private Mac integrityMD;
+	private byte pwHash[];
+    
+	protected AgileEncryptor(AgileEncryptionInfoBuilder builder) {
+		this.builder = builder;
+	}
+
+    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;
+        
+        byte[] verifierSalt = new byte[blockSize]
+             , verifier = new byte[blockSize]
+             , keySalt = new byte[blockSize]
+             , keySpec = new byte[keySize]
+             , integritySalt = new byte[hashSize];
+        r.nextBytes(verifierSalt); // blocksize
+        r.nextBytes(verifier); // blocksize
+        r.nextBytes(keySalt); // blocksize
+        r.nextBytes(keySpec); // keysize
+        r.nextBytes(integritySalt); // hashsize
+        
+        confirmPassword(password, keySpec, keySalt, verifierSalt, verifier, integritySalt);
+    }
+	
+	public void confirmPassword(String password, byte keySpec[], byte keySalt[], byte verifier[], byte verifierSalt[], byte integritySalt[]) {
+        AgileEncryptionVerifier ver = builder.getVerifier();
+        ver.setSalt(verifierSalt);
+        AgileEncryptionHeader header = builder.getHeader();
+        header.setKeySalt(keySalt);
+        HashAlgorithm hashAlgo = ver.getHashAlgorithm();
+
+        int blockSize = header.getBlockSize();
+	    
+        pwHash = hashPassword(password, hashAlgo, verifierSalt, ver.getSpinCount());
+        
+        /**
+         * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
+         * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize
+         *    attribute.
+         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79.
+         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
+         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
+         *    integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of
+         *    blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte encryptedVerifier[] = hashInput(builder, pwHash, kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
+        ver.setEncryptedVerifier(encryptedVerifier);
+	    
+
+        /**
+         * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps:
+         * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for
+         *    encryptedVerifierHashInput.
+         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e.
+         * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as
+         *    an initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of
+         *    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.
+         */
+        MessageDigest hashMD = getMessageDigest(hashAlgo);
+        byte[] hashedVerifier = hashMD.digest(verifier);
+        byte encryptedVerifierHash[] = hashInput(builder, pwHash, kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
+        ver.setEncryptedVerifierHash(encryptedVerifierHash);
+        
+        /**
+         * encryptedKeyValue: This attribute MUST be generated by using the following steps:
+         * 1. Generate a random array of bytes that is the same size as specified by the
+         *    Encryptor.KeyData.keyBits attribute of the parent element.
+         * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password,
+         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
+         *    consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6.
+         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
+         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
+         *    integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of
+         *    blockSize bytes.
+         * 4. Use base64 to encode the result of step 3.
+         */
+        byte encryptedKey[] = hashInput(builder, pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
+        ver.setEncryptedKey(encryptedKey);
+        
+        SecretKey secretKey = new SecretKeySpec(keySpec, ver.getCipherAlgorithm().jceId);
+        setSecretKey(secretKey);
+        
+        /*
+         * 2.3.4.14 DataIntegrity Generation (Agile Encryption)
+         * 
+         * The DataIntegrity element contained within an Encryption element MUST be generated by using
+         * the following steps:
+         * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor
+         *    contained within the KeyEncryptors sequence. Use this key for encryption operations in the
+         *    remaining steps of this section.
+         * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the
+         *    KeyData.hashSize attribute.
+         * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the
+         *    KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes:
+         *    0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an initialization vector as
+         *    specified in section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize
+         *    bytes, pad the array with 0x00 to the next integral multiple of blockSize bytes.
+         * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3.
+         * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
+         *    which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
+         *    Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
+         *    used as the message.
+         * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
+         *    0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
+         * 7.  Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6. 
+         */
+        this.integritySalt = integritySalt;
+
+        try {
+            byte vec[] = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityKeyBlock, header.getBlockSize());
+            Cipher cipher = getCipher(secretKey, ver.getCipherAlgorithm(), ver.getChainingMode(), vec, Cipher.ENCRYPT_MODE);
+            byte filledSalt[] = getBlock0(integritySalt, getNextBlockSize(integritySalt.length, blockSize));
+            byte encryptedHmacKey[] = cipher.doFinal(filledSalt);
+            header.setEncryptedHmacKey(encryptedHmacKey);
+
+            this.integrityMD = CryptoFunctions.getMac(hashAlgo);
+            this.integrityMD.init(new SecretKeySpec(integritySalt, hashAlgo.jceHmacId));
+
+        
+            cipher = Cipher.getInstance("RSA");
+            for (AgileCertificateEntry ace : ver.getCertificates()) {
+                cipher.init(Cipher.ENCRYPT_MODE, ace.x509.getPublicKey());
+                ace.encryptedKey = cipher.doFinal(getSecretKey().getEncoded());
+                Mac x509Hmac = CryptoFunctions.getMac(hashAlgo);
+                x509Hmac.init(getSecretKey());
+                ace.certVerifier = x509Hmac.doFinal(ace.x509.getEncoded());
+            }
+        } catch (GeneralSecurityException e) {
+            throw new EncryptedDocumentException(e);
+        }
+	}
+	
+    public OutputStream getDataStream(DirectoryNode dir)
+            throws IOException, GeneralSecurityException {
+        // TODO: initialize headers
+        OutputStream countStream = new ChunkedCipherOutputStream(dir);
+    	return countStream;
+    }
+
+    /**
+     * 2.3.4.15 Data Encryption (Agile Encryption)
+     * 
+     * The EncryptedPackage stream (1) MUST be encrypted in 4096-byte segments to facilitate nearly
+     * random access while allowing CBC modes to be used in the encryption process.
+     * The initialization vector for the encryption process MUST be obtained by using the zero-based
+     * segment number as a blockKey and the binary form of the KeyData.saltValue as specified in
+     * section 2.3.4.12. The block number MUST be represented as a 32-bit unsigned integer.
+     * Data blocks MUST then be encrypted by using the initialization vector and the intermediate key
+     * obtained by decrypting the encryptedKeyValue from a KeyEncryptor contained within the
+     * KeyEncryptors sequence as specified in section 2.3.4.10. The final data block MUST be padded to
+     * the next integral multiple of the KeyData.blockSize value. Any padding bytes can be used. Note
+     * that the StreamSize field of the EncryptedPackage field specifies the number of bytes of
+     * unencrypted data as specified in section 2.3.4.4.
+     */
+    private class ChunkedCipherOutputStream extends FilterOutputStream implements POIFSWriterListener {
+        private long _pos = 0;
+        private final byte[] _chunk = new byte[4096];
+        private Cipher _cipher;
+        private final File fileOut;
+        protected final DirectoryNode dir;
+
+        public ChunkedCipherOutputStream(DirectoryNode dir) throws IOException {
+            super(null);
+            fileOut = TempFile.createTempFile("encrypted_package", "crypt");
+            this.out = new FileOutputStream(fileOut);
+            this.dir = dir;
+            EncryptionHeader header = builder.getHeader();
+            _cipher = getCipher(getSecretKey(), header.getCipherAlgorithm(), header.getChainingMode(), null, Cipher.ENCRYPT_MODE);
+        }
+
+        public void write(int b) throws IOException {
+            write(new byte[]{(byte)b});
+        }
+
+        public void write(byte[] b) throws IOException {
+            write(b, 0, b.length);
+        }
+
+        public void write(byte[] b, int off, int len)
+        throws IOException {
+            if (len == 0) return;
+            
+            if (len < 0 || b.length < off+len) {
+                throw new IOException("not enough bytes in your input buffer");
+            }
+            
+            while (len > 0) {
+                int posInChunk = (int)(_pos & 0xfff);
+                int nextLen = Math.min(4096-posInChunk, len);
+                System.arraycopy(b, off, _chunk, posInChunk, nextLen);
+                _pos += nextLen;
+                off += nextLen;
+                len -= nextLen;
+                if ((_pos & 0xfff) == 0) {
+                    writeChunk();
+                }
+            }
+        }
+
+        private void writeChunk() throws IOException {
+            EncryptionHeader header = builder.getHeader();
+            int blockSize = header.getBlockSize();
+
+            int posInChunk = (int)(_pos & 0xfff);
+            // normally posInChunk is 0, i.e. on the next chunk (-> index-1)
+            // but if called on close(), posInChunk is somewhere within the chunk data
+            int index = (int)(_pos >> 12);
+            if (posInChunk==0) {
+                index--;
+                posInChunk = 4096;
+            } else {
+                // pad the last chunk
+                _cipher = getCipher(getSecretKey(), header.getCipherAlgorithm(), header.getChainingMode(), null, Cipher.ENCRYPT_MODE, "PKCS5Padding");
+            }
+
+            byte[] blockKey = new byte[4];
+            LittleEndian.putInt(blockKey, 0, index);
+            byte[] iv = generateIv(header.getHashAlgorithmEx(), header.getKeySalt(), blockKey, blockSize);
+            try {
+                _cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(), new IvParameterSpec(iv));
+                int ciLen = _cipher.doFinal(_chunk, 0, posInChunk, _chunk);
+                out.write(_chunk, 0, ciLen);
+            } catch (GeneralSecurityException e) {
+                throw new IOException(e);
+            }
+        }
+        
+        public void close() throws IOException {
+            writeChunk();
+            super.close();
+            writeToPOIFS();
+        }
+
+        void writeToPOIFS() throws IOException {
+            DataSpaceMapUtils.addDefaultDataSpace(dir);
+            
+            /**
+             * Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message), 
+             * which the DataIntegrity element will verify by using the Salt generated in step 2 as the key. 
+             * Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be 
+             * used as the message.
+             * 
+             * Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
+             * 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
+             **/
+            byte buf[] = new byte[4096];
+            LittleEndian.putLong(buf, 0, _pos);
+            integrityMD.update(buf, 0, LittleEndianConsts.LONG_SIZE);
+            
+            InputStream fis = new FileInputStream(fileOut);
+            for (int readBytes; (readBytes = fis.read(buf)) != -1; integrityMD.update(buf, 0, readBytes));
+            fis.close();
+            
+            AgileEncryptionHeader header = builder.getHeader(); 
+            int blockSize = header.getBlockSize();
+            
+            byte hmacValue[] = integrityMD.doFinal();
+            byte iv[] = CryptoFunctions.generateIv(header.getHashAlgorithmEx(), header.getKeySalt(), kIntegrityValueBlock, header.getBlockSize());
+            Cipher cipher = CryptoFunctions.getCipher(getSecretKey(), header.getCipherAlgorithm(), header.getChainingMode(), iv, Cipher.ENCRYPT_MODE);
+            try {
+                byte hmacValueFilled[] = getBlock0(hmacValue, getNextBlockSize(hmacValue.length, blockSize));
+                byte encryptedHmacValue[] = cipher.doFinal(hmacValueFilled);
+                header.setEncryptedHmacValue(encryptedHmacValue);
+            } catch (GeneralSecurityException e) {
+                throw new EncryptedDocumentException(e);
+            }
+
+            createEncryptionInfoEntry(dir);
+            
+            int oleStreamSize = (int)(fileOut.length()+LittleEndianConsts.LONG_SIZE);
+            dir.createDocument("EncryptedPackage", oleStreamSize, this);
+            // TODO: any properties???
+        }
+    
+        public void processPOIFSWriterEvent(POIFSWriterEvent event) {
+            try {
+                LittleEndianOutputStream leos = new LittleEndianOutputStream(event.getStream());
+
+                // StreamSize (8 bytes): An unsigned integer that specifies the number of bytes used by data 
+                // encrypted within the EncryptedData field, not including the size of the StreamSize field. 
+                // Note that the actual size of the \EncryptedPackage stream (1) can be larger than this 
+                // value, depending on the block size of the chosen encryption algorithm
+                leos.writeLong(_pos);
+
+                FileInputStream fis = new FileInputStream(fileOut);
+                IOUtils.copy(fis, leos);
+                fis.close();
+                fileOut.delete();
+
+                leos.close();
+            } catch (IOException e) {
+                throw new EncryptedDocumentException(e);
+            }
+        }
+    }
+
+    protected void createEncryptionInfoEntry(DirectoryNode dir) throws IOException {
+        AgileEncryptionVerifier ver = builder.getVerifier();
+        AgileEncryptionHeader header = builder.getHeader();
+        
+        EncryptionDocument ed = EncryptionDocument.Factory.newInstance();
+        CTEncryption edRoot = ed.addNewEncryption();
+        
+        CTKeyData keyData = edRoot.addNewKeyData();
+        CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();
+        CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();
+        keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_PASSWORD);
+        CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();
+
+        keyPass.setSpinCount(ver.getSpinCount());
+        
+        keyData.setSaltSize(header.getBlockSize());
+        keyPass.setSaltSize(header.getBlockSize());
+        
+        keyData.setBlockSize(header.getBlockSize());
+        keyPass.setBlockSize(header.getBlockSize());
+
+        keyData.setKeyBits(header.getKeySize());
+        keyPass.setKeyBits(header.getKeySize());
+
+        HashAlgorithm hashAlgo = header.getHashAlgorithmEx();
+        keyData.setHashSize(hashAlgo.hashSize);
+        keyPass.setHashSize(hashAlgo.hashSize);
+
+        STCipherAlgorithm.Enum xmlCipherAlgo = STCipherAlgorithm.Enum.forString(header.getCipherAlgorithm().xmlId);
+        if (xmlCipherAlgo == null) {
+            throw new EncryptedDocumentException("CipherAlgorithm "+header.getCipherAlgorithm()+" not supported.");
+        }
+        keyData.setCipherAlgorithm(xmlCipherAlgo);
+        keyPass.setCipherAlgorithm(xmlCipherAlgo);
+        
+        switch (header.getChainingMode()) {
+        case cbc: 
+            keyData.setCipherChaining(STCipherChaining.CHAINING_MODE_CBC);
+            keyPass.setCipherChaining(STCipherChaining.CHAINING_MODE_CBC);
+            break;
+        case cfb:
+            keyData.setCipherChaining(STCipherChaining.CHAINING_MODE_CFB);
+            keyPass.setCipherChaining(STCipherChaining.CHAINING_MODE_CFB);
+            break;
+        default:
+            throw new EncryptedDocumentException("ChainingMode "+header.getChainingMode()+" not supported.");
+        }
+        
+        STHashAlgorithm.Enum xmlHashAlgo = STHashAlgorithm.Enum.forString(hashAlgo.ecmaString);
+        if (xmlHashAlgo == null) {
+            throw new EncryptedDocumentException("HashAlgorithm "+hashAlgo+" not supported.");
+        }
+        keyData.setHashAlgorithm(xmlHashAlgo);
+        keyPass.setHashAlgorithm(xmlHashAlgo);
+
+        keyData.setSaltValue(header.getKeySalt());
+        keyPass.setSaltValue(ver.getSalt());
+        keyPass.setEncryptedVerifierHashInput(ver.getEncryptedVerifier());
+        keyPass.setEncryptedVerifierHashValue(ver.getEncryptedVerifierHash());
+        keyPass.setEncryptedKeyValue(ver.getEncryptedKey());
+        
+        CTDataIntegrity hmacData = edRoot.addNewDataIntegrity();
+        hmacData.setEncryptedHmacKey(header.getEncryptedHmacKey());
+        hmacData.setEncryptedHmacValue(header.getEncryptedHmacValue());
+        
+        for (AgileCertificateEntry ace : ver.getCertificates()) {
+            keyEnc = keyEncList.addNewKeyEncryptor();
+            keyEnc.setUri(CTKeyEncryptor.Uri.HTTP_SCHEMAS_MICROSOFT_COM_OFFICE_2006_KEY_ENCRYPTOR_CERTIFICATE);
+            CTCertificateKeyEncryptor certData = keyEnc.addNewEncryptedCertificateKey();
+            try {
+                certData.setX509Certificate(ace.x509.getEncoded());
+            } catch (CertificateEncodingException e) {
+                throw new EncryptedDocumentException(e);
+            }
+            certData.setEncryptedKeyValue(ace.encryptedKey);
+            certData.setCertVerifier(ace.certVerifier);
+        }
+
+        XmlOptions xo = new XmlOptions();
+        xo.setCharacterEncoding("UTF-8");
+        Map<String,String> nsMap = new HashMap<String,String>();
+        nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/password","p");
+        nsMap.put("http://schemas.microsoft.com/office/2006/keyEncryptor/certificate", "c");
+        nsMap.put("http://schemas.microsoft.com/office/2006/encryption","");
+        xo.setSaveSuggestedPrefixes(nsMap);
+        xo.setSaveNamespacesFirst();
+        xo.setSaveAggressiveNamespaces();
+        // setting standalone doesn't work with xmlbeans-2.3
+        xo.setSaveNoXmlDecl();
+        
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        bos.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n".getBytes("UTF-8"));
+        ed.save(bos, xo);
+
+        final byte buf[] = new byte[5000];        
+        LittleEndianByteArrayOutputStream leos = new LittleEndianByteArrayOutputStream(buf, 0);
+        EncryptionInfo info = builder.getInfo();
+
+        // EncryptionVersionInfo (4 bytes): A Version structure (section 2.1.4), where 
+        // Version.vMajor MUST be 0x0004 and Version.vMinor MUST be 0x0004
+        leos.writeShort(info.getVersionMajor());
+        leos.writeShort(info.getVersionMinor());
+        // Reserved (4 bytes): A value that MUST be 0x00000040
+        leos.writeInt(0x40);
+        leos.write(bos.toByteArray());
+        
+        dir.createDocument("EncryptionInfo", leos.getWriteIndex(), new POIFSWriterListener() {
+            public void processPOIFSWriterEvent(POIFSWriterEvent event) {
+                try {
+                    event.getStream().write(buf, 0, event.getLimit());
+                } catch (IOException e) {
+                    throw new EncryptedDocumentException(e);
+                }
+            }
+        });
+    }
+}

Modified: poi/trunk/src/ooxml/java/org/apache/poi/util/OOXMLLite.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/util/OOXMLLite.java?rev=1553336&r1=1553335&r2=1553336&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/util/OOXMLLite.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/util/OOXMLLite.java Tue Dec 24 23:13:21 2013
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -32,10 +33,13 @@ import java.util.Vector;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
+import junit.framework.JUnit4TestAdapter;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 import junit.textui.TestRunner;
 
+import org.junit.Test;
+
 /**
  * Build a 'lite' version of the ooxml-schemas.jar
  *
@@ -103,9 +107,18 @@ public final class OOXMLLite {
 
             String cls = arg.replace(".class", "");
             try {
-                @SuppressWarnings("unchecked")
-				Class<? extends TestCase> test = (Class<? extends TestCase>) Class.forName(cls);
-                suite.addTestSuite(test);
+                Class<?> testclass = Class.forName(cls);
+                boolean isTest = TestCase.class.isAssignableFrom(testclass);
+                if (!isTest) {
+                    for (Method m : testclass.getDeclaredMethods()) {
+                        isTest = m.isAnnotationPresent(Test.class);
+                        if (isTest) break;
+                    }
+                }
+                
+                if (isTest) {
+                    suite.addTest(new JUnit4TestAdapter(testclass));
+                }
             } catch (ClassNotFoundException e) {
                 throw new RuntimeException(e);
             }
@@ -181,8 +194,12 @@ public final class OOXMLLite {
             Vector<Class<?>> classes = (Vector<Class<?>>) _classes.get(appLoader);
             Map<String, Class<?>> map = new HashMap<String, Class<?>>();
             for (Class<?> cls : classes) {
-                String jar = cls.getProtectionDomain().getCodeSource().getLocation().toString();
-                if(jar.indexOf(ptrn) != -1) map.put(cls.getName(), cls);
+                try {
+                    String jar = cls.getProtectionDomain().getCodeSource().getLocation().toString();
+                    if(jar.indexOf(ptrn) != -1) map.put(cls.getName(), cls);
+                } catch (NullPointerException e) {
+                    continue;
+                }
             }
             return map;
         } catch (IllegalAccessException e) {

Added: poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsd
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsd?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsd (added)
+++ poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsd Tue Dec 24 23:13:21 2013
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   ====================================================================
+-->
+<xs:schema xmlns="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" xmlns:e="http://schemas.microsoft.com/office/2006/encryption" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:import namespace="http://schemas.microsoft.com/office/2006/encryption" schemaLocation="encryptionInfo.xsd"/>
+	<xs:simpleType name="ST_PasswordKeyEncryptorUri">
+		<xs:restriction base="xs:token">
+			<xs:enumeration value="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="CT_CertificateKeyEncryptor">
+		<xs:attribute name="encryptedKeyValue" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded value that specifies the encrypted form of the intermediate key, which is encrypted with the public key contained within the X509Certificate attribute.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="X509Certificate" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded value that specifies a DER-encoded X.509 certificate (1) used to encrypt the intermediate key. The certificate (1) MUST contain only the public portion of the public-private key pair.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="certVerifier" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded value that specifies the HMAC of the binary data obtained by base64-decoding the X509Certificate attribute. The hashing algorithm used to derive the HMAC MUST be the hashing algorithm specified for the Encryption.keyData element. The secret key used to derive the HMAC MUST be the intermediate key. If the intermediate key is reset, any CertificateKeyEncryptor elements are also reset to contain the new intermediate key, except that the certVerifier attribute MUST match the value calculated using the current intermediate key, to verify that the CertificateKeyEncryptor element actually encrypted the current intermediate key. If a CertificateKeyEncryptor element does not have a correct certVerifier attribute, it MUST be discarded.</xs:documentation></xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:element name="encryptedKey" type="CT_CertificateKeyEncryptor"/>
+</xs:schema>

Added: poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsdconfig
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsdconfig?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsdconfig (added)
+++ poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionCertificate.xsdconfig Tue Dec 24 23:13:21 2013
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   ====================================================================
+-->
+<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config" xmlns:c="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate">
+
+<xb:qname name="c:encryptedKey" javaname="EncryptedCertificateKey"/>
+  
+</xb:config>
\ No newline at end of file

Added: poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsd
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsd?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsd (added)
+++ poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsd Tue Dec 24 23:13:21 2013
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   ====================================================================
+-->
+<xs:schema xmlns="http://schemas.microsoft.com/office/2006/encryption" xmlns:p="http://schemas.microsoft.com/office/2006/keyEncryptor/password" xmlns:c="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schemas.microsoft.com/office/2006/encryption" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:import namespace="http://schemas.microsoft.com/office/2006/keyEncryptor/password" schemaLocation="encryptionPassword.xsd"/>
+	<xs:import namespace="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" schemaLocation="encryptionCertificate.xsd"/>
+	<xs:simpleType name="ST_SaltSize">
+		<xs:annotation>
+			<xs:documentation>An unsigned integer that specifies the number of bytes used by a salt. It MUST be at least 1 and no greater than 65,536.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:unsignedInt">
+			<xs:minInclusive value="1"/>
+			<xs:maxInclusive value="65536"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_BlockSize">
+		<xs:annotation>
+			<xs:documentation>An unsigned integer that specifies the number of bytes used to encrypt one block of data. It MUST be at least 2, no greater than 4096, and a multiple of 2.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:unsignedInt">
+			<xs:minInclusive value="2"/>
+			<xs:maxInclusive value="4096"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_KeyBits">
+		<xs:annotation>
+			<xs:documentation>An unsigned integer that specifies the number of bits used by an encryption algorithm. It MUST be at least 8 and a multiple of 8.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:unsignedInt">
+			<xs:minInclusive value="8"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_HashSize">
+		<xs:annotation>
+			<xs:documentation>An unsigned integer that specifies the number of bytes used by a hash value. It MUST be at least 1, no greater than 65,536, and the same number of bytes as the hash algorithm emits.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:unsignedInt">
+			<xs:minInclusive value="1"/>
+			<xs:maxInclusive value="65536"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_SpinCount">
+		<xs:annotation>
+			<xs:documentation>An unsigned integer that specifies the number of times to iterate on a hash of a password. It MUST NOT be greater than 10,000,000.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:unsignedInt">
+			<xs:minInclusive value="0"/>
+			<xs:maxInclusive value="10000000"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_CipherAlgorithm">
+		<xs:annotation>
+			<xs:appinfo>modified for poi - list is restricted to given list in [ms-offcrypto]</xs:appinfo>
+			<xs:documentation>A string that specifies the cipher algorithm. Values that are not defined MAY be used, and a compliant implementation is not required to support all defined values. Any algorithm that can be resolved by name by the underlying operating system can be used for hashing or encryption. Only block algorithms are supported for encryption. AES-128 is the default encryption algorithm, and SHA-1 is the default hashing algorithm if no other algorithms have been configured.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:token">
+			<xs:enumeration value="AES">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the AES algorithm.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="RC2">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the algorithm as specified in [RFC2268] (http://tools.ietf.org/html/rfc2268). The use of RC2 is not recommended. If RC2 is used with a key length of less than 128 bits, documents could interoperate incorrectly across different versions of Windows.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="RC4">
+				<xs:annotation>
+					<xs:documentation>MUST NOT be used.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="DES">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the DES algorithm. The use of DES is not recommended. If DES is used, the key length specified in the KeyBits element is required to be set to 64 for 56-bit encryption, and the key decrypted from encryptedKeyValue of KeyEncryptor is required to include the DES parity bits.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="DESX">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the algorithm as specified in [DRAFT-DESX] (http://tools.ietf.org/html/draft-ietf-ipsec-ciph-desx-00). The use of DESX is not recommended. If DESX is used, documents could interoperate incorrectly across different versions of Windows.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="3DES">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the algorithm as specified in [RFC1851] (http://tools.ietf.org/html/rfc1851). If 3DES or 3DES_112 is used, the key length specified in the KeyBits element is required to be set to 192 for 168-bit encryption and 128 for 112-bit encryption, and the key decrypted from encryptedKeyValue of KeyEncryptor is required to include the DES parity bits.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="3DES_112">
+				<xs:annotation>
+					<xs:documentation>see 3DES</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_CipherChaining">
+		<xs:annotation>
+			<xs:documentation>A string that specifies the chaining mode used by CipherAlgorithm. For more details about chaining modes, see [BCMO800-38A] (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf).</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:token">
+			<xs:enumeration value="ChainingModeCBC">
+				<xs:annotation>
+					<xs:documentation>block chaining (CBC)</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="ChainingModeCFB">
+				<xs:annotation>
+					<xs:documentation>Cipher feedback chaining (CFB), with an 8-bit window</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:simpleType name="ST_HashAlgorithm">
+		<xs:annotation>
+			<xs:appinfo>modified for poi - list is restricted to given list in [ms-offcrypto]</xs:appinfo>
+			<xs:documentation>A string specifying a hashing algorithm. Values that are not defined MAY be used, and a compliant implementation is not required to support all defined values.</xs:documentation>
+		</xs:annotation>
+		<xs:restriction base="xs:token">
+			<xs:enumeration value="SHA1">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the algorithm as specified in [RFC4634] (http://tools.ietf.org/html/rfc4634).</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="SHA256">
+				<xs:annotation>
+					<xs:documentation>see SHA1</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="SHA384">
+				<xs:annotation>
+					<xs:documentation>see SHA1</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="SHA512">
+				<xs:annotation>
+					<xs:documentation>see SHA1</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="MD5">
+				<xs:annotation>
+					<xs:documentation>MUST conform to MD5.</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="MD4">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the algorithm as specified in [RFC1320] (http://tools.ietf.org/html/rfc1320).</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="MD2">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the algorithm as specified in [RFC1319] (http://tools.ietf.org/html/rfc1319).</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="RIPEMD-128">
+				<xs:annotation>
+					<xs:documentation>MUST conform to the hash functions specified in [ISO/IEC 10118]. (https://en.wikipedia.org/wiki/RIPEMD)</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="RIPEMD-160">
+				<xs:annotation>
+					<xs:documentation>see RIPEMD-128 (https://en.wikipedia.org/wiki/RIPEMD)</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+			<xs:enumeration value="WHIRLPOOL">
+				<xs:annotation>
+					<xs:documentation>see RIPEMD-128 (https://en.wikipedia.org/wiki/ISO/IEC_10118-3)</xs:documentation>
+				</xs:annotation>
+			</xs:enumeration>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="CT_KeyData">
+		<xs:annotation>
+			<xs:documentation>A complex type that specifies the encryption used within this element. The saltValue attribute is a base64-encoded binary value that is randomly generated. The number of bytes required to decode the saltValue attribute MUST be equal to the value of the saltSize attribute.</xs:documentation>
+		</xs:annotation>
+		<xs:attribute name="saltSize" type="ST_SaltSize" use="required"/>
+		<xs:attribute name="blockSize" type="ST_BlockSize" use="required"/>
+		<xs:attribute name="keyBits" type="ST_KeyBits" use="required"/>
+		<xs:attribute name="hashSize" type="ST_HashSize" use="required"/>
+		<xs:attribute name="cipherAlgorithm" type="ST_CipherAlgorithm" use="required"/>
+		<xs:attribute name="cipherChaining" type="ST_CipherChaining" use="required"/>
+		<xs:attribute name="hashAlgorithm" type="ST_HashAlgorithm" use="required"/>
+		<xs:attribute name="saltValue" type="xs:base64Binary" use="required"/>
+	</xs:complexType>
+	<xs:complexType name="CT_DataIntegrity">
+		<xs:annotation>
+			<xs:documentation>A complex type that specifies data used to verify whether the encrypted data passes an integrity check. It MUST be generated using the method specified in section 2.3.4.14 (http://msdn.microsoft.com/en-us/library/dd924068(v=office.12).aspx).</xs:documentation>
+		</xs:annotation>
+		<xs:attribute name="encryptedHmacKey" type="xs:base64Binary" use="required">
+			<xs:annotation>
+				<xs:documentation>A base64-encoded value that specifies an encrypted key used in calculating the encryptedHmacValue.</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="encryptedHmacValue" type="xs:base64Binary" use="required">
+			<xs:annotation>
+				<xs:documentation>A base64-encoded value that specifies an HMAC derived from encryptedHmacKey and the encrypted data.</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:complexType name="CT_KeyEncryptor">
+		<xs:annotation>
+			<xs:appinfo>modified for POI</xs:appinfo>
+			<xs:documentation>A complex type that specifies the parameters used to encrypt an intermediate key, which is used to perform the final encryption of the document. To ensure extensibility, arbitrary elements can be defined to encrypt the intermediate key. The intermediate key MUST be the same for all KeyEncryptor elements.</xs:documentation>
+		</xs:annotation>
+		<xs:choice>
+			<xs:element ref="p:encryptedKey"/>
+			<xs:element ref="c:encryptedKey"/>
+		</xs:choice>
+		<xs:attribute name="uri">
+			<xs:annotation>
+				<xs:appinfo>modified for POI</xs:appinfo>
+			</xs:annotation>
+			<xs:simpleType>
+				<xs:restriction base="xs:token">
+					<xs:enumeration value="http://schemas.microsoft.com/office/2006/keyEncryptor/password"/>
+					<xs:enumeration value="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate"/>
+				</xs:restriction>
+			</xs:simpleType>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:complexType name="CT_KeyEncryptors">
+		<xs:annotation>
+			<xs:documentation>A sequence of KeyEncryptor elements. Exactly one KeyEncryptors element MUST be present, and the KeyEncryptors element MUST contain at least one KeyEncryptor.</xs:documentation>
+		</xs:annotation>
+		<xs:sequence>
+			<xs:element name="keyEncryptor" type="CT_KeyEncryptor" maxOccurs="unbounded"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="CT_Encryption">
+		<xs:sequence>
+			<xs:element name="keyData" type="CT_KeyData"/>
+			<xs:element name="dataIntegrity" type="CT_DataIntegrity">
+				<xs:annotation>
+					<xs:appinfo>modified for POI</xs:appinfo>
+					<xs:documentation>All ECMA-376 documents [ECMA-376] encrypted by Microsoft Office using agile encryption will have a DataIntegrity element present. The schema allows for a DataIntegrity element to not be present because the encryption schema can be used by applications that do not create ECMA-376 documents [ECMA-376].</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="keyEncryptors" type="CT_KeyEncryptors">
+				<xs:annotation>
+					<xs:documentation>The KeyEncryptor element, which MUST be used when encrypting password-protected agile encryption documents, is either a PasswordKeyEncryptor or a CertificateKeyEncryptor. Exactly one PasswordKeyEncryptor MUST be present. Zero or more CertificateKeyEncryptor elements are contained within the KeyEncryptors element.</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:element name="encryption" type="CT_Encryption"/>
+</xs:schema>

Added: poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsdconfig
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsdconfig?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsdconfig (added)
+++ poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionInfo.xsdconfig Tue Dec 24 23:13:21 2013
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   ====================================================================
+-->
+<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config" xmlns:c="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" xmlns:p="http://schemas.microsoft.com/office/2006/keyEncryptor/password">
+
+<xb:qname name="c:encryptedKey" javaname="EncryptedCertificateKey"/>
+<xb:qname name="p:encryptedKey" javaname="EncryptedPasswordKey"/>
+  
+</xb:config>
\ No newline at end of file

Added: poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsd
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsd?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsd (added)
+++ poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsd Tue Dec 24 23:13:21 2013
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   ====================================================================
+-->
+<xs:schema xmlns="http://schemas.microsoft.com/office/2006/keyEncryptor/password" xmlns:e="http://schemas.microsoft.com/office/2006/encryption" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schemas.microsoft.com/office/2006/keyEncryptor/password" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:import namespace="http://schemas.microsoft.com/office/2006/encryption" schemaLocation="encryptionInfo.xsd"/>
+	<xs:simpleType name="ST_PasswordKeyEncryptorUri">
+		<xs:restriction base="xs:token">
+			<xs:enumeration value="http://schemas.microsoft.com/office/2006/keyEncryptor/password"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:complexType name="CT_PasswordKeyEncryptor">
+		<xs:attribute name="saltSize" type="e:ST_SaltSize" use="required">
+			<xs:annotation><xs:documentation>A SaltSize that specifies the size of the salt for a PasswordKeyEncryptor.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="blockSize" type="e:ST_BlockSize" use="required">
+			<xs:annotation><xs:documentation>A BlockSize that specifies the block size for a PasswordKeyEncryptor.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="keyBits" type="e:ST_KeyBits" use="required">
+			<xs:annotation><xs:documentation>A KeyBits that specifies the number of bits for a PasswordKeyEncryptor.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="hashSize" type="e:ST_HashSize" use="required">
+			<xs:annotation><xs:documentation>A HashSize that specifies the size of the binary form of the hash for a PasswordKeyEncryptor.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="cipherAlgorithm" type="e:ST_CipherAlgorithm" use="required">
+			<xs:annotation><xs:documentation>A CipherAlgorithm that specifies the cipher algorithm for a PasswordKeyEncryptor. The cipher algorithm specified MUST be the same as the cipher algorithm specified for the Encryption.keyData element.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="cipherChaining" type="e:ST_CipherChaining" use="required">
+			<xs:annotation><xs:documentation>A CipherChaining that specifies the cipher chaining mode for a PasswordKeyEncryptor.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="hashAlgorithm" type="e:ST_HashAlgorithm" use="required">
+			<xs:annotation><xs:documentation>A HashAlgorithm that specifies the hashing algorithm for a PasswordKeyEncryptor. The hashing algorithm specified MUST be the same as the hashing algorithm specified for the Encryption.keyData element.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="saltValue" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded binary byte array that specifies the salt value for a PasswordKeyEncryptor. The number of bytes required by the decoded form of this element MUST be saltSize.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="spinCount" type="e:ST_SpinCount" use="required">
+			<xs:annotation><xs:documentation>A SpinCount that specifies the spin count for a PasswordKeyEncryptor.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="encryptedVerifierHashInput" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded value that specifies the encrypted verifier hash input for a PasswordKeyEncryptor used in password verification.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="encryptedVerifierHashValue" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded value that specifies the encrypted verifier hash value for a PasswordKeyEncryptor used in password verification.</xs:documentation></xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="encryptedKeyValue" type="xs:base64Binary" use="required">
+			<xs:annotation><xs:documentation>A base64-encoded value that specifies the encrypted form of the intermediate key.</xs:documentation></xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:element name="encryptedKey" type="CT_PasswordKeyEncryptor"/>
+</xs:schema>

Added: poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsdconfig
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsdconfig?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsdconfig (added)
+++ poi/trunk/src/ooxml/resources/org/apache/poi/poifs/crypt/encryptionPassword.xsdconfig Tue Dec 24 23:13:21 2013
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   ====================================================================
+-->
+<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config" xmlns:p="http://schemas.microsoft.com/office/2006/keyEncryptor/password">
+
+<xb:qname name="p:encryptedKey" javaname="EncryptedPasswordKey"/>
+  
+</xb:config>
\ No newline at end of file

Added: poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java (added)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/AllPOIFSCryptoTests.java Tue Dec 24 23:13:21 2013
@@ -0,0 +1,36 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.crypt;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+
+/**
+ * Tests for org.apache.poi.poifs.crypt
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+      TestEncryptionInfo.class
+    , TestDecryptor.class
+    , TestEncryptor.class
+    , TestAgileEncryptionParameters.class
+    , TestCertificateEncryption.class
+})
+public final class AllPOIFSCryptoTests {
+}
\ No newline at end of file

Added: poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java (added)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestAgileEncryptionParameters.java Tue Dec 24 23:13:21 2013
@@ -0,0 +1,102 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.poifs.crypt;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestAgileEncryptionParameters {
+
+    static byte testData[];
+    
+    @Parameter(value = 0)
+    public CipherAlgorithm ca;
+    @Parameter(value = 1)
+    public HashAlgorithm ha;
+    @Parameter(value = 2)
+    public ChainingMode cm;
+
+    @Parameters
+    public static Collection<Object[]> data() {
+        CipherAlgorithm caList[] = { CipherAlgorithm.aes128, CipherAlgorithm.aes192, CipherAlgorithm.aes256, CipherAlgorithm.rc2, CipherAlgorithm.des, CipherAlgorithm.des3 };
+        HashAlgorithm haList[] = { HashAlgorithm.sha1, HashAlgorithm.sha256, HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.md5 };
+        ChainingMode cmList[] = { ChainingMode.cbc, ChainingMode.cfb };
+
+        List<Object[]> data = new ArrayList<Object[]>();
+        for (CipherAlgorithm ca : caList) {
+            for (HashAlgorithm ha : haList) {
+                for (ChainingMode cm : cmList) {
+                    data.add(new Object[]{ca,ha,cm});
+                }
+            }
+        }
+        
+        return data;
+    }
+    
+    @BeforeClass
+    public static void initTestData() throws Exception {
+        InputStream testFile = POIDataSamples.getDocumentInstance().openResourceAsStream("SampleDoc.docx");
+        testData = IOUtils.toByteArray(testFile);
+        testFile.close();
+    }
+    
+    @Test
+    public void testAgileEncryptionModes() throws Exception {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+        POIFSFileSystem fsEnc = new POIFSFileSystem();
+        EncryptionInfo infoEnc = new EncryptionInfo(fsEnc, EncryptionMode.agile, ca, ha, -1, -1, cm);
+        Encryptor enc = infoEnc.getEncryptor();
+        enc.confirmPassword("foobaa");
+        OutputStream os = enc.getDataStream(fsEnc);
+        os.write(testData);
+        os.close();
+        bos.reset();
+        fsEnc.writeFilesystem(bos);
+        
+        POIFSFileSystem fsDec = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
+        EncryptionInfo infoDec = new EncryptionInfo(fsDec);
+        Decryptor dec = infoDec.getDecryptor();
+        boolean passed = dec.verifyPassword("foobaa");
+        assertTrue(passed);
+        InputStream is = dec.getDataStream(fsDec);
+        byte actualData[] = IOUtils.toByteArray(is);
+        is.close();
+        assertThat("Failed roundtrip - "+ca+"-"+ha+"-"+cm, testData, equalTo(actualData));
+    }
+}

Added: poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestCertificateEncryption.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestCertificateEncryption.java?rev=1553336&view=auto
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestCertificateEncryption.java (added)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestCertificateEncryption.java Tue Dec 24 23:13:21 2013
@@ -0,0 +1,193 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.poifs.crypt;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.poifs.crypt.agile.AgileDecryptor;
+import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.CertificateAlgorithmId;
+import sun.security.x509.CertificateIssuerName;
+import sun.security.x509.CertificateSerialNumber;
+import sun.security.x509.CertificateSubjectName;
+import sun.security.x509.CertificateValidity;
+import sun.security.x509.CertificateVersion;
+import sun.security.x509.CertificateX509Key;
+import sun.security.x509.X500Name;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.X509CertInfo;
+
+/**
+ * {@linkplain http://stackoverflow.com/questions/1615871/creating-an-x509-certificate-in-java-without-bouncycastle}
+ */
+public class TestCertificateEncryption {
+    /**
+     * how many days from now the Certificate is valid for
+     */
+    static final int days = 1000;
+    /**
+     * the signing algorithm, eg "SHA1withRSA"
+     */
+    static final String algorithm = "SHA1withRSA";
+    static final String password = "foobaa";
+    static final String certAlias = "poitest";
+    /**
+     * the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
+     */
+    static final String certDN = "CN=poitest";
+    // static final File pfxFile = TempFile.createTempFile("poitest", ".pfx");
+    static byte pfxFileBytes[];
+    
+    static class CertData {
+        KeyPair keypair;
+        X509Certificate x509;
+    }
+    
+    /** 
+     * Create a self-signed X.509 Certificate
+     * 
+     * The keystore generation / loading is split, because normally the keystore would
+     * already exist.
+     */ 
+    @BeforeClass
+    public static void initKeystore() throws GeneralSecurityException, IOException {
+        CertData certData = new CertData();
+        
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(1024);
+        certData.keypair = keyGen.generateKeyPair();
+        PrivateKey privkey = certData.keypair.getPrivate();
+        PublicKey publkey = certData.keypair.getPublic();
+    
+        X509CertInfo info = new X509CertInfo();
+        Date from = new Date();
+        Date to = new Date(from.getTime() + days * 86400000l);
+        CertificateValidity interval = new CertificateValidity(from, to);
+        BigInteger sn = new BigInteger(64, new SecureRandom());
+        X500Name owner = new X500Name(certDN);
+        
+        info.set(X509CertInfo.VALIDITY, interval);
+        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
+        info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
+        info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
+        info.set(X509CertInfo.KEY, new CertificateX509Key(publkey));
+        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
+        AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
+        info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
+        
+        // Sign the cert to identify the algorithm that's used.
+        X509CertImpl cert = new X509CertImpl(info);
+        cert.sign(privkey, algorithm);
+        
+        // Update the algorith, and resign.
+        algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
+        info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
+        cert = new X509CertImpl(info);
+        cert.sign(privkey, algorithm);
+        certData.x509 = cert;
+        
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        keystore.load(null, password.toCharArray());
+        keystore.setKeyEntry(certAlias, certData.keypair.getPrivate(), password.toCharArray(), new Certificate[]{certData.x509});
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        keystore.store(bos, password.toCharArray());
+        pfxFileBytes = bos.toByteArray();
+    }
+
+    public CertData loadKeystore()
+    throws GeneralSecurityException, IOException {
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        
+        InputStream fis = new ByteArrayInputStream(pfxFileBytes);
+        keystore.load(fis, password.toCharArray());
+        
+        X509Certificate x509 = (X509Certificate)keystore.getCertificate(certAlias);
+        PrivateKey privateKey = (PrivateKey)keystore.getKey(certAlias, password.toCharArray());
+        PublicKey publicKey = x509.getPublicKey();
+
+        CertData certData = new CertData();
+        certData.keypair = new KeyPair(publicKey, privateKey);
+        certData.x509 = x509;
+        
+        return certData;
+    }
+    
+    @Test
+    public void testCertificateEncryption() throws Exception {
+        POIFSFileSystem fs = new POIFSFileSystem();
+        EncryptionInfo info = new EncryptionInfo(fs, EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha1, -1, -1, ChainingMode.cbc);
+        AgileEncryptionVerifier aev = (AgileEncryptionVerifier)info.getVerifier();
+        CertData certData = loadKeystore();
+        aev.addCertificate(certData.x509);
+        
+        Encryptor enc = info.getEncryptor();
+        enc.confirmPassword("foobaa");
+        
+        File file = POIDataSamples.getDocumentInstance().getFile("VariousPictures.docx");
+        InputStream fis = new FileInputStream(file);
+        byte byteExpected[] = IOUtils.toByteArray(fis);
+        fis.close();
+        
+        OutputStream os = enc.getDataStream(fs);
+        IOUtils.copy(new ByteArrayInputStream(byteExpected), os);
+        os.close();
+        
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        fs.writeFilesystem(bos);
+        bos.close();
+        
+        fs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
+        info = new EncryptionInfo(fs);
+        AgileDecryptor agDec = (AgileDecryptor)info.getDecryptor();
+        boolean passed = agDec.verifyPassword(certData.keypair, certData.x509);
+        assertTrue("certificate verification failed", passed);
+        
+        fis = agDec.getDataStream(fs);
+        byte byteActual[] = IOUtils.toByteArray(fis);
+        fis.close();
+        
+        assertThat(byteExpected, equalTo(byteActual));
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org