From d8ecac31301960d58a6dc856939a97d709e82773 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Tue, 03 May 2016 09:43:02 +0000
Subject: [PATCH] OPENDJ-2617 Add confidentiality (encryption) option for replication changelog

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java                           |    5 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java                               |   17 +
 opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java                                      |    4 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java             |    9 
 opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java    |    5 
 opendj-server-legacy/src/messages/org/opends/messages/replication.properties                                            |    5 
 opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java  |   25 +-
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java               |   78 ++++++-
 opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java                           |    8 
 opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java                                            |   85 ++++----
 opendj-server-legacy/resource/schema/02-config.ldif                                                                     |    5 
 opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java           |   41 +++-
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java     |    3 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java      |    7 
 opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java                |   24 ++
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java                             |    5 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java              |    4 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java                          |   20 ++
 opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml |  100 +++++++++++
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java                             |   35 ++-
 opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java                    |    7 
 opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java                 |    3 
 opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java                                           |    3 
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java                |    6 
 24 files changed, 379 insertions(+), 125 deletions(-)

diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml
index cec8277..00ece7b 100644
--- a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ReplicationServerConfiguration.xml
@@ -13,7 +13,7 @@
   information: "Portions Copyright [year] [name of copyright owner]".
 
   Copyright 2007-2010 Sun Microsystems, Inc.
-  Portions copyright 2011-2015 ForgeRock AS.
+  Portions copyright 2011-2016 ForgeRock AS.
   ! -->
 <adm:managed-object name="replication-server"
   plural-name="replication-servers"
@@ -368,4 +368,102 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="cipher-transformation">
+    <adm:synopsis>
+      Specifies the cipher for the directory server.
+      The syntax is "algorithm/mode/padding".
+    </adm:synopsis>
+    <adm:description>
+      The full transformation is required: specifying only an algorithm
+      and allowing the cipher provider to supply the default mode and
+      padding is not supported, because there is no guarantee these
+      default values are the same among different implementations.
+      Some cipher algorithms, including RC4 and ARCFOUR, do not have a
+      mode or padding, and hence must be specified using NONE for the
+      mode field and NoPadding for the padding field. For example,
+      RC4/NONE/NoPadding.
+    </adm:description>
+    <adm:requires-admin-action>
+      <adm:none>
+        <adm:synopsis>
+          Changes to this property take effect immediately but
+          only affect cryptographic operations performed after the
+          change.
+        </adm:synopsis>
+      </adm:none>
+    </adm:requires-admin-action>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>AES/CBC/PKCS5Padding</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-cipher-transformation</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="cipher-key-length">
+    <adm:synopsis>
+      Specifies the key length in bits for the preferred cipher.
+    </adm:synopsis>
+    <adm:requires-admin-action>
+      <adm:none>
+        <adm:synopsis>
+          Changes to this property take effect immediately but
+          only affect cryptographic operations performed after the
+          change.
+        </adm:synopsis>
+      </adm:none>
+    </adm:requires-admin-action>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>128</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-cipher-key-length</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="confidentiality-enabled">
+    <adm:synopsis>
+      Indicates whether the replication change-log should make records readable only by Directory Server.
+      Throughput and disk space are affected by the more expensive operations taking place.
+    </adm:synopsis>
+    <adm:description>
+      Confidentiality is achieved by encrypting records on all domains managed by this replication server.
+      Encrypting the records prevents unauthorized parties from accessing contents of LDAP operations.
+      For complete protection, consider enabling secure communications between servers.
+      Change number indexing is not affected by the setting.
+    </adm:description>
+    <adm:requires-admin-action>
+      <adm:none>
+        <adm:synopsis>
+          Changes to this property take effect immediately but
+          only affect operations performed after the change.
+        </adm:synopsis>
+      </adm:none>
+    </adm:requires-admin-action>
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>false</adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:boolean/>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-confidentiality-enabled</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
 </adm:managed-object>
diff --git a/opendj-server-legacy/resource/schema/02-config.ldif b/opendj-server-legacy/resource/schema/02-config.ldif
index 6926c4c..f4e4fba 100644
--- a/opendj-server-legacy/resource/schema/02-config.ldif
+++ b/opendj-server-legacy/resource/schema/02-config.ldif
@@ -4560,7 +4560,10 @@
         ds-cfg-weight $
         ds-cfg-monitoring-period $
         ds-cfg-compute-change-number $
-        ds-cfg-source-address )
+        ds-cfg-source-address $
+        ds-cfg-cipher-transformation $
+        ds-cfg-cipher-key-length $
+        ds-cfg-confidentiality-enabled)
   X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.65
   NAME 'ds-backup-directory'
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
index 00fd5bb..e9980bd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -108,11 +108,10 @@
     private MatchingRuleIndex(EntryContainer entryContainer, AttributeType attributeType, State state, Indexer indexer,
         int indexEntryLimit, boolean encryptValues, CryptoSuite cryptoSuite)
     {
-      super(getIndexName(entryContainer, attributeType, indexer.getIndexID()), state, indexEntryLimit, entryContainer);
+      super(getIndexName(entryContainer, attributeType, indexer.getIndexID()), state, indexEntryLimit, entryContainer,
+          cryptoSuite);
       this.attributeType = attributeType;
       this.indexer = indexer;
-      this.encryptValues = encryptValues;
-      this.cryptoSuite = cryptoSuite;
     }
 
     Set<ByteString> indexEntry(Entry entry)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java
index 75538b0..7dbedef 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DefaultIndex.java
@@ -53,7 +53,6 @@
   private int indexEntryLimit;
 
   private EntryIDSetCodec codec;
-  protected boolean encryptValues;
   protected CryptoSuite cryptoSuite;
 
   /**
@@ -79,16 +78,18 @@
    *          The configured limit on the number of entry IDs that may be indexed by one key.
    * @param entryContainer
    *          The entryContainer holding this index.
+   * @param cryptoSuite
    * @throws StorageRuntimeException
    *           If an error occurs in the storage.
    */
-  DefaultIndex(TreeName name, State state, int indexEntryLimit, EntryContainer entryContainer)
+  DefaultIndex(TreeName name, State state, int indexEntryLimit, EntryContainer entryContainer, CryptoSuite cryptoSuite)
       throws StorageRuntimeException
   {
     super(name);
     this.indexEntryLimit = indexEntryLimit;
     this.state = state;
     this.entryContainer = entryContainer;
+    this.cryptoSuite = cryptoSuite;
   }
 
   @Override
@@ -96,7 +97,7 @@
   {
     final EnumSet<IndexFlag> flags = state.getIndexFlags(txn, getName());
     codec = flags.contains(COMPACTED) ? CODEC_V2 : CODEC_V1;
-    if (encryptValues)
+    if (cryptoSuite.isEncrypted())
     {
       codec = new EntryIDSet.EntryIDSetCodecV3(codec, cryptoSuite);
     }
@@ -154,12 +155,14 @@
   // Keeps temporary values during import encrypted even in on-disk buffers.
   long importDecodeValue(ByteString value)
   {
-    return encryptValues ? decodeValue(ByteString.empty(), value).iterator().next().longValue() : value.toLong();
+    return cryptoSuite.isEncrypted()
+        ? decodeValue(ByteString.empty(), value).iterator().next().longValue()
+        : value.toLong();
   }
 
   ByteString importToValue(EntryID entryID)
   {
-    return encryptValues ? toValue(newDefinedSet(entryID.longValue())) : entryID.toByteString();
+    return cryptoSuite.isEncrypted() ? toValue(newDefinedSet(entryID.longValue())) : entryID.toByteString();
   }
 
   @Override
@@ -293,9 +296,7 @@
   @Override
   public boolean setConfidential(boolean indexConfidential)
   {
-    final boolean rebuildRequired = !this.encryptValues && indexConfidential;
-    this.encryptValues = indexConfidential;
-    return rebuildRequired;
+    return cryptoSuite.isEncrypted() != indexConfidential;
   }
 
   @Override
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
index 8e71e8a..c2bd410 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -154,6 +154,8 @@
 
   /** The set of attribute indexes. */
   private final Map<AttributeType, AttributeIndex> attrIndexMap = new HashMap<>();
+
+  private final Map<AttributeType, CryptoSuite> attrCryptoMap = new HashMap<>();
   /** The set of VLV (Virtual List View) indexes. */
   private final Map<String, VLVIndex> vlvIndexMap = new HashMap<>();
 
@@ -165,8 +167,6 @@
 
   private final ServerContext serverContext;
 
-  private CryptoSuite cryptoSuite;
-
   /**
    * This class is responsible for managing the configuration for attribute
    * indexes used within this entry container.
@@ -180,7 +180,7 @@
     {
       try
       {
-        newAttributeIndex(cfg);
+        newAttributeIndex(cfg, null);
         return true;
       }
       catch(Exception e)
@@ -196,7 +196,8 @@
       final ConfigChangeResult ccr = new ConfigChangeResult();
       try
       {
-        final AttributeIndex index = newAttributeIndex(cfg);
+        final CryptoSuite cryptoSuite = newCryptoSuite(cfg.isConfidentialityEnabled());
+        final AttributeIndex index = newAttributeIndex(cfg, cryptoSuite);
         storage.write(new WriteOperation()
         {
           @Override
@@ -209,6 +210,7 @@
               ccr.addMessage(NOTE_INDEX_ADD_REQUIRES_REBUILD.get(cfg.getAttribute().getNameOrOID()));
             }
             attrIndexMap.put(cfg.getAttribute(), index);
+            attrCryptoMap.put(cfg.getAttribute(), cryptoSuite);
           }
         });
       }
@@ -242,6 +244,7 @@
           public void run(WriteableTransaction txn) throws Exception
           {
             attrIndexMap.remove(cfg.getAttribute()).closeAndDelete(txn);
+            attrCryptoMap.remove(cfg.getAttribute());
           }
         });
       }
@@ -370,7 +373,13 @@
     config.addBackendVLVIndexDeleteListener(vlvIndexCfgManager);
   }
 
-  private AttributeIndex newAttributeIndex(BackendIndexCfg cfg) throws ConfigException
+  private CryptoSuite newCryptoSuite(boolean confidentiality)
+  {
+    return serverContext.getCryptoManager().newCryptoSuite(config.getCipherTransformation(),
+        config.getCipherKeyLength(), confidentiality);
+  }
+
+  private AttributeIndex newAttributeIndex(BackendIndexCfg cfg, CryptoSuite cryptoSuite) throws ConfigException
   {
     return new AttributeIndex(cfg, state, this, cryptoSuite);
   }
@@ -381,7 +390,8 @@
         .compress(config.isEntriesCompressed())
         .encode(config.isCompactEncoding())
         .encrypt(config.isConfidentialityEnabled())
-        .cryptoSuite(cryptoSuite)
+        .cryptoSuite(serverContext.getCryptoManager().newCryptoSuite(config.getCipherTransformation(),
+            config.getCipherKeyLength(),config.isConfidentialityEnabled()))
         .schema(rootContainer.getCompressedSchema())
         .build();
   }
@@ -404,8 +414,6 @@
     boolean shouldCreate = accessMode.isWriteable();
     try
     {
-      cryptoSuite = serverContext.getCryptoManager().newCryptoSuite(config.getCipherTransformation(),
-          config.getCipherKeyLength());
       id2entry = new ID2Entry(getIndexName(ID2ENTRY_TREE_NAME), newDataConfig(config));
       id2entry.open(txn, shouldCreate);
       id2childrenCount.open(txn, shouldCreate);
@@ -417,13 +425,15 @@
       {
         BackendIndexCfg indexCfg = config.getBackendIndex(idx);
 
-        final AttributeIndex index = newAttributeIndex(indexCfg);
+        CryptoSuite cryptoSuite = newCryptoSuite(indexCfg.isConfidentialityEnabled());
+        final AttributeIndex index = newAttributeIndex(indexCfg, cryptoSuite);
         index.open(txn, shouldCreate);
         if(!index.isTrusted())
         {
           logger.info(NOTE_INDEX_ADD_REQUIRES_REBUILD, index.getName());
         }
         attrIndexMap.put(indexCfg.getAttribute(), index);
+        attrCryptoMap.put(indexCfg.getAttribute(), cryptoSuite);
       }
 
       for (String idx : config.listBackendVLVIndexes())
@@ -2386,13 +2396,14 @@
         @Override
         public void run(WriteableTransaction txn) throws Exception
         {
-          cryptoSuite.setCipherTransformation(cfg.getCipherTransformation());
-          cryptoSuite.setCipherKeyLength(cfg.getCipherKeyLength());
           id2entry.setDataConfig(newDataConfig(cfg));
-
           EntryContainer.this.config = cfg;
         }
       });
+      for (CryptoSuite indexCrypto : attrCryptoMap.values())
+      {
+        indexCrypto.newParameters(cfg.getCipherTransformation(), cfg.getCipherKeyLength(), indexCrypto.isEncrypted());
+      }
     }
     catch (Exception e)
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
index 8a69589..04c921f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
@@ -2752,8 +2752,8 @@
   }
 
   @Override
-  public CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength)
+  public CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength, boolean encrypt)
   {
-    return new CryptoSuite(this, cipherTransformation, cipherKeyLength);
+    return new CryptoSuite(this, cipherTransformation, cipherKeyLength, encrypt);
   }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java
index d6f3e67..e1bc522 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoSuite.java
@@ -15,6 +15,7 @@
  */
 package org.opends.server.crypto;
 
+import net.jcip.annotations.Immutable;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
@@ -33,8 +34,23 @@
 /** Defines cipher transformation and hash algorithm for cryptographic related operations. */
 public class CryptoSuite
 {
-  private String cipherTransformation;
-  private int cipherKeyLength;
+  /** Cipher specific settings that can change at runtime. */
+  @Immutable
+  private static final class CipherInfo
+  {
+    private final String cipherTransformation;
+    private final int cipherKeyLength;
+    private final boolean encrypt;
+
+    CipherInfo(String cipherTransformation, int cipherKeyLength, boolean encrypt)
+    {
+      this.cipherTransformation = cipherTransformation;
+      this.cipherKeyLength = cipherKeyLength;
+      this.encrypt = encrypt;
+    }
+  }
+
+  private volatile CipherInfo cipherInfo;
   private final CryptoManager cryptoManager;
 
   /**
@@ -42,52 +58,24 @@
    * @param cryptoManager the CryptoManager to use for cryptographic operations
    * @param cipherTransformation the initial cipher transformation
    * @param cipherKeyLength the initial key length for the cipher
+   * @param encrypt if the user of the crypto suite needs encryption
    */
-  public CryptoSuite(CryptoManager cryptoManager, String cipherTransformation, int cipherKeyLength)
+  public CryptoSuite(CryptoManager cryptoManager, String cipherTransformation, int cipherKeyLength, boolean encrypt)
   {
     this.cryptoManager = cryptoManager;
-    this.cipherTransformation = cipherTransformation;
-    this.cipherKeyLength = cipherKeyLength;
+    this.cipherInfo = new CipherInfo(cipherTransformation, cipherKeyLength, encrypt);
   }
 
   /**
-   * Returns the cipher transformation to use.
-   *
-   * @return the cipher transformation to use
-   */
-  public String getCipherTransformation()
-  {
-    return cipherTransformation;
-  }
-
-  /**
-   * Returns the cipher key length to use.
-   *
-   * @return the cipher key length to use
-   */
-  public int getCipherKeyLength()
-  {
-    return cipherKeyLength;
-  }
-
-  /**
-   * Sets the cipher transformation for the CryptoSuite.
+   * Set new cipher and enable parameters for the crypto suite.
    *
    * @param cipherTransformation the new cipher transformation
-   */
-  public void setCipherTransformation(String cipherTransformation)
-  {
-    this.cipherTransformation = cipherTransformation;
-  }
-
-  /**
-   * Sets the key length for the CryptoSuite.
-   *
    * @param cipherKeyLength the new key length
+   * @param enabled true if the user of the crypto suite needs encryption
    */
-  public void setCipherKeyLength(int cipherKeyLength)
+  public void newParameters(String cipherTransformation, int cipherKeyLength, boolean enabled)
   {
-    this.cipherKeyLength = cipherKeyLength;
+    cipherInfo = new CipherInfo(cipherTransformation, cipherKeyLength, enabled);
   }
 
   /**
@@ -113,7 +101,8 @@
    */
   public byte[] encrypt(byte[] data) throws GeneralSecurityException, CryptoManagerException
   {
-    return cryptoManager.encrypt(cipherTransformation, cipherKeyLength, data);
+    CipherInfo currentCipher = cipherInfo;
+    return cryptoManager.encrypt(currentCipher.cipherTransformation, currentCipher.cipherKeyLength, data);
   }
 
   /**
@@ -127,7 +116,8 @@
    */
   public CipherOutputStream getCipherOutputStream(OutputStream os) throws CryptoManagerException
   {
-    return cryptoManager.getCipherOutputStream(cipherTransformation, cipherKeyLength, os);
+    CipherInfo currentCipher = cipherInfo;
+    return cryptoManager.getCipherOutputStream(currentCipher.cipherTransformation, currentCipher.cipherKeyLength, os);
   }
 
   /**
@@ -162,14 +152,27 @@
     }
   }
 
+  /**
+   * Returns whether the user of the crypto suite needs encryption.
+   *
+   * @return true if the user of the crypto suite needs encryption
+   */
+  public boolean isEncrypted()
+  {
+    return cipherInfo.encrypt;
+  }
+
   @Override
   public String toString()
   {
     StringBuilder builder = new StringBuilder();
+    CipherInfo currentCipher = cipherInfo;
     builder.append("CryptoSuite(cipherTransformation=");
-    builder.append(cipherTransformation);
+    builder.append(currentCipher.cipherTransformation);
     builder.append(", keyLength=");
-    builder.append(cipherKeyLength);
+    builder.append(currentCipher.cipherKeyLength);
+    builder.append(", encrypt=");
+    builder.append(currentCipher.encrypt);
     builder.append(")");
     return builder.toString();
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java
index 75d825f..bb0f2bd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/ReplicationMsg.java
@@ -12,7 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2006-2010 Sun Microsystems, Inc.
- * Portions copyright 2013-2014 ForgeRock AS.
+ * Portions copyright 2013-2016 ForgeRock AS.
  */
 package org.opends.server.replication.protocol;
 
@@ -27,6 +27,9 @@
  */
 public abstract class ReplicationMsg
 {
+  /** Reserved type for uses other than protocol messages. */
+  public static final byte MSG_TYPE_DISK_ENCODING = -1;
+
   // PDU type values kept for compatibility with replication protocol version 1
   static final byte MSG_TYPE_MODIFY_V1 = 1;
   static final byte MSG_TYPE_ADD_V1 = 2;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
index f58a2c0..01377c6 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
@@ -53,6 +53,7 @@
 import org.opends.server.api.VirtualAttributeProvider;
 import org.opends.server.backends.ChangelogBackend;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.replication.common.CSN;
 import org.opends.server.replication.common.MultiDomainServerState;
 import org.opends.server.replication.common.ServerState;
@@ -129,6 +130,8 @@
    */
   private static final List<ReplicationServer> allInstances = new ArrayList<>();
 
+  private final CryptoSuite cryptoSuite;
+
   /**
    * Creates a new Replication server using the provided configuration entry.
    *
@@ -170,7 +173,10 @@
     this.domainPredicate = predicate;
 
     enableExternalChangeLog();
-    this.changelogDB = new FileChangelogDB(this, config.getReplicationDBDirectory());
+    cryptoSuite = DirectoryServer.getInstance().getServerContext().getCryptoManager().
+        newCryptoSuite(cfg.getCipherTransformation(), cfg.getCipherKeyLength(), cfg.isConfidentialityEnabled());
+
+    this.changelogDB = new FileChangelogDB(this, config.getReplicationDBDirectory(), cryptoSuite);
 
     replSessionSecurity = new ReplSessionSecurity();
     initialize();
@@ -871,6 +877,9 @@
       }
     }
 
+    cryptoSuite.newParameters(config.getCipherTransformation(), config.getCipherKeyLength(),
+        config.isConfidentialityEnabled());
+
     // changing the listen port requires to stop the listen thread
     // and restart it.
     if (getReplicationPort() != oldConfig.getReplicationPort())
@@ -1337,6 +1346,15 @@
     return MultimasterReplication.isECLEnabled();
   }
 
+  /**
+   * Return whether change-log records should be encrypted.
+   * @return trus if change-log records should be encrypted
+   */
+  public boolean isEncrypted()
+  {
+    return config.isConfidentialityEnabled();
+  }
+
   @Override
   public String toString()
   {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java
index dcc93de..526f542 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/BlockLogWriter.java
@@ -11,7 +11,7 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2014-2015 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
  */
 package org.opends.server.replication.server.changelog.file;
 
@@ -123,7 +123,7 @@
       write(parser.encodeRecord(record));
       writer.flush();
     }
-    catch (IOException e)
+    catch (Exception e)
     {
       throw new ChangelogException(ERR_CHANGELOG_UNABLE_TO_ADD_RECORD.get(record.toString(),
           writer.getFile().getPath()), e);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java
index c9ec958..642c29d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangeNumberIndexDB.java
@@ -17,6 +17,7 @@
 
 import static org.opends.messages.ReplicationMessages.*;
 
+import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -388,7 +389,7 @@
     private static final byte STRING_SEPARATOR = 0;
 
     @Override
-    public ByteString encodeRecord(final Record<Long, ChangeNumberIndexRecord> record)
+    public ByteString encodeRecord(final Record<Long, ChangeNumberIndexRecord> record) throws IOException
     {
       final ChangeNumberIndexRecord cnIndexRecord = record.getValue();
       return new ByteStringBuilder()
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
index defe9e2..2ea1b35 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
@@ -42,6 +42,7 @@
 import org.forgerock.util.time.TimeService;
 import org.opends.server.api.DirectoryThread;
 import org.opends.server.backends.ChangelogBackend;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.replication.common.CSN;
 import org.opends.server.replication.common.MultiDomainServerState;
 import org.opends.server.replication.common.ServerState;
@@ -116,6 +117,7 @@
   private static final DBCursor<UpdateMsg> EMPTY_CURSOR_REPLICA_DB =
       new FileReplicaDBCursor(EMPTY_CURSOR, null, AFTER_MATCHING_KEY);
 
+  private final CryptoSuite cryptoSuite;
   /**
    * Creates a new changelog DB.
    *
@@ -123,14 +125,17 @@
    *          the local replication server.
    * @param dbDirectoryPath
    *          the path where the changelog files reside.
+   * @param cryptoSuite
+   *          the cryptosuite to use for encryption
    * @throws ConfigException
    *           if a problem occurs opening the supplied directory
    */
-  public FileChangelogDB(final ReplicationServer replicationServer, String dbDirectoryPath)
+  public FileChangelogDB(final ReplicationServer replicationServer, String dbDirectoryPath, CryptoSuite cryptoSuite)
       throws ConfigException
   {
     this.replicationServer = replicationServer;
     this.dbDirectory = makeDir(dbDirectoryPath);
+    this.cryptoSuite = cryptoSuite;
   }
 
   private File makeDir(final String dbDirName) throws ConfigException
@@ -266,7 +271,7 @@
         return null;
       }
 
-      final FileReplicaDB newDB = new FileReplicaDB(serverId, baseDN, server, replicationEnv);
+      final FileReplicaDB newDB = new FileReplicaDB(serverId, baseDN, server, cryptoSuite, replicationEnv);
       domainMap.put(serverId, newDB);
       return Pair.of(newDB, true);
     }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java
index 23228b8..709b87e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileReplicaDB.java
@@ -16,7 +16,10 @@
 package org.opends.server.replication.server.changelog.file;
 
 import static org.opends.messages.ReplicationMessages.*;
+import static org.opends.server.replication.protocol.ProtocolVersion.REPLICATION_PROTOCOL_V7;
 
+import java.io.IOException;
+import java.security.GeneralSecurityException;
 import java.util.Date;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -24,12 +27,13 @@
 
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ByteStringBuilder;
 import org.opends.server.api.MonitorData;
 import org.forgerock.opendj.server.config.server.MonitorProviderCfg;
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.replication.common.CSN;
-import org.opends.server.replication.protocol.ProtocolVersion;
 import org.opends.server.replication.protocol.UpdateMsg;
 import org.opends.server.replication.server.ReplicationServer;
 import org.opends.server.replication.server.ReplicationServerDomain;
@@ -39,6 +43,7 @@
 import org.opends.server.replication.server.changelog.api.DBCursor.PositionStrategy;
 import org.opends.server.replication.server.changelog.file.Log.RepositionableCursor;
 import org.forgerock.opendj.ldap.DN;
+import org.opends.server.types.CryptoManagerException;
 import org.opends.server.types.InitializationException;
 
 /**
@@ -54,10 +59,6 @@
  */
 class FileReplicaDB
 {
-
-  /** The parser of records stored in Replica DB. */
-  static final RecordParser<CSN, UpdateMsg> RECORD_PARSER = new ReplicaDBParser();
-
   /** Class that allows atomically setting oldest and newest CSNs without synchronization. */
   @Immutable
   private static final class CSNLimits
@@ -105,13 +106,13 @@
    *           If a database problem happened
    */
   FileReplicaDB(final int serverId, final DN baseDN, final ReplicationServer replicationServer,
-      final ReplicationEnvironment replicationEnv) throws ChangelogException
+      final CryptoSuite cryptoSuite, final ReplicationEnvironment replicationEnv) throws ChangelogException
   {
     this.serverId = serverId;
     this.baseDN = baseDN;
     this.replicationServer = replicationServer;
     this.replicationEnv = replicationEnv;
-    this.log = createLog(replicationEnv);
+    this.log = createLog(replicationEnv, cryptoSuite);
     this.csnLimits = new CSNLimits(readOldestCSN(), readNewestCSN());
 
     DirectoryServer.deregisterMonitorProvider(dbMonitor);
@@ -130,10 +131,11 @@
     return record == null ? null : record.getKey();
   }
 
-  private Log<CSN, UpdateMsg> createLog(final ReplicationEnvironment replicationEnv) throws ChangelogException
+  private Log<CSN, UpdateMsg> createLog(final ReplicationEnvironment replicationEnv, final CryptoSuite cryptoSuite)
+      throws ChangelogException
   {
     final ReplicationServerDomain domain = replicationServer.getReplicationServerDomain(baseDN, true);
-    return replicationEnv.getOrCreateReplicaDB(baseDN, serverId, domain.getGenerationId());
+    return replicationEnv.getOrCreateReplicaDB(baseDN, serverId, domain.getGenerationId(), cryptoSuite);
   }
 
   /**
@@ -336,14 +338,49 @@
     log.dumpAsTextFile(log.getPath());
   }
 
+  static ReplicaDBParser newReplicaDBParser(final CryptoSuite cryptoSuite)
+  {
+    return new ReplicaDBParser(cryptoSuite);
+  }
+
   /** Parser of records persisted in the ReplicaDB log. */
   private static class ReplicaDBParser implements RecordParser<CSN, UpdateMsg>
   {
+    private static final byte RECORD_VERSION = 0x01;
+    private final CryptoSuite cryptoSuite;
+    /** Adjusts the ByteStringBuilder capacity to avoid capacity increases (and copies) when encoding records. */
+    private int encryptionOverhead;
+
+    ReplicaDBParser(CryptoSuite cryptoSuite)
+    {
+      this.cryptoSuite = cryptoSuite;
+    }
 
     @Override
-    public ByteString encodeRecord(final Record<CSN, UpdateMsg> record)
+    public ByteString encodeRecord(final Record<CSN, UpdateMsg> record) throws IOException
     {
       final UpdateMsg message = record.getValue();
+      if (cryptoSuite.isEncrypted())
+      {
+        try
+        {
+          byte[] messageBytes = message.getBytes();
+          ByteStringBuilder builder = new ByteStringBuilder(messageBytes.length + encryptionOverhead);
+          builder.appendByte(UpdateMsg.MSG_TYPE_DISK_ENCODING);
+          builder.appendByte(RECORD_VERSION);
+          builder.appendBytes(cryptoSuite.encrypt(messageBytes));
+          final int overhead = builder.length() - messageBytes.length;
+          if (encryptionOverhead < overhead)
+          {
+            encryptionOverhead = overhead;
+          }
+          return builder.toByteString();
+        }
+        catch (GeneralSecurityException | CryptoManagerException e)
+        {
+          throw new IOException(e);
+        }
+      }
       return ByteString.wrap(message.getBytes());
     }
 
@@ -352,8 +389,21 @@
     {
       try
       {
-        final UpdateMsg msg =
-            (UpdateMsg) UpdateMsg.generateMsg(data.toByteArray(), ProtocolVersion.REPLICATION_PROTOCOL_V7);
+        byte[] recordBytes;
+        if (data.byteAt(0) == UpdateMsg.MSG_TYPE_DISK_ENCODING)
+        {
+          final int version = data.byteAt(1);
+          if (version != RECORD_VERSION)
+          {
+            throw new DecodingException(ERR_UNRECOGNIZED_RECORD_VERSION.get(version));
+          }
+          recordBytes = cryptoSuite.decrypt(data.subSequence(2, data.length()).toByteArray());
+        }
+        else
+        {
+          recordBytes = data.toByteArray();
+        }
+        final UpdateMsg msg = (UpdateMsg) UpdateMsg.generateMsg(recordBytes, REPLICATION_PROTOCOL_V7);
         return Record.from(msg.getCSN(), msg);
       }
       catch (Exception e)
@@ -362,26 +412,22 @@
       }
     }
 
-    /** {@inheritDoc} */
     @Override
     public CSN decodeKeyFromString(String key) throws ChangelogException
     {
       return new CSN(key);
     }
 
-    /** {@inheritDoc} */
     @Override
     public String encodeKeyToString(CSN key)
     {
       return key.toString();
     }
 
-    /** {@inheritDoc} */
     @Override
     public CSN getMaxKey()
     {
       return CSN.MAX_CSN_VALUE;
     }
   }
-
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java
index e7d40e3..e31489d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/RecordParser.java
@@ -11,13 +11,15 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2014 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
  */
 package org.opends.server.replication.server.changelog.file;
 
 import org.forgerock.opendj.ldap.ByteString;
 import org.opends.server.replication.server.changelog.api.ChangelogException;
 
+import java.io.IOException;
+
 /**
  * Parser of a log record.
  * <p>
@@ -55,7 +57,7 @@
    *          The record to encode.
    * @return the bytes array representing the (key,value) record
    */
-  ByteString encodeRecord(Record<K, V> record);
+  ByteString encodeRecord(Record<K, V> record) throws IOException;
 
   /**
    * Read the key from the provided string.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java
index c05faee..9d0cedf 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironment.java
@@ -48,6 +48,7 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.util.time.TimeService;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.replication.common.CSN;
 import org.opends.server.replication.protocol.UpdateMsg;
 import org.opends.server.replication.server.ChangelogState;
@@ -338,8 +339,8 @@
    * @throws ChangelogException
    *           if an error occurs.
    */
-  Log<CSN, UpdateMsg> getOrCreateReplicaDB(final DN domainDN, final int serverId, final long generationId)
-      throws ChangelogException
+  Log<CSN, UpdateMsg> getOrCreateReplicaDB(final DN domainDN, final int serverId, final long generationId,
+      final CryptoSuite cryptoSuite) throws ChangelogException
   {
     if (logger.isTraceEnabled())
     {
@@ -367,7 +368,7 @@
         ensureGenerationIdFileExists(generationIdPath);
         changelogState.setDomainGenerationId(domainDN, generationId);
 
-        return openLog(serverIdPath, FileReplicaDB.RECORD_PARSER,
+        return openLog(serverIdPath, FileReplicaDB.newReplicaDBParser(cryptoSuite),
             new LogRotationParameters(REPLICA_DB_MAX_LOG_FILE_SIZE_IN_BYTES, 0, 0), logsReplicaDB);
       }
     }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java b/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java
index 5bdda79..2e9ddc7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/CryptoManager.java
@@ -430,6 +430,7 @@
    * @return a new {@link CryptoSuite} for the cipher and key
    * @param cipherTransformation cipher transformation string specification
    * @param cipherKeyLength length of key in bits
+   * @param encrypt true if the user of the crypto suite needs encryption
    */
-  CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength);
+  CryptoSuite newCryptoSuite(String cipherTransformation, int cipherKeyLength, boolean encrypt);
 }
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/replication.properties b/opendj-server-legacy/src/messages/org/opends/messages/replication.properties
index f83bfb3..7056411 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/replication.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/replication.properties
@@ -589,5 +589,6 @@
 ERR_CHANGELOG_RESET_CHANGE_NUMBER_CSN_TOO_OLD_294=The change number could not be reset to %d because the associated \
   change with CSN '%s' has already been purged from the change log. Try resetting to a more recent change
 ERR_REPLICATION_CHANGE_NUMBER_DISABLED_295=Change number indexing is disabled for replication domain '%s'
-INFO_CHANGELOG_FILTER_OUT_RECORD_BREAKING_ORDER_296=Filtering out from log file '%s' the record '%s'\
- because it would break ordering. Last key appended is '%s'.
\ No newline at end of file
+INFO_CHANGELOG_FILTER_OUT_RECORD_BREAKING_ORDER_296=Filtering out from log file '%s' the record '%s' \
+ because it would break ordering. Last key appended is '%s'.
+ERR_UNRECOGNIZED_RECORD_VERSION_297=Cannot decode change-log record with version %x
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
index 29ee4ce..e3b01b8 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
@@ -11,7 +11,7 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2015 ForgeRock AS.
+ * Copyright 2015-2016 ForgeRock AS.
  */
 package org.opends.server.backends.pluggable;
 
@@ -41,6 +41,7 @@
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.UpdateFunction;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;
+import org.opends.server.crypto.CryptoSuite;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -118,7 +119,10 @@
   {
     final State state = mock(State.class);
     when(state.getIndexFlags(any(ReadableTransaction.class), any(TreeName.class))).thenReturn(indexFlags);
-    return new DefaultIndex(new TreeName("dc=example,dc=com", name), state, indexLimit, mock(EntryContainer.class));
+    final CryptoSuite cryptoSuite = mock(CryptoSuite.class);
+    when(cryptoSuite.isEncrypted()).thenReturn(false);
+    return new DefaultIndex(new TreeName("dc=example,dc=com", name), state, indexLimit, mock(EntryContainer.class),
+        cryptoSuite);
   }
 
   static final class DummyWriteableTransaction implements WriteableTransaction {
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java
index e8dac4f..4cdfafd 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/OnDiskMergeImporterTest.java
@@ -61,6 +61,7 @@
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;
+import org.opends.server.crypto.CryptoSuite;
 import org.testng.annotations.Test;
 
 import com.forgerock.opendj.util.PackedLong;
@@ -483,6 +484,7 @@
   {
     private static final State state;
     private static final EntryContainer entryContainer;
+    private static final CryptoSuite cryptoSuite;
 
     static
     {
@@ -493,11 +495,14 @@
       state = Mockito.mock(State.class);
       Mockito.when(state.getIndexFlags(Mockito.any(ReadableTransaction.class), Mockito.any(TreeName.class))).thenReturn(
           EnumSet.of(State.IndexFlag.COMPACTED));
+
+      cryptoSuite = Mockito.mock(CryptoSuite.class);
+      Mockito.when(cryptoSuite.isEncrypted()).thenReturn(false);
     };
 
     DummyIndex(int indexEntryLimit) throws StorageRuntimeException
     {
-      super(TreeName.valueOf("/dumy/dummy"), state, indexEntryLimit, entryContainer);
+      super(TreeName.valueOf("/dummy/dummy"), state, indexEntryLimit, entryContainer, cryptoSuite);
       open(Mockito.mock(WriteableTransaction.class), false);
     }
   }
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java
index 3bc909d..d7f2d6d 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/ReplServerFakeConfiguration.java
@@ -40,6 +40,7 @@
   private int queueSize;
   private int windowSize;
   private SortedSet<String> servers;
+  private boolean confidentialityEnabled;
 
   /*
    * Assured mode properties
@@ -203,12 +204,30 @@
   }
 
   @Override
+  public boolean isConfidentialityEnabled()
+  {
+    return confidentialityEnabled;
+  }
+
+  @Override
   public long getAssuredTimeout()
   {
     return assuredTimeout;
   }
 
   @Override
+  public int getCipherKeyLength()
+  {
+    return 128;
+  }
+
+  @Override
+  public String getCipherTransformation()
+  {
+    return "AES/CBC/PKCS5Padding";
+  }
+
+  @Override
   public int getDegradedStatusThreshold()
   {
     return degradedStatusThreshold;
@@ -246,4 +265,9 @@
   {
     this.computeChangenumber = computeChangenumber;
   }
+
+  public void setConfidentialityEnabled(boolean confidentialityEnabled)
+  {
+    this.confidentialityEnabled = confidentialityEnabled;
+  }
 }
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java
index cd0ec2b..be57032 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/BlockLogReaderWriterTest.java
@@ -11,7 +11,7 @@
  * Header, with the fields enclosed by brackets [] replaced by your own identifying
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
- * Copyright 2014-2015 ForgeRock AS.
+ * Copyright 2014-2016 ForgeRock AS.
  */
 package org.opends.server.replication.server.changelog.file;
 
@@ -22,6 +22,7 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -494,7 +495,7 @@
     }
 
     @Override
-    public ByteString encodeRecord(Record<Integer, Integer> record)
+    public ByteString encodeRecord(Record<Integer, Integer> record) throws IOException
     {
       return new ByteStringBuilder().appendInt(record.getKey()).appendInt(record.getValue()).toByteString();
     }
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java
index 28d7c57..89627f1 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/FileReplicaDBTest.java
@@ -25,6 +25,8 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.util.time.TimeService;
 import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.replication.ReplicationTestCase;
 import org.opends.server.replication.common.CSN;
 import org.opends.server.replication.common.CSNGenerator;
@@ -54,6 +56,8 @@
 public class FileReplicaDBTest extends ReplicationTestCase
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+  private final String cipherTransformation = "AES/CBC/PKCS5Padding";
+  private final int keyLength = 128;
   private DN TEST_ROOT_DN;
 
   /**
@@ -76,16 +80,17 @@
   {
     CSN[] csns = generateCSNs(1, 0, 2);
     return new Object[][] {
-      { new DeleteMsg(TEST_ROOT_DN, csns[0], "uid") },
-      { new DeleteMsg(TEST_ROOT_DN, csns[1], "uid") },
+      { new DeleteMsg(TEST_ROOT_DN, csns[0], "uid"), false },
+      { new DeleteMsg(TEST_ROOT_DN, csns[1], "uid"), false },
+      { new DeleteMsg(TEST_ROOT_DN, csns[0], "uid"), true },
+      { new DeleteMsg(TEST_ROOT_DN, csns[1], "uid"), true },
     };
   }
 
   @Test(dataProvider="messages")
-  public void testRecordParser(UpdateMsg msg) throws Exception
+  public void testRecordParser(UpdateMsg msg, boolean confidential) throws Exception
   {
-    RecordParser<CSN, UpdateMsg> parser = FileReplicaDB.RECORD_PARSER;
-
+    RecordParser<CSN, UpdateMsg> parser = FileReplicaDB.newReplicaDBParser(createCryptoSuite(confidential));
     ByteString data = parser.encodeRecord(Record.from(msg.getCSN(), msg));
     Record<CSN, UpdateMsg> record = parser.decodeRecord(data);
 
@@ -94,6 +99,23 @@
     assertThat(record.getValue()).isEqualTo(msg);
   }
 
+  @Test(dataProvider="messages")
+  public void testRecordEncodingWithAndWithoutConfidentiality(UpdateMsg msg, boolean confidential) throws Exception
+  {
+    CryptoSuite cryptoSuite = createCryptoSuite(confidential);
+    RecordParser<CSN, UpdateMsg> parser = FileReplicaDB.newReplicaDBParser(cryptoSuite);
+
+    ByteString data1 = parser.encodeRecord(Record.from(msg.getCSN(), msg));
+    cryptoSuite.newParameters(cipherTransformation, keyLength, !confidential);
+    ByteString data2 = parser.encodeRecord(Record.from(msg.getCSN(), msg));
+
+    assertFalse(data1.equals(data2));
+  }
+
+  private CryptoSuite createCryptoSuite(boolean confidential)
+  {
+    return DirectoryServer.getCryptoManager().newCryptoSuite(cipherTransformation, keyLength, confidential);
+  }
   @Test
   public void testDomainDNWithForwardSlashes() throws Exception
   {
@@ -407,7 +429,7 @@
 
       testRoot = createCleanDir();
       dbEnv = new ReplicationEnvironment(testRoot.getPath(), replicationServer, TimeService.SYSTEM);
-      replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, dbEnv);
+      replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, createCryptoSuite(false), dbEnv);
 
       // Populate the db with 'max' msg
       int mySeqnum = 1;
@@ -428,7 +450,7 @@
       debugInfo(tn, "SHUTDOWN replicaDB and recreate");
       replicaDB.shutdown();
 
-      replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, dbEnv);
+      replicaDB = new FileReplicaDB(1, TEST_ROOT_DN, replicationServer, createCryptoSuite(false), dbEnv);
       assertLimits(replicaDB, csns[1], csns[max]);
 
       // Populate the db with 'max' msg
@@ -521,8 +543,9 @@
       throws IOException, ConfigException
   {
     final int changelogPort = findFreePort();
-    return new ReplicationServer(
-        new ReplServerFakeConfiguration(changelogPort, null, 0, 2, queueSize, windowSize, null));
+    ReplServerFakeConfiguration replServerFakeCfg =
+        new ReplServerFakeConfiguration(changelogPort, null, 0, 2, queueSize, windowSize, null);
+    return new ReplicationServer(replServerFakeCfg);
   }
 
   private FileReplicaDB newReplicaDB(ReplicationServer rs) throws Exception
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java
index 2247dcf..8dfc2d0 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/LogFileTest.java
@@ -16,6 +16,7 @@
 package org.opends.server.replication.server.changelog.file;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.RandomAccessFile;
 
 import org.forgerock.i18n.LocalizableMessage;
@@ -327,7 +328,7 @@
     }
 
     @Override
-    public ByteString encodeRecord(Record<String, String> record)
+    public ByteString encodeRecord(Record<String, String> record) throws IOException
     {
       return new ByteStringBuilder()
         .appendUtf8(record.getKey()).appendByte(STRING_SEPARATOR)
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java
index 899435c..26dd93f 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/replication/server/changelog/file/ReplicationEnvironmentTest.java
@@ -24,6 +24,7 @@
 import org.forgerock.util.time.TimeService;
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.server.TestCaseUtils;
+import org.opends.server.crypto.CryptoSuite;
 import org.opends.server.replication.common.CSN;
 import org.opends.server.replication.common.CSNGenerator;
 import org.opends.server.replication.protocol.UpdateMsg;
@@ -52,14 +53,16 @@
   private static final String DN1_AS_STRING = "cn=test1,dc=company.com";
   private static final String DN2_AS_STRING = "cn=te::st2,dc=company.com";
   private static final String DN3_AS_STRING = "cn=test3,dc=company.com";
-
   private static final String TEST_DIRECTORY_CHANGELOG = "test-output/changelog";
 
+  private static final CryptoSuite cryptoSuite = mock(CryptoSuite.class);
+
   @BeforeClass
   public void setUp() throws Exception
   {
     // This test suite depends on having the schema available for DN decoding.
     TestCaseUtils.startFakeServer();
+    when(cryptoSuite.isEncrypted()).thenReturn(false);
   }
 
   @AfterClass
@@ -89,8 +92,8 @@
       final DN domainDN = DN.valueOf(DN1_AS_STRING);
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
       cnDB = environment.getOrCreateCNIndexDB();
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
-      replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
+      replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1, cryptoSuite);
 
       final ChangelogState state = environment.readOnDiskChangelogState();
 
@@ -123,7 +126,7 @@
         for (int j = 1; j <= 10; j++)
         {
           // 3 domains, 10 server id each, generation id is different for each domain
-          replicaDBs.add(environment.getOrCreateReplicaDB(domainDNs.get(i), j, i+1));
+          replicaDBs.add(environment.getOrCreateReplicaDB(domainDNs.get(i), j, i+1, cryptoSuite));
         }
       }
 
@@ -159,7 +162,7 @@
       final DN domainDN = DN.valueOf(DN1_AS_STRING);
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
       cnDB = environment.getOrCreateCNIndexDB();
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
 
       // put server id 1 offline
       CSN offlineCSN = new CSN(TimeThread.getTime(), 0, SERVER_ID_1);
@@ -189,7 +192,7 @@
       final DN domainDN = DN.valueOf(DN1_AS_STRING);
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
       cnDB = environment.getOrCreateCNIndexDB();
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
 
       File offlineStateFile = new File(environment.getServerIdPath("1", 1), REPLICA_OFFLINE_STATE_FILENAME);
       offlineStateFile.createNewFile();
@@ -214,7 +217,7 @@
 
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
       cnDB = environment.getOrCreateCNIndexDB();
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
 
       // put server id 1 offline twice
       CSNGenerator csnGenerator = new CSNGenerator(SERVER_ID_1, 100);
@@ -245,7 +248,7 @@
 
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
       cnDB = environment.getOrCreateCNIndexDB();
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
 
       // put server id 1 offline
       environment.notifyReplicaOffline(domainDN, new CSN(TimeThread.getTime(), 0, SERVER_ID_1));
@@ -274,7 +277,7 @@
 
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
       cnDB = environment.getOrCreateCNIndexDB();
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
       CSN offlineCSN = new CSN(TimeThread.getTime(), 0, SERVER_ID_1);
       environment.notifyReplicaOffline(domainDN, offlineCSN);
 
@@ -304,8 +307,8 @@
       File rootPath = new File(TEST_DIRECTORY_CHANGELOG);
       DN domainDN = DN.valueOf(DN1_AS_STRING);
       ReplicationEnvironment environment = createReplicationEnv(rootPath);
-      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1);
-      replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1);
+      replicaDB = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_1, 1, cryptoSuite);
+      replicaDB2 = environment.getOrCreateReplicaDB(domainDN, SERVER_ID_2, 1, cryptoSuite);
 
       // delete the domain directory created for the 2 replica DBs to break the
       // consistency with domain state file

--
Gitblit v1.10.0