Index: jspwiki-war/src/main/java/org/apache/wiki/WikiEngine.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/WikiEngine.java	(revision 1622810)
+++ jspwiki-war/src/main/java/org/apache/wiki/WikiEngine.java	(working copy)
@@ -18,31 +18,6 @@
  */
 package org.apache.wiki;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
-import java.util.TimeZone;
-import java.util.TreeSet;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletRequest;
-import javax.servlet.http.HttpServletRequest;
-
 import org.apache.commons.lang.time.StopWatch;
 import org.apache.log4j.Logger;
 import org.apache.log4j.PropertyConfigurator;
@@ -62,6 +37,7 @@
 import org.apache.wiki.auth.acl.DefaultAclManager;
 import org.apache.wiki.auth.authorize.GroupManager;
 import org.apache.wiki.content.PageRenamer;
+import org.apache.wiki.crypto.CryptoManager;
 import org.apache.wiki.diff.DifferenceManager;
 import org.apache.wiki.event.WikiEngineEvent;
 import org.apache.wiki.event.WikiEventListener;
@@ -94,7 +70,32 @@
 import org.apache.wiki.workflow.WorkflowBuilder;
 import org.apache.wiki.workflow.WorkflowManager;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+import java.util.TreeSet;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+
 /**
  *  Provides Wiki services to the JSP page.
  *
@@ -290,6 +291,9 @@
     /** Each engine has its own workflow manager. */
     private WorkflowManager m_workflowMgr = null;
 
+    /** Each engine has its own cryptography manager. */
+    private CryptoManager m_cryptoMgr = null;
+
     private AdminBeanManager m_adminBeanManager;
 
     /** Stores wikiengine attributes. */
@@ -592,6 +596,9 @@
             m_workflowMgr = (WorkflowManager)ClassUtil.getMappedObject(WorkflowManager.class.getName());
             m_workflowMgr.initialize(this, props);
 
+            // Create a new CryptoManager
+            m_cryptoMgr = new CryptoManager(this);
+
             m_internationalizationManager = (InternationalizationManager)
                 ClassUtil.getMappedObject(InternationalizationManager.class.getName(),this);
 
@@ -1327,6 +1334,17 @@
     }
 
     /**
+     * Returns the {@link org.apache.wiki.crypto.CryptoManager} associated with this
+     * WikiEngine. If the WIkiEngine has not been initialized, this method will return
+     * <code>null</code>.
+     * @return the cryptoManager
+     */
+    public CryptoManager getCryptoManager()
+    {
+        return m_cryptoMgr;
+    }
+
+    /**
      *  Returns the un-HTMLized text of the latest version of a page.
      *  This method also replaces the &lt; and &amp; -characters with
      *  their respective HTML entities, thus making it suitable
Index: jspwiki-war/src/main/java/org/apache/wiki/api/exceptions/EncryptionException.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/api/exceptions/EncryptionException.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/api/exceptions/EncryptionException.java	(working copy)
@@ -0,0 +1,39 @@
+/*
+    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.wiki.api.exceptions;
+
+/**
+ *  A generic exception for anything with the crypto libraries.
+ *
+ *  @since 2.10.2
+ */
+public class EncryptionException extends WikiException {
+
+    private static final long serialVersionUID = -490652869936404653L;
+
+    /**
+     *  Constructs an exception.
+     *
+     *  @param msg {@inheritDoc}
+     */
+    public EncryptionException( String msg ) {
+        super( msg );
+    }
+
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/crypto/BaseCryptoProvider.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/crypto/BaseCryptoProvider.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/crypto/BaseCryptoProvider.java	(working copy)
@@ -0,0 +1,124 @@
+
+package org.apache.wiki.crypto;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.wiki.WikiEngine;
+import org.apache.wiki.api.exceptions.EncryptionException;
+import org.apache.wiki.api.exceptions.NoRequiredPropertyException;
+import org.apache.wiki.util.PropertyReader;
+import org.apache.wiki.util.TextUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * This default implementation just does an identity return, not encrypting or decrypting any
+ * content. This should be overwritten by more advanced cryptography providers.
+ * @since 2.10.2
+ */
+public class BaseCryptoProvider implements CryptoProvider {
+    public Logger log = Logger.getLogger(this.getClass());
+
+    /** The "jspwiki.cryptoFile" property key */
+    public static final String PROP_CRYPTO_FILE = "jspwiki.cryptoFile";
+
+    /** The internal {@link org.apache.wiki.WikiEngine} */
+    private WikiEngine m_engine;
+    /** The properties loaded from the "jspwiki.cryptoFile" */
+    Properties cryptoProperties = new Properties();
+
+    /**
+     * initialise the BaseCrpytoProvider, by setting the WikiEngine, and CryptoProperties, as
+     * defined in {@link this.getCryptoProperties}.
+     * @param engine WikiEngine to own this provider
+     * @param properties A set of properties used to initialize this provider
+     * @throws NoRequiredPropertyException
+     * @throws IOException
+     */
+    @Override
+    public void initialize(WikiEngine engine, Properties properties) throws NoRequiredPropertyException, IOException {
+        m_engine = engine;
+        cryptoProperties = getCryptoProperties(properties);
+    }
+
+    /**
+     * Returns the content provided.
+     * Key parameter is ignored.
+     */
+    public byte[] encrypt(char[] key, byte[] content) throws EncryptionException {
+        return content;
+    }
+
+    /**
+     * Returns the cotent provided.
+     * Key parameter is ignored.
+     */
+    public byte[] decrypt(char[] key, byte[] content) throws EncryptionException {
+        return content;
+    }
+
+    /**
+     * Returns the simpleName of this class
+     * @return
+     */
+    @Override
+    public String getProviderInfo() {
+        return getClass().getSimpleName();
+    }
+
+    /**
+     * Get the cryptoProperties as defined within the property parameter {@link this.PROP_CRYPTO_FILE}.
+     * The default is {@link org.apache.wiki.crypto.CryptoProvider:DEFAULT_CRYPTO_FILENAME}
+     * "jspwiki-crypto.properties".
+     * The location of the file can be an absolute path or something that can be found by
+     * {@link org.apache.wiki.util.PropertyReader:locateClassPathResource}.
+     * @param properties the properties which contain the "jspwiki.cryptoFile" key entry.
+     * @return the cryptoProperties loaded from the cryptoFile
+     * @throws IOException
+     * @throws FileNotFoundException
+     */
+    protected Properties getCryptoProperties(Properties properties) throws IOException, FileNotFoundException {
+        Properties cryptoProperties = new Properties();
+        String filename = TextUtil.getStringProperty(properties, PROP_CRYPTO_FILE, CryptoProvider.DEFAULT_CRYPTO_FILENAME);
+        File f = new File(filename);
+        if (!f.exists()) {
+            InputStream is = PropertyReader.locateClassPathResource(m_engine.getServletContext(), filename);
+            if (is != null) {
+                cryptoProperties.load(is);
+            } else {
+                log.warn("The file specified by " + PROP_CRYPTO_FILE + "=" + f.getAbsolutePath() + " does not exist!");
+            }
+        } else {
+            cryptoProperties.load(new FileReader(f));
+        }
+        return cryptoProperties;
+    }
+
+    /**
+     * Get additional properties from the cryptoProperties file, with a null default value.
+     * @param key the property key
+     * @return the property value
+     */
+    public String getExtraCryptoProperty(String key) {
+        return getExtraCryptoProperty(key,null);
+    }
+
+    /**
+     * Get additional properties from the cryptoProperties file.
+     * @param key the property key
+     * @param defaultValue the default value to return
+     * @return the property value
+     */
+    public String getExtraCryptoProperty(String key, String defaultValue) {
+        String result = (String)cryptoProperties.get(key);
+        if (StringUtils.isNotEmpty(result)) {
+            return result;
+        }
+        return defaultValue;
+    }
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/crypto/CryptoManager.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/crypto/CryptoManager.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/crypto/CryptoManager.java	(working copy)
@@ -0,0 +1,76 @@
+/*
+    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.wiki.crypto;
+
+import org.apache.log4j.Logger;
+import org.apache.wiki.WikiEngine;
+import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.util.ClassUtil;
+import org.apache.wiki.util.TextUtil;
+
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Class for managing the {@link org.apache.wiki.crypto.CryptoProvider}.
+ *
+ * The cryptoProvider is read from the {@link this.PROP_CRYPTO_PROVIDER} property "jspwiki.cryptoProvider".
+ *
+ * The default cyptoProvider is {@link org.apache.wiki.crypto.BaseCryptoProvider}.
+ *
+ * @since 2.10.2
+ */
+public class CryptoManager {
+
+    private static final Logger log = Logger.getLogger(CryptoManager.class);
+
+    public static final String PROP_CRYPTO_PROVIDER = "jspwiki.cryptoProvider";
+    public static final String DEFAULT_CRYPTO_PROVIDER = "org.apache.wiki.crypto.BaseCryptoProvider";
+
+    private CryptoProvider cryptoProvider;
+    private WikiEngine m_engine;
+
+    public CryptoManager(WikiEngine engine) {
+        m_engine = engine;
+    }
+
+    /**
+     * Get the CryptoProvider by className as specified in the properties file.
+     * This uses the {@link org.apache.wiki.util.ClassUtil:getMappedObject} to find the class.
+     * The CryptoProvider instance then calls {@link this.initialise}
+     * @return the configured CryptoProvider
+     * @throws WikiException if the class cannot be found or initialised or any other issue
+     */
+    public CryptoProvider getCryptoProvider() throws WikiException {
+        Properties properties = m_engine.getWikiProperties();
+        String providerClassName = TextUtil.getStringProperty(properties, PROP_CRYPTO_PROVIDER, DEFAULT_CRYPTO_PROVIDER);
+
+        try {
+            cryptoProvider = (CryptoProvider) ClassUtil.getMappedObject(providerClassName);
+            if (cryptoProvider != null) {
+                cryptoProvider.initialize(m_engine, properties);
+            }
+        } catch (WikiException e) {
+            throw new WikiException("Could not create cryptoProvider for "+PROP_CRYPTO_PROVIDER+"="+providerClassName+". "+e.getMessage());
+        } catch (IOException e) {
+            throw new WikiException("Could not initialise cryptoProvider for "+PROP_CRYPTO_PROVIDER+"="+providerClassName+". "+e.getMessage());
+        }
+        return cryptoProvider;
+    }
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/crypto/CryptoProvider.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/crypto/CryptoProvider.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/crypto/CryptoProvider.java	(working copy)
@@ -0,0 +1,58 @@
+/*
+    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.wiki.crypto;
+
+import org.apache.wiki.WikiProvider;
+import org.apache.wiki.api.exceptions.EncryptionException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Provides cryptographic encryption and decryption services
+ * @since 2.10.2
+ */
+public interface CryptoProvider extends WikiProvider {
+    /** The default filename of the cryptoProperties file is  "jspwiki-crypto.properties" */
+    public static final String DEFAULT_CRYPTO_FILENAME = "jspwiki-crypto.properties";
+
+    /** Get additional properties from the cryptoProperties, with defaultValue null */
+    public String getExtraCryptoProperty(String key);
+    /** Get additional properties from the cryptoProperties, with the given defaultValue */
+    public String getExtraCryptoProperty(String key, String defaultValue);
+
+    /**
+     * Encrypt content of data given a key
+     * @param key the key required for the encryption
+     * @param content the content to be encrypted
+     * @return the encrypted content
+     * @throws EncryptionException if there is any encryption error
+     */
+    public byte[] encrypt(char[] key, byte[] content) throws EncryptionException;
+
+    /**
+     * Decrypt content of data given a key
+     * @param key the key required for the decryption
+     * @param content the content to be decrypted
+     * @return the decrypted content
+     * @throws EncryptionException if there is any decryption error
+     */
+    public byte[] decrypt(char[] key, byte[] content) throws EncryptionException;
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/crypto/PBECryptoProvider.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/crypto/PBECryptoProvider.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/crypto/PBECryptoProvider.java	(working copy)
@@ -0,0 +1,211 @@
+/*
+    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.wiki.crypto;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.apache.wiki.WikiEngine;
+import org.apache.wiki.api.exceptions.EncryptionException;
+import org.apache.wiki.api.exceptions.NoRequiredPropertyException;
+import org.apache.wiki.util.TextUtil;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+/**
+ * Provides cryptographic encryption and decryption services.
+ *
+ * See: <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">Oracle CryptoSpec.html</a>
+ *
+ * This provider implementation uses a password-based encryption (PBE) cipher.
+ *
+ * The configuration expects <b>jspwiki.cryptoFile</b> in jspwiki-custom.properties which
+ * is the absolute path to a file specifying the other cryptographic properties. The default
+ * filename for this is "jspwiki-crypto.properties".
+ * Ideally this file should be well protected, and read only.
+ *
+ *
+ * Properties within the "jspwiki.cryptoFile" include:
+ * <table>
+ *     <th>
+ *         <td>property</td>
+ *         <td>description</td>
+ *         <td>default</td>
+ *     </th>
+ *     <tr>
+ *         <td>crypto.base64</td>
+ *         <td>If true will apply base64 encoding and decoding to the encrypted content.
+ *         This ensures the content store in the {@link org.apache.wiki.providers.WikiPageProvider} is not just binary, but base64 encoded.
+ *         Default is true</td>
+ *         <td>true</td>
+ *     </tr>
+ *     <tr>
+ *         <td>crypto.salt</td>
+ *         <td>The salt used to create the PBEParameterSpec</td>
+ *         <td>A random string</td>
+ *     </tr>
+ *     <tr>
+ *         <td>crypto.blocksize</td>
+ *         <td>The blocksize specified the length of the salt, must be equal or smaller than the salt length</td>
+ *         <td>8</td>
+ *     </tr>
+ *     <tr>
+ *         <td>crypto.itrcount</td>
+ *         <td>The iteration count used to create the PBEParameterSpec</td>
+ *         <td>2048</td>
+ *     </tr>
+ *     <tr>
+ *         <td>crypto.algorithm</td>
+ *         <td>The algorithm to use to create the SecretKeyFactory and Cipher</td>
+ *         <td>PBEWithMD5AndDES</td>
+ *     </tr>
+ *
+ * </table>
+ *
+ * @since 2.10.2
+ */
+public class PBECryptoProvider extends BaseCryptoProvider {
+
+    private static final Logger log = Logger.getLogger(PBECryptoProvider.class);
+
+    public static final String PROP_CRYPTO_BASE64 = "crypto.base64";
+    public static final String PROP_CRYPTO_SALT = "crypto.salt";
+    public static final String PROP_CRYPTO_BLOCKSIZE = "crypto.blocksize";
+    public static final String PROP_CRYPTO_ITERATIONCOUNT = "crypto.itrcount";
+    public static final String PROP_CRYPTO_ALGORITHM = "crypto.algorithm";
+
+    private static final Boolean DEFAULT_CRYPTO_BASE64 = true;
+    private static final String DEFAULT_CRYPTO_SALT = "Ra%$ESSQA#!@)#$@)";
+    private static final int DEFAULT_CRYPTO_BLOCKSIZE = 8;
+    private static final int DEFAULT_CRYPTO_ITERATIONCOUNT = 2048;
+    private static final String DEFAULT_CRYPTO_ALGORITHM = "PBEWithMD5AndDES";
+
+    private boolean base64 = DEFAULT_CRYPTO_BASE64;
+    private String salt = DEFAULT_CRYPTO_SALT;
+    private int blockSize = DEFAULT_CRYPTO_BLOCKSIZE;
+    private int iterationCount = DEFAULT_CRYPTO_ITERATIONCOUNT;
+    private String algorithm = DEFAULT_CRYPTO_ALGORITHM;
+
+    /**
+     * Initialise the PBECryptoProperties with values within the cryptoProperties file.
+     * @param engine WikiEngine to own this provider
+     * @param properties A set of properties used to initialize this provider
+     * @throws NoRequiredPropertyException
+     * @throws IOException
+     */
+    @Override
+    public void initialize(WikiEngine engine, Properties properties) throws NoRequiredPropertyException, IOException {
+        super.initialize(engine,properties);
+        base64 = TextUtil.getBooleanProperty(cryptoProperties, PROP_CRYPTO_BASE64, DEFAULT_CRYPTO_BASE64);
+        salt = TextUtil.getStringProperty(cryptoProperties,PROP_CRYPTO_SALT, DEFAULT_CRYPTO_SALT);
+        blockSize = TextUtil.getIntegerProperty(cryptoProperties, PROP_CRYPTO_BLOCKSIZE, DEFAULT_CRYPTO_BLOCKSIZE);
+        iterationCount = TextUtil.getIntegerProperty(cryptoProperties,PROP_CRYPTO_ITERATIONCOUNT, DEFAULT_CRYPTO_ITERATIONCOUNT);
+        algorithm = TextUtil.getStringProperty(cryptoProperties,PROP_CRYPTO_ALGORITHM, DEFAULT_CRYPTO_ALGORITHM);
+        if (blockSize > salt.length()) {
+            throw new NoRequiredPropertyException("The block size specified is longer then the salt length",PROP_CRYPTO_BLOCKSIZE);
+        }
+    }
+
+    /**
+     * Encrypt content using the {@link this.getCipher} cipher.
+     * @param key the secret password
+     * @param content the content to encrypt
+     * @return the encrypted content
+     * @throws EncryptionException
+     */
+    @Override
+    public byte[] encrypt(char[] key, byte[] content) throws EncryptionException {
+        try {
+            Cipher pbeCipher = getCipher(key, Cipher.ENCRYPT_MODE);
+            byte[] encrypted = pbeCipher.doFinal(content);
+            if (base64) {
+                encrypted = Base64.encodeBase64(encrypted);
+            }
+            return encrypted;
+        } catch (Exception e) {
+            throw new EncryptionException("Could not encrypt content. ERROR="+e+" "+e.getMessage());
+        }
+    }
+
+    /**
+     * Decrypt content using the {@link this.getCipher} cipher.
+     * @param key the secret password
+     * @param content the content to decrypt
+     * @return the decrypted content
+     * @throws EncryptionException
+     */
+    @Override
+    public byte[] decrypt(char[] key, byte[] content) throws EncryptionException {
+        try {
+            Cipher pbeCipher = getCipher(key, Cipher.DECRYPT_MODE);
+            if (base64) {
+                content = Base64.decodeBase64(content);
+            }
+            content = pbeCipher.doFinal(content);
+            return content;
+        } catch (Exception e) {
+            throw new EncryptionException("Could not decrypt content. ERROR="+e+" "+e.getMessage());
+        }
+    }
+
+    /**
+     * A PBE base cipher generated with {@link javax.crypto.spec.PBEKeySpec}
+     * @param key the secret password
+     * @param mode the mode encrypt or decrypt
+     * @return the Cipher in the correct mode
+     * @throws EncryptionException
+     */
+    private Cipher getCipher(char[] key, int mode) throws EncryptionException {
+        Cipher cipher = null;
+        try {
+            String transformation = algorithm;
+            byte[] saltBytes = salt.substring(0, blockSize).getBytes();
+            int count = iterationCount;
+
+            // Create PBE parameter set
+            PBEParameterSpec pbeParamSpec = new PBEParameterSpec(saltBytes, count);
+            PBEKeySpec pbeKeySpec = new PBEKeySpec(key);
+            SecretKeyFactory keyFac = SecretKeyFactory.getInstance(transformation);
+            SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
+
+            Cipher pbeCipher = Cipher.getInstance(transformation);
+            pbeCipher.init(mode, pbeKey, pbeParamSpec);
+            return pbeCipher;
+        } catch (Exception e) {
+            throw new EncryptionException("Could not create cipher. ERROR="+e+" "+e.getMessage());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getExtraCryptoProperty(String key, String defaultValue) {
+        if (key!=null && !key.equals(PROP_CRYPTO_SALT)) {
+            return super.getExtraCryptoProperty(key,defaultValue);
+        }
+        return null;
+    }
+
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/filters/EncryptedPageFilter.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/filters/EncryptedPageFilter.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/filters/EncryptedPageFilter.java	(working copy)
@@ -0,0 +1,225 @@
+/*
+    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.wiki.filters;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.wiki.WikiContext;
+import org.apache.wiki.WikiEngine;
+import org.apache.wiki.api.exceptions.FilterException;
+import org.apache.wiki.api.filters.BasicPageFilter;
+import org.apache.wiki.crypto.BaseCryptoProvider;
+import org.apache.wiki.crypto.CryptoProvider;
+
+import java.util.Properties;
+
+/**
+ * This class uses a {@link org.apache.wiki.crypto.CryptoProvider} to encrypt and decrypt page content.
+ *
+ * The default crypto provider for this filter is {@link org.apache.wiki.crypto.BaseCryptoProvider}
+ * which does no encryption at all.
+ *
+ * An alternative crypto provider can be set by setting <b>jspwiki.cryptoProvider</b> in
+ * <i>jspwiki-custom.properties</i>.
+ *
+ * The encryption happens on a {@link org.apache.wiki.api.filters.BasicPageFilter:preSave()} and
+ * decryption on {@link org.apache.wiki.api.filters.BasicPageFilter:preTranslate()}.
+ * One page is encrypted at a time, as saved or loaded.
+ * See also: {@link org.apache.wiki.PageManager} for when filters are executed.
+ *
+ * The configuration expects <b>jspwiki.cryptoFile</b> in <i>jspwiki-custom.properties</i> which
+ * is the absolute path to a file specifying the other cryptographic properties.
+ * Ideally this file should be well protected, and read only.
+ *
+ * <div style="color: red>WARNING: Once you use this <b>EncryptedPageFilter</b> there is no going
+ * back. Make sure you know what you are doing!</div>
+ *
+ * In future there are plans to be able to export your wiki content, so you can import it back with
+ * with a simple {@link org.apache.wiki.providers.FileSystemProvider}. This does not exist yet!!
+ *
+ * Additional properties within the "jspwiki.cryptoFile" include:
+ * <b>Note: All values here must be a minimum of 10 characters long!</b>
+ * <table>
+ *     <th>
+ *         <td>property</td>
+ *         <td>description</td>
+ *         <td>default</td>
+ *     </th>
+ *     <tr>
+ *         <td>crypto.key</td>
+ *         <td>The password that will do the encryption and decryption of content. <b>Required</b></td>
+ *         <td></td>
+ *     </tr>
+ *     <tr>
+ *         <td>crypto.prefix</td>
+ *         <td>A value used to determine if the page content is correctly decrypted. Should be a random string of minimum 10 length</td>
+ *         <td>A random string</td>
+ *     </tr>
+ *     <tr>
+ *         <td>crypto.suffix</td>
+ *         <td>A value appended to the end of the encrypted string. Should be a random string of minimum 10 length</td>
+ *         <td>A random string</td>
+ *     </tr>
+ *     <tr>
+ *         <td>pagename.prefix</td>
+ *         <td>Only pages that start with this value are encrypted. If this is enabled you
+ *         will not be able to rename these pages outside this prefix.</td>
+ *         <td>empty string</td>
+ *     </tr>
+ *     <tr>
+ *         <td>pagename.suffix</td>
+ *         <td>Only pages that end with this value are encrypted. If this is enabled you
+ *         will not be able to rename these pages outside this suffix.</td>
+ *         <td>empty string</td>
+ *     </tr>
+ * </table>
+ *
+ * @since 2.10.2
+ */
+public class EncryptedPageFilter extends BasicPageFilter {
+
+    private static final Logger log = Logger.getLogger(EncryptedPageFilter.class);
+
+    private static final int MIN_LENGTH = 10;
+    private static final int MIN_LENGTH_PAGENAME = 2;
+    public static final String PROP_CRYPTO_KEY = "crypto.key";
+    public static final String PROP_CRYPTO_PREFIX = "crypto.prefix";
+    public static final String PROP_CRYPTO_SUFFIX = "crypto.suffix";
+    public static final String PROP_PAGENAME_PREFIX = "pagename.prefix";
+    public static final String PROP_PAGENAME_SUFFIX = "pagename.suffix";
+
+    private static final String DEFAULT_CRYPTO_PREFIX = "A@I@#!)KDAS)$:";
+    private static final String DEFAULT_CRYPTO_SUFFIX = ")FEJ*$Y@LSDFKJ@V";
+    private static final String DEFAULT_PAGENAME_PREFIX = "";
+    private static final String DEFAULT_PAGENAME_SUFFIX = "";
+
+    private CryptoProvider cryptoProvider;
+    private char[] key;
+    private String prefix = DEFAULT_CRYPTO_PREFIX;
+    private String suffix = DEFAULT_CRYPTO_SUFFIX;
+    private String pagenamePrefix = DEFAULT_PAGENAME_PREFIX;
+    private String pagenameSuffix = DEFAULT_PAGENAME_SUFFIX;
+
+    @Override
+    public void initialize(WikiEngine engine, Properties properties) throws FilterException {
+
+        try {
+            cryptoProvider = engine.getCryptoManager().getCryptoProvider();
+        } catch (Exception e) {
+            throw new FilterException(e.getMessage());
+        }
+
+        String keyValue = cryptoProvider.getExtraCryptoProperty(PROP_CRYPTO_KEY);
+        if (keyValue != null) {
+            key = keyValue.toCharArray();
+        } else {
+            throw new FilterException("The encryption key "+PROP_CRYPTO_KEY+" has not been set!");
+        }
+        if (key.length < MIN_LENGTH) {
+            throw new FilterException("The encryption key "+PROP_CRYPTO_KEY+" provided is to short. Min Length required is " + MIN_LENGTH);
+        }
+        if (key.length < MIN_LENGTH) {
+            throw new FilterException("The encryption key "+PROP_CRYPTO_KEY+" provided is to short. Min Length required is " + MIN_LENGTH);
+        }
+        prefix = cryptoProvider.getExtraCryptoProperty(PROP_CRYPTO_PREFIX, DEFAULT_CRYPTO_PREFIX);
+        if (prefix.length() < MIN_LENGTH) {
+            throw new FilterException("The property value "+PROP_CRYPTO_PREFIX+"="+ prefix + " is to short. Min Length required is " + MIN_LENGTH);
+        }
+        suffix = cryptoProvider.getExtraCryptoProperty(PROP_CRYPTO_SUFFIX, DEFAULT_CRYPTO_SUFFIX);
+        if (suffix.length() < MIN_LENGTH) {
+            throw new FilterException("The property value "+PROP_CRYPTO_SUFFIX+"="+ suffix + " is to short. Min Length required is " + MIN_LENGTH);
+        }
+        pagenamePrefix = cryptoProvider.getExtraCryptoProperty(PROP_PAGENAME_PREFIX, DEFAULT_PAGENAME_PREFIX);
+        if (pagenamePrefix.length() > 0 && pagenamePrefix.length() < MIN_LENGTH_PAGENAME) {
+            throw new FilterException("The property value "+PROP_PAGENAME_PREFIX+"="+ pagenamePrefix + " is to short. Min Length required is " + MIN_LENGTH_PAGENAME);
+        }
+        pagenameSuffix = cryptoProvider.getExtraCryptoProperty(PROP_PAGENAME_SUFFIX, DEFAULT_PAGENAME_SUFFIX);
+        if (pagenameSuffix.length() > 0 && pagenameSuffix.length() < MIN_LENGTH_PAGENAME) {
+            throw new FilterException("The property value "+PROP_PAGENAME_SUFFIX+"="+ pagenameSuffix + " is to short. Min Length required is " + MIN_LENGTH_PAGENAME);
+        }
+    }
+
+    /**
+     * Given the initialised cryptoProvider and a key, encrypt the content provided on preSave.
+     * The actual implementation adds a prefix to the raw content, and a suffix to the encrypted
+     * content.
+     * This calls {@link this.enableEncrpytion} to determine if encryption should occur
+     * If the cryptoProvier is of class {@link org.apache.wiki.crypto.BaseCryptoProvider}, we
+     * do nothing here, just return the content.
+     */
+    @Override
+    public String preSave(WikiContext wikiContext, String content) throws FilterException {
+        try {
+            if (enableEncrpytion(wikiContext)) {
+                if (cryptoProvider.getClass().getName().equals(new BaseCryptoProvider().getClass().getName())) {
+                    return super.preSave(wikiContext, content);
+                }
+                content = prefix + content;
+                content = new String(cryptoProvider.encrypt(key, content.getBytes()));
+                content += suffix;
+            }
+        } catch (Exception e) {
+            throw new FilterException("Error encrypting content. ERROR="+e+" "+e.getMessage());
+        }
+        return super.preSave(wikiContext, content);
+    }
+
+    /**
+     * Given the initialised cryptoProvider and a key, decrypt the content provided on preTranslate.
+     * If the suffix does not match the provided suffix, we assume the page was not encrypted and
+     * return the content.
+     * Otherwise we trim the suffix, decrypt, remove the prefix and return the plain content.
+     */
+    @Override
+    public String preTranslate(WikiContext wikiContext, String content) throws FilterException {
+        String result = super.preTranslate(wikiContext, content);
+        try {
+            if (result.endsWith(suffix)) {
+                result = result.substring(0,result.length()-suffix.length());
+                String plain = new String(cryptoProvider.decrypt(key, result.getBytes()));
+                if (plain.startsWith(prefix)) {
+                    result = plain.substring(prefix.length());
+                } else {
+                    throw new Exception("The decrypted content did not start with the expected prefix!!!");
+                }
+            }
+
+        } catch (Exception e) {
+            throw new FilterException("Error decrypting content. ERROR="+e+" "+e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * Validate the
+     * @param wikiContext
+     * @return
+     */
+    private boolean enableEncrpytion(WikiContext wikiContext) {
+        boolean result = false;
+        String pageName = wikiContext.getPage().getName();
+        if (StringUtils.isNotEmpty(pageName)) {
+            if (pageName.startsWith(pagenamePrefix) && pageName.endsWith(pagenameSuffix)) {
+                result = true;
+            }
+        }
+        return result;
+    }
+
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/plugin/EncryptPlugin.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/plugin/EncryptPlugin.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/plugin/EncryptPlugin.java	(working copy)
@@ -0,0 +1,63 @@
+/*
+    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.wiki.plugin;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.wiki.WikiContext;
+import org.apache.wiki.api.exceptions.EncryptionException;
+import org.apache.wiki.api.exceptions.PluginException;
+import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.api.plugin.WikiPlugin;
+import org.apache.wiki.crypto.CryptoProvider;
+
+import java.util.Map;
+
+/**
+ *
+ * @since 2.10.2
+ */
+public class EncryptPlugin implements WikiPlugin {
+
+    private static Logger log = Logger.getLogger( EncryptPlugin.class );
+
+    /**
+     *  {@inheritDoc}
+     */
+    public String execute(WikiContext context, Map<String, String> params) throws PluginException
+    {
+        CryptoProvider cryptoProvider;
+        try {
+            cryptoProvider = context.getEngine().getCryptoManager().getCryptoProvider();
+        } catch (WikiException e) {
+            throw new PluginException("Encryption not configured correctly. "+e.getMessage());
+        }
+        String body = params.get(DefaultPluginManager.PARAM_BODY);
+        if (StringUtils.isNotEmpty(body)) {
+            String hiddenData = "";
+            try {
+                hiddenData = new String(cryptoProvider.encrypt("password".toCharArray(), body.getBytes()));
+            } catch (EncryptionException e) {
+                throw new PluginException("Encryption failed: " + e.getMessage());
+            }
+            return "<div class='encrypted'>" + hiddenData + "</div>";
+        }
+        return "";
+    }
+}
Index: jspwiki-war/src/main/resources/ini/classmappings.xml
===================================================================
--- jspwiki-war/src/main/resources/ini/classmappings.xml	(revision 1622810)
+++ jspwiki-war/src/main/resources/ini/classmappings.xml	(working copy)
@@ -123,4 +123,12 @@
     <requestedClass>org.apache.wiki.workflow.WorkflowManager</requestedClass>
     <mappedClass>org.apache.wiki.workflow.WorkflowManager</mappedClass>
   </mapping>
+  <mapping>
+    <requestedClass>org.apache.wiki.crypto.CryptoProvider</requestedClass>
+    <mappedClass>org.apache.wiki.crypto.BaseCryptoProvider</mappedClass>
+  </mapping>
+  <mapping>
+    <requestedClass>org.apache.wiki.crypto.PBECryptoProvider</requestedClass>
+    <mappedClass>org.apache.wiki.crypto.PBECryptoProvider</mappedClass>
+  </mapping>
 </classmappings>
Index: jspwiki-war/src/main/resources/ini/jspwiki.properties
===================================================================
--- jspwiki-war/src/main/resources/ini/jspwiki.properties	(revision 1622810)
+++ jspwiki-war/src/main/resources/ini/jspwiki.properties	(working copy)
@@ -338,6 +338,19 @@
 #
 #jspwiki.lucene.analyzer = org.apache.lucene.analysis.standard.StandardAnalyzer
 
+#
+#  The implementing class of the Cryptographic Provider (CryptoProvider) for jspwiki.
+#  Default is BaseCryptoProvider, but you can enhance this to use PBECryptoProvider.
+#
+jspwiki.cryptoProvider = org.apache.wiki.crypto.BaseCryptoProvider
+#
+#  The location of the jspwiki cryptographic settings file. This file should be protected at all
+#  costs, as it contains the passwords and settings for your encryption and decryption ciphers.
+#  WARNING: If this file is lost, or altered, you will no longer be able to read any wiki content.
+#
+#jspwiki.cryptoFile = /usr/local/etc/jspwiki-crypto.properties
+
+
 ############################################################################
 #
 #  Special page references.
Index: jspwiki-war/src/main/resources/ini/jspwiki_module.xml
===================================================================
--- jspwiki-war/src/main/resources/ini/jspwiki_module.xml	(revision 1622810)
+++ jspwiki-war/src/main/resources/ini/jspwiki_module.xml	(working copy)
@@ -55,9 +55,19 @@
       <minVersion>2.4</minVersion>
    </plugin>
 
+   <plugin class="org.apache.wiki.plugin.EncryptPlugin">
+      <author>David Vittor</author>
+      <minVersion>2.10.2</minVersion>
+       <alias>Encrypt</alias>
+   </plugin>
+
    <filter class="org.apache.wiki.filters.SpamFilter">
       <author>Janne Jalkanen</author>
       <minVersion>2.6</minVersion>
    </filter>
-   
+   <filter class="org.apache.wiki.filters.EncryptedPageFilter">
+       <author>David Vittor</author>
+       <minVersion>2.10.2</minVersion>
+   </filter>
+
 </modules>
\ No newline at end of file
Index: jspwiki-war/src/test/java/org/apache/wiki/crypto/PBECryptoProviderTest.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/crypto/PBECryptoProviderTest.java	(revision 0)
+++ jspwiki-war/src/test/java/org/apache/wiki/crypto/PBECryptoProviderTest.java	(working copy)
@@ -0,0 +1,75 @@
+/*
+    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.wiki.crypto;
+
+import junit.framework.TestCase;
+
+import org.apache.wiki.TestEngine;
+import org.apache.wiki.api.exceptions.EncryptionException;
+
+import java.util.Properties;
+
+/**
+ * Test the class {@link org.apache.wiki.crypto.PBECryptoProvider}
+ *
+ * @since 2.10.2
+ */
+public class PBECryptoProviderTest extends TestCase {
+
+    TestEngine m_engine;
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        Properties props = TestEngine.getTestProperties();
+        m_engine = new TestEngine(props);
+    }
+
+    /**
+     * Test the {@link org.apache.wiki.crypto.PBECryptoProvider} with some sample content,
+     * both the encrypt and decrypt methods.
+     * @throws Exception
+     */
+    public void testEncryptAndDecrypt() throws Exception {
+        PBECryptoProvider provider = new PBECryptoProvider();
+        provider.initialize(m_engine,m_engine.getWikiProperties());
+        char[] password1 = "P@ssword1".toCharArray();
+        char[] password2 = "Pa$$w0rd2".toCharArray();
+        String content1 = "This is simple";
+        String content2 = "This may work";
+
+        // Test content1&2 with password1
+        byte[] secret1 = provider.encrypt(password1,content1.getBytes());
+        byte[] secret2 = provider.encrypt(password1,content2.getBytes());
+        String result1 = new String(provider.decrypt(password1,secret1));
+        String result2 = new String(provider.decrypt(password1,secret2));
+        assertNotNull(result1);
+        assertNotNull(result2);
+        assertEquals(content1,result1);
+        assertEquals(content2,result2);
+
+        try {
+            result1 = new String(provider.decrypt(password2, secret1));
+        } catch (EncryptionException e) {
+            assertTrue(e.getMessage().contains("BadPaddingException"));
+        }
+        assertEquals(content1, result1);
+    }
+
+}
Index: jspwiki-war/src/test/java/org/apache/wiki/filters/AllTests.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/filters/AllTests.java	(revision 1622810)
+++ jspwiki-war/src/test/java/org/apache/wiki/filters/AllTests.java	(working copy)
@@ -33,6 +33,7 @@
         TestSuite suite = new TestSuite("PageFilter tests");
 
         suite.addTest( DefaultFilterManagerTest.suite() );
+        suite.addTest( EncryptedPageFilterTest.suite() );
 
         return suite;
     }
Index: jspwiki-war/src/test/java/org/apache/wiki/filters/DefaultFilterManagerTest.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/filters/DefaultFilterManagerTest.java	(revision 1622810)
+++ jspwiki-war/src/test/java/org/apache/wiki/filters/DefaultFilterManagerTest.java	(working copy)
@@ -51,7 +51,7 @@
 
         List l = m.getFilterList();
 
-        assertEquals("Wrong number of filters", 2, l.size());
+        assertEquals("Wrong number of filters", 3, l.size());
 
         Iterator i = l.iterator();
         PageFilter f1 = (PageFilter)i.next();
@@ -61,6 +61,10 @@
         PageFilter f2 = (PageFilter)i.next();
 
         assertTrue("Not a Testfilter", f2 instanceof TestFilter);
+
+        PageFilter f3 = (PageFilter)i.next();
+
+        assertTrue("Not a EncryptedPageFilter", f3 instanceof EncryptedPageFilter);
     }
 
     public void testInitParams() throws Exception {
Index: jspwiki-war/src/test/java/org/apache/wiki/filters/EncryptedPageFilterTest.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/filters/EncryptedPageFilterTest.java	(revision 0)
+++ jspwiki-war/src/test/java/org/apache/wiki/filters/EncryptedPageFilterTest.java	(working copy)
@@ -0,0 +1,155 @@
+/*
+    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.wiki.filters;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import net.sf.ehcache.CacheManager;
+import net.sourceforge.stripes.mock.MockHttpServletRequest;
+
+import org.apache.wiki.TestEngine;
+import org.apache.wiki.WikiContext;
+import org.apache.wiki.WikiPage;
+import org.apache.wiki.WikiSession;
+import org.apache.wiki.api.exceptions.WikiException;
+import org.apache.wiki.auth.Users;
+import org.apache.wiki.providers.WikiPageProvider;
+
+import java.util.Properties;
+
+/**
+ * Test the filter {@link org.apache.wiki.filters.EncryptedPageFilter}.
+ *
+ * @since 2.10.2
+ */
+public class EncryptedPageFilterTest extends TestCase {
+    TestEngine pbeTestEngine;
+    TestEngine testEngine;
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        Properties props = TestEngine.getTestProperties();
+        CacheManager.getInstance().removeAllCaches();
+        TestEngine.emptyWorkDir();
+        pbeTestEngine = new TestEngine(props);
+
+        props.setProperty("jspwiki.cryptoProvider", "org.apache.wiki.crypto.BaseCryptoProvider");
+        testEngine = new TestEngine(props);
+    }
+
+    /**
+     * Returns a {@link WikiContext} for the given page and testEngine,
+     * with user {@link org.apache.wiki.auth.Users#ADMIN} logged in.
+     *
+     * @param testEngine give {@link org.apache.wiki.TestEngine}
+     * @param page given {@link WikiPage}.
+     * @return {@link WikiContext} associated to given {@link WikiPage}.
+     * @throws org.apache.wiki.api.exceptions.WikiException problems while logging in.
+     */
+    WikiContext getAdminBasedWikiContextFor( TestEngine testEngine, WikiPage page ) throws WikiException
+    {
+        MockHttpServletRequest request = testEngine.newHttpRequest();
+        WikiSession session =  WikiSession.getWikiSession( testEngine, request );
+        testEngine.getAuthenticationManager().login( session,
+                request,
+                Users.ADMIN,
+                Users.ADMIN_PASS );
+
+        return new WikiContext( testEngine, request, page );
+    }
+
+    /**
+     * Run a simple test storing content to a page, using the {@link org.apache.wiki.TestEngine}
+     * with {@link org.apache.wiki.crypto.BaseCryptoProvider} configured.
+     * @throws Exception
+     */
+    public void testBaseEncryptAndDecrypt() throws Exception {
+        String ENDLINE = "\n";
+        String src = "test content"+ENDLINE;
+        String expected = "test content"+ENDLINE;
+
+        testEngine.saveText( "Test", src );
+        WikiPage page = testEngine.getPage( "Test", WikiPageProvider.LATEST_VERSION );
+        WikiContext context = getAdminBasedWikiContextFor(testEngine,page);
+        String res = testEngine.getHTML( context, page );
+        assertEquals( expected, res );
+
+        String text = testEngine.getPageManager().getPageText( page.getName(), WikiPageProvider.LATEST_VERSION  );
+        assertEquals( "test content\r"+ENDLINE, text );
+        text = testEngine.getHTML(page.getName());
+        assertEquals( expected, text );
+
+        String change = "Text changed"+ENDLINE;
+        String expectedChange = "Text changed"+ENDLINE;
+        testEngine.saveText( context, change);
+        String textChanged = testEngine.getHTML( page.getName() );
+        assertEquals(expectedChange, textChanged);
+    }
+
+    /**
+     * Run a simple test storing content to two pages, "Test" and "secureTest",
+     * using the {@link org.apache.wiki.TestEngine}
+     * with {@link org.apache.wiki.crypto.PBECryptoProvider} configured.
+     * The "Test" page content should remain the same, while the "secureTest" content gets encrypted.
+     * @throws Exception
+     */
+    public void testPBEEncryptAndDecrypt() throws Exception {
+
+        String ENDLINE = "\n";
+        String src = "test content"+ENDLINE;
+        String expected = "test content"+ENDLINE;
+
+        pbeTestEngine.saveText( "Test", src );
+        pbeTestEngine.saveText( "secureTest", src );
+        WikiPage pageTest = pbeTestEngine.getPage( "Test", WikiPageProvider.LATEST_VERSION );
+        WikiPage pageSecure = pbeTestEngine.getPage( "secureTest", WikiPageProvider.LATEST_VERSION );
+        WikiContext contextTest = getAdminBasedWikiContextFor(pbeTestEngine,pageTest);
+        WikiContext contextSecure = getAdminBasedWikiContextFor(pbeTestEngine,pageSecure);
+        String resTest = pbeTestEngine.getHTML( contextTest, pageTest );
+        String resSecure = pbeTestEngine.getHTML( contextSecure, pageSecure );
+        assertEquals( expected, resTest );
+        assertEquals( expected, resSecure );
+
+        String text = pbeTestEngine.getPageManager().getPageText( pageTest.getName(), WikiPageProvider.LATEST_VERSION  );
+        assertEquals( "test content\r"+ENDLINE, text );
+        text = testEngine.getHTML(pageTest.getName());
+        assertEquals( expected, text );
+        text = pbeTestEngine.getPageManager().getPageText( pageSecure.getName(), WikiPageProvider.LATEST_VERSION  );
+        assertNotSame( expected, text );
+        assertEquals( "jO9mPV4LSAsOBL9cV9mQlxcrZ9lip7lKTqNduAeViww=)FEJ*$Y@LSDFKJ@V", text );
+        text = pbeTestEngine.getHTML(pageSecure.getName());
+        assertEquals( expected, text );
+
+        String change = "Text changed"+ENDLINE;
+        String expectedChange = "Text changed"+ENDLINE;
+        pbeTestEngine.saveText( contextTest, change);
+        pbeTestEngine.saveText( contextSecure, change);
+        String textChanged = pbeTestEngine.getHTML( pageTest.getName() );
+        assertEquals(expectedChange, textChanged);
+        textChanged = pbeTestEngine.getHTML( pageSecure.getName() );
+        assertEquals(expectedChange, textChanged);
+    }
+
+    public static Test suite() {
+        return new TestSuite( EncryptedPageFilterTest.class );
+    }
+}
Index: jspwiki-war/src/test/java/org/apache/wiki/ui/admin/beans/PluginBeanTest.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/ui/admin/beans/PluginBeanTest.java	(revision 1622810)
+++ jspwiki-war/src/test/java/org/apache/wiki/ui/admin/beans/PluginBeanTest.java	(working copy)
@@ -44,6 +44,7 @@
                                 "<h4>Plugins</h4>" +
                                 "<table border=\"1\">" +
                                   "<tr><th>Name</th><th>Alias</th><th>Author</th><th>Notes</th></tr>" +
+                                  "<tr><td>EncryptPlugin</td><td>Encrypt</td><td>David Vittor</td><td></td></tr>" +
                                   "<tr><td>IfPlugin</td><td>If</td><td>Janne Jalkanen</td><td></td></tr>" +
                                   "<tr><td>Note</td><td></td><td>Janne Jalkanen</td><td></td></tr>" +
                                   "<tr><td>SamplePlugin</td><td>samplealias</td><td>Janne Jalkanen</td><td></td></tr>" +
Index: jspwiki-war/src/test/java/org/apache/wiki/util/XmlUtilTest.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/util/XmlUtilTest.java	(revision 1622810)
+++ jspwiki-war/src/test/java/org/apache/wiki/util/XmlUtilTest.java	(working copy)
@@ -40,10 +40,10 @@
     
     public void testParseFromClasspath() {
     	List< Element > elements = XmlUtil.parse( ModuleManager.PLUGIN_RESOURCE_LOCATION, "/modules/plugin" );
-    	assertEquals( 4, elements.size() ); // 2 on src/main/resources, another 2 on src/test/resources
+    	assertEquals( 5, elements.size() ); // 2 on src/main/resources, another 2 on src/test/resources
     	
     	elements = XmlUtil.parse( ModuleManager.PLUGIN_RESOURCE_LOCATION, "/modules/filter" );
-     	assertEquals( 1, elements.size() );
+     	assertEquals( 2, elements.size() );
      	
      	elements = XmlUtil.parse( ModuleManager.PLUGIN_RESOURCE_LOCATION, "/modules/editor" );
      	assertEquals( 1, elements.size() );
@@ -61,7 +61,7 @@
      	assertEquals( 0, elements.size() );
      	
      	elements = XmlUtil.parse( ClassUtil.MAPPINGS, "/classmappings/mapping" );
-     	assertEquals( 19, elements.size() );
+     	assertEquals( 21, elements.size() );
     }
     
     public void testParseFromStream() throws FileNotFoundException {
Index: jspwiki-war/src/test/resources/filters.xml
===================================================================
--- jspwiki-war/src/test/resources/filters.xml	(revision 1622810)
+++ jspwiki-war/src/test/resources/filters.xml	(working copy)
@@ -23,7 +23,7 @@
    <filter>
       <class>org.apache.wiki.filters.ProfanityFilter</class>
    </filter>
-   
+
    <filter>
       <class>org.apache.wiki.filters.TestFilter</class>
 
@@ -38,4 +38,8 @@
       </param>
    </filter>
 
+    <filter>
+      <class>org.apache.wiki.filters.EncryptedPageFilter</class>
+    </filter>
+
 </pagefilters>
Index: jspwiki-war/src/test/resources/jspwiki-crypto.properties
===================================================================
--- jspwiki-war/src/test/resources/jspwiki-crypto.properties	(revision 0)
+++ jspwiki-war/src/test/resources/jspwiki-crypto.properties	(working copy)
@@ -0,0 +1,2 @@
+crypto.key=xyzpwd123456
+pagename.prefix=secure
\ No newline at end of file
Index: jspwiki-war/src/test/resources/jspwiki-custom.properties
===================================================================
--- jspwiki-war/src/test/resources/jspwiki-custom.properties	(revision 1622810)
+++ jspwiki-war/src/test/resources/jspwiki-custom.properties	(working copy)
@@ -72,6 +72,9 @@
 #mail.smtp.account =
 #mail.smtp.password =
 
+# for EncryptedPageFilterTest
+jspwiki.cryptoProvider = org.apache.wiki.crypto.PBECryptoProvider
+
 # for JDBC tests
 server.port=9321
 server.database.0=file:target/jspwiki.hsqldb
