You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ni...@apache.org on 2018/10/05 10:03:44 UTC

[1/6] ignite git commit: IGNITE-8485: TDE implementation. - Fixes #4167.

Repository: ignite
Updated Branches:
  refs/heads/master 754c7337d -> aabacfa00


http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/yardstick/config/benchmark-multicast-tde.properties
----------------------------------------------------------------------
diff --git a/modules/yardstick/config/benchmark-multicast-tde.properties b/modules/yardstick/config/benchmark-multicast-tde.properties
new file mode 100644
index 0000000..d361ba2
--- /dev/null
+++ b/modules/yardstick/config/benchmark-multicast-tde.properties
@@ -0,0 +1,128 @@
+# 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.
+
+#
+# Contains all multicast benchmarks
+#
+
+now0=`date +'%H%M%S'`
+
+# JVM options.
+JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false -DENCRYPTION_ENABLED=true"
+
+# Uncomment to enable concurrent garbage collection (GC) if you encounter long GC pauses.
+JVM_OPTS=${JVM_OPTS}" \
+-Xms8g \
+-Xmx8g \
+-Xloggc:./gc${now0}.log \
+-XX:+PrintGCDetails \
+-verbose:gc \
+-XX:+UseParNewGC \
+-XX:+UseConcMarkSweepGC \
+-XX:+PrintGCDateStamps \
+"
+
+#Ignite version
+ver="RELEASE-"
+
+# List of default probes.
+# Add DStatProbe or VmStatProbe if your OS supports it (e.g. if running on Linux).
+BENCHMARK_DEFAULT_PROBES=ThroughputLatencyProbe,PercentileProbe,DStatProbe
+
+# Packages where the specified benchmark is searched by reflection mechanism.
+BENCHMARK_PACKAGES=org.yardstickframework,org.apache.ignite.yardstick
+
+# Flag which indicates to restart the servers before every benchmark execution.
+RESTART_SERVERS=true
+
+# Probe point writer class name.
+# BENCHMARK_WRITER=
+
+# Comma-separated list of the hosts to run BenchmarkServers on.
+SERVER_HOSTS=localhost,localhost,localhost
+
+# Comma-separated list of the hosts to run BenchmarkDrivers on.
+DRIVER_HOSTS=localhost
+
+# Remote username.
+# REMOTE_USER=
+
+# Number of nodes, used to wait for the specified number of nodes to start.
+nodesNum=$((`echo ${SERVER_HOSTS} | tr ',' '\n' | wc -l` + `echo ${DRIVER_HOSTS} | tr ',' '\n' | wc -l`))
+
+# Backups count.
+b=1
+
+# Warmup.
+w=60
+
+# Duration.
+d=300
+
+# Threads count.
+t=64
+
+# Sync mode.
+sm=PRIMARY_SYNC
+
+# Jobs.
+j=10
+
+# Run configuration which contains all benchmarks.
+# Note that each benchmark is set to run for 300 seconds (5 min) with warm-up set to 60 seconds (1 minute).
+CONFIGS="\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgnitePutBenchmark -sn IgniteNode -ds ${ver}atomic-put-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgnitePutGetBenchmark -sn IgniteNode -ds ${ver}atomic-put-get-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgnitePutGetEntryBenchmark -sn IgniteNode -ds ${ver}atomic-put-getEntry-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgnitePutTxImplicitBenchmark -sn IgniteNode -ds ${ver}tx-optimistic-put-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -txc OPTIMISTIC -dn IgnitePutGetTxBenchmark -sn IgniteNode -ds ${ver}tx-optim-repRead-put-get-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -txc OPTIMISTIC -dn IgnitePutGetEntryTxBenchmark -sn IgniteNode -ds ${ver}tx-optim-repRead-put-getEntry-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -txc PESSIMISTIC -dn IgnitePutGetTxBenchmark -sn IgniteNode -ds ${ver}tx-pessim-repRead-put-get-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -txc PESSIMISTIC -dn IgnitePutGetEntryTxBenchmark -sn IgniteNode -ds ${ver}tx-pessim-repRead-put-getEntry-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -txc OPTIMISTIC -txi SERIALIZABLE -dn IgnitePutGetTxBenchmark -sn IgniteNode -ds ${ver}tx-opt-serial-put-get-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -txc OPTIMISTIC -txi SERIALIZABLE -dn IgnitePutGetEntryTxBenchmark -sn IgniteNode -ds ${ver}tx-opt-serial-put-getEntry-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlQueryBenchmark -sn IgniteNode -ds ${ver}sql-query-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlQueryJoinBenchmark -sn IgniteNode -ds ${ver}sql-query-join-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlQueryPutBenchmark -sn IgniteNode -ds ${ver}sql-query-put-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -j ${j} -dn IgniteAffinityCallBenchmark -sn IgniteNode -ds ${ver}affcall-compute-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -j ${j} -dn IgniteApplyBenchmark -sn IgniteNode -ds ${ver}apply-compute-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -j ${j} -dn IgniteBroadcastBenchmark -sn IgniteNode -ds ${ver}broad-compute-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -j ${j} -dn IgniteExecuteBenchmark -sn IgniteNode -ds ${ver}exec-compute-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -j ${j} -dn IgniteRunBenchmark -sn IgniteNode -ds ${ver}run-compute-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 100 -dn IgnitePutAllBenchmark -sn IgniteNode -ds ${ver}atomic-putAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 100 -dn IgnitePutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-putAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 100 -dn IgnitePutAllSerializableTxBenchmark -sn IgniteNode -ds ${ver}tx-putAllSerializable-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 100 -dn IgniteSqlMergeAllBenchmark -sn IgniteNode -ds ${ver}sql-merge-all-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteReplaceIndexedValue1Benchmark -sn IgniteNode -ds ${ver}replace-indexed1-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgnitePutIfAbsentIndexedValue1Benchmark -sn IgniteNode -ds ${ver}put-if-absent-indexed1-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlMergeBenchmark -sn IgniteNode -ds ${ver}sql-merge-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlMergeQueryBenchmark -sn IgniteNode -ds ${ver}sql-merge-query-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlMergeIndexedValue1Benchmark -sn IgniteNode -ds ${ver}sql-merge-indexed1-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlMergeIndexedValue2Benchmark -sn IgniteNode -ds ${ver}sql-merge-indexed2-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlMergeIndexedValue8Benchmark -sn IgniteNode -ds ${ver}sql-merge-indexed8-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlInsertIndexedValue1Benchmark -sn IgniteNode -ds ${ver}sql-insert-indexed1-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlInsertIndexedValue2Benchmark -sn IgniteNode -ds ${ver}sql-insert-indexed2-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlInsertIndexedValue8Benchmark -sn IgniteNode -ds ${ver}sql-insert-indexed8-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -r 300000 -dn IgniteSqlDeleteBenchmark -sn IgniteNode -ds ${ver}sql-delete-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlDeleteFilteredBenchmark -sn IgniteNode -ds ${ver}sql-delete-filtered-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlUpdateBenchmark -sn IgniteNode -ds ${ver}sql-update-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -dn IgniteSqlUpdateFilteredBenchmark -sn IgniteNode -ds ${ver}sql-update-filtered-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 10 -txc OPTIMISTIC  -dn IgniteGetAllPutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-optimistic-getAllPutAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 10 -txc OPTIMISTIC  -dn IgniteGetEntriesPutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-optimistic-getEntriesPutAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 10 -txc PESSIMISTIC -dn IgniteGetAllPutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-pessimistic-getAllPutAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 10 -txc PESSIMISTIC -dn IgniteGetEntriesPutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-pessimistic-getEntriesPutAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 10 -txc OPTIMISTIC -txi SERIALIZABLE -dn IgniteGetAllPutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-opt-serializable-getAllPutAll-${b}-backup,\
+-cfg ${SCRIPT_DIR}/../config/ignite-tde-config.xml -nn ${nodesNum} -b ${b} -w ${w} -d ${d} -t ${t} -sm ${sm} -bs 10 -txc OPTIMISTIC -txi SERIALIZABLE -dn IgniteGetEntriesPutAllTxBenchmark -sn IgniteNode -ds ${ver}tx-opt-serializable-getEntriesPutAll-${b}-backup,\
+"

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/yardstick/config/ignite-base-config.xml
----------------------------------------------------------------------
diff --git a/modules/yardstick/config/ignite-base-config.xml b/modules/yardstick/config/ignite-base-config.xml
index 33a52e6..6db8b6e 100644
--- a/modules/yardstick/config/ignite-base-config.xml
+++ b/modules/yardstick/config/ignite-base-config.xml
@@ -22,8 +22,12 @@
 -->
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
-        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+    <context:property-placeholder />
+
     <bean id="base-ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration" abstract="true">
         <property name="peerClassLoadingEnabled" value="false"/>
 
@@ -37,6 +41,8 @@
                     <property name="cacheMode" value="PARTITIONED"/>
 
                     <property name="atomicityMode" value="ATOMIC"/>
+
+                    <property name="encryptionEnabled" value="${ENCRYPTION_ENABLED:false}" />
                 </bean>
 
                 <bean class="org.apache.ignite.configuration.CacheConfiguration">
@@ -46,6 +52,8 @@
 
                     <property name="atomicityMode" value="TRANSACTIONAL"/>
 
+                    <property name="encryptionEnabled" value="${ENCRYPTION_ENABLED:false}" />
+
                 </bean>
 
                 <bean class="org.apache.ignite.configuration.CacheConfiguration">
@@ -67,6 +75,8 @@
                             <value>org.apache.ignite.yardstick.cache.model.Person8</value>
                         </list>
                     </property>
+
+                    <property name="encryptionEnabled" value="${ENCRYPTION_ENABLED:false}" />
                 </bean>
 
                 <bean class="org.apache.ignite.configuration.CacheConfiguration">
@@ -97,6 +107,8 @@
                             <value>org.apache.ignite.yardstick.cache.model.Person8</value>
                         </list>
                     </property>
+
+                    <property name="encryptionEnabled" value="${ENCRYPTION_ENABLED:false}" />
                 </bean>
 
                 <bean class="org.apache.ignite.configuration.CacheConfiguration">
@@ -121,6 +133,8 @@
                             <value>java.lang.Integer</value>
                         </list>
                     </property>
+
+                    <property name="encryptionEnabled" value="${ENCRYPTION_ENABLED:false}" />
                 </bean>
 
                 <bean class="org.apache.ignite.configuration.CacheConfiguration">
@@ -129,6 +143,8 @@
                     <property name="cacheMode" value="PARTITIONED"/>
 
                     <property name="atomicityMode" value="TRANSACTIONAL"/>
+
+                    <property name="encryptionEnabled" value="${ENCRYPTION_ENABLED:false}" />
                 </bean>
             </list>
         </property>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/yardstick/config/ignite-tde-config.xml
----------------------------------------------------------------------
diff --git a/modules/yardstick/config/ignite-tde-config.xml b/modules/yardstick/config/ignite-tde-config.xml
new file mode 100644
index 0000000..28e4598
--- /dev/null
+++ b/modules/yardstick/config/ignite-tde-config.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    Ignite Spring configuration file to startup grid.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+    <import resource="ignite-base-config.xml"/>
+
+    <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration" parent="base-ignite.cfg">
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="ipFinder">
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder"/>
+                </property>
+            </bean>
+        </property>
+
+        <property name="encryptionSpi">
+            <bean class="org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi">
+                <property name="keyStorePath" value="tde.jks"/>
+                <property name="keyStorePassword" value="love_sex_god"/>
+            </bean>
+        </property>
+
+        <property name="dataStorageConfiguration" >
+            <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
+                <property name="defaultDataRegionConfiguration">
+                    <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
+                        <property name="persistenceEnabled" value="true"/>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/yardstick/src/main/resources/tde.jks
----------------------------------------------------------------------
diff --git a/modules/yardstick/src/main/resources/tde.jks b/modules/yardstick/src/main/resources/tde.jks
new file mode 100644
index 0000000..1bf532c
Binary files /dev/null and b/modules/yardstick/src/main/resources/tde.jks differ


[6/6] ignite git commit: IGNITE-8485: TDE implementation. - Fixes #4167.

Posted by ni...@apache.org.
IGNITE-8485: TDE implementation. - Fixes #4167.

Signed-off-by: Nikolay Izhikov <ni...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/aabacfa0
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/aabacfa0
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/aabacfa0

Branch: refs/heads/master
Commit: aabacfa00f5fd7ef89c9a5bda7b236ff45ed2ac4
Parents: 754c733
Author: Nikolay Izhikov <ni...@apache.org>
Authored: Fri Oct 5 12:55:06 2018 +0300
Committer: Nikolay Izhikov <ni...@apache.org>
Committed: Fri Oct 5 12:55:06 2018 +0300

----------------------------------------------------------------------
 .../JmhKeystoreEncryptionSpiBenchmark.java      | 117 +++
 .../ignite/codegen/MessageCodeGenerator.java    |   2 +
 .../configuration/CacheConfiguration.java       |  33 +
 .../configuration/IgniteConfiguration.java      |  27 +
 .../apache/ignite/internal/GridComponent.java   |   9 +-
 .../ignite/internal/GridKernalContext.java      |   8 +
 .../ignite/internal/GridKernalContextImpl.java  |  12 +
 .../org/apache/ignite/internal/GridTopic.java   |   5 +-
 .../apache/ignite/internal/IgniteKernal.java    |   2 +
 .../ignite/internal/IgniteNodeAttributes.java   |   3 +
 .../org/apache/ignite/internal/IgnitionEx.java  |   4 +
 .../communication/GridIoMessageFactory.java     |  12 +
 .../discovery/GridDiscoveryManager.java         |   2 +
 .../GenerateEncryptionKeyRequest.java           | 142 +++
 .../GenerateEncryptionKeyResponse.java          | 148 ++++
 .../encryption/GridEncryptionManager.java       | 864 +++++++++++++++++++
 .../ignite/internal/pagemem/PageMemory.java     |   6 +
 .../pagemem/impl/PageMemoryNoStoreImpl.java     |   5 +
 .../internal/pagemem/store/PageStore.java       |  27 +
 .../pagemem/wal/record/EncryptedRecord.java     |  60 ++
 .../pagemem/wal/record/PageSnapshot.java        |  19 +-
 .../internal/pagemem/wal/record/WALRecord.java  |   8 +-
 .../delta/DataPageInsertFragmentRecord.java     |   2 +-
 .../wal/record/delta/DataPageInsertRecord.java  |   2 +-
 .../delta/DataPageMvccMarkUpdatedRecord.java    |   2 +-
 .../DataPageMvccUpdateNewTxStateHintRecord.java |   2 +-
 .../DataPageMvccUpdateTxStateHintRecord.java    |   2 +-
 .../wal/record/delta/DataPageRemoveRecord.java  |   2 +-
 .../wal/record/delta/DataPageUpdateRecord.java  |   2 +-
 .../wal/record/delta/InitNewPageRecord.java     |   2 +-
 .../wal/record/delta/MetaPageAddRootRecord.java |   2 +-
 .../wal/record/delta/MetaPageCutRootRecord.java |   2 +-
 .../wal/record/delta/MetaPageInitRecord.java    |   2 +-
 .../delta/MetaPageInitRootInlineRecord.java     |   2 +-
 .../record/delta/MetaPageInitRootRecord.java    |   2 +-
 .../wal/record/delta/NewRootInitRecord.java     |   3 +-
 .../record/delta/PagesListAddPageRecord.java    |   2 +-
 .../delta/PagesListInitNewPageRecord.java       |   4 +-
 .../record/delta/TrackingPageDeltaRecord.java   |   2 +-
 .../IgniteAuthenticationProcessor.java          |  16 +-
 .../processors/cache/ClusterCachesInfo.java     |  34 +-
 .../cache/DynamicCacheChangeRequest.java        |  17 +
 .../processors/cache/GridCacheAttributes.java   |   9 +-
 .../processors/cache/GridCacheProcessor.java    | 135 ++-
 .../processors/cache/GridCacheUtils.java        |  23 +
 .../cache/IgniteCacheOffheapManagerImpl.java    |  10 +-
 .../GridDhtPartitionsExchangeFuture.java        |   2 +
 .../processors/cache/mvcc/MvccUtils.java        |   3 +-
 .../cache/persistence/CacheDataRowAdapter.java  |   2 +-
 .../cache/persistence/DataStructure.java        |   6 +-
 .../GridCacheDatabaseSharedManager.java         |   3 +
 .../persistence/GridCacheOffheapManager.java    |  23 +-
 .../cache/persistence/file/EncryptedFileIO.java | 371 ++++++++
 .../file/EncryptedFileIOFactory.java            | 100 +++
 .../cache/persistence/file/FilePageStore.java   |  28 +-
 .../persistence/file/FilePageStoreFactory.java  |   3 +-
 .../persistence/file/FilePageStoreManager.java  |  76 +-
 .../file/FileVersionCheckingFactory.java        |  25 +-
 .../cache/persistence/freelist/PagesList.java   |   4 +-
 .../persistence/metastorage/MetaStorage.java    |   2 +
 .../persistence/pagemem/PageMemoryImpl.java     |  30 +-
 .../cache/persistence/tree/io/BPlusIO.java      |   4 +-
 .../cache/persistence/tree/io/PageIO.java       |   5 +-
 .../tree/io/PagePartitionCountersIO.java        |   2 +-
 .../persistence/tree/util/PageHandler.java      |  50 +-
 .../wal/reader/StandaloneGridKernalContext.java |   6 +
 .../reader/StandaloneWalRecordsIterator.java    |   3 +
 .../wal/serializer/RecordDataV1Serializer.java  | 355 +++++++-
 .../wal/serializer/RecordDataV2Serializer.java  |  60 +-
 .../serializer/RecordSerializerFactoryImpl.java |   5 +-
 .../wal/serializer/RecordV1Serializer.java      |   8 +-
 .../wal/serializer/RecordV2Serializer.java      |   2 +-
 .../cluster/ChangeGlobalStateMessage.java       |   6 +-
 .../cluster/GridClusterStateProcessor.java      |   2 +
 .../utils/PlatformConfigurationUtils.java       |  59 ++
 .../processors/query/GridQueryProcessor.java    |   6 +-
 .../ignite/internal/util/IgniteUtils.java       |  65 ++
 .../ignite/internal/util/lang/GridFunc.java     |   6 +-
 .../ignite/spi/encryption/EncryptionSpi.java    | 113 +++
 .../keystore/KeystoreEncryptionKey.java         |  84 ++
 .../keystore/KeystoreEncryptionSpi.java         | 501 +++++++++++
 .../spi/encryption/keystore/package-info.java   |  22 +
 .../spi/encryption/noop/NoopEncryptionSpi.java  | 101 +++
 .../ignite/spi/encryption/package-info.java     |  22 +
 .../encryption/AbstractEncryptionTest.java      | 245 ++++++
 .../encryption/EncryptedCacheBigEntryTest.java  | 114 +++
 .../encryption/EncryptedCacheCreateTest.java    | 164 ++++
 .../encryption/EncryptedCacheDestroyTest.java   | 127 +++
 .../EncryptedCacheGroupCreateTest.java          | 116 +++
 .../encryption/EncryptedCacheNodeJoinTest.java  | 237 +++++
 .../EncryptedCachePreconfiguredRestartTest.java |  87 ++
 .../encryption/EncryptedCacheRestartTest.java   |  64 ++
 .../pagemem/impl/PageMemoryNoLoadSelfTest.java  |  18 +-
 ...gnitePdsRecoveryAfterFileCorruptionTest.java |   8 +-
 ...ckpointSimulationWithRealCpDisabledTest.java |  21 +-
 .../db/file/IgnitePdsPageReplacementTest.java   |   2 +-
 .../persistence/db/wal/WalCompactionTest.java   |  12 +-
 .../pagemem/BPlusTreePageMemoryImplTest.java    |  22 +-
 .../BPlusTreeReuseListPageMemoryImplTest.java   |  18 +-
 ...gnitePageMemReplaceDelayedWriteUnitTest.java |   7 +-
 .../pagemem/IndexStoragePageMemoryImplTest.java |  22 +-
 .../pagemem/PageMemoryImplNoLoadTest.java       |  22 +-
 .../persistence/pagemem/PageMemoryImplTest.java |   7 +
 .../wal/memtracker/PageMemoryTracker.java       |  13 +
 .../KeystoreEncryptionSpiSelfTest.java          | 123 +++
 .../ignite/testframework/GridTestUtils.java     |  81 +-
 .../testframework/junits/GridAbstractTest.java  |   4 +-
 .../IgniteBasicWithPersistenceTestSuite.java    |  15 +
 .../testsuites/IgniteKernalSelfTestSuite.java   |   1 -
 .../ignite/testsuites/IgniteSpiTestSuite.java   |   3 +
 .../src/test/resources/other_tde_keystore.jks   | Bin 0 -> 347 bytes
 modules/core/src/test/resources/tde.jks         | Bin 0 -> 347 bytes
 .../query/h2/ddl/DdlStatementsProcessor.java    |   3 +-
 .../query/h2/sql/GridSqlCreateTable.java        |  17 +
 .../query/h2/sql/GridSqlQueryParser.java        |   8 +
 .../cache/encryption/EncryptedSqlTableTest.java |  69 ++
 .../cache/index/H2DynamicTableSelfTest.java     |   4 +-
 .../IgniteCacheQuerySelfTestSuite.java          |   2 +
 modules/indexing/src/test/resources/tde.jks     | Bin 0 -> 347 bytes
 .../Apache.Ignite.Core.Tests.DotNetCore/tde.jks | Bin 0 -> 347 bytes
 .../ApiParity/IgniteConfigurationParityTest.cs  |   5 +-
 .../IgniteConfigurationTest.cs                  |  17 +
 .../Apache.Ignite.Core.csproj                   |   6 +-
 .../Cache/Configuration/CacheConfiguration.cs   |  13 +
 .../Encryption/IEncryptionSpi.cs                |  34 +
 .../Keystore/KeystoreEncryptionSpi.cs           |  84 ++
 .../Encryption/Keystore/Package-Info.cs         |  26 +
 .../Encryption/Package-Info.cs                  |  26 +
 .../Apache.Ignite.Core/IgniteConfiguration.cs   |  31 +
 .../IgniteConfigurationSection.xsd              |  39 +-
 .../spring/src/test/config/enc/base-enc-cfg.xml |  70 ++
 .../src/test/config/enc/enc-cache-client.xml    |  35 +
 .../spring/src/test/config/enc/enc-cache.xml    |  35 +
 .../spring/src/test/config/enc/enc-group-2.xml  |  36 +
 .../spring/src/test/config/enc/enc-group.xml    |  37 +
 .../config/enc/not-encrypted-cache-in-group.xml |  36 +
 .../src/test/config/enc/not-encrypted-cache.xml |  35 +
 .../SpringEncryptedCacheRestartClientTest.java  |  60 ++
 .../SpringEncryptedCacheRestartTest.java        | 190 ++++
 .../testsuites/IgniteSpringTestSuite.java       |   6 +
 modules/spring/src/test/resources/tde.jks       | Bin 0 -> 347 bytes
 .../config/benchmark-multicast-tde.properties   | 128 +++
 modules/yardstick/config/ignite-base-config.xml |  18 +-
 modules/yardstick/config/ignite-tde-config.xml  |  55 ++
 modules/yardstick/src/main/resources/tde.jks    | Bin 0 -> 347 bytes
 145 files changed, 6319 insertions(+), 320 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java
----------------------------------------------------------------------
diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java
new file mode 100644
index 0000000..932d57e
--- /dev/null
+++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/encryption/JmhKeystoreEncryptionSpiBenchmark.java
@@ -0,0 +1,117 @@
+/*
+ * 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.ignite.internal.benchmarks.jmh.encryption;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.ThreadLocalRandom;
+import org.apache.ignite.internal.benchmarks.jmh.JmhAbstractBenchmark;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath;
+
+/**
+ */
+public class JmhKeystoreEncryptionSpiBenchmark extends JmhAbstractBenchmark {
+    /** Data amount. */
+    private static final int DATA_AMOUNT = 100;
+
+    public static final int PAGE_SIZE = 1024 * 4;
+
+    /** */
+    @Benchmark
+    public void encryptBenchmark(EncryptionData d, Blackhole receiver) {
+        for (int i = 0; i < DATA_AMOUNT; i++) {
+            ByteBuffer[] dt = d.randomData[i];
+
+            KeystoreEncryptionKey key = d.keys[ThreadLocalRandom.current().nextInt(4)];
+
+            d.encSpi.encryptNoPadding(dt[0], key, dt[1]);
+
+            receiver.consume(d.res);
+
+            dt[0].rewind();
+            dt[1].rewind();
+
+            d.encSpi.decryptNoPadding(dt[1], key, dt[0]);
+        }
+    }
+
+    @State(Scope.Thread)
+    public static class EncryptionData {
+        KeystoreEncryptionSpi encSpi;
+
+        KeystoreEncryptionKey[] keys = new KeystoreEncryptionKey[4];
+
+        ByteBuffer[][] randomData = new ByteBuffer[DATA_AMOUNT][2];
+
+        ByteBuffer res = ByteBuffer.allocate(PAGE_SIZE);
+
+        public EncryptionData() {
+            encSpi = new KeystoreEncryptionSpi();
+
+            encSpi.setKeyStorePath(resolveIgnitePath("modules/core/src/test/resources/tde.jks").getAbsolutePath());
+            encSpi.setKeyStorePassword("love_sex_god".toCharArray());
+
+            encSpi.onBeforeStart();
+            encSpi.spiStart("test-instance");
+        }
+
+        @Setup(Level.Invocation)
+        public void prepareCollection() {
+            for (int i = 0; i < keys.length; i++)
+                keys[i] = encSpi.create();
+
+            for (int i = 0; i < DATA_AMOUNT; i++) {
+                byte[] dt = new byte[PAGE_SIZE - 16];
+
+                ThreadLocalRandom.current().nextBytes(dt);
+
+                randomData[i][0] = ByteBuffer.wrap(dt);
+                randomData[i][1] = ByteBuffer.allocate(PAGE_SIZE);
+            }
+        }
+
+        @TearDown(Level.Iteration)
+        public void tearDown() {
+            //No - op
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        Options opt = new OptionsBuilder()
+            .include(JmhKeystoreEncryptionSpiBenchmark.class.getSimpleName())
+            .threads(1)
+            .forks(1)
+            .warmupIterations(10)
+            .measurementIterations(20)
+            .build();
+
+        new Runner(opt).run();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
----------------------------------------------------------------------
diff --git a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
index 2f7e6c0..2599d7a 100644
--- a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
+++ b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
@@ -240,6 +240,8 @@ public class MessageCodeGenerator {
 //        gen.generateAndWrite(GridH2DmlResponse.class);
 //        gen.generateAndWrite(GridNearTxEnlistRequest.class);
 //        gen.generateAndWrite(GridNearTxEnlistResponse.class);
+//        gen.generateAndWrite(GenerateEncryptionKeyRequest.class);
+//        gen.generateAndWrite(GenerateEncryptionKeyResponse.class);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
index fb3789d..795fcfd 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
@@ -50,7 +50,9 @@ import org.apache.ignite.cache.query.annotations.QuerySqlFunction;
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.CacheStoreSessionListener;
 import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.internal.binary.BinaryContext;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.A;
@@ -373,6 +375,15 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
     /** Events disabled. */
     private boolean evtsDisabled = DFLT_EVENTS_DISABLED;
 
+    /**
+     * Flag indicating whether data must be encrypted.
+     * If {@code true} data on the disk will be encrypted.
+     *
+     * @see EncryptionSpi
+     * @see KeystoreEncryptionSpi
+     */
+    private boolean encryptionEnabled;
+
     /** Empty constructor (all values are initialized to their defaults). */
     public CacheConfiguration() {
         /* No-op. */
@@ -412,6 +423,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
         cpOnRead = cc.isCopyOnRead();
         dfltLockTimeout = cc.getDefaultLockTimeout();
         eagerTtl = cc.isEagerTtl();
+        encryptionEnabled = cc.isEncryptionEnabled();
         evictFilter = cc.getEvictionFilter();
         evictPlc = cc.getEvictionPolicy();
         evictPlcFactory = cc.getEvictionPolicyFactory();
@@ -2268,6 +2280,27 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
         return this;
     }
 
+    /**
+     * Gets flag indicating whether data must be encrypted.
+     *
+     * @return {@code True} if this cache persistent data is encrypted.
+     */
+    public boolean isEncryptionEnabled() {
+        return encryptionEnabled;
+    }
+
+    /**
+     * Sets encrypted flag.
+     *
+     * @param encryptionEnabled {@code True} if this cache persistent data should be encrypted.
+     * @return {@code this} for chaining.
+     */
+    public CacheConfiguration<K, V> setEncryptionEnabled(boolean encryptionEnabled) {
+        this.encryptionEnabled = encryptionEnabled;
+        
+        return this;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(CacheConfiguration.class, this);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
index 964c73b..1dbec7d 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
@@ -40,6 +40,7 @@ import org.apache.ignite.cluster.ClusterGroup;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.compute.ComputeJob;
 import org.apache.ignite.compute.ComputeTask;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
 import org.apache.ignite.failure.FailureHandler;
@@ -367,6 +368,9 @@ public class IgniteConfiguration {
     /** Address resolver. */
     private AddressResolver addrRslvr;
 
+    /** Encryption SPI. */
+    private EncryptionSpi encryptionSpi;
+
     /** Cache configurations. */
     private CacheConfiguration[] cacheCfg;
 
@@ -537,6 +541,7 @@ public class IgniteConfiguration {
         failSpi = cfg.getFailoverSpi();
         loadBalancingSpi = cfg.getLoadBalancingSpi();
         indexingSpi = cfg.getIndexingSpi();
+        encryptionSpi = cfg.getEncryptionSpi();
 
         commFailureRslvr = cfg.getCommunicationFailureResolver();
 
@@ -2062,6 +2067,28 @@ public class IgniteConfiguration {
     }
 
     /**
+     * Sets fully configured instances of {@link EncryptionSpi}.
+     *
+     * @param encryptionSpi Fully configured instance of {@link EncryptionSpi}.
+     * @see IgniteConfiguration#getEncryptionSpi()
+     * @return {@code this} for chaining.
+     */
+    public IgniteConfiguration setEncryptionSpi(EncryptionSpi encryptionSpi) {
+        this.encryptionSpi = encryptionSpi;
+
+        return this;
+    }
+
+    /**
+     * Gets fully configured encryption SPI implementations.
+     *
+     * @return Encryption SPI implementation.
+     */
+    public EncryptionSpi getEncryptionSpi() {
+        return encryptionSpi;
+    }
+
+    /**
      * Gets address resolver for addresses mapping determination.
      *
      * @return Address resolver.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java b/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
index 0cf3a6e..607217e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
@@ -67,7 +67,10 @@ public interface GridComponent {
         AUTH_PROC,
 
         /** */
-        CACHE_CRD_PROC
+        CACHE_CRD_PROC,
+
+        /** Encryption manager. */
+        ENCRYPTION_MGR
     }
 
     /**
@@ -153,7 +156,7 @@ public interface GridComponent {
     @Nullable public IgniteNodeValidationResult validateNode(ClusterNode node);
 
     /** */
-    @Nullable public IgniteNodeValidationResult validateNode(ClusterNode node, DiscoveryDataBag.JoiningNodeDiscoveryData discoData);
+    @Nullable public IgniteNodeValidationResult validateNode(ClusterNode node, JoiningNodeDiscoveryData discoData);
 
     /**
      * Gets unique component type to distinguish components providing discovery data. Must return non-null value
@@ -180,4 +183,4 @@ public interface GridComponent {
      * @return Future to wait before completing reconnect future.
      */
     @Nullable public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) throws IgniteCheckedException;
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
index 4cb68da..970b8e7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
@@ -28,6 +28,7 @@ import org.apache.ignite.internal.managers.collision.GridCollisionManager;
 import org.apache.ignite.internal.managers.communication.GridIoManager;
 import org.apache.ignite.internal.managers.deployment.GridDeploymentManager;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.managers.eventstorage.GridEventStorageManager;
 import org.apache.ignite.internal.managers.failover.GridFailoverManager;
 import org.apache.ignite.internal.managers.indexing.GridIndexingManager;
@@ -425,6 +426,13 @@ public interface GridKernalContext extends Iterable<GridComponent> {
     public GridIndexingManager indexing();
 
     /**
+     * Gets encryption manager.
+     *
+     * @return Encryption manager.
+     */
+    public GridEncryptionManager encryption();
+
+    /**
      * Gets workers registry.
      *
      * @return Workers registry.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
index a0e3f93..f23e650 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
@@ -38,6 +38,7 @@ import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.failure.FailureType;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.managers.checkpoint.GridCheckpointManager;
 import org.apache.ignite.internal.managers.collision.GridCollisionManager;
 import org.apache.ignite.internal.managers.communication.GridIoManager;
@@ -162,6 +163,10 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
     @GridToStringExclude
     private GridIndexingManager indexingMgr;
 
+    /** */
+    @GridToStringExclude
+    private GridEncryptionManager encryptionMgr;
+
     /*
      * Processors.
      * ==========
@@ -557,6 +562,8 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
             loadMgr = (GridLoadBalancerManager)comp;
         else if (comp instanceof GridIndexingManager)
             indexingMgr = (GridIndexingManager)comp;
+        else if (comp instanceof GridEncryptionManager)
+            encryptionMgr = (GridEncryptionManager)comp;
 
         /*
          * Processors.
@@ -802,6 +809,11 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
     }
 
     /** {@inheritDoc} */
+    @Override public GridEncryptionManager encryption() {
+        return encryptionMgr;
+    }
+
+    /** {@inheritDoc} */
     @Override public WorkersRegistry workersRegistry() {
         return workersRegistry;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java b/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
index 98a4d8d..95d7717 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
@@ -133,7 +133,10 @@ public enum GridTopic {
     TOPIC_EXCHANGE,
 
     /** */
-    TOPIC_CACHE_COORDINATOR;
+    TOPIC_CACHE_COORDINATOR,
+
+    /** */
+    TOPIC_GEN_ENC_KEY;
 
     /** Enum values. */
     private static final GridTopic[] VALS = values();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 32e5dd8..cfde78f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -101,6 +101,7 @@ import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.binary.BinaryUtils;
 import org.apache.ignite.internal.cluster.ClusterGroupAdapter;
 import org.apache.ignite.internal.cluster.IgniteClusterEx;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.managers.GridManager;
 import org.apache.ignite.internal.managers.checkpoint.GridCheckpointManager;
 import org.apache.ignite.internal.managers.collision.GridCollisionManager;
@@ -987,6 +988,7 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
             startManager(new GridFailoverManager(ctx));
             startManager(new GridCollisionManager(ctx));
             startManager(new GridIndexingManager(ctx));
+            startManager(new GridEncryptionManager(ctx));
 
             ackSecurity();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
index 5b764e4..4ca4f1b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
@@ -196,6 +196,9 @@ public final class IgniteNodeAttributes {
     /** User authentication enabled flag. */
     public static final String ATTR_AUTHENTICATION_ENABLED = ATTR_PREFIX + ".authentication.enabled";
 
+    /** Encryption master key digest. */
+    public static final String ATTR_ENCRYPTION_MASTER_KEY_DIGEST = ATTR_PREFIX + ".master.key.digest";
+
     /** Rebalance thread pool size. */
     public static final String ATTR_REBALANCE_POOL_SIZE = ATTR_PREFIX + ".rebalance.pool.size";
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
index ed0fbe9..95001de 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
@@ -115,6 +115,7 @@ import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.deployment.local.LocalDeploymentSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.spi.eventstorage.NoopEventStorageSpi;
 import org.apache.ignite.spi.failover.always.AlwaysFailoverSpi;
 import org.apache.ignite.spi.indexing.noop.NoopIndexingSpi;
@@ -2444,6 +2445,9 @@ public class IgnitionEx {
 
             if (cfg.getIndexingSpi() == null)
                 cfg.setIndexingSpi(new NoopIndexingSpi());
+
+            if (cfg.getEncryptionSpi() == null)
+                cfg.setEncryptionSpi(new NoopEncryptionSpi());
         }
 
         /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
index 54efb47..e405d7d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
@@ -46,6 +46,8 @@ import org.apache.ignite.internal.processors.cache.CacheEvictionEntry;
 import org.apache.ignite.internal.processors.cache.CacheInvokeDirectResult;
 import org.apache.ignite.internal.processors.cache.CacheObjectByteArrayImpl;
 import org.apache.ignite.internal.processors.cache.CacheObjectImpl;
+import org.apache.ignite.internal.managers.encryption.GenerateEncryptionKeyRequest;
+import org.apache.ignite.internal.managers.encryption.GenerateEncryptionKeyResponse;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheMvccEntryInfo;
 import org.apache.ignite.internal.processors.cache.GridCacheReturn;
@@ -1084,6 +1086,16 @@ public class GridIoMessageFactory implements MessageFactory {
 
                 break;
 
+            case 162:
+                msg = new GenerateEncryptionKeyRequest();
+
+                break;
+
+            case 163:
+                msg = new GenerateEncryptionKeyResponse();
+
+                break;
+
                 // [-3..119] [124..129] [-23..-27] [-36..-55]- this
             // [120..123] - DR
             // [-4..-22, -30..-35] - SQL

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index 19c11ac..d7514a0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -795,6 +795,8 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> {
                         ctx.cache().context().exchange().onLocalJoin(discoEvt, discoCache);
 
                         ctx.authentication().onLocalJoin();
+
+                        ctx.encryption().onLocalJoin();
                     }
 
                     IgniteInternalFuture<Boolean> transitionWaitFut = ctx.state().onLocalJoin(discoCache);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java
new file mode 100644
index 0000000..3d48014
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyRequest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.ignite.internal.managers.encryption;
+
+import java.nio.ByteBuffer;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MessageReader;
+import org.apache.ignite.plugin.extensions.communication.MessageWriter;
+
+/**
+ * Generate encryption key request.
+ */
+public class GenerateEncryptionKeyRequest implements Message {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Request ID. */
+    private IgniteUuid id = IgniteUuid.randomUuid();
+
+    /** */
+    private int keyCnt;
+
+    /** */
+    public GenerateEncryptionKeyRequest() {
+    }
+
+    /**
+     * @param keyCnt Count of encryption key to generate.
+     */
+    public GenerateEncryptionKeyRequest(int keyCnt) {
+        this.keyCnt = keyCnt;
+    }
+
+    /**
+     * @return Request id.
+     */
+    public IgniteUuid id() {
+        return id;
+    }
+
+    /**
+     * @return Count of encryption key to generate.
+     */
+    public int keyCount() {
+        return keyCnt;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+        writer.setBuffer(buf);
+
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(directType(), fieldsCount()))
+                return false;
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 0:
+                if (!writer.writeIgniteUuid("id", id))
+                    return false;
+
+                writer.incrementState();
+
+            case 1:
+                if (!writer.writeInt("keyCnt", keyCnt))
+                    return false;
+
+                writer.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+        reader.setBuffer(buf);
+
+        if (!reader.beforeMessageRead())
+            return false;
+
+        switch (reader.state()) {
+            case 0:
+                id = reader.readIgniteUuid("id");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 1:
+                keyCnt = reader.readInt("keyCnt");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+        }
+
+        return reader.afterMessageRead(GenerateEncryptionKeyRequest.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public short directType() {
+        return 162;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte fieldsCount() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onAckReceived() {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(GenerateEncryptionKeyRequest.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java
new file mode 100644
index 0000000..8971248
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GenerateEncryptionKeyResponse.java
@@ -0,0 +1,148 @@
+/*
+ * 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.ignite.internal.managers.encryption;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import org.apache.ignite.internal.GridDirectCollection;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
+import org.apache.ignite.plugin.extensions.communication.MessageReader;
+import org.apache.ignite.plugin.extensions.communication.MessageWriter;
+
+/**
+ * Generate encryption key response.
+ */
+public class GenerateEncryptionKeyResponse implements Message {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Request message ID. */
+    private IgniteUuid id;
+
+    /** */
+    @GridDirectCollection(byte[].class)
+    private Collection<byte[]> encKeys;
+
+    /** */
+    public GenerateEncryptionKeyResponse() {
+    }
+
+    /**
+     * @param id Request id.
+     * @param encKeys Encryption keys.
+     */
+    public GenerateEncryptionKeyResponse(IgniteUuid id, Collection<byte[]> encKeys) {
+        this.id = id;
+        this.encKeys = encKeys;
+    }
+
+    /**
+     * @return Request id.
+     */
+    public IgniteUuid requestId() {
+        return id;
+    }
+
+    /**
+     * @return Encryption keys.
+     */
+    public Collection<byte[]> encryptionKeys() {
+        return encKeys;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+        writer.setBuffer(buf);
+
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(directType(), fieldsCount()))
+                return false;
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 0:
+                if (!writer.writeCollection("encKeys", encKeys, MessageCollectionItemType.BYTE_ARR))
+                    return false;
+
+                writer.incrementState();
+
+            case 1:
+                if (!writer.writeIgniteUuid("id", id))
+                    return false;
+
+                writer.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+        reader.setBuffer(buf);
+
+        if (!reader.beforeMessageRead())
+            return false;
+
+        switch (reader.state()) {
+            case 0:
+                encKeys = reader.readCollection("encKeys", MessageCollectionItemType.BYTE_ARR);
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 1:
+                id = reader.readIgniteUuid("id");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+        }
+
+        return reader.afterMessageRead(GenerateEncryptionKeyResponse.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public short directType() {
+        return 163;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte fieldsCount() {
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onAckReceived() {
+        //No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(GenerateEncryptionKeyResponse.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java
new file mode 100644
index 0000000..a1c0fdc
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java
@@ -0,0 +1,864 @@
+/*
+ * 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.ignite.internal.managers.encryption;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.managers.GridManagerAdapter;
+import org.apache.ignite.internal.managers.communication.GridMessageListener;
+import org.apache.ignite.internal.managers.eventstorage.DiscoveryEventListener;
+import org.apache.ignite.internal.processors.cache.CacheGroupDescriptor;
+import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
+import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastorageLifecycleListener;
+import org.apache.ignite.internal.processors.cache.persistence.metastorage.ReadOnlyMetastorage;
+import org.apache.ignite.internal.processors.cache.persistence.metastorage.ReadWriteMetastorage;
+import org.apache.ignite.internal.processors.cluster.IgniteChangeGlobalStateSupport;
+import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
+import org.apache.ignite.internal.util.lang.GridPlainClosure;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteFuture;
+import org.apache.ignite.lang.IgniteFutureCancelledException;
+import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.lang.IgniteProductVersion;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.spi.IgniteNodeValidationResult;
+import org.apache.ignite.spi.discovery.DiscoveryDataBag;
+import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData;
+import org.apache.ignite.spi.discovery.DiscoveryDataBag.JoiningNodeDiscoveryData;
+import org.apache.ignite.spi.discovery.DiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.events.EventType.EVT_NODE_FAILED;
+import static org.apache.ignite.events.EventType.EVT_NODE_LEFT;
+import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.ENCRYPTION_MGR;
+import static org.apache.ignite.internal.GridTopic.TOPIC_GEN_ENC_KEY;
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_ENCRYPTION_MASTER_KEY_DIGEST;
+import static org.apache.ignite.internal.managers.communication.GridIoPolicy.SYSTEM_POOL;
+
+/**
+ * Manages cache keys and {@code EncryptionSpi} instances.
+ *
+ * NOTE: Following protocol applied to statically configured caches.
+ * For dynamically created caches key generated in request creation.
+ *
+ * Group keys generation protocol:
+ *
+ * <ul>
+ *     <li>Joining node:
+ *     <ul>
+ *         <li>1. Collects and send all stored group keys to coordinator.</li>
+ *         <li>2. Generate(but doesn't store locally!) and send keys for all statically configured groups in case the not presented in metastore.</li>
+ *         <li>3. Store all keys received from coordinator to local store.</li>
+ *     </ul>
+ *     </li>
+ *     <li>Coordinator:
+ *     <ul>
+ *         <li>1. Checks master key digest are equal to local. If not join is rejected.</li>
+ *         <li>2. Checks all stored keys from joining node are equal to stored keys. If not join is rejected.</li>
+ *         <li>3. Collects all stored keys and sends it to joining node.</li>
+ *     </ul>
+ *     </li>
+ *     <li>All nodes:
+ *     <ul>
+ *         <li>1. If new key for group doesn't exists locally it added to local store.</li>
+ *         <li>2. If new key for group exists locally, then received key skipped.</li>
+ *     </ul>
+ *     </li>
+ * </ul>
+ *
+ * @see GridCacheProcessor#generateEncryptionKeysAndStartCacheAfter(int, GridPlainClosure)
+ */
+public class GridEncryptionManager extends GridManagerAdapter<EncryptionSpi> implements MetastorageLifecycleListener,
+    IgniteChangeGlobalStateSupport {
+    /**
+     * Cache encryption introduced in this Ignite version.
+     */
+    private static final IgniteProductVersion CACHE_ENCRYPTION_SINCE = IgniteProductVersion.fromString("2.7.0");
+
+    /** Synchronization mutex. */
+    private final Object metaStorageMux = new Object();
+
+    /** Synchronization mutex for an generate encryption keys operations. */
+    private final Object genEcnKeyMux = new Object();
+
+    /** Disconnected flag. */
+    private volatile boolean disconnected;
+
+    /** Stopped flag. */
+    private volatile boolean stopped;
+
+    /** Flag to enable/disable write to metastore on cluster state change. */
+    private volatile boolean writeToMetaStoreEnabled;
+
+    /** Prefix for a encryption group key in meta store. */
+    public static final String ENCRYPTION_KEY_PREFIX = "grp-encryption-key-";
+
+    /** Encryption key predicate for meta store. */
+    private static final IgnitePredicate<String> ENCRYPTION_KEY_PREFIX_PRED =
+        (IgnitePredicate<String>)key -> key.startsWith(ENCRYPTION_KEY_PREFIX);
+
+    /** Group encryption keys. */
+    private Map<Integer, Serializable> grpEncKeys = new HashMap<>();
+
+    /** Pending generate encryption key futures. */
+    private ConcurrentMap<IgniteUuid, GenerateEncryptionKeyFuture> genEncKeyFuts = new ConcurrentHashMap<>();
+
+    /** Metastorage. */
+    private volatile ReadWriteMetastorage metaStorage;
+
+    /** I/O message listener. */
+    private GridMessageListener ioLsnr;
+
+    /** System discovery message listener. */
+    private DiscoveryEventListener discoLsnr;
+
+    /**
+     * @param ctx Kernel context.
+     */
+    public GridEncryptionManager(GridKernalContext ctx) {
+        super(ctx, ctx.config().getEncryptionSpi());
+
+        ctx.internalSubscriptionProcessor().registerMetastorageListener(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start() throws IgniteCheckedException {
+        startSpi();
+
+        if (getSpi().masterKeyDigest() != null)
+            ctx.addNodeAttribute(ATTR_ENCRYPTION_MASTER_KEY_DIGEST, getSpi().masterKeyDigest());
+
+        ctx.event().addDiscoveryEventListener(discoLsnr = (evt, discoCache) -> {
+            UUID leftNodeId = evt.eventNode().id();
+
+            synchronized (genEcnKeyMux) {
+                Iterator<Map.Entry<IgniteUuid, GenerateEncryptionKeyFuture>> futsIter =
+                    genEncKeyFuts.entrySet().iterator();
+
+                while (futsIter.hasNext()) {
+                    GenerateEncryptionKeyFuture fut = futsIter.next().getValue();
+
+                    if (!F.eq(leftNodeId, fut.nodeId()))
+                        return;
+
+                    try {
+                        futsIter.remove();
+
+                        sendGenerateEncryptionKeyRequest(fut);
+
+                        genEncKeyFuts.put(fut.id(), fut);
+                    }
+                    catch (IgniteCheckedException e) {
+                        fut.onDone(null, e);
+                    }
+                }
+            }
+        }, EVT_NODE_LEFT, EVT_NODE_FAILED);
+
+        ctx.io().addMessageListener(TOPIC_GEN_ENC_KEY, ioLsnr = (nodeId, msg, plc) -> {
+            synchronized (genEcnKeyMux) {
+                if (msg instanceof GenerateEncryptionKeyRequest) {
+                    GenerateEncryptionKeyRequest req = (GenerateEncryptionKeyRequest)msg;
+
+                    assert req.keyCount() != 0;
+
+                    List<byte[]> encKeys = new ArrayList<>(req.keyCount());
+
+                    for (int i = 0; i < req.keyCount(); i++)
+                        encKeys.add(getSpi().encryptKey(getSpi().create()));
+
+                    try {
+                        ctx.io().sendToGridTopic(nodeId, TOPIC_GEN_ENC_KEY,
+                            new GenerateEncryptionKeyResponse(req.id(), encKeys), SYSTEM_POOL);
+                    }
+                    catch (IgniteCheckedException e) {
+                        U.error(log, "Unable to send generate key response[nodeId=" + nodeId + "]");
+                    }
+                }
+                else {
+                    GenerateEncryptionKeyResponse resp = (GenerateEncryptionKeyResponse)msg;
+
+                    GenerateEncryptionKeyFuture fut = genEncKeyFuts.get(resp.requestId());
+
+                    if (fut != null)
+                        fut.onDone(resp.encryptionKeys(), null);
+                    else
+                        U.warn(log, "Response received for a unknown request.[reqId=" + resp.requestId() + "]");
+                }
+            }
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop(boolean cancel) throws IgniteCheckedException {
+        stopSpi();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void onKernalStart0() throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void onKernalStop0(boolean cancel) {
+        synchronized (genEcnKeyMux) {
+            stopped = true;
+
+            if (ioLsnr != null)
+                ctx.io().removeMessageListener(TOPIC_GEN_ENC_KEY, ioLsnr);
+
+            if (discoLsnr != null)
+                ctx.event().removeDiscoveryEventListener(discoLsnr, EVT_NODE_LEFT, EVT_NODE_FAILED);
+
+            cancelFutures("Kernal stopped.");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onDisconnected(IgniteFuture<?> reconnectFut) {
+        synchronized (genEcnKeyMux) {
+            assert !disconnected;
+
+            disconnected = true;
+
+            cancelFutures("Client node was disconnected from topology (operation result is unknown).");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) {
+        synchronized (genEcnKeyMux) {
+            assert disconnected;
+
+            disconnected = false;
+
+            return null;
+        }
+    }
+
+    /**
+     * Callback for local join.
+     */
+    public void onLocalJoin() {
+        if (notCoordinator())
+            return;
+
+        //We can't store keys before node join to cluster(on statically configured cache registration).
+        //Because, keys should be received from cluster.
+        //Otherwise, we would generate different keys on each started node.
+        //So, after starting, coordinator saves locally newly generated encryption keys.
+        //And sends that keys to every joining node.
+        synchronized (metaStorageMux) {
+            //Keys read from meta storage.
+            HashMap<Integer, byte[]> knownEncKeys = knownEncryptionKeys();
+
+            //Generated(not saved!) keys for a new caches.
+            //Configured statically in config, but doesn't stored on the disk.
+            HashMap<Integer, byte[]> newEncKeys =
+                newEncryptionKeys(knownEncKeys == null ? Collections.EMPTY_SET : knownEncKeys.keySet());
+
+            if (newEncKeys == null)
+                return;
+
+            //We can store keys to the disk, because we are on a coordinator.
+            for (Map.Entry<Integer, byte[]> entry : newEncKeys.entrySet()) {
+                groupKey(entry.getKey(), entry.getValue());
+
+                U.quietAndInfo(log, "Added encryption key on local join [grpId=" + entry.getKey() + "]");
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public IgniteNodeValidationResult validateNode(ClusterNode node,
+        JoiningNodeDiscoveryData discoData) {
+        IgniteNodeValidationResult res = super.validateNode(node, discoData);
+
+        if (res != null)
+            return res;
+
+        if (node.isClient())
+            return null;
+
+        res = validateNode(node);
+
+        if (res != null)
+            return res;
+
+        if (!discoData.hasJoiningNodeData()) {
+            U.quietAndInfo(log, "Joining node doesn't have encryption data [node=" + node.id() + "]");
+
+            return null;
+        }
+
+        NodeEncryptionKeys nodeEncKeys = (NodeEncryptionKeys)discoData.joiningNodeData();
+
+        if (nodeEncKeys == null || F.isEmpty(nodeEncKeys.knownKeys)) {
+            U.quietAndInfo(log, "Joining node doesn't have stored group keys [node=" + node.id() + "]");
+
+            return null;
+        }
+
+        for (Map.Entry<Integer, byte[]> entry : nodeEncKeys.knownKeys.entrySet()) {
+            Serializable locEncKey = grpEncKeys.get(entry.getKey());
+
+            if (locEncKey == null)
+                continue;
+
+            Serializable rmtKey = getSpi().decryptKey(entry.getValue());
+
+            if (F.eq(locEncKey, rmtKey))
+                continue;
+
+            return new IgniteNodeValidationResult(ctx.localNodeId(),
+                "Cache key differs! Node join is rejected. [node=" + node.id() + ", grp=" + entry.getKey() + "]",
+                "Cache key differs! Node join is rejected.");
+        }
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public IgniteNodeValidationResult validateNode(ClusterNode node) {
+        IgniteNodeValidationResult res = super.validateNode(node);
+
+        if (res != null)
+            return res;
+
+        if (node.isClient())
+            return null;
+
+        byte[] lclMkDig = getSpi().masterKeyDigest();
+
+        byte[] rmtMkDig = node.attribute(ATTR_ENCRYPTION_MASTER_KEY_DIGEST);
+
+        if (Arrays.equals(lclMkDig, rmtMkDig))
+            return null;
+
+        return new IgniteNodeValidationResult(ctx.localNodeId(),
+            "Master key digest differs! Node join is rejected. [node=" + node.id() + "]",
+            "Master key digest differs! Node join is rejected.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void collectJoiningNodeData(DiscoveryDataBag dataBag) {
+        HashMap<Integer, byte[]> knownEncKeys = knownEncryptionKeys();
+
+        HashMap<Integer, byte[]> newKeys =
+            newEncryptionKeys(knownEncKeys == null ? Collections.EMPTY_SET : knownEncKeys.keySet());
+
+        if ((knownEncKeys == null && newKeys == null) || dataBag.isJoiningNodeClient())
+            return;
+
+        if (log.isInfoEnabled()) {
+            String knownGrps = F.isEmpty(knownEncKeys) ? null : F.concat(knownEncKeys.keySet(), ",");
+
+            if (knownGrps != null)
+                U.quietAndInfo(log, "Sending stored group keys to coordinator [grps=" + knownGrps + "]");
+
+            String newGrps = F.isEmpty(newKeys) ? null : F.concat(newKeys.keySet(), ",");
+
+            if (newGrps != null)
+                U.quietAndInfo(log, "Sending new group keys to coordinator [grps=" + newGrps + "]");
+        }
+
+        dataBag.addJoiningNodeData(ENCRYPTION_MGR.ordinal(), new NodeEncryptionKeys(knownEncKeys, newKeys));
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onJoiningNodeDataReceived(JoiningNodeDiscoveryData data) {
+        NodeEncryptionKeys nodeEncryptionKeys = (NodeEncryptionKeys)data.joiningNodeData();
+
+        if (nodeEncryptionKeys == null || nodeEncryptionKeys.newKeys == null || ctx.clientNode())
+            return;
+
+        for (Map.Entry<Integer, byte[]> entry : nodeEncryptionKeys.newKeys.entrySet()) {
+            if (groupKey(entry.getKey()) == null) {
+                U.quietAndInfo(log, "Store group key received from joining node [node=" +
+                        data.joiningNodeId() + ", grp=" + entry.getKey() + "]");
+
+                groupKey(entry.getKey(), entry.getValue());
+            }
+            else {
+                U.quietAndInfo(log, "Skip group key received from joining node. Already exists. [node=" +
+                    data.joiningNodeId() + ", grp=" + entry.getKey() + "]");
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void collectGridNodeData(DiscoveryDataBag dataBag) {
+        if (dataBag.isJoiningNodeClient() || dataBag.commonDataCollectedFor(ENCRYPTION_MGR.ordinal()))
+            return;
+
+        HashMap<Integer, byte[]> knownEncKeys = knownEncryptionKeys();
+
+        HashMap<Integer, byte[]> newKeys =
+            newEncryptionKeys(knownEncKeys == null ? Collections.EMPTY_SET : knownEncKeys.keySet());
+
+        if (knownEncKeys == null)
+            knownEncKeys = newKeys;
+        else if (newKeys != null) {
+            for (Map.Entry<Integer, byte[]> entry : newKeys.entrySet()) {
+                byte[] old = knownEncKeys.putIfAbsent(entry.getKey(), entry.getValue());
+
+                assert old == null;
+            }
+        }
+
+        dataBag.addGridCommonData(ENCRYPTION_MGR.ordinal(), knownEncKeys);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onGridDataReceived(GridDiscoveryData data) {
+        Map<Integer, byte[]> encKeysFromCluster = (Map<Integer, byte[]>)data.commonData();
+
+        if (F.isEmpty(encKeysFromCluster))
+            return;
+
+        for (Map.Entry<Integer, byte[]> entry : encKeysFromCluster.entrySet()) {
+            if (groupKey(entry.getKey()) == null) {
+                U.quietAndInfo(log, "Store group key received from coordinator [grp=" + entry.getKey() + "]");
+
+                groupKey(entry.getKey(), entry.getValue());
+            }
+            else {
+                U.quietAndInfo(log, "Skip group key received from coordinator. Already exists. [grp=" +
+                    entry.getKey() + "]");
+            }
+        }
+    }
+
+    /**
+     * Returns group encryption key.
+     *
+     * @param grpId Group id.
+     * @return Group encryption key.
+     */
+    @Nullable public Serializable groupKey(int grpId) {
+        return grpEncKeys.get(grpId);
+    }
+
+    /**
+     * Store group encryption key.
+     *
+     * @param grpId Group id.
+     * @param encGrpKey Encrypted group key.
+     */
+    public void groupKey(int grpId, byte[] encGrpKey) {
+        assert !grpEncKeys.containsKey(grpId);
+
+        Serializable encKey = getSpi().decryptKey(encGrpKey);
+
+        synchronized (metaStorageMux) {
+            if (log.isDebugEnabled())
+                log.debug("Key added. [grp=" + grpId + "]");
+
+            grpEncKeys.put(grpId, encKey);
+
+            writeToMetaStore(grpId, encGrpKey);
+        }
+    }
+
+    /**
+     * Removes encryption key.
+     *
+     * @param grpId Group id.
+     */
+    private void removeGroupKey(int grpId) {
+        synchronized (metaStorageMux) {
+            ctx.cache().context().database().checkpointReadLock();
+
+            try {
+                grpEncKeys.remove(grpId);
+
+                metaStorage.remove(ENCRYPTION_KEY_PREFIX + grpId);
+
+                if (log.isDebugEnabled())
+                    log.debug("Key removed. [grp=" + grpId + "]");
+            }
+            catch (IgniteCheckedException e) {
+                U.error(log, "Failed to clear meta storage", e);
+            }
+            finally {
+                ctx.cache().context().database().checkpointReadUnlock();
+            }
+        }
+    }
+
+    /**
+     * Callback for cache group start event.
+     * @param grpId Group id.
+     * @param encKey Encryption key
+     */
+    public void beforeCacheGroupStart(int grpId, @Nullable byte[] encKey) {
+        if (encKey == null || ctx.clientNode())
+            return;
+
+        groupKey(grpId, encKey);
+    }
+
+    /**
+     * Callback for cache group destroy event.
+     * @param grpId Group id.
+     */
+    public void onCacheGroupDestroyed(int grpId) {
+        if (groupKey(grpId) == null)
+            return;
+
+        removeGroupKey(grpId);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onReadyForRead(ReadOnlyMetastorage metastorage) {
+        try {
+            Map<String, ? extends Serializable> encKeys = metastorage.readForPredicate(ENCRYPTION_KEY_PREFIX_PRED);
+
+            if (encKeys.isEmpty())
+                return;
+
+            for (String key : encKeys.keySet()) {
+                Integer grpId = Integer.valueOf(key.replace(ENCRYPTION_KEY_PREFIX, ""));
+
+                byte[] encGrpKey = (byte[])encKeys.get(key);
+
+                grpEncKeys.putIfAbsent(grpId, getSpi().decryptKey(encGrpKey));
+            }
+
+            if (!grpEncKeys.isEmpty()) {
+                U.quietAndInfo(log, "Encryption keys loaded from metastore. [grps=" +
+                    F.concat(grpEncKeys.keySet(), ",") + "]");
+            }
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to read encryption keys state.", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onReadyForReadWrite(ReadWriteMetastorage metaStorage) throws IgniteCheckedException {
+        synchronized (metaStorageMux) {
+            this.metaStorage = metaStorage;
+
+            writeToMetaStoreEnabled = true;
+
+            writeAllToMetaStore();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onActivate(GridKernalContext kctx) throws IgniteCheckedException {
+        synchronized (metaStorageMux) {
+            writeToMetaStoreEnabled = metaStorage != null;
+
+            if (writeToMetaStoreEnabled)
+                writeAllToMetaStore();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onDeActivate(GridKernalContext kctx) {
+        synchronized (metaStorageMux) {
+            writeToMetaStoreEnabled = false;
+        }
+    }
+
+    /**
+     * @param keyCnt Count of keys to generate.
+     * @return Future that will contain results of generation.
+     */
+    public IgniteInternalFuture<Collection<byte[]>> generateKeys(int keyCnt) {
+        if (keyCnt == 0 || !ctx.clientNode())
+            return new GridFinishedFuture<>(createKeys(keyCnt));
+
+        synchronized (genEcnKeyMux) {
+            if (disconnected || stopped) {
+                return new GridFinishedFuture<>(
+                    new IgniteFutureCancelledException("Node " + (stopped ? "stopped" : "disconnected")));
+            }
+
+            try {
+                GenerateEncryptionKeyFuture genEncKeyFut = new GenerateEncryptionKeyFuture(keyCnt);
+
+                sendGenerateEncryptionKeyRequest(genEncKeyFut);
+
+                genEncKeyFuts.put(genEncKeyFut.id(), genEncKeyFut);
+
+                return genEncKeyFut;
+            }
+            catch (IgniteCheckedException e) {
+                return new GridFinishedFuture<>(e);
+            }
+        }
+    }
+
+    /** */
+    private void sendGenerateEncryptionKeyRequest(GenerateEncryptionKeyFuture fut) throws IgniteCheckedException {
+        ClusterNode rndNode = U.randomServerNode(ctx);
+
+        if (rndNode == null)
+            throw new IgniteCheckedException("There is no node to send GenerateEncryptionKeyRequest to");
+
+        GenerateEncryptionKeyRequest req = new GenerateEncryptionKeyRequest(fut.keyCount());
+
+        fut.id(req.id());
+        fut.nodeId(rndNode.id());
+
+        ctx.io().sendToGridTopic(rndNode.id(), TOPIC_GEN_ENC_KEY, req, SYSTEM_POOL);
+    }
+
+    /**
+     * Writes all unsaved grpEncKeys to metaStorage.
+     * @throws IgniteCheckedException If failed.
+     */
+    private void writeAllToMetaStore() throws IgniteCheckedException {
+        for (Map.Entry<Integer, Serializable> entry : grpEncKeys.entrySet()) {
+            if (metaStorage.read(ENCRYPTION_KEY_PREFIX + entry.getKey()) != null)
+                continue;
+
+            writeToMetaStore(entry.getKey(), getSpi().encryptKey(entry.getValue()));
+        }
+    }
+
+    /**
+     * Checks cache encryption supported by all nodes in cluster.
+     *
+     * @throws IgniteCheckedException If check fails.
+     */
+    public void checkEncryptedCacheSupported() throws IgniteCheckedException {
+        Collection<ClusterNode> nodes = ctx.grid().cluster().nodes();
+
+        for (ClusterNode node : nodes) {
+            if (CACHE_ENCRYPTION_SINCE.compareTo(node.version()) > 0) {
+                throw new IgniteCheckedException("All nodes in cluster should be 2.7.0 or greater " +
+                    "to create encrypted cache! [nodeId=" + node.id() + "]");
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public DiscoveryDataExchangeType discoveryDataType() {
+        return ENCRYPTION_MGR;
+    }
+
+    /**
+     * Writes encryption key to metastore.
+     *
+     * @param grpId Group id.
+     * @param encGrpKey Group encryption key.
+     */
+    private void writeToMetaStore(int grpId, byte[] encGrpKey) {
+        if (metaStorage == null || !writeToMetaStoreEnabled)
+            return;
+
+        ctx.cache().context().database().checkpointReadLock();
+
+        try {
+            metaStorage.write(ENCRYPTION_KEY_PREFIX + grpId, encGrpKey);
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to write cache group encryption key [grpId=" + grpId + ']', e);
+        }
+        finally {
+            ctx.cache().context().database().checkpointReadUnlock();
+        }
+    }
+
+    /**
+     * @param knownKeys Saved keys set.
+     * @return New keys for local cache groups.
+     */
+    @Nullable private HashMap<Integer, byte[]> newEncryptionKeys(Set<Integer> knownKeys) {
+        Map<Integer, CacheGroupDescriptor> grpDescs = ctx.cache().cacheGroupDescriptors();
+
+        HashMap<Integer, byte[]> newKeys = null;
+
+        for (CacheGroupDescriptor grpDesc : grpDescs.values()) {
+            if (knownKeys.contains(grpDesc.groupId()) || !grpDesc.config().isEncryptionEnabled())
+                continue;
+
+            if (newKeys == null)
+                newKeys = new HashMap<>();
+
+            newKeys.put(grpDesc.groupId(), getSpi().encryptKey(getSpi().create()));
+        }
+
+        return newKeys;
+    }
+
+    /**
+     * @return Local encryption keys.
+     */
+    @Nullable private HashMap<Integer, byte[]> knownEncryptionKeys() {
+        if (F.isEmpty(grpEncKeys))
+            return null;
+
+        HashMap<Integer, byte[]> knownKeys = new HashMap<>();
+
+        for (Map.Entry<Integer, Serializable> entry : grpEncKeys.entrySet())
+            knownKeys.put(entry.getKey(), getSpi().encryptKey(entry.getValue()));
+
+        return knownKeys;
+    }
+
+    /**
+     * Generates required count of encryption keys.
+     *
+     * @param keyCnt Keys count.
+     * @return Collection with newly generated encryption keys.
+     */
+    private Collection<byte[]> createKeys(int keyCnt) {
+        if (keyCnt == 0)
+            return Collections.emptyList();
+
+        List<byte[]> encKeys = new ArrayList<>(keyCnt);
+
+        for(int i=0; i<keyCnt; i++)
+            encKeys.add(getSpi().encryptKey(getSpi().create()));
+
+        return encKeys;
+    }
+
+    /**
+     * @param msg Error message.
+     */
+    private void cancelFutures(String msg) {
+        for (GenerateEncryptionKeyFuture fut : genEncKeyFuts.values())
+            fut.onDone(new IgniteFutureCancelledException(msg));
+    }
+
+    /**
+     * Checks whether local node is coordinator. Nodes that are leaving or failed
+     * (but are still in topology) are removed from search.
+     *
+     * @return {@code true} if local node is coordinator.
+     */
+    private boolean notCoordinator() {
+        DiscoverySpi spi = ctx.discovery().getInjectedDiscoverySpi();
+
+        if (spi instanceof TcpDiscoverySpi)
+            return !((TcpDiscoverySpi)spi).isLocalNodeCoordinator();
+        else {
+            ClusterNode crd = null;
+
+            for (ClusterNode node : ctx.discovery().aliveServerNodes()) {
+                if (crd == null || crd.order() > node.order())
+                    crd = node;
+            }
+
+            return crd == null || !F.eq(ctx.localNodeId(), crd.id());
+        }
+    }
+
+    /** */
+    public static class NodeEncryptionKeys implements Serializable {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** */
+        NodeEncryptionKeys(Map<Integer, byte[]> knownKeys, Map<Integer, byte[]> newKeys) {
+            this.knownKeys = knownKeys;
+            this.newKeys = newKeys;
+        }
+
+        /** Known i.e. stored in {@code ReadWriteMetastorage} keys from node. */
+        Map<Integer, byte[]> knownKeys;
+
+        /**  New keys i.e. keys for a local statically configured caches. */
+        Map<Integer, byte[]> newKeys;
+    }
+
+    /** */
+    @SuppressWarnings("ExternalizableWithoutPublicNoArgConstructor")
+    private class GenerateEncryptionKeyFuture extends GridFutureAdapter<Collection<byte[]>> {
+        /** */
+        private IgniteUuid id;
+
+        /** */
+        private int keyCnt;
+
+        /** */
+        private UUID nodeId;
+
+        /**
+         * @param keyCnt Count of keys to generate.
+         */
+        private GenerateEncryptionKeyFuture(int keyCnt) {
+            this.keyCnt = keyCnt;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean onDone(@Nullable Collection<byte[]> res, @Nullable Throwable err) {
+            // Make sure to remove future before completion.
+            genEncKeyFuts.remove(id, this);
+
+            return super.onDone(res, err);
+        }
+
+        /** */
+        public IgniteUuid id() {
+            return id;
+        }
+
+        /** */
+        public void id(IgniteUuid id) {
+            this.id = id;
+        }
+
+        /** */
+        public UUID nodeId() {
+            return nodeId;
+        }
+
+        /** */
+        public void nodeId(UUID nodeId) {
+            this.nodeId = nodeId;
+        }
+
+        /** */
+        public int keyCount() {
+            return keyCnt;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(GenerateEncryptionKeyFuture.class, this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java
index f7391d2..3ef0ec7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageMemory.java
@@ -43,6 +43,12 @@ public interface PageMemory extends PageIdAllocator, PageSupport {
     public int pageSize();
 
     /**
+     * @param grpId Group id.
+     * @return Page size without encryption overhead.
+     */
+    public int realPageSize(int grpId);
+
+    /**
      * @return Page size with system overhead, in bytes.
      */
     public int systemPageSize();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java
index 02afac8..66d713c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoStoreImpl.java
@@ -341,6 +341,11 @@ public class PageMemoryNoStoreImpl implements PageMemory {
         return sysPageSize;
     }
 
+    /** {@inheritDoc} */
+    @Override public int realPageSize(int grpId) {
+        return pageSize();
+    }
+
     /**
      * @return Next index.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
index 42d584d..7a7f964 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.pagemem.store;
 import org.apache.ignite.IgniteCheckedException;
 
 import java.nio.ByteBuffer;
+import org.apache.ignite.internal.processors.cache.persistence.StorageException;
 
 /**
  * Persistent store of pages.
@@ -101,4 +102,30 @@ public interface PageStore {
      * @return Page store version.
      */
     public int version();
+
+    /**
+     * @param cleanFile {@code True} to delete file.
+     * @throws StorageException If failed.
+     */
+    public void stop(boolean cleanFile) throws StorageException;
+
+    /**
+     * Starts recover process.
+     */
+    public void beginRecover();
+
+    /**
+     * Ends recover process.
+     *
+     * @throws StorageException If failed.
+     */
+    public void finishRecover() throws StorageException;
+
+    /**
+     * Truncates and deletes partition file.
+     *
+     * @param tag New partition tag.
+     * @throws StorageException If failed.
+     */
+    public void truncate(int tag) throws StorageException;
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java
new file mode 100644
index 0000000..234292b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/EncryptedRecord.java
@@ -0,0 +1,60 @@
+/*
+ * 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.ignite.internal.pagemem.wal.record;
+
+/**
+ * Encrypted record from WAL.
+ * That types of record returned from a {@code RecordDataSerializer} on offline WAL iteration.
+ */
+public class EncryptedRecord extends WALRecord implements WalRecordCacheGroupAware {
+    /**
+     * Group id.
+     */
+    private int grpId;
+
+    /**
+     * Type of plain record.
+     */
+    private RecordType plainRecType;
+
+    /**
+     * @param grpId Group id
+     * @param plainRecType Plain record type.
+     */
+    public EncryptedRecord(int grpId, RecordType plainRecType) {
+        this.grpId = grpId;
+        this.plainRecType = plainRecType;
+    }
+
+    /** {@inheritDoc} */
+    @Override public RecordType type() {
+        return RecordType.ENCRYPTED_RECORD;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int groupId() {
+        return grpId;
+    }
+
+    /**
+     * @return Type of plain record.
+     */
+    public RecordType plainRecordType() {
+        return plainRecType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
index 1aa065e..d3a465d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/PageSnapshot.java
@@ -38,21 +38,30 @@ public class PageSnapshot extends WALRecord implements WalRecordCacheGroupAware{
     private FullPageId fullPageId;
 
     /**
+     * PageSIze without encryption overhead.
+     */
+    private int realPageSize;
+
+    /**
      * @param fullId Full page ID.
      * @param arr Read array.
+     * @param realPageSize Page size without encryption overhead.
      */
-    public PageSnapshot(FullPageId fullId, byte[] arr) {
-        fullPageId = fullId;
-        pageData = arr;
+    public PageSnapshot(FullPageId fullId, byte[] arr, int realPageSize) {
+        this.fullPageId = fullId;
+        this.pageData = arr;
+        this.realPageSize = realPageSize;
     }
 
     /**
      * @param fullPageId Full page ID.
      * @param ptr Pointer to copy from.
      * @param pageSize Page size.
+     * @param realPageSize Page size without encryption overhead.
      */
-    public PageSnapshot(FullPageId fullPageId, long ptr, int pageSize) {
+    public PageSnapshot(FullPageId fullPageId, long ptr, int pageSize, int realPageSize) {
         this.fullPageId = fullPageId;
+        this.realPageSize = realPageSize;
 
         pageData = new byte[pageSize];
 
@@ -88,7 +97,7 @@ public class PageSnapshot extends WALRecord implements WalRecordCacheGroupAware{
 
         try {
             return "PageSnapshot [fullPageId = " + fullPageId() + ", page = [\n"
-                + PageIO.printPage(addr, pageData.length)
+                + PageIO.printPage(addr, realPageSize)
                 + "],\nsuper = ["
                 + super.toString() + "]]";
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
index a555aae..667f8d9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
@@ -193,7 +193,13 @@ public abstract class WALRecord {
         MVCC_DATA_PAGE_TX_STATE_HINT_UPDATED_RECORD,
 
         /** */
-        MVCC_DATA_PAGE_NEW_TX_STATE_HINT_UPDATED_RECORD;
+        MVCC_DATA_PAGE_NEW_TX_STATE_HINT_UPDATED_RECORD,
+
+        /** Encrypted WAL-record. */
+        ENCRYPTED_RECORD,
+
+        /** Ecnrypted data record */
+        ENCRYPTED_DATA_RECORD;
 
         /** */
         private static final RecordType[] VALS = RecordType.values();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java
index 2b02bb57..650ae1e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertFragmentRecord.java
@@ -57,7 +57,7 @@ public class DataPageInsertFragmentRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         AbstractDataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.addRowFragment(PageIO.getPageId(pageAddr), pageAddr, payload, lastLink, pageMem.pageSize());
+        io.addRowFragment(PageIO.getPageId(pageAddr), pageAddr, payload, lastLink, pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java
index 2c9a8e7..9b0637d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageInsertRecord.java
@@ -58,7 +58,7 @@ public class DataPageInsertRecord extends PageDeltaRecord {
 
         AbstractDataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.addRow(pageAddr, payload, pageMem.pageSize());
+        io.addRow(pageAddr, payload, pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java
index 5e89f8e..907f4c0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccMarkUpdatedRecord.java
@@ -60,7 +60,7 @@ public class DataPageMvccMarkUpdatedRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         DataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.updateNewVersion(pageAddr, itemId, pageMem.pageSize(), newMvccCrd, newMvccCntr, newMvccOpCntr);
+        io.updateNewVersion(pageAddr, itemId, pageMem.realPageSize(groupId()), newMvccCrd, newMvccCntr, newMvccOpCntr);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java
index 4a244a1..f3d235d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateNewTxStateHintRecord.java
@@ -50,7 +50,7 @@ public class DataPageMvccUpdateNewTxStateHintRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         DataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.updateNewTxState(pageAddr, itemId, pageMem.pageSize(), txState);
+        io.updateNewTxState(pageAddr, itemId, pageMem.realPageSize(groupId()), txState);
     }
 
     /** {@inheritDoc} */


[3/6] ignite git commit: IGNITE-8485: TDE implementation. - Fixes #4167.

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/package-info.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/package-info.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/package-info.java
new file mode 100644
index 0000000..71f1634
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Contains encryption SPI implementation based on standard jdk keystore.
+ */
+package org.apache.ignite.spi.encryption.keystore;

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/spi/encryption/noop/NoopEncryptionSpi.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/noop/NoopEncryptionSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/noop/NoopEncryptionSpi.java
new file mode 100644
index 0000000..1de64d9
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/noop/NoopEncryptionSpi.java
@@ -0,0 +1,101 @@
+/*
+ * 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.ignite.spi.encryption.noop;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.spi.IgniteSpiAdapter;
+import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.IgniteSpiNoop;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * No operation {@code EncryptionSPI} implementation.
+ *
+ * @see EncryptionSpi
+ * @see KeystoreEncryptionSpi
+ */
+@IgniteSpiNoop
+public class NoopEncryptionSpi extends IgniteSpiAdapter implements EncryptionSpi {
+    /** {@inheritDoc} */
+    @Override public byte[] masterKeyDigest() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Serializable create() throws IgniteException {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void encrypt(ByteBuffer data, Serializable key, ByteBuffer res) {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void encryptNoPadding(ByteBuffer data, Serializable key, ByteBuffer res) {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] decrypt(byte[] data, Serializable key) {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void decryptNoPadding(ByteBuffer data, Serializable key, ByteBuffer res) {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] encryptKey(Serializable key) {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Serializable decryptKey(byte[] key) {
+        throw new IgniteSpiException("You have to configure custom EncryptionSpi implementation.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int encryptedSize(int dataSize) {
+        return dataSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int encryptedSizeNoPadding(int dataSize) {
+        return dataSize;
+    }
+
+    @Override public int blockSize() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void spiStart(@Nullable String igniteInstanceName) throws IgniteSpiException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void spiStop() throws IgniteSpiException {
+        // No-op.
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/spi/encryption/package-info.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/package-info.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/package-info.java
new file mode 100644
index 0000000..9805aaf
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Contains APIs for encryption SPI.
+ */
+package org.apache.ignite.spi.encryption;

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/AbstractEncryptionTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/AbstractEncryptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/AbstractEncryptionTest.java
new file mode 100644
index 0000000..f267186
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/AbstractEncryptionTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.util.HashSet;
+import java.util.Set;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.configuration.WALMode.FSYNC;
+import static org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi.CIPHER_ALGO;
+import static org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi.DEFAULT_MASTER_KEY_NAME;
+
+/**
+ * Abstract encryption test.
+ */
+public abstract class AbstractEncryptionTest extends GridCommonAbstractTest {
+    /** */
+    static final String ENCRYPTED_CACHE = "encrypted";
+
+    /** */
+    public static final String KEYSTORE_PATH =
+        IgniteUtils.resolveIgnitePath("modules/core/src/test/resources/tde.jks").getAbsolutePath();
+
+    /** */
+    static final String GRID_0 = "grid-0";
+
+    /** */
+    static final String GRID_1 = "grid-1";
+
+    /** */
+    public static final String KEYSTORE_PASSWORD = "love_sex_god";
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String name) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(name);
+
+        KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi();
+
+        encSpi.setKeyStorePath(keystorePath());
+        encSpi.setKeyStorePassword(keystorePassword());
+
+        cfg.setEncryptionSpi(encSpi);
+
+        DataStorageConfiguration memCfg = new DataStorageConfiguration()
+            .setDefaultDataRegionConfiguration(
+                new DataRegionConfiguration()
+                    .setMaxSize(10L * 1024 * 1024)
+                    .setPersistenceEnabled(true))
+            .setPageSize(4 * 1024)
+            .setWalMode(FSYNC);
+
+        cfg.setDataStorageConfiguration(memCfg);
+
+        return cfg;
+    }
+
+    /** */
+    private char[] keystorePassword() {
+        return KEYSTORE_PASSWORD.toCharArray();
+    }
+
+    /** */
+    protected String keystorePath() {
+        return KEYSTORE_PATH;
+    }
+
+    /** */
+    void checkEncryptedCaches(IgniteEx grid0, IgniteEx grid1) {
+        Set<String> cacheNames = new HashSet<>(grid0.cacheNames());
+
+        cacheNames.addAll(grid1.cacheNames());
+
+        for (String cacheName : cacheNames) {
+            CacheConfiguration ccfg = grid1.cache(cacheName).getConfiguration(CacheConfiguration.class);
+
+            if (!ccfg.isEncryptionEnabled())
+                continue;
+
+            IgniteInternalCache<?, ?> encrypted0 = grid0.cachex(cacheName);
+
+            int grpId = CU.cacheGroupId(cacheName, ccfg.getGroupName());
+
+            assertNotNull(encrypted0);
+
+            IgniteInternalCache<?, ?> encrypted1 = grid1.cachex(cacheName);
+
+            assertNotNull(encrypted1);
+
+            assertTrue(encrypted1.configuration().isEncryptionEnabled());
+
+            KeystoreEncryptionKey encKey0 = (KeystoreEncryptionKey)grid0.context().encryption().groupKey(grpId);
+
+            assertNotNull(encKey0);
+            assertNotNull(encKey0.key());
+
+            if (!grid1.configuration().isClientMode()) {
+                KeystoreEncryptionKey encKey1 = (KeystoreEncryptionKey)grid1.context().encryption().groupKey(grpId);
+
+                assertNotNull(encKey1);
+                assertNotNull(encKey1.key());
+
+                assertEquals(encKey0.key(), encKey1.key());
+            }
+            else
+                assertNull(grid1.context().encryption().groupKey(grpId));
+        }
+
+        checkData(grid0);
+    }
+
+    /** */
+    protected void checkData(IgniteEx grid0) {
+        IgniteCache<Long, String> cache = grid0.cache(cacheName());
+
+        assertNotNull(cache);
+
+        for (long i=0; i<100; i++)
+            assertEquals("" + i, cache.get(i));
+    }
+
+    /** */
+    protected void createEncryptedCache(IgniteEx grid0, @Nullable IgniteEx grid1, String cacheName, String cacheGroup)
+        throws IgniteInterruptedCheckedException {
+        createEncryptedCache(grid0, grid1, cacheName, cacheGroup, true);
+    }
+
+    /** */
+    protected void createEncryptedCache(IgniteEx grid0, @Nullable IgniteEx grid1, String cacheName, String cacheGroup,
+        boolean putData) throws IgniteInterruptedCheckedException {
+        CacheConfiguration<Long, String> ccfg = new CacheConfiguration<Long, String>(cacheName)
+            .setWriteSynchronizationMode(FULL_SYNC)
+            .setGroupName(cacheGroup)
+            .setEncryptionEnabled(true);
+
+        IgniteCache<Long, String> cache = grid0.createCache(ccfg);
+
+        if (grid1 != null)
+            GridTestUtils.waitForCondition(() -> grid1.cachex(cacheName()) != null, 2_000L);
+
+        if (putData) {
+            for (long i = 0; i < 100; i++)
+                cache.put(i, "" + i);
+
+            for (long i = 0; i < 100; i++)
+                assertEquals("" + i, cache.get(i));
+        }
+    }
+
+    /**
+     * Starts tests grid instances.
+     *
+     * @param clnPersDir If {@code true} than before start persistence dir are cleaned.
+     * @return Started grids.
+     * @throws Exception If failed.
+     */
+    protected T2<IgniteEx, IgniteEx> startTestGrids(boolean clnPersDir) throws Exception {
+        if (clnPersDir)
+            cleanPersistenceDir();
+
+        IgniteEx grid0 = startGrid(GRID_0);
+
+        IgniteEx grid1 = startGrid(GRID_1);
+
+        grid0.cluster().active(true);
+
+        awaitPartitionMapExchange();
+
+        return new T2<>(grid0, grid1);
+    }
+
+    /** */
+    @NotNull protected String cacheName() {
+        return ENCRYPTED_CACHE;
+    }
+
+    /**
+     * Method to create new keystore.
+     * Use it whenever you need special keystore for an encryption tests.
+     */
+    @SuppressWarnings("unused")
+    protected File createKeyStore(String keystorePath) throws Exception {
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+
+        ks.load(null, null);
+
+        KeyGenerator gen = KeyGenerator.getInstance(CIPHER_ALGO);
+
+        gen.init(KeystoreEncryptionSpi.DEFAULT_KEY_SIZE);
+
+        SecretKey key = gen.generateKey();
+
+        ks.setEntry(
+            DEFAULT_MASTER_KEY_NAME,
+            new KeyStore.SecretKeyEntry(key),
+            new KeyStore.PasswordProtection(KEYSTORE_PASSWORD.toCharArray()));
+
+        File keyStoreFile = new File(keystorePath);
+
+        keyStoreFile.createNewFile();
+
+        try (OutputStream os = new FileOutputStream(keyStoreFile)) {
+            ks.store(os, KEYSTORE_PASSWORD.toCharArray());
+        }
+
+        return keyStoreFile;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheBigEntryTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheBigEntryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheBigEntryTest.java
new file mode 100644
index 0000000..deb72e4
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheBigEntryTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import java.util.Arrays;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Tests to check encryption of entry bigger then page size.
+ */
+public class EncryptedCacheBigEntryTest extends AbstractEncryptionTest {
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids(false);
+
+        cleanPersistenceDir();
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateEncryptedCacheWithBigEntry() throws Exception {
+        T2<IgniteEx, IgniteEx> grids = startTestGrids(true);
+
+        createEncryptedCache(grids.get1(), grids.get2(), cacheName(), null);
+
+        checkEncryptedCaches(grids.get1(), grids.get2());
+
+        int grpId = CU.cacheGroupId(cacheName(), null);
+
+        KeystoreEncryptionKey keyBeforeRestart =
+            (KeystoreEncryptionKey)grids.get1().context().encryption().groupKey(grpId);
+
+        stopAllGrids();
+
+        grids = startTestGrids(false);
+
+        checkEncryptedCaches(grids.get1(), grids.get2());
+
+        KeystoreEncryptionKey keyAfterRestart = (KeystoreEncryptionKey)grids.get1().context().encryption().groupKey(grpId);
+
+        assertNotNull(keyAfterRestart);
+        assertNotNull(keyAfterRestart.key());
+
+        assertEquals(keyBeforeRestart.key(), keyAfterRestart.key());
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void createEncryptedCache(IgniteEx grid0, @Nullable IgniteEx grid1, String cacheName,
+        String cacheGroup, boolean putData) throws IgniteInterruptedCheckedException {
+        CacheConfiguration<Integer, byte[]> ccfg = new CacheConfiguration<Integer, byte[]>(cacheName)
+            .setWriteSynchronizationMode(FULL_SYNC)
+            .setGroupName(cacheGroup)
+            .setEncryptionEnabled(true);
+
+        IgniteCache<Integer, byte[]> cache = grid0.createCache(ccfg);
+
+        if (grid1 != null)
+            GridTestUtils.waitForCondition(() -> grid1.cachex(cacheName()) != null, 2_000L);
+
+        if (putData) {
+            cache.put(1, bigArray(grid0));
+
+            assertTrue(Arrays.equals(bigArray(grid0), cache.get(1)));
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void checkData(IgniteEx grid0) {
+        IgniteCache<Integer, byte[]> cache = grid0.cache(cacheName());
+
+        assertTrue(Arrays.equals(bigArray(grid0), cache.get(1)));
+    }
+
+    /** */
+    private byte[] bigArray(IgniteEx grid) {
+        int arrSz = grid.configuration().getDataStorageConfiguration().getPageSize() * 3;
+
+        byte[] bigArr = new byte[arrSz];
+
+        for (int i=0; i<bigArr.length; i++)
+            bigArr[i] = (byte)i;
+
+        return bigArr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java
new file mode 100644
index 0000000..47d8d8f
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheCreateTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import com.google.common.primitives.Bytes;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+import org.apache.ignite.testframework.GridTestUtils;
+
+/** */
+public class EncryptedCacheCreateTest extends AbstractEncryptionTest {
+    /** Non-persistent data region name. */
+    private static final String NO_PERSISTENCE_REGION = "no-persistence-region";
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        cleanPersistenceDir();
+
+        IgniteEx igniteEx = startGrid(0);
+
+        startGrid(1);
+
+        igniteEx.cluster().active(true);
+
+        awaitPartitionMapExchange();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String name) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(name);
+
+        DataStorageConfiguration memCfg = cfg.getDataStorageConfiguration();
+
+        memCfg.setDataRegionConfigurations(new DataRegionConfiguration()
+            .setMaxSize(10L * 1024 * 1024)
+            .setName(NO_PERSISTENCE_REGION)
+            .setPersistenceEnabled(false));
+
+        return cfg;
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateEncryptedCache() throws Exception {
+        CacheConfiguration<Long, String> ccfg = new CacheConfiguration<>(ENCRYPTED_CACHE);
+
+        ccfg.setEncryptionEnabled(true);
+
+        IgniteEx grid = grid(0);
+
+        grid.createCache(ccfg);
+
+        IgniteInternalCache<Object, Object> enc = grid.cachex(ENCRYPTED_CACHE);
+
+        assertNotNull(enc);
+
+        KeystoreEncryptionKey key =
+            (KeystoreEncryptionKey)grid.context().encryption().groupKey(CU.cacheGroupId(ENCRYPTED_CACHE, null));
+
+        assertNotNull(key);
+        assertNotNull(key.key());
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateEncryptedNotPersistedCacheFail() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-8640");
+
+        GridTestUtils.assertThrowsWithCause(() -> {
+            CacheConfiguration<Long, String> ccfg = new CacheConfiguration<>(NO_PERSISTENCE_REGION);
+
+            ccfg.setEncryptionEnabled(true);
+            ccfg.setDataRegionName(NO_PERSISTENCE_REGION);
+
+            grid(0).createCache(ccfg);
+        }, IgniteCheckedException.class);
+    }
+
+    /** @throws Exception If failed. */
+    public void testPersistedContentEncrypted() throws Exception {
+        IgniteCache<Integer, String> enc = grid(0).createCache(
+            new CacheConfiguration<Integer, String>(ENCRYPTED_CACHE)
+                .setEncryptionEnabled(true));
+
+        IgniteCache<Integer, String> plain = grid(0).createCache(new CacheConfiguration<>("plain-cache"));
+
+        assertNotNull(enc);
+
+        String encValPart = "AAAAAAAAAA";
+        String plainValPart = "BBBBBBBBBB";
+
+        StringBuilder longEncVal = new StringBuilder(encValPart.length()*100);
+        StringBuilder longPlainVal = new StringBuilder(plainValPart.length()*100);
+
+        for (int i = 0; i < 100; i++) {
+            longEncVal.append(encValPart);
+            longPlainVal.append(plainValPart);
+        }
+
+        enc.put(1, longEncVal.toString());
+        plain.put(1, longPlainVal.toString());
+
+        stopAllGrids(false);
+
+        byte[] encValBytes = encValPart.getBytes(StandardCharsets.UTF_8);
+        byte[] plainValBytes = plainValPart.getBytes(StandardCharsets.UTF_8);
+
+        final boolean[] plainBytesFound = {false};
+
+        Files.walk(U.resolveWorkDirectory(U.defaultWorkDirectory(), "db", false).toPath())
+            .filter(Files::isRegularFile)
+            .forEach(f -> {
+                try {
+                    if (Files.size(f) == 0)
+                        return;
+
+                    byte[] fileBytes = Files.readAllBytes(f);
+
+                    boolean notFound = Bytes.indexOf(fileBytes, encValBytes) == -1;
+
+                    assertTrue("Value should be encrypted in persisted file. " + f.getFileName(), notFound);
+
+                    plainBytesFound[0] = plainBytesFound[0] || Bytes.indexOf(fileBytes, plainValBytes) != -1;
+
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+
+        assertTrue("Plain value should be found in persistent store", plainBytesFound[0]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheDestroyTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheDestroyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheDestroyTest.java
new file mode 100644
index 0000000..11855ec
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheDestroyTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import java.util.Collection;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaStorage;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+
+import static org.apache.ignite.internal.managers.encryption.GridEncryptionManager.ENCRYPTION_KEY_PREFIX;
+
+/**
+ */
+public class EncryptedCacheDestroyTest extends AbstractEncryptionTest {
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testEncryptedCacheDestroy() throws Exception {
+        T2<IgniteEx, IgniteEx> grids = startTestGrids(true);
+
+        createEncryptedCache(grids.get1(), grids.get2(), cacheName(), null);
+
+        checkEncryptedCaches(grids.get1(), grids.get2());
+
+        String encryptedCacheName = cacheName();
+
+        grids.get1().destroyCache(encryptedCacheName);
+
+        checkCacheDestroyed(grids.get2(), encryptedCacheName, null, true);
+
+        stopAllGrids(true);
+
+        grids = startTestGrids(false);
+
+        checkCacheDestroyed(grids.get1(), encryptedCacheName, null, true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testEncryptedCacheFromGroupDestroy() throws Exception {
+        T2<IgniteEx, IgniteEx> grids = startTestGrids(true);
+
+        String encCacheName = cacheName();
+
+        String grpName = "group1";
+
+        createEncryptedCache(grids.get1(), grids.get2(), encCacheName + "2", grpName);
+        createEncryptedCache(grids.get1(), grids.get2(), encCacheName, grpName);
+
+        checkEncryptedCaches(grids.get1(), grids.get2());
+
+        grids.get1().destroyCache(encCacheName);
+
+        checkCacheDestroyed(grids.get2(), encCacheName, grpName, false);
+
+        stopAllGrids(true);
+
+        grids = startTestGrids(false);
+
+        checkCacheDestroyed(grids.get1(), encCacheName, grpName, false);
+
+        grids.get1().destroyCache(encCacheName + "2");
+
+        checkCacheDestroyed(grids.get1(), encCacheName + "2", grpName, true);
+
+        stopAllGrids(true);
+
+        grids = startTestGrids(false);
+
+        checkCacheDestroyed(grids.get1(), encCacheName, grpName, true);
+
+        checkCacheDestroyed(grids.get1(), encCacheName + "2", grpName, true);
+    }
+
+    /** */
+    private void checkCacheDestroyed(IgniteEx grid, String encCacheName, String grpName, boolean keyShouldBeEmpty)
+        throws Exception {
+        awaitPartitionMapExchange();
+
+        Collection<String> cacheNames = grid.cacheNames();
+
+        for (String cacheName : cacheNames) {
+            if (cacheName.equals(encCacheName))
+                fail(encCacheName + " should be destroyed.");
+        }
+
+        int grpId = CU.cacheGroupId(encCacheName, grpName);
+
+        KeystoreEncryptionKey encKey = (KeystoreEncryptionKey)grid.context().encryption().groupKey(grpId);
+        MetaStorage metaStore = grid.context().cache().context().database().metaStorage();
+
+        if (keyShouldBeEmpty) {
+            assertNull(encKey);
+
+            assertNull(metaStore.getData(ENCRYPTION_KEY_PREFIX + grpId));
+        } else {
+            assertNotNull(encKey);
+
+            assertNotNull(metaStore.getData(ENCRYPTION_KEY_PREFIX + grpId));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheGroupCreateTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheGroupCreateTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheGroupCreateTest.java
new file mode 100644
index 0000000..56f578d
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheGroupCreateTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+import org.apache.ignite.testframework.GridTestUtils;
+
+/**
+ */
+public class EncryptedCacheGroupCreateTest extends AbstractEncryptionTest {
+    /** */
+    public static final String ENCRYPTED_GROUP = "encrypted-group";
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        cleanPersistenceDir();
+
+        IgniteEx igniteEx = startGrid(0);
+
+        startGrid(1);
+
+        igniteEx.cluster().active(true);
+
+        awaitPartitionMapExchange();
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateEncryptedCacheGroup() throws Exception {
+        KeystoreEncryptionKey key = createEncryptedCache(ENCRYPTED_CACHE, ENCRYPTED_GROUP);
+
+        CacheConfiguration<Long, String> ccfg = new CacheConfiguration<>(ENCRYPTED_CACHE + "2");
+
+        ccfg.setEncryptionEnabled(true);
+        ccfg.setGroupName(ENCRYPTED_GROUP);
+
+        IgniteEx grid = grid(0);
+
+        grid.createCache(ccfg);
+
+        IgniteInternalCache<Object, Object> encrypted2 = grid.cachex(ENCRYPTED_CACHE + "2");
+
+        GridEncryptionManager encMgr = encrypted2.context().kernalContext().encryption();
+
+        KeystoreEncryptionKey key2 = (KeystoreEncryptionKey)encMgr.groupKey(CU.cacheGroupId(ENCRYPTED_CACHE, ENCRYPTED_GROUP));
+
+        assertNotNull(key2);
+        assertNotNull(key2.key());
+
+        assertEquals(key.key(), key2.key());
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateNotEncryptedCacheInEncryptedGroupFails() throws Exception {
+        createEncryptedCache(ENCRYPTED_CACHE + "3", ENCRYPTED_GROUP + "3");
+
+        IgniteEx grid = grid(0);
+
+        GridTestUtils.assertThrowsWithCause(() -> {
+            grid.createCache(new CacheConfiguration<>(ENCRYPTED_CACHE + "4")
+                .setEncryptionEnabled(false)
+                .setGroupName(ENCRYPTED_GROUP + "3"));
+        }, IgniteCheckedException.class);
+    }
+
+    /** */
+    private KeystoreEncryptionKey createEncryptedCache(String cacheName, String grpName) {
+        CacheConfiguration<Long, String> ccfg = new CacheConfiguration<>(cacheName);
+
+        ccfg.setEncryptionEnabled(true);
+        ccfg.setGroupName(grpName);
+
+        IgniteEx grid = grid(0);
+
+        grid.createCache(ccfg);
+
+        IgniteInternalCache<Object, Object> enc = grid.cachex(cacheName);
+
+        assertNotNull(enc);
+
+        KeystoreEncryptionKey key =
+            (KeystoreEncryptionKey)grid.context().encryption().groupKey(CU.cacheGroupId(cacheName, grpName));
+
+        assertNotNull(key);
+        assertNotNull(key.key());
+
+        return key;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java
new file mode 100644
index 0000000..41a250c
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
+
+/**
+ */
+public class EncryptedCacheNodeJoinTest extends AbstractEncryptionTest {
+    /** */
+    private static final String GRID_2 = "grid-2";
+
+    /** */
+    private static final String GRID_3 = "grid-3";
+
+    /** */
+    private static final String GRID_4 = "grid-4";
+
+    /** */
+    private static final String GRID_5 = "grid-5";
+
+    /** */
+    public static final String CLIENT = "client";
+
+    /** */
+    private boolean configureCache;
+
+    /** */
+    private static final String KEYSTORE_PATH_2 =
+        IgniteUtils.resolveIgnitePath("modules/core/src/test/resources/other_tde_keystore.jks").getAbsolutePath();
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+
+        configureCache = false;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String grid) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(grid);
+
+        cfg.setConsistentId(grid);
+
+        if (grid.equals(GRID_0) ||
+            grid.equals(GRID_2) ||
+            grid.equals(GRID_3) ||
+            grid.equals(GRID_4) ||
+            grid.equals(GRID_5)) {
+            KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi();
+
+            encSpi.setKeyStorePath(grid.equals(GRID_2) ? KEYSTORE_PATH_2 : KEYSTORE_PATH);
+            encSpi.setKeyStorePassword(KEYSTORE_PASSWORD.toCharArray());
+
+            cfg.setEncryptionSpi(encSpi);
+        }
+        else
+            cfg.setEncryptionSpi(null);
+
+        cfg.setClientMode(grid.equals(CLIENT));
+
+        if (configureCache)
+            cfg.setCacheConfiguration(cacheConfiguration(grid));
+
+        return cfg;
+    }
+
+    /** */
+    protected CacheConfiguration cacheConfiguration(String gridName) {
+        CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        ccfg.setName(cacheName());
+        ccfg.setEncryptionEnabled(gridName.equals(GRID_0));
+
+        return ccfg;
+    }
+
+    /** */
+    public void testNodeCantJoinWithoutEncryptionSpi() throws Exception {
+        startGrid(GRID_0);
+
+        assertThrowsWithCause(() -> {
+            try {
+                startGrid(GRID_1);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+
+    /** */
+    public void testNodeCantJoinWithDifferentKeyStore() throws Exception {
+        startGrid(GRID_0);
+
+        assertThrowsWithCause(() -> {
+            try {
+                startGrid(GRID_2);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+
+    /** */
+    public void testNodeCanJoin() throws Exception {
+        startGrid(GRID_0);
+
+        startGrid(GRID_3).cluster().active(true);
+    }
+
+    /** */
+    public void testNodeCantJoinWithDifferentCacheKeys() throws Exception {
+        IgniteEx grid0 = startGrid(GRID_0);
+        startGrid(GRID_3);
+
+        grid0.cluster().active(true);
+
+        stopGrid(GRID_3, false);
+
+        createEncryptedCache(grid0, null, cacheName(), null, false);
+
+        stopGrid(GRID_0, false);
+        IgniteEx grid3 = startGrid(GRID_3);
+
+        grid3.cluster().active(true);
+
+        createEncryptedCache(grid3, null, cacheName(), null, false);
+
+        assertThrowsWithCause(() -> {
+            try {
+                startGrid(GRID_0);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+
+    /** */
+    public void testThirdNodeCanJoin() throws Exception {
+        IgniteEx grid0 = startGrid(GRID_0);
+
+        IgniteEx grid3 = startGrid(GRID_3);
+
+        grid3.cluster().active(true);
+
+        createEncryptedCache(grid0, grid3, cacheName(), null);
+
+        checkEncryptedCaches(grid0, grid3);
+
+        IgniteEx grid4 = startGrid(GRID_4);
+
+        awaitPartitionMapExchange();
+
+        checkEncryptedCaches(grid0, grid4);
+    }
+
+    /** */
+    public void testClientNodeJoin() throws Exception {
+        IgniteEx grid0 = startGrid(GRID_0);
+
+        IgniteEx grid3 = startGrid(GRID_3);
+
+        grid3.cluster().active(true);
+
+        IgniteEx client = startGrid(CLIENT);
+
+        createEncryptedCache(client, grid0, cacheName(), null);
+    }
+
+    /** */
+    public void testNodeCantJoinWithSameNameButNotEncCache() throws Exception {
+        configureCache = true;
+
+        IgniteEx grid0 = startGrid(GRID_0);
+
+        grid0.cluster().active(true);
+
+        assertThrowsWithCause(() -> {
+            try {
+                startGrid(GRID_5);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+
+    /** */
+    public void testNodeCantJoinWithSameNameButEncCache() throws Exception {
+        configureCache = true;
+
+        IgniteEx grid0 = startGrid(GRID_5);
+
+        grid0.cluster().active(true);
+
+        assertThrowsWithCause(() -> {
+            try {
+                startGrid(GRID_0);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCachePreconfiguredRestartTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCachePreconfiguredRestartTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCachePreconfiguredRestartTest.java
new file mode 100644
index 0000000..2e13340
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCachePreconfiguredRestartTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.jetbrains.annotations.NotNull;
+
+/** */
+public class EncryptedCachePreconfiguredRestartTest extends EncryptedCacheRestartTest {
+    /** */
+    private boolean differentCachesOnNodes;
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        cleanPersistenceDir();
+    }
+
+    /** @throws Exception If failed. */
+    public void testDifferentPreconfiguredCachesOnNodes() throws Exception {
+        differentCachesOnNodes = true;
+
+        super.testCreateEncryptedCache();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void testCreateEncryptedCache() throws Exception {
+        differentCachesOnNodes = false;
+
+        super.testCreateEncryptedCache();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        String cacheName = ENCRYPTED_CACHE + (differentCachesOnNodes ? "." + igniteInstanceName : "");
+
+        CacheConfiguration ccfg = new CacheConfiguration(cacheName)
+            .setEncryptionEnabled(true);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        return cfg;
+    }
+
+    /**
+     * @return Cache name.
+     */
+    @NotNull @Override protected String cacheName() {
+        return ENCRYPTED_CACHE + (differentCachesOnNodes ? "." + GRID_1 : "");
+    }
+
+    /**
+     * Creates encrypted cache.
+     */
+    @Override protected void createEncryptedCache(IgniteEx grid0, IgniteEx grid1, String cacheName, String groupName) {
+        IgniteCache<Long, String> cache = grid0.cache(cacheName());
+
+        for (long i=0; i<100; i++)
+            cache.put(i, "" + i);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheRestartTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheRestartTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheRestartTest.java
new file mode 100644
index 0000000..2b01072
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheRestartTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.ignite.internal.encryption;
+
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+
+/** */
+public class EncryptedCacheRestartTest extends AbstractEncryptionTest {
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids(false);
+
+        cleanPersistenceDir();
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateEncryptedCache() throws Exception {
+        T2<IgniteEx, IgniteEx> grids = startTestGrids(true);
+
+        createEncryptedCache(grids.get1(), grids.get2(), cacheName(), null);
+
+        checkEncryptedCaches(grids.get1(), grids.get2());
+
+        int grpId = CU.cacheGroupId(cacheName(), null);
+
+        KeystoreEncryptionKey keyBeforeRestart = (KeystoreEncryptionKey)grids.get1().context().encryption().groupKey(grpId);
+
+        stopAllGrids();
+
+        grids = startTestGrids(false);
+
+        checkEncryptedCaches(grids.get1(), grids.get2());
+
+        KeystoreEncryptionKey keyAfterRestart = (KeystoreEncryptionKey)grids.get1().context().encryption().groupKey(grpId);
+
+        assertNotNull(keyAfterRestart);
+        assertNotNull(keyAfterRestart.key());
+
+        assertEquals(keyBeforeRestart.key(), keyAfterRestart.key());
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoLoadSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoLoadSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoLoadSelfTest.java
index c5988e3..b393634 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoLoadSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/pagemem/impl/PageMemoryNoLoadSelfTest.java
@@ -77,8 +77,8 @@ public class PageMemoryNoLoadSelfTest extends GridCommonAbstractTest {
                     ", page2Id=" + fullId2.pageId() + ", page2=" + page2 + ']');
 
                 try {
-                    writePage(mem, fullId1.pageId(), page1, 1);
-                    writePage(mem, fullId2.pageId(), page2, 2);
+                    writePage(mem, fullId1, page1, 1);
+                    writePage(mem, fullId2, page2, 2);
 
                     readPage(mem, fullId1.pageId(), page1, 1);
                     readPage(mem, fullId2.pageId(), page2, 2);
@@ -149,7 +149,7 @@ public class PageMemoryNoLoadSelfTest extends GridCommonAbstractTest {
                     if (i % 64 == 0)
                         info("Writing page [idx=" + i + ", pageId=" + fullId.pageId() + ", page=" + page + ']');
 
-                    writePage(mem, fullId.pageId(), page, i + 1);
+                    writePage(mem, fullId, page, i + 1);
                 }
                 finally {
                     mem.releasePage(fullId.groupId(), fullId.pageId(), page);
@@ -230,7 +230,7 @@ public class PageMemoryNoLoadSelfTest extends GridCommonAbstractTest {
                     assertNotNull(pageAddr);
 
                     try {
-                        PAGE_IO.initNewPage(pageAddr, id.pageId(), mem.pageSize());
+                        PAGE_IO.initNewPage(pageAddr, id.pageId(), mem.realPageSize(id.groupId()));
 
                         long updId = PageIdUtils.rotatePageId(id.pageId());
 
@@ -332,21 +332,21 @@ public class PageMemoryNoLoadSelfTest extends GridCommonAbstractTest {
 
     /**
      * @param mem Page memory.
-     * @param pageId Page ID.
+     * @param fullId Page ID.
      * @param page Page pointer.
      * @param val Value to write.
      */
-    private void writePage(PageMemory mem, long pageId, long page, int val) {
-        long pageAddr = mem.writeLock(-1, pageId, page);
+    private void writePage(PageMemory mem, FullPageId fullId, long page, int val) {
+        long pageAddr = mem.writeLock(-1, fullId.pageId(), page);
 
         try {
-            PAGE_IO.initNewPage(pageAddr, pageId, mem.pageSize());
+            PAGE_IO.initNewPage(pageAddr, fullId.pageId(), mem.realPageSize(fullId.groupId()));
 
             for (int i = PageIO.COMMON_HEADER_END; i < PAGE_SIZE; i++)
                 PageUtils.putByte(pageAddr, i, (byte)val);
         }
         finally {
-            mem.writeUnlock(-1, pageId, page, null, true);
+            mem.writeUnlock(-1, fullId.pageId(), page, null, true);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
index af6c8b7..15205e0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
@@ -202,7 +202,7 @@ public class IgnitePdsRecoveryAfterFileCorruptionTest extends GridCommonAbstract
             final long pageAddr = mem.writeLock(fullId.groupId(), fullId.pageId(), page);
 
             try {
-                pageIO.initNewPage(pageAddr, fullId.pageId(), mem.pageSize());
+                pageIO.initNewPage(pageAddr, fullId.pageId(), mem.realPageSize(fullId.groupId()));
             }
             finally {
                 mem.writeUnlock(fullId.groupId(), fullId.pageId(), page, null, true);
@@ -261,7 +261,7 @@ public class IgnitePdsRecoveryAfterFileCorruptionTest extends GridCommonAbstract
                 try {
                     long pageAddr = mem.readLock(fullId.groupId(), fullId.pageId(), page);
 
-                    for (int j = PageIO.COMMON_HEADER_END; j < mem.pageSize(); j += 4)
+                    for (int j = PageIO.COMMON_HEADER_END; j < mem.realPageSize(fullId.groupId()); j += 4)
                         assertEquals(j + (int)fullId.pageId(), PageUtils.getInt(pageAddr, j));
 
                     mem.readUnlock(fullId.groupId(), fullId.pageId(), page);
@@ -305,7 +305,7 @@ public class IgnitePdsRecoveryAfterFileCorruptionTest extends GridCommonAbstract
                 PageIO.setPageId(pageAddr, fullId.pageId());
 
                 try {
-                    for (int j = PageIO.COMMON_HEADER_END; j < mem.pageSize(); j += 4)
+                    for (int j = PageIO.COMMON_HEADER_END; j < mem.realPageSize(fullId.groupId()); j += 4)
                         PageUtils.putInt(pageAddr, j, j + (int)fullId.pageId());
                 }
                 finally {
@@ -346,7 +346,7 @@ public class IgnitePdsRecoveryAfterFileCorruptionTest extends GridCommonAbstract
                     cp += cpEnd - cpStart;
                     tmpBuf.rewind();
 
-                    for (int j = PageIO.COMMON_HEADER_END; j < mem.pageSize(); j += 4)
+                    for (int j = PageIO.COMMON_HEADER_END; j < mem.realPageSize(fullId.groupId()); j += 4)
                         assertEquals(j + (int)fullId.pageId(), tmpBuf.getInt(j));
 
                     tmpBuf.rewind();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
index 5fa618b..620814f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsCheckpointSimulationWithRealCpDisabledTest.java
@@ -238,12 +238,13 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
                     long pageAddr = mem.writeLock(fullId.groupId(), fullId.pageId(), page);
 
                     try {
-                        DataPageIO.VERSIONS.latest().initNewPage(pageAddr, fullId.pageId(), mem.pageSize());
+                        DataPageIO.VERSIONS.latest().initNewPage(pageAddr, fullId.pageId(),
+                            mem.realPageSize(fullId.groupId()));
 
                         for (int i = PageIO.COMMON_HEADER_END + DataPageIO.ITEMS_OFF; i < mem.pageSize(); i++)
                             PageUtils.putByte(pageAddr, i, (byte)0xAB);
 
-                        PageIO.printPage(pageAddr, mem.pageSize());
+                        PageIO.printPage(pageAddr, mem.realPageSize(fullId.groupId()));
                     }
                     finally {
                         mem.writeUnlock(fullId.groupId(), fullId.pageId(), page, null, true);
@@ -544,7 +545,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
                     long pageAddr = mem.writeLock(fullId.groupId(), fullId.pageId(), page);
 
                     try {
-                        pageIO.initNewPage(pageAddr, fullId.pageId(), mem.pageSize());
+                        pageIO.initNewPage(pageAddr, fullId.pageId(), mem.realPageSize(fullId.groupId()));
 
                         assertTrue(mem.isDirty(fullId.groupId(), fullId.pageId(), page));
                     }
@@ -632,7 +633,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
             long pageAddr = mem.writeLock(fullId.groupId(), fullId.pageId(), page);
 
             try {
-                DataPageIO.VERSIONS.latest().initNewPage(pageAddr, fullId.pageId(), mem.pageSize());
+                DataPageIO.VERSIONS.latest().initNewPage(pageAddr, fullId.pageId(), mem.realPageSize(fullId.groupId()));
 
                 ThreadLocalRandom rnd = ThreadLocalRandom.current();
 
@@ -707,7 +708,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
                 long pageAddr = mem.readLock(fullId.groupId(), fullId.pageId(), page);
 
                 try {
-                    for (int i = PageIO.COMMON_HEADER_END; i < mem.pageSize(); i++) {
+                    for (int i = PageIO.COMMON_HEADER_END; i < mem.realPageSize(fullId.groupId()); i++) {
                         int expState = state & 0xFF;
                         int pageState = PageUtils.getByte(pageAddr, i) & 0xFF;
                         int walState = walData[i] & 0xFF;
@@ -818,7 +819,8 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
                                                 ", bhc=" + U.hexLong(System.identityHashCode(pageAddr)) +
                                                 ", page=" + U.hexLong(System.identityHashCode(page)) + ']');
 
-                                        for (int i = PageIO.COMMON_HEADER_END; i < mem.pageSize(); i++)
+                                        for (int i = PageIO.COMMON_HEADER_END; i < mem.realPageSize(fullId.groupId());
+                                            i++) {
                                             assertEquals("Verify page failed [fullId=" + fullId +
                                                     ", i=" + i +
                                                     ", state=" + state +
@@ -826,6 +828,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
                                                     ", bhc=" + U.hexLong(System.identityHashCode(pageAddr)) +
                                                     ", page=" + U.hexLong(System.identityHashCode(page)) + ']',
                                                 state & 0xFF, PageUtils.getByte(pageAddr, i) & 0xFF);
+                                        }
                                     }
 
                                     state = (state + 1) & 0xFF;
@@ -836,7 +839,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
                                             ", bhc=" + U.hexLong(System.identityHashCode(pageAddr)) +
                                             ", page=" + U.hexLong(System.identityHashCode(page)) + ']');
 
-                                    for (int i = PageIO.COMMON_HEADER_END; i < mem.pageSize(); i++)
+                                    for (int i = PageIO.COMMON_HEADER_END; i < mem.realPageSize(fullId.groupId()); i++)
                                         PageUtils.putByte(pageAddr, i, (byte)state);
 
                                     resMap.put(fullId, state);
@@ -926,7 +929,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
 
                         Integer first = null;
 
-                        for (int i = PageIO.COMMON_HEADER_END; i < mem.pageSize(); i++) {
+                        for (int i = PageIO.COMMON_HEADER_END; i < mem.realPageSize(fullId.groupId()); i++) {
                             int val = tmpBuf.get(i) & 0xFF;
 
                             if (first == null)
@@ -1027,7 +1030,7 @@ public class IgnitePdsCheckpointSimulationWithRealCpDisabledTest extends GridCom
             final long pageAddr = mem.writeLock(fullId.groupId(), fullId.pageId(), page);
 
             try {
-                pageIO.initNewPage(pageAddr, fullId.pageId(), mem.pageSize());
+                pageIO.initNewPage(pageAddr, fullId.pageId(), mem.realPageSize(fullId.groupId()));
             }
             finally {
                 mem.writeUnlock(fullId.groupId(), fullId.pageId(), page, null, true);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsPageReplacementTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsPageReplacementTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsPageReplacementTest.java
index 432393e..2697c01 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsPageReplacementTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/file/IgnitePdsPageReplacementTest.java
@@ -201,7 +201,7 @@ public class IgnitePdsPageReplacementTest extends GridCommonAbstractTest {
             final long pageAddr = mem.writeLock(fullId.groupId(), fullId.pageId(), page);
 
             try {
-                pageIO.initNewPage(pageAddr, fullId.pageId(), mem.pageSize());
+                pageIO.initNewPage(pageAddr, fullId.pageId(), mem.realPageSize(fullId.groupId()));
             }
             finally {
                 mem.writeUnlock(fullId.groupId(), fullId.pageId(), page, null, true);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
index e617455..dcc2280 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalCompactionTest.java
@@ -149,8 +149,10 @@ public class WalCompactionTest extends GridCommonAbstractTest {
         }
 
         // Spam WAL to move all data records to compressible WAL zone.
-        for (int i = 0; i < WAL_SEGMENT_SIZE / DFLT_PAGE_SIZE * 2; i++)
-            ig.context().cache().context().wal().log(new PageSnapshot(new FullPageId(-1, -1), new byte[DFLT_PAGE_SIZE]));
+        for (int i = 0; i < WAL_SEGMENT_SIZE / DFLT_PAGE_SIZE * 2; i++) {
+            ig.context().cache().context().wal().log(new PageSnapshot(new FullPageId(-1, -1), new byte[DFLT_PAGE_SIZE],
+                DFLT_PAGE_SIZE));
+        }
 
         // WAL archive segment is allowed to be compressed when it's at least one checkpoint away from current WAL head.
         ig.context().cache().context().database().wakeupForCheckpoint("Forced checkpoint").get();
@@ -347,8 +349,10 @@ public class WalCompactionTest extends GridCommonAbstractTest {
         }
 
         // Spam WAL to move all data records to compressible WAL zone.
-        for (int i = 0; i < WAL_SEGMENT_SIZE / DFLT_PAGE_SIZE * 2; i++)
-            ig.context().cache().context().wal().log(new PageSnapshot(new FullPageId(-1, -1), new byte[DFLT_PAGE_SIZE]));
+        for (int i = 0; i < WAL_SEGMENT_SIZE / DFLT_PAGE_SIZE * 2; i++) {
+            ig.context().cache().context().wal().log(new PageSnapshot(new FullPageId(-1, -1), new byte[DFLT_PAGE_SIZE],
+                DFLT_PAGE_SIZE));
+        }
 
         // WAL archive segment is allowed to be compressed when it's at least one checkpoint away from current WAL head.
         ig.context().cache().context().database().wakeupForCheckpoint("Forced checkpoint").get();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreePageMemoryImplTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreePageMemoryImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreePageMemoryImplTest.java
index 7719b43..bb0c416 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreePageMemoryImplTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreePageMemoryImplTest.java
@@ -17,17 +17,25 @@
 
 package org.apache.ignite.internal.processors.cache.persistence.pagemem;
 
+import java.util.Collections;
 import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
 import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider;
 import org.apache.ignite.internal.pagemem.FullPageId;
 import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.persistence.CheckpointWriteProgressSupplier;
 import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.database.BPlusTreeSelfTest;
+import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
+import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor;
 import org.apache.ignite.internal.util.typedef.CIX3;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.testframework.junits.GridTestKernalContext;
+import org.mockito.Mockito;
 
 /**
  *
@@ -44,8 +52,18 @@ public class BPlusTreePageMemoryImplTest extends BPlusTreeSelfTest {
 
         DirectMemoryProvider provider = new UnsafeMemoryProvider(log);
 
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setEncryptionSpi(new NoopEncryptionSpi());
+
+        GridTestKernalContext cctx = new GridTestKernalContext(log, cfg);
+
+        cctx.add(new IgnitePluginProcessor(cctx, cfg, Collections.emptyList()));
+        cctx.add(new GridInternalSubscriptionProcessor(cctx));
+        cctx.add(new GridEncryptionManager(cctx));
+
         GridCacheSharedContext<Object, Object> sharedCtx = new GridCacheSharedContext<>(
-            new GridTestKernalContext(log),
+            cctx,
             null,
             null,
             null,
@@ -78,7 +96,7 @@ public class BPlusTreePageMemoryImplTest extends BPlusTreeSelfTest {
             () -> true,
             new DataRegionMetricsImpl(new DataRegionConfiguration()),
             PageMemoryImpl.ThrottlingPolicy.DISABLED,
-            null
+            Mockito.mock(CheckpointWriteProgressSupplier.class)
         );
 
         mem.start();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreeReuseListPageMemoryImplTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreeReuseListPageMemoryImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreeReuseListPageMemoryImplTest.java
index 71eb129..71e308b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreeReuseListPageMemoryImplTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/BPlusTreeReuseListPageMemoryImplTest.java
@@ -17,7 +17,10 @@
 
 package org.apache.ignite.internal.processors.cache.persistence.pagemem;
 
+import java.util.Collections;
 import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
 import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider;
 import org.apache.ignite.internal.pagemem.FullPageId;
@@ -27,7 +30,10 @@ import org.apache.ignite.internal.processors.cache.persistence.CheckpointWritePr
 import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.database.BPlusTreeReuseSelfTest;
+import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
+import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor;
 import org.apache.ignite.internal.util.lang.GridInClosure3X;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.testframework.junits.GridTestKernalContext;
 import org.mockito.Mockito;
 
@@ -46,8 +52,18 @@ public class BPlusTreeReuseListPageMemoryImplTest extends BPlusTreeReuseSelfTest
 
         DirectMemoryProvider provider = new UnsafeMemoryProvider(log);
 
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setEncryptionSpi(new NoopEncryptionSpi());
+
+        GridTestKernalContext cctx = new GridTestKernalContext(log, cfg);
+
+        cctx.add(new IgnitePluginProcessor(cctx, cfg, Collections.emptyList()));
+        cctx.add(new GridInternalSubscriptionProcessor(cctx));
+        cctx.add(new GridEncryptionManager(cctx));
+
         GridCacheSharedContext<Object, Object> sharedCtx = new GridCacheSharedContext<>(
-            new GridTestKernalContext(log),
+            cctx,
             null,
             null,
             null,

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgnitePageMemReplaceDelayedWriteUnitTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgnitePageMemReplaceDelayedWriteUnitTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgnitePageMemReplaceDelayedWriteUnitTest.java
index 5c965b1..b6031fa 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgnitePageMemReplaceDelayedWriteUnitTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IgnitePageMemReplaceDelayedWriteUnitTest.java
@@ -36,12 +36,14 @@ import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider;
 import org.apache.ignite.internal.pagemem.FullPageId;
 import org.apache.ignite.internal.pagemem.PageIdAllocator;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.persistence.CheckpointWriteProgressSupplier;
 import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl;
 import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
 import org.apache.ignite.internal.util.GridMultiCollectionWrapper;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.logger.NullLogger;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.jetbrains.annotations.NotNull;
 import org.junit.Rule;
@@ -231,7 +233,8 @@ public class IgnitePageMemReplaceDelayedWriteUnitTest {
         DirectMemoryProvider provider = new UnsafeMemoryProvider(log);
 
         PageMemoryImpl memory = new PageMemoryImpl(provider, sizes, sctx, pageSize,
-            pageWriter, null, () -> true, memMetrics, PageMemoryImpl.ThrottlingPolicy.DISABLED, null);
+            pageWriter, null, () -> true, memMetrics, PageMemoryImpl.ThrottlingPolicy.DISABLED,
+            mock(CheckpointWriteProgressSupplier.class));
 
         memory.start();
         return memory;
@@ -244,6 +247,8 @@ public class IgnitePageMemReplaceDelayedWriteUnitTest {
     @NotNull private IgniteConfiguration getConfiguration(long overallSize) {
         IgniteConfiguration cfg = new IgniteConfiguration();
 
+        cfg.setEncryptionSpi(new NoopEncryptionSpi());
+
         cfg.setDataStorageConfiguration(
             new DataStorageConfiguration()
                 .setDefaultDataRegionConfiguration(

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IndexStoragePageMemoryImplTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IndexStoragePageMemoryImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IndexStoragePageMemoryImplTest.java
index 43fbb6e..d3530b4 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IndexStoragePageMemoryImplTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/IndexStoragePageMemoryImplTest.java
@@ -18,18 +18,26 @@
 package org.apache.ignite.internal.processors.cache.persistence.pagemem;
 
 import java.io.File;
+import java.util.Collections;
 import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
 import org.apache.ignite.internal.mem.file.MappedFileMemoryProvider;
 import org.apache.ignite.internal.pagemem.FullPageId;
 import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.persistence.CheckpointWriteProgressSupplier;
 import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.database.IndexStorageSelfTest;
+import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
+import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor;
 import org.apache.ignite.internal.util.lang.GridInClosure3X;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.testframework.junits.GridTestKernalContext;
+import org.mockito.Mockito;
 
 /**
  *
@@ -59,8 +67,18 @@ public class IndexStoragePageMemoryImplTest extends IndexStorageSelfTest {
 
         DirectMemoryProvider provider = new MappedFileMemoryProvider(log(), allocationPath);
 
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setEncryptionSpi(new NoopEncryptionSpi());
+
+        GridTestKernalContext cctx = new GridTestKernalContext(log, cfg);
+
+        cctx.add(new IgnitePluginProcessor(cctx, cfg, Collections.emptyList()));
+        cctx.add(new GridInternalSubscriptionProcessor(cctx));
+        cctx.add(new GridEncryptionManager(cctx));
+
         GridCacheSharedContext<Object, Object> sharedCtx = new GridCacheSharedContext<>(
-            new GridTestKernalContext(log),
+            cctx,
             null,
             null,
             null,
@@ -93,7 +111,7 @@ public class IndexStoragePageMemoryImplTest extends IndexStorageSelfTest {
             () -> true,
             new DataRegionMetricsImpl(new DataRegionConfiguration()),
             PageMemoryImpl.ThrottlingPolicy.DISABLED,
-            null
+            Mockito.mock(CheckpointWriteProgressSupplier.class)
         );
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplNoLoadTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplNoLoadTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplNoLoadTest.java
index 52aff0c..83e1894 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplNoLoadTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplNoLoadTest.java
@@ -18,7 +18,10 @@
 package org.apache.ignite.internal.processors.cache.persistence.pagemem;
 
 import java.io.File;
+import java.util.Collections;
 import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
 import org.apache.ignite.internal.mem.file.MappedFileMemoryProvider;
 import org.apache.ignite.internal.pagemem.FullPageId;
@@ -26,11 +29,16 @@ import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.pagemem.impl.PageMemoryNoLoadSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.persistence.CheckpointLockStateChecker;
+import org.apache.ignite.internal.processors.cache.persistence.CheckpointWriteProgressSupplier;
 import org.apache.ignite.internal.processors.cache.persistence.DataRegionMetricsImpl;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
+import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor;
 import org.apache.ignite.internal.util.lang.GridInClosure3X;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.testframework.junits.GridTestKernalContext;
+import org.mockito.Mockito;
 
 /**
  *
@@ -49,8 +57,18 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest {
 
         DirectMemoryProvider provider = new MappedFileMemoryProvider(log(), memDir);
 
+        IgniteConfiguration cfg = new IgniteConfiguration();
+
+        cfg.setEncryptionSpi(new NoopEncryptionSpi());
+
+        GridTestKernalContext cctx = new GridTestKernalContext(log, cfg);
+
+        cctx.add(new IgnitePluginProcessor(cctx, cfg, Collections.emptyList()));
+        cctx.add(new GridInternalSubscriptionProcessor(cctx));
+        cctx.add(new GridEncryptionManager(cctx));
+
         GridCacheSharedContext<Object, Object> sharedCtx = new GridCacheSharedContext<>(
-            new GridTestKernalContext(log),
+            cctx,
             null,
             null,
             null,
@@ -88,7 +106,7 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest {
             },
             new DataRegionMetricsImpl(new DataRegionConfiguration()),
             PageMemoryImpl.ThrottlingPolicy.DISABLED,
-            null
+            Mockito.mock(CheckpointWriteProgressSupplier.class)
         );
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplTest.java
index 000131a..fe79105 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImplTest.java
@@ -30,6 +30,7 @@ import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.failure.NoOpFailureHandler;
 import org.apache.ignite.internal.IgniteFutureTimeoutCheckedException;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
 import org.apache.ignite.internal.mem.IgniteOutOfMemoryException;
 import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider;
@@ -44,8 +45,10 @@ import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDataba
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
 import org.apache.ignite.internal.processors.failure.FailureProcessor;
 import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
+import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor;
 import org.apache.ignite.internal.util.lang.GridInClosure3X;
 import org.apache.ignite.plugin.PluginProvider;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.GridTestKernalContext;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -271,9 +274,13 @@ public class PageMemoryImplTest extends GridCommonAbstractTest {
         IgniteConfiguration igniteCfg = new IgniteConfiguration();
         igniteCfg.setDataStorageConfiguration(new DataStorageConfiguration());
         igniteCfg.setFailureHandler(new NoOpFailureHandler());
+        igniteCfg.setEncryptionSpi(new NoopEncryptionSpi());
 
         GridTestKernalContext kernalCtx = new GridTestKernalContext(new GridTestLog4jLogger(), igniteCfg);
+
         kernalCtx.add(new IgnitePluginProcessor(kernalCtx, igniteCfg, Collections.<PluginProvider>emptyList()));
+        kernalCtx.add(new GridInternalSubscriptionProcessor(kernalCtx));
+        kernalCtx.add(new GridEncryptionManager(kernalCtx));
 
         FailureProcessor failureProc = new FailureProcessor(kernalCtx);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/memtracker/PageMemoryTracker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/memtracker/PageMemoryTracker.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/memtracker/PageMemoryTracker.java
index 661b6c7..09cacfb 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/memtracker/PageMemoryTracker.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/memtracker/PageMemoryTracker.java
@@ -32,6 +32,7 @@ import java.util.concurrent.locks.ReentrantLock;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
@@ -222,9 +223,21 @@ public class PageMemoryTracker implements IgnitePlugin {
 
         pageSize = ctx.igniteConfiguration().getDataStorageConfiguration().getPageSize();
 
+        EncryptionSpi encSpi = ctx.igniteConfiguration().getEncryptionSpi();
+
         pageMemoryMock = Mockito.mock(PageMemory.class);
 
         Mockito.doReturn(pageSize).when(pageMemoryMock).pageSize();
+        Mockito.when(pageMemoryMock.realPageSize(Mockito.anyInt())).then(mock -> {
+            int grpId = (Integer) mock.getArguments()[0];
+
+            if (gridCtx.encryption().groupKey(grpId) == null)
+                return pageSize;
+
+            return pageSize
+                - (encSpi.encryptedSizeNoPadding(pageSize) - pageSize)
+                - encSpi.blockSize() /* For CRC. */;
+        });
 
         GridCacheSharedContext sharedCtx = gridCtx.cache().context();
 


[5/6] ignite git commit: IGNITE-8485: TDE implementation. - Fixes #4167.

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateTxStateHintRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateTxStateHintRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateTxStateHintRecord.java
index 7e53609..fd77728 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateTxStateHintRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageMvccUpdateTxStateHintRecord.java
@@ -50,7 +50,7 @@ public class DataPageMvccUpdateTxStateHintRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         DataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.updateTxState(pageAddr, itemId, pageMem.pageSize(), txState);
+        io.updateTxState(pageAddr, itemId, pageMem.realPageSize(groupId()), txState);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageRemoveRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageRemoveRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageRemoveRecord.java
index f7776be..abc84ea 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageRemoveRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageRemoveRecord.java
@@ -53,7 +53,7 @@ public class DataPageRemoveRecord extends PageDeltaRecord {
         throws IgniteCheckedException {
         AbstractDataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.removeRow(pageAddr, itemId, pageMem.pageSize());
+        io.removeRow(pageAddr, itemId, pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageUpdateRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageUpdateRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageUpdateRecord.java
index ed469a4..6f5d8fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageUpdateRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/DataPageUpdateRecord.java
@@ -71,7 +71,7 @@ public class DataPageUpdateRecord extends PageDeltaRecord {
 
         AbstractDataPageIO io = PageIO.getPageIO(pageAddr);
 
-        io.updateRow(pageAddr, itemId, pageMem.pageSize(), payload, null, 0);
+        io.updateRow(pageAddr, itemId, pageMem.realPageSize(groupId()), payload, null, 0);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/InitNewPageRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/InitNewPageRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/InitNewPageRecord.java
index c177a04..d0ba2aa 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/InitNewPageRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/InitNewPageRecord.java
@@ -57,7 +57,7 @@ public class InitNewPageRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         PageIO io = PageIO.getPageIO(ioType, ioVer);
 
-        io.initNewPage(pageAddr, newPageId, pageMem.pageSize());
+        io.initNewPage(pageAddr, newPageId, pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageAddRootRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageAddRootRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageAddRootRecord.java
index 4972155..9bf3aef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageAddRootRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageAddRootRecord.java
@@ -44,7 +44,7 @@ public class MetaPageAddRootRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr);
 
-        io.addRoot(pageAddr, rootId, pageMem.pageSize());
+        io.addRoot(pageAddr, rootId, pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageCutRootRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageCutRootRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageCutRootRecord.java
index 5b896f6..1383a38 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageCutRootRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageCutRootRecord.java
@@ -38,7 +38,7 @@ public class MetaPageCutRootRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr);
 
-        io.cutRoot(pageAddr, pageMem.pageSize());
+        io.cutRoot(pageAddr, pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRecord.java
index ca995bf..7b3f3a9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRecord.java
@@ -76,7 +76,7 @@ public class MetaPageInitRecord extends InitNewPageRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         PageMetaIO io = PageMetaIO.getPageIO(ioType, ioVer);
 
-        io.initNewPage(pageAddr, newPageId, pageMem.pageSize());
+        io.initNewPage(pageAddr, newPageId, pageMem.realPageSize(groupId()));
 
         io.setTreeRoot(pageAddr, treeRoot);
         io.setReuseListRoot(pageAddr, reuseListRoot);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java
index 0d3c155..71ae85d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootInlineRecord.java
@@ -51,7 +51,7 @@ public class MetaPageInitRootInlineRecord extends MetaPageInitRootRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr);
 
-        io.initRoot(pageAddr, rootId, pageMem.pageSize());
+        io.initRoot(pageAddr, rootId, pageMem.realPageSize(groupId()));
         io.setInlineSize(pageAddr, inlineSize);
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java
index 78a7e4f..7eca278 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/MetaPageInitRootRecord.java
@@ -44,7 +44,7 @@ public class MetaPageInitRootRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr);
 
-        io.initRoot(pageAddr, rootId, pageMem.pageSize());
+        io.initRoot(pageAddr, rootId, pageMem.realPageSize(groupId()));
         io.setInlineSize(pageAddr, 0);
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/NewRootInitRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/NewRootInitRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/NewRootInitRecord.java
index 4b8f747..1d78033 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/NewRootInitRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/NewRootInitRecord.java
@@ -71,7 +71,8 @@ public class NewRootInitRecord<L> extends PageDeltaRecord {
 
     /** {@inheritDoc} */
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
-        io.initNewRoot(pageAddr, newRootId, leftChildId, null, rowBytes, rightChildId, pageMem.pageSize(), false);
+        io.initNewRoot(pageAddr, newRootId, leftChildId, null, rowBytes, rightChildId, pageMem.realPageSize(groupId()),
+            false);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListAddPageRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListAddPageRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListAddPageRecord.java
index 6c7fc71..6f877b9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListAddPageRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListAddPageRecord.java
@@ -54,7 +54,7 @@ public class PagesListAddPageRecord extends PageDeltaRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         PagesListNodeIO io = PagesListNodeIO.VERSIONS.forPage(pageAddr);
 
-        int cnt = io.addPage(pageAddr, dataPageId, pageMem.pageSize());
+        int cnt = io.addPage(pageAddr, dataPageId, pageMem.realPageSize(groupId()));
 
         assert cnt >= 0 : cnt;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListInitNewPageRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListInitNewPageRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListInitNewPageRecord.java
index b2512aa..53c23b1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListInitNewPageRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/PagesListInitNewPageRecord.java
@@ -76,11 +76,11 @@ public class PagesListInitNewPageRecord extends InitNewPageRecord {
     @Override public void applyDelta(PageMemory pageMem, long pageAddr) throws IgniteCheckedException {
         PagesListNodeIO io = PageIO.getPageIO(PageIO.T_PAGE_LIST_NODE, ioVer);
 
-        io.initNewPage(pageAddr, pageId(), pageMem.pageSize());
+        io.initNewPage(pageAddr, pageId(), pageMem.realPageSize(groupId()));
         io.setPreviousId(pageAddr, prevPageId);
 
         if (addDataPageId != 0L) {
-            int cnt = io.addPage(pageAddr, addDataPageId, pageMem.pageSize());
+            int cnt = io.addPage(pageAddr, addDataPageId, pageMem.realPageSize(groupId()));
 
             assert cnt == 0 : cnt;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/TrackingPageDeltaRecord.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/TrackingPageDeltaRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/TrackingPageDeltaRecord.java
index 089eb9a..3f11c58 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/TrackingPageDeltaRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/delta/TrackingPageDeltaRecord.java
@@ -76,7 +76,7 @@ public class TrackingPageDeltaRecord extends PageDeltaRecord {
             pageIdToMark,
             nextSnapshotId,
             lastSuccessfulSnapshotId,
-            pageMem.pageSize());
+            pageMem.realPageSize(groupId()));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAuthenticationProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAuthenticationProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAuthenticationProcessor.java
index ded37e7..d1598cd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAuthenticationProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAuthenticationProcessor.java
@@ -97,9 +97,6 @@ public class IgniteAuthenticationProcessor extends GridProcessorAdapter implemen
     /** Whan the future is done the node is ready for authentication. */
     private final GridFutureAdapter<Void> readyForAuthFut = new GridFutureAdapter<>();
 
-    /** Random is used to get random server node to authentication from client node. */
-    private static final Random RND = new Random(System.currentTimeMillis());
-
     /** Operation mutex. */
     private final Object mux = new Object();
 
@@ -313,18 +310,7 @@ public class IgniteAuthenticationProcessor extends GridProcessorAdapter implemen
                 AuthenticateFuture fut;
 
                 synchronized (mux) {
-                    Collection<ClusterNode> aliveNodes = ctx.discovery().aliveServerNodes();
-
-                    int rndIdx = RND.nextInt(aliveNodes.size()) + 1;
-
-                    int i = 0;
-                    ClusterNode rndNode = null;
-
-                    for (Iterator<ClusterNode> it = aliveNodes.iterator(); i < rndIdx && it.hasNext(); i++)
-                        rndNode = it.next();
-
-                    if (rndNode == null)
-                        assert rndNode != null;
+                    ClusterNode rndNode = U.randomServerNode(ctx);
 
                     fut = new AuthenticateFuture(rndNode.id());
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
index 8bed063..6ab4e67 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
@@ -158,17 +158,6 @@ class ClusterCachesInfo {
     }
 
     /**
-     * @param cacheName Cache name.
-     * @param grpName Group name.
-     * @return Group ID.
-     */
-    private int cacheGroupId(String cacheName, @Nullable String grpName) {
-        assert cacheName != null;
-
-        return grpName != null ? CU.cacheId(grpName) : CU.cacheId(cacheName);
-    }
-
-    /**
      * @param checkConsistency {@code True} if need check cache configurations consistency.
      * @throws IgniteCheckedException If failed.
      */
@@ -363,6 +352,9 @@ class ClusterCachesInfo {
                     "Query parallelism", locAttr.qryParallelism(), rmtAttr.qryParallelism(), true);
             }
         }
+
+        CU.checkAttributeMismatch(log, rmtAttr.cacheName(), rmt, "isEncryptionEnabled",
+            "Cache encrypted", locAttr.isEncryptionEnabled(), rmtAttr.isEncryptionEnabled(), true);
     }
 
     /**
@@ -574,7 +566,8 @@ class ClusterCachesInfo {
                             ccfg,
                             cacheId,
                             req.initiatingNodeId(),
-                            req.deploymentId());
+                            req.deploymentId(),
+                            req.encryptionKey());
 
                         DynamicCacheDescriptor startDesc = new DynamicCacheDescriptor(ctx,
                             ccfg,
@@ -1536,7 +1529,7 @@ class ClusterCachesInfo {
                     ", conflictingCacheName=" + desc.cacheName() + ']';
         }
 
-        int grpId = cacheGroupId(cfg.getName(), cfg.getGroupName());
+        int grpId = CU.cacheGroupId(cfg.getName(), cfg.getGroupName());
 
         if (cfg.getGroupName() != null) {
             if (cacheGroupByName(cfg.getGroupName()) == null) {
@@ -1647,7 +1640,8 @@ class ClusterCachesInfo {
             cfg,
             cacheId,
             nodeId,
-            joinData.cacheDeploymentId());
+            joinData.cacheDeploymentId(),
+            null);
 
         ctx.discovery().setCacheFilter(
             cacheId,
@@ -1761,6 +1755,7 @@ class ClusterCachesInfo {
      * @param cacheId Cache ID.
      * @param rcvdFrom Node ID cache was recived from.
      * @param deploymentId Deployment ID.
+     * @param encKey Encryption key.
      * @return Group descriptor.
      */
     private CacheGroupDescriptor registerCacheGroup(
@@ -1769,7 +1764,8 @@ class ClusterCachesInfo {
         CacheConfiguration<?, ?> startedCacheCfg,
         Integer cacheId,
         UUID rcvdFrom,
-        IgniteUuid deploymentId) {
+        IgniteUuid deploymentId,
+        @Nullable byte[] encKey) {
         if (startedCacheCfg.getGroupName() != null) {
             CacheGroupDescriptor desc = cacheGroupByName(startedCacheCfg.getGroupName());
 
@@ -1780,7 +1776,7 @@ class ClusterCachesInfo {
             }
         }
 
-        int grpId = cacheGroupId(startedCacheCfg.getName(), startedCacheCfg.getGroupName());
+        int grpId = CU.cacheGroupId(startedCacheCfg.getName(), startedCacheCfg.getGroupName());
 
         Map<String, Integer> caches = Collections.singletonMap(startedCacheCfg.getName(), cacheId);
 
@@ -1798,6 +1794,9 @@ class ClusterCachesInfo {
             persistent,
             null);
 
+        if (startedCacheCfg.isEncryptionEnabled())
+            ctx.encryption().beforeCacheGroupStart(grpId, encKey);
+
         if (ctx.cache().context().pageStore() != null)
             ctx.cache().context().pageStore().beforeCacheGroupStart(grpDesc);
 
@@ -1930,6 +1929,9 @@ class ClusterCachesInfo {
             CU.validateCacheGroupsAttributesMismatch(log, cfg, startCfg, "backups", "Backups",
                 cfg.getBackups(), startCfg.getBackups(), true);
         }
+
+        CU.validateCacheGroupsAttributesMismatch(log, cfg, startCfg, "encryptionEnabled", "Encrypted",
+            cfg.isEncryptionEnabled(), startCfg.isEncryptionEnabled(), true);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
index 2b942b0..5b8a89c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
@@ -95,6 +95,9 @@ public class DynamicCacheChangeRequest implements Serializable {
     /** */
     private transient boolean locallyConfigured;
 
+    /** Encryption key. */
+    @Nullable private byte[] encKey;
+
     /**
      * @param reqId Unique request ID.
      * @param cacheName Cache stop name.
@@ -424,6 +427,20 @@ public class DynamicCacheChangeRequest implements Serializable {
         this.disabledAfterStart = disabledAfterStart;
     }
 
+    /**
+     * @param encKey Encryption key.
+     */
+    public void encryptionKey(@Nullable byte[] encKey) {
+        this.encKey = encKey;
+    }
+
+    /**
+     * @return Encryption key.
+     */
+    @Nullable public byte[] encryptionKey() {
+        return encKey;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return "DynamicCacheChangeRequest [cacheName=" + cacheName() +

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
index 01daee2..230320a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
@@ -353,6 +353,13 @@ public class GridCacheAttributes implements Serializable {
     }
 
     /**
+     * @return Is cache encryption enabled.
+     */
+    public boolean isEncryptionEnabled() {
+        return ccfg.isEncryptionEnabled();
+    }
+
+    /**
      * @param obj Object to get class of.
      * @return Class name or {@code null}.
      */
@@ -364,4 +371,4 @@ public class GridCacheAttributes implements Serializable {
     @Override public String toString() {
         return S.toString(GridCacheAttributes.class, this);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index 16e1799..f595ecf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -25,6 +25,7 @@ import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
@@ -61,6 +62,7 @@ import org.apache.ignite.configuration.MemoryConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.events.EventType;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
@@ -136,6 +138,7 @@ import org.apache.ignite.internal.util.F0;
 import org.apache.ignite.internal.util.future.GridCompoundFuture;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
+import org.apache.ignite.internal.util.lang.GridPlainClosure;
 import org.apache.ignite.internal.util.lang.IgniteOutClosureX;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.CIX1;
@@ -149,6 +152,7 @@ import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteClosure;
 import org.apache.ignite.lang.IgniteFuture;
+import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.lifecycle.LifecycleAware;
@@ -598,6 +602,22 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
                 }
             }
         }
+
+        if (cc.isEncryptionEnabled() && !ctx.clientNode()) {
+            if (!CU.isPersistentCache(cc, c.getDataStorageConfiguration())) {
+                throw new IgniteCheckedException("Using encryption is not allowed" +
+                    " for not persistent cache  [cacheName=" + cc.getName() + ", groupName=" + cc.getGroupName() +
+                    ", cacheType=" + cacheType + "]");
+            }
+
+            EncryptionSpi encSpi = c.getEncryptionSpi();
+
+            if (encSpi == null) {
+                throw new IgniteCheckedException("EncryptionSpi should be configured to use encrypted cache " +
+                    "[cacheName=" + cc.getName() + ", groupName=" + cc.getGroupName() +
+                    ", cacheType=" + cacheType + "]");
+            }
+        }
     }
 
     /**
@@ -903,6 +923,15 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
                 ", configuredAtomicityMode=" + cfg.getAtomicityMode() +
                 ", storedAtomicityMode=" + cfgFromStore.getAtomicityMode() + "]");
         }
+
+        boolean staticCfgVal = cfg.isEncryptionEnabled();
+
+        boolean storedVal = cfgFromStore.isEncryptionEnabled();
+
+        if (storedVal != staticCfgVal) {
+            throw new IgniteCheckedException("Encrypted flag value differs. Static config value is '" + staticCfgVal +
+                "' and value stored on the disk is '" + storedVal + "'");
+        }
     }
 
     /**
@@ -1311,7 +1340,8 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
                 ", mode=" + cfg.getCacheMode() +
                 ", atomicity=" + cfg.getAtomicityMode() +
                 ", backups=" + cfg.getBackups() +
-                ", mvcc=" + cacheCtx.mvccEnabled() +']');
+                ", mvcc=" + cacheCtx.mvccEnabled() +']' +
+                ", encryptionEnabled=" + cfg.isEncryptionEnabled() +']');
         }
     }
 
@@ -3107,7 +3137,9 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
         if (checkThreadTx)
             checkEmptyTransactions();
 
-        try {
+        GridPlainClosure<Collection<byte[]>, IgniteInternalFuture<Boolean>> startCacheClsr = (grpKeys) -> {
+            assert ccfg == null || !ccfg.isEncryptionEnabled() || !grpKeys.isEmpty();
+
             DynamicCacheChangeRequest req = prepareCacheChangeRequest(
                 ccfg,
                 cacheName,
@@ -3117,7 +3149,8 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
                 failIfExists,
                 failIfNotStarted,
                 false,
-                null);
+                null,
+                ccfg != null && ccfg.isEncryptionEnabled() ? grpKeys.iterator().next() : null);
 
             if (req != null) {
                 if (req.clientStartOnly())
@@ -3127,6 +3160,16 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
             }
             else
                 return new GridFinishedFuture<>();
+        };
+
+        try {
+            if (ccfg != null && ccfg.isEncryptionEnabled()) {
+                ctx.encryption().checkEncryptedCacheSupported();
+
+                return generateEncryptionKeysAndStartCacheAfter(1, startCacheClsr);
+            }
+
+            return startCacheClsr.apply(Collections.EMPTY_SET);
         }
         catch (Exception e) {
             return new GridFinishedFuture<>(e);
@@ -3134,6 +3177,48 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
     }
 
     /**
+     * Send {@code GenerateEncryptionKeyRequest} and execute {@code after} closure if succeed.
+     *
+     * @param keyCnt Count of keys to generate.
+     * @param after Closure to execute after encryption keys would be generated.
+     */
+    private IgniteInternalFuture<Boolean> generateEncryptionKeysAndStartCacheAfter(int keyCnt,
+        GridPlainClosure<Collection<byte[]>, IgniteInternalFuture<Boolean>> after) {
+        IgniteInternalFuture<Collection<byte[]>> genEncKeyFut = ctx.encryption().generateKeys(keyCnt);
+
+        GridFutureAdapter<Boolean> res = new GridFutureAdapter<>();
+
+        genEncKeyFut.listen(new IgniteInClosure<IgniteInternalFuture<Collection<byte[]>>>() {
+            @Override public void apply(IgniteInternalFuture<Collection<byte[]>> fut) {
+                try {
+                    Collection<byte[]> grpKeys = fut.result();
+
+                    if (F.size(grpKeys, F.alwaysTrue()) != keyCnt)
+                        res.onDone(false, fut.error());
+
+                    IgniteInternalFuture<Boolean> dynStartCacheFut = after.apply(grpKeys);
+
+                    dynStartCacheFut.listen(new IgniteInClosure<IgniteInternalFuture<Boolean>>() {
+                        @Override public void apply(IgniteInternalFuture<Boolean> fut) {
+                            try {
+                                res.onDone(fut.get(), fut.error());
+                            }
+                            catch (IgniteCheckedException e) {
+                                res.onDone(false, e);
+                            }
+                        }
+                    });
+                }
+                catch (Exception e) {
+                    res.onDone(false, e);
+                }
+            }
+        });
+
+        return res;
+    }
+
+    /**
      * @param startReqs Start requests.
      * @param cachesToClose Cache tp close.
      * @return Future for cache change operation.
@@ -3167,7 +3252,7 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
      * @param disabledAfterStart If true, cache proxies will be only activated after {@link #restartProxies()}.
      * @return Future that will be completed when all caches are deployed.
      */
-    public IgniteInternalFuture<?> dynamicStartCaches(Collection<CacheConfiguration> ccfgList, boolean failIfExists,
+    public IgniteInternalFuture<Boolean> dynamicStartCaches(Collection<CacheConfiguration> ccfgList, boolean failIfExists,
         boolean checkThreadTx, boolean disabledAfterStart) {
         return dynamicStartCachesByStoredConf(
             ccfgList.stream().map(StoredCacheData::new).collect(Collectors.toList()),
@@ -3186,7 +3271,7 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
      * @param disabledAfterStart If true, cache proxies will be only activated after {@link #restartProxies()}.
      * @return Future that will be completed when all caches are deployed.
      */
-    public IgniteInternalFuture<?> dynamicStartCachesByStoredConf(
+    public IgniteInternalFuture<Boolean> dynamicStartCachesByStoredConf(
         Collection<StoredCacheData> storedCacheDataList,
         boolean failIfExists,
         boolean checkThreadTx,
@@ -3194,11 +3279,15 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
         if (checkThreadTx)
             checkEmptyTransactions();
 
-        List<DynamicCacheChangeRequest> srvReqs = null;
-        Map<String, DynamicCacheChangeRequest> clientReqs = null;
+        GridPlainClosure<Collection<byte[]>, IgniteInternalFuture<Boolean>> startCacheClsr = (grpKeys) -> {
+            List<DynamicCacheChangeRequest> srvReqs = null;
+            Map<String, DynamicCacheChangeRequest> clientReqs = null;
+
+            Iterator<byte[]> grpKeysIter = grpKeys.iterator();
 
-        try {
             for (StoredCacheData ccfg : storedCacheDataList) {
+                assert !ccfg.config().isEncryptionEnabled() || grpKeysIter.hasNext();
+
                 DynamicCacheChangeRequest req = prepareCacheChangeRequest(
                     ccfg.config(),
                     ccfg.config().getName(),
@@ -3208,7 +3297,8 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
                     failIfExists,
                     true,
                     disabledAfterStart,
-                    ccfg.queryEntities());
+                    ccfg.queryEntities(),
+                    ccfg.config().isEncryptionEnabled() ? grpKeysIter.next() : null);
 
                 if (req != null) {
                     if (req.clientStartOnly()) {
@@ -3225,16 +3315,14 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
                     }
                 }
             }
-        }
-        catch (Exception e) {
-            return new GridFinishedFuture<>(e);
-        }
 
-        if (srvReqs != null || clientReqs != null) {
+            if (srvReqs == null && clientReqs == null)
+                return new GridFinishedFuture<>();
+
             if (clientReqs != null && srvReqs == null)
                 return startClientCacheChange(clientReqs, null);
 
-            GridCompoundFuture<?, ?> compoundFut = new GridCompoundFuture<>();
+            GridCompoundFuture<?, Boolean> compoundFut = new GridCompoundFuture<>();
 
             for (DynamicCacheStartFuture fut : initiateCacheChanges(srvReqs))
                 compoundFut.add((IgniteInternalFuture)fut);
@@ -3248,9 +3336,16 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
             compoundFut.markInitialized();
 
             return compoundFut;
+        };
+
+        int encGrpCnt = 0;
+
+        for (StoredCacheData ccfg : storedCacheDataList) {
+            if (ccfg.config().isEncryptionEnabled())
+                encGrpCnt++;
         }
-        else
-            return new GridFinishedFuture<>();
+
+        return generateEncryptionKeysAndStartCacheAfter(encGrpCnt, startCacheClsr);
     }
 
     /** Resolve cache type for input cacheType */
@@ -4539,6 +4634,7 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
      * @param failIfNotStarted If {@code true} fails if cache is not started.
      * @param disabledAfterStart If true, cache proxies will be only activated after {@link #restartProxies()}.
      * @param qryEntities Query entities.
+     * @param encKey Encryption key.
      * @return Request or {@code null} if cache already exists.
      * @throws IgniteCheckedException if some of pre-checks failed
      * @throws CacheExistsException if cache exists and failIfExists flag is {@code true}
@@ -4552,7 +4648,8 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
         boolean failIfExists,
         boolean failIfNotStarted,
         boolean disabledAfterStart,
-        @Nullable Collection<QueryEntity> qryEntities
+        @Nullable Collection<QueryEntity> qryEntities,
+        @Nullable byte[] encKey
     ) throws IgniteCheckedException {
         DynamicCacheDescriptor desc = cacheDescriptor(cacheName);
 
@@ -4564,6 +4661,8 @@ public class GridCacheProcessor extends GridProcessorAdapter implements Metastor
 
         req.disabledAfterStart(disabledAfterStart);
 
+        req.encryptionKey(encKey);
+
         if (ccfg != null) {
             cloneCheckSerializable(ccfg);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
index 91a449f..c316621 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
@@ -58,6 +58,7 @@ import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -1149,6 +1150,17 @@ public class GridCacheUtils {
     }
 
     /**
+     * @param cacheName Cache name.
+     * @param grpName Group name.
+     * @return Group ID.
+     */
+    public static int cacheGroupId(String cacheName, @Nullable String grpName) {
+        assert cacheName != null;
+
+        return grpName != null ? CU.cacheId(grpName) : CU.cacheId(cacheName);
+    }
+
+    /**
      * @param cfg Grid configuration.
      * @param cacheName Cache name.
      * @return {@code True} in this is IGFS data or meta cache.
@@ -1900,6 +1912,17 @@ public class GridCacheUtils {
     }
 
     /**
+     * @param pageSize Page size.
+     * @param encSpi Encryption spi.
+     * @return Page size without encryption overhead.
+     */
+    public static int encryptedPageSize(int pageSize, EncryptionSpi encSpi) {
+        return pageSize
+            - (encSpi.encryptedSizeNoPadding(pageSize) - pageSize)
+            - encSpi.blockSize(); /* For CRC. */
+    }
+
+    /**
      * @param sctx Shared context.
      * @param cacheIds Cache ids.
      * @return First partitioned cache or {@code null} in case no partitioned cache ids are in list.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
index a968737..0182c8a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
@@ -3139,7 +3139,8 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager
 
             DataPageIO iox = (DataPageIO)io;
 
-            int offset = iox.getPayloadOffset(pageAddr, itemId, grp.dataRegion().pageMemory().pageSize(), MVCC_INFO_SIZE);
+            int offset = iox.getPayloadOffset(pageAddr, itemId,
+                grp.dataRegion().pageMemory().realPageSize(grp.groupId()), MVCC_INFO_SIZE);
 
             long newCrd = iox.newMvccCoordinator(pageAddr, offset);
             long newCntr = iox.newMvccCounter(pageAddr, offset);
@@ -3168,8 +3169,8 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager
 
             DataPageIO iox = (DataPageIO)io;
 
-            int pageSize = grp.dataRegion().pageMemory().pageSize();
-            int offset = iox.getPayloadOffset(pageAddr, itemId, pageSize, MVCC_INFO_SIZE);
+            int offset = iox.getPayloadOffset(pageAddr, itemId,
+                grp.dataRegion().pageMemory().realPageSize(grp.groupId()), MVCC_INFO_SIZE);
 
             long crd = iox.mvccCoordinator(pageAddr, offset);
             long cntr = iox.mvccCounter(pageAddr, offset);
@@ -3222,7 +3223,8 @@ public class IgniteCacheOffheapManagerImpl implements IgniteCacheOffheapManager
 
             DataPageIO iox = (DataPageIO)io;
 
-            int offset = iox.getPayloadOffset(pageAddr, itemId, grp.dataRegion().pageMemory().pageSize(), MVCC_INFO_SIZE);
+            int offset = iox.getPayloadOffset(pageAddr, itemId,
+                grp.dataRegion().pageMemory().realPageSize(grp.groupId()), MVCC_INFO_SIZE);
 
             long crd = iox.mvccCoordinator(pageAddr, offset);
             long cntr = iox.mvccCounter(pageAddr, offset);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
index f43afa0..2052c36 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
@@ -1052,6 +1052,8 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
 
                     registerCachesFuture = cctx.affinity().onCacheChangeRequest(this, crd, exchActions);
 
+                    cctx.kernalContext().encryption().onDeActivate(cctx.kernalContext());
+
                     if (log.isInfoEnabled()) {
                         log.info("Successfully deactivated data structures, services and caches [" +
                             "nodeId=" + cctx.localNodeId() +

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
index 896c9aa..a659245 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
@@ -577,7 +577,8 @@ public class MvccUtils {
             try{
                 DataPageIO dataIo = DataPageIO.VERSIONS.forPage(pageAddr);
 
-                int offset = dataIo.getPayloadOffset(pageAddr, itemId(link), pageMem.pageSize(), MVCC_INFO_SIZE);
+                int offset = dataIo.getPayloadOffset(pageAddr, itemId(link), pageMem.realPageSize(grpId),
+                    MVCC_INFO_SIZE);
 
                 long mvccCrd = dataIo.mvccCoordinator(pageAddr, offset);
                 long mvccCntr = dataIo.mvccCounter(pageAddr, offset);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
index 574e6d5..8b44ff6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/CacheDataRowAdapter.java
@@ -155,7 +155,7 @@ public class CacheDataRowAdapter implements CacheDataRow {
 
                     DataPagePayload data = io.readPayload(pageAddr,
                         itemId(nextLink),
-                        pageMem.pageSize());
+                        pageMem.realPageSize(grpId));
 
                     nextLink = data.nextLink();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStructure.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStructure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStructure.java
index 0177407..c23a970 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStructure.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStructure.java
@@ -387,10 +387,10 @@ public abstract class DataStructure implements PageLockListener {
     }
 
     /**
-     * @return Page size.
+     * @return Page size without encryption overhead.
      */
-    protected final int pageSize() {
-        return pageMem.pageSize();
+    protected int pageSize() {
+        return pageMem.realPageSize(grpId);
     }
 
     @Override public void onBeforeWriteLock(int cacheId, long pageId, long page) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
index 1d048c0..e4a385f 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
@@ -1430,6 +1430,9 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
             grpIds.add(tup.get1().groupId());
 
             pageMem.onCacheGroupDestroyed(tup.get1().groupId());
+
+            if (tup.get2())
+                cctx.kernalContext().encryption().onCacheGroupDestroyed(gctx.groupId());
         }
 
         Collection<IgniteInternalFuture<Void>> clearFuts = new ArrayList<>(destroyed.size());

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
index 801703b..c6f8415 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
@@ -482,8 +482,6 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple
             try {
                 final long curAddr = pageMem.writeLock(grpId, curId, curPage);
 
-                int pageSize = pageMem.pageSize();
-
                 assert curAddr != 0;
 
                 try {
@@ -492,12 +490,12 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple
                     if (init) {
                         partCntrIo = PagePartitionCountersIO.VERSIONS.latest();
 
-                        partCntrIo.initNewPage(curAddr, curId, pageSize);
+                        partCntrIo.initNewPage(curAddr, curId, pageMem.realPageSize(grpId));
                     }
                     else
                         partCntrIo = PageIO.getPageIO(curAddr);
 
-                    written += partCntrIo.writeCacheSizes(pageSize, curAddr, data, written);
+                    written += partCntrIo.writeCacheSizes(pageMem.realPageSize(grpId), curAddr, data, written);
 
                     nextId = partCntrIo.getNextCountersPageId(curAddr);
 
@@ -727,7 +725,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple
                 if (PageIO.getType(pageAddr) != PageIO.T_META) {
                     PageMetaIO pageIO = PageMetaIO.VERSIONS.latest();
 
-                    pageIO.initNewPage(pageAddr, metaId, pageMem.pageSize());
+                    pageIO.initNewPage(pageAddr, metaId, pageMem.realPageSize(grpId));
 
                     metastoreRoot = pageMem.allocatePage(grpId, PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX);
                     reuseListRoot = pageMem.allocatePage(grpId, PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX);
@@ -1464,7 +1462,7 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple
                     if (PageIO.getType(pageAddr) != PageIO.T_PART_META) {
                         PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.latest();
 
-                        io.initNewPage(pageAddr, partMetaId, pageMem.pageSize());
+                        io.initNewPage(pageAddr, partMetaId, pageMem.realPageSize(grpId));
 
                         treeRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA);
                         reuseListRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA);
@@ -1478,8 +1476,10 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple
                         io.setReuseListRoot(pageAddr, reuseListRoot);
                         io.setPendingTreeRoot(pageAddr, pendingTreeRoot);
 
-                        if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null))
-                            wal.log(new PageSnapshot(new FullPageId(partMetaId, grpId), pageAddr, pageMem.pageSize()));
+                        if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null)) {
+                            wal.log(new PageSnapshot(new FullPageId(partMetaId, grpId), pageAddr,
+                                pageMem.pageSize(), pageMem.realPageSize(grpId)));
+                        }
 
                         allocated = true;
                     }
@@ -1508,8 +1508,11 @@ public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl imple
 
                             io.setPendingTreeRoot(pageAddr, pendingTreeRoot);
 
-                            if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null))
-                                wal.log(new PageSnapshot(new FullPageId(partMetaId, grpId), pageAddr, pageMem.pageSize()));
+                            if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal,
+                                null)) {
+                                wal.log(new PageSnapshot(new FullPageId(partMetaId, grpId), pageAddr,
+                                    pageMem.pageSize(), pageMem.realPageSize(grpId)));
+                            }
 
                             pendingTreeAllocated = true;
                         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIO.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIO.java
new file mode 100644
index 0000000..008a728
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIO.java
@@ -0,0 +1,371 @@
+/*
+ * 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.ignite.internal.processors.cache.persistence.file;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
+import org.apache.ignite.internal.processors.cache.persistence.wal.crc.PureJavaCrc32;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+
+/**
+ * Implementation of {@code FileIO} that supports encryption(decryption) of pages written(readed) to(from) file.
+ *
+ * @see EncryptedFileIOFactory
+ */
+public class EncryptedFileIO implements FileIO {
+    /**
+     * Underlying file.
+     */
+    private final FileIO plainFileIO;
+
+    /**
+     * Group id.
+     */
+    private final int groupId;
+
+    /**
+     * Size of plain data page in bytes.
+     */
+    private final int pageSize;
+
+    /**
+     * Size of file header in bytes.
+     */
+    private final int headerSize;
+
+    /**
+     * Shared database manager.
+     */
+    private final GridEncryptionManager encMgr;
+
+    /**
+     * Shared database manager.
+     */
+    private final EncryptionSpi encSpi;
+
+    /**
+     * Encryption key.
+     */
+    private Serializable encKey;
+
+    /**
+     * Extra bytes added by encryption.
+     */
+    private final int encryptionOverhead;
+
+    /**
+     * Array of zeroes to fulfill tail of decrypted page.
+     */
+    private final byte[] zeroes;
+
+    /**
+     * @param plainFileIO Underlying file.
+     * @param groupId Group id.
+     * @param pageSize Size of plain data page in bytes.
+     * @param headerSize Size of file header in bytes.
+     * @param encMgr Encryption manager.
+     */
+    EncryptedFileIO(FileIO plainFileIO, int groupId, int pageSize, int headerSize,
+        GridEncryptionManager encMgr, EncryptionSpi encSpi) {
+        this.plainFileIO = plainFileIO;
+        this.groupId = groupId;
+        this.pageSize = pageSize;
+        this.headerSize = headerSize;
+        this.encMgr = encMgr;
+        this.encSpi = encSpi;
+
+        this.encryptionOverhead = pageSize - CU.encryptedPageSize(pageSize, encSpi);
+        this.zeroes =  new byte[encryptionOverhead];
+    }
+
+    /** {@inheritDoc} */
+    @Override public long position() throws IOException {
+        return plainFileIO.position();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void position(long newPosition) throws IOException {
+        plainFileIO.position(newPosition);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int read(ByteBuffer destBuf) throws IOException {
+        assert position() == 0;
+
+        return plainFileIO.read(destBuf);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int readFully(ByteBuffer destBuf) throws IOException {
+        return read(destBuf);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int read(ByteBuffer destBuf, long position) throws IOException {
+        assert destBuf.remaining() >= pageSize;
+        assert position() != 0;
+
+        ByteBuffer encrypted = ByteBuffer.allocate(pageSize);
+
+        int res = plainFileIO.read(encrypted, position);
+
+        if (res < 0)
+            return res;
+
+        if (res != pageSize) {
+            throw new IllegalStateException("Expecting to read whole page[" + pageSize + " bytes], " +
+                "but read only " + res + " bytes");
+        }
+
+        encrypted.rewind();
+
+        decrypt(encrypted, destBuf);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int readFully(ByteBuffer destBuf, long position) throws IOException {
+        assert destBuf.capacity() == pageSize;
+        assert position() != 0;
+
+        ByteBuffer encrypted = ByteBuffer.allocate(pageSize);
+
+        int res = plainFileIO.readFully(encrypted, position);
+
+        if (res < 0)
+            return res;
+
+        if (res != pageSize) {
+            throw new IllegalStateException("Expecting to read whole page[" + pageSize + " bytes], " +
+                "but read only " + res + " bytes");
+        }
+
+        encrypted.rewind();
+
+        decrypt(encrypted, destBuf);
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int read(byte[] buf, int off, int len) throws IOException {
+        throw new UnsupportedOperationException("Encrypted File doesn't support this operation");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int readFully(byte[] buf, int off, int len) throws IOException {
+        return read(buf, off, len);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int write(ByteBuffer srcBuf) throws IOException {
+        assert position() == 0;
+        assert headerSize == srcBuf.capacity();
+
+        return plainFileIO.write(srcBuf);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int writeFully(ByteBuffer srcBuf) throws IOException {
+        return write(srcBuf);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int write(ByteBuffer srcBuf, long position) throws IOException {
+        ByteBuffer encrypted = ByteBuffer.allocate(pageSize);
+
+        encrypt(srcBuf, encrypted);
+
+        encrypted.rewind();
+
+        return plainFileIO.write(encrypted, position);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int writeFully(ByteBuffer srcBuf, long position) throws IOException {
+        ByteBuffer encrypted = ByteBuffer.allocate(pageSize);
+
+        encrypt(srcBuf, encrypted);
+
+        encrypted.rewind();
+
+        return plainFileIO.writeFully(encrypted, position);
+    }
+
+    /**
+     * @param srcBuf Source buffer.
+     * @param res Destination buffer.
+     * @throws IOException If failed.
+     */
+    private void encrypt(ByteBuffer srcBuf, ByteBuffer res) throws IOException {
+        assert position() != 0;
+        assert srcBuf.remaining() >= pageSize;
+        assert tailIsEmpty(srcBuf, PageIO.getType(srcBuf));
+
+        int srcLimit = srcBuf.limit();
+
+        srcBuf.limit(srcBuf.position() + plainDataSize());
+
+        encSpi.encryptNoPadding(srcBuf, key(), res);
+
+        res.rewind();
+
+        storeCRC(res);
+
+        srcBuf.limit(srcLimit);
+        srcBuf.position(srcBuf.position() + encryptionOverhead);
+    }
+
+    /**
+     * @param encrypted Encrypted buffer.
+     * @param destBuf Destination buffer.
+     */
+    private void decrypt(ByteBuffer encrypted, ByteBuffer destBuf) throws IOException {
+        assert encrypted.remaining() >= pageSize;
+        assert encrypted.limit() >= pageSize;
+
+        checkCRC(encrypted);
+
+        encrypted.limit(encryptedDataSize());
+
+        encSpi.decryptNoPadding(encrypted, key(), destBuf);
+
+        destBuf.put(zeroes); //Forcibly purge page buffer tail.
+    }
+
+    /**
+     * Stores CRC in res.
+     *
+     * @param res Destination buffer.
+     */
+    private void storeCRC(ByteBuffer res) {
+        int crc = PureJavaCrc32.calcCrc32(res, encryptedDataSize());
+
+        res.put((byte) (crc >> 24));
+        res.put((byte) (crc >> 16));
+        res.put((byte) (crc >> 8));
+        res.put((byte) crc);
+    }
+
+    /**
+     * Checks encrypted data integrity.
+     *
+     * @param encrypted Encrypted data buffer.
+     */
+    private void checkCRC(ByteBuffer encrypted) throws IOException {
+        int crc = PureJavaCrc32.calcCrc32(encrypted, encryptedDataSize());
+
+        int storedCrc = 0;
+
+        storedCrc |= (int)encrypted.get() << 24;
+        storedCrc |= ((int)encrypted.get() & 0xff) << 16;
+        storedCrc |= ((int)encrypted.get() & 0xff) << 8;
+        storedCrc |= encrypted.get() & 0xff;
+
+        if(crc != storedCrc) {
+            throw new IOException("Content of encrypted page is broken. [StoredCrc=" + storedCrc +
+                ", calculatedCrd=" + crc + "]");
+        }
+
+        encrypted.position(encrypted.position() - (encryptedDataSize() + 4 /* CRC size. */));
+    }
+
+    /**
+     * @return Encrypted data size.
+     */
+    private int encryptedDataSize() {
+        return pageSize - encSpi.blockSize();
+    }
+
+    /**
+     * @return Plain data size.
+     */
+    private int plainDataSize() {
+        return pageSize - encryptionOverhead;
+    }
+
+    /** */
+    private boolean tailIsEmpty(ByteBuffer src, int pageType) {
+        int srcPos = src.position();
+
+        src.position(srcPos + plainDataSize());
+
+        for (int i = 0; i < encryptionOverhead; i++)
+            assert src.get() == 0 : "Tail of src should be empty [i=" + i + ", pageType=" + pageType + "]";
+
+        src.position(srcPos);
+
+        return true;
+    }
+
+    /**
+     * @return Encryption key.
+     */
+    private Serializable key() {
+        if (encKey == null)
+            return encKey = encMgr.groupKey(groupId);
+
+        return encKey;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int write(byte[] buf, int off, int len) throws IOException {
+        throw new UnsupportedOperationException("Encrypted File doesn't support this operation");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int writeFully(byte[] buf, int off, int len) throws IOException {
+        return write(buf, off, len);
+    }
+
+    /** {@inheritDoc} */
+    @Override public MappedByteBuffer map(int sizeBytes) throws IOException {
+        throw new UnsupportedOperationException("Encrypted File doesn't support this operation");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void force() throws IOException {
+        plainFileIO.force();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void force(boolean withMetadata) throws IOException {
+        plainFileIO.force(withMetadata);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long size() throws IOException {
+        return plainFileIO.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clear() throws IOException {
+        plainFileIO.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void close() throws IOException {
+        plainFileIO.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIOFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIOFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIOFactory.java
new file mode 100644
index 0000000..336aab6
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/EncryptedFileIOFactory.java
@@ -0,0 +1,100 @@
+/*
+ * 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.ignite.internal.processors.cache.persistence.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.OpenOption;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
+
+/**
+ * Factory to produce {@code EncryptedFileIO}.
+ */
+public class EncryptedFileIOFactory implements FileIOFactory {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Factory to produce underlying {@code FileIO} instances.
+     */
+    private FileIOFactory plainIOFactory;
+
+    /**
+     * Size of plain data page in bytes.
+     */
+    private int pageSize;
+
+    /**
+     * Size of file header in bytes.
+     */
+    private int headerSize;
+
+    /**
+     * Group id.
+     */
+    private int groupId;
+
+    /**
+     * Encryption manager.
+     */
+    private GridEncryptionManager encMgr;
+
+    /**
+     * Encryption spi.
+     */
+    private EncryptionSpi encSpi;
+
+    /**
+     * @param plainIOFactory Underlying file factory.
+     * @param groupId Group id.
+     * @param pageSize Size of plain data page in bytes.
+     * @param encMgr Encryption manager.
+     */
+    EncryptedFileIOFactory(FileIOFactory plainIOFactory, int groupId, int pageSize, GridEncryptionManager encMgr,
+        EncryptionSpi encSpi) {
+        this.plainIOFactory = plainIOFactory;
+        this.groupId = groupId;
+        this.pageSize = pageSize;
+        this.encMgr = encMgr;
+        this.encSpi = encSpi;
+    }
+
+    /** {@inheritDoc} */
+    @Override public FileIO create(File file) throws IOException {
+        FileIO io = plainIOFactory.create(file);
+
+        return new EncryptedFileIO(io, groupId, pageSize, headerSize, encMgr, encSpi);
+    }
+
+    /** {@inheritDoc} */
+    @Override public FileIO create(File file, OpenOption... modes) throws IOException {
+        FileIO io = plainIOFactory.create(file, modes);
+
+        return new EncryptedFileIO(io, groupId, pageSize, headerSize, encMgr, encSpi);
+    }
+
+    /**
+     * Sets size of file header in bytes.
+     *
+     * @param headerSize Size of file header in bytes.
+     */
+    void headerSize(int headerSize) {
+        this.headerSize = headerSize;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
index 110807c..2e07867 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
@@ -235,11 +235,8 @@ public class FilePageStore implements PageStore {
         return fileSize;
     }
 
-    /**
-     * @param delete {@code True} to delete file.
-     * @throws StorageException If failed in case of underlying I/O exception.
-     */
-    public void stop(boolean delete) throws StorageException {
+    /** {@inheritDoc} */
+    @Override public void stop(boolean delete) throws StorageException {
         lock.writeLock().lock();
 
         try {
@@ -264,13 +261,8 @@ public class FilePageStore implements PageStore {
         }
     }
 
-    /**
-     * Truncates and deletes partition file.
-     *
-     * @param tag New partition tag.
-     * @throws StorageException If failed in case of underlying I/O exception.
-     */
-    public void truncate(int tag) throws StorageException {
+    /** {@inheritDoc} */
+    @Override public void truncate(int tag) throws StorageException {
         init();
 
         lock.writeLock().lock();
@@ -298,10 +290,8 @@ public class FilePageStore implements PageStore {
         }
     }
 
-    /**
-     *
-     */
-    public void beginRecover() {
+    /** {@inheritDoc} */
+    @Override public void beginRecover() {
         lock.writeLock().lock();
 
         try {
@@ -312,10 +302,8 @@ public class FilePageStore implements PageStore {
         }
     }
 
-    /**
-     * @throws StorageException If failed in case of underlying I/O exception.
-     */
-    public void finishRecover() throws StorageException {
+    /** {@inheritDoc} */
+    @Override public void finishRecover() throws StorageException {
         lock.writeLock().lock();
 
         try {

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
index fe93d07..2fb1d50 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.cache.persistence.file;
 import java.io.File;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.pagemem.PageIdAllocator;
+import org.apache.ignite.internal.pagemem.store.PageStore;
 import org.apache.ignite.internal.processors.cache.persistence.AllocatedPageTracker;
 
 /**
@@ -32,5 +33,5 @@ public interface FilePageStoreFactory {
      * @param type Data type, can be {@link PageIdAllocator#FLAG_IDX} or {@link PageIdAllocator#FLAG_DATA}.
      * @param file File Page store file.
      */
-    public FilePageStore createPageStore(byte type, File file, AllocatedPageTracker allocatedTracker) throws IgniteCheckedException;
+    PageStore createPageStore(byte type, File file, AllocatedPageTracker allocatedTracker) throws IgniteCheckedException;
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
index 101a33d..c6cd9e5 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
@@ -262,7 +262,7 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
         for (CacheStoreHolder holder : idxCacheStores.values()) {
             holder.idxStore.beginRecover();
 
-            for (FilePageStore partStore : holder.partStores)
+            for (PageStore partStore : holder.partStores)
                 partStore.beginRecover();
         }
     }
@@ -273,7 +273,7 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
             for (CacheStoreHolder holder : idxCacheStores.values()) {
                 holder.idxStore.finishRecover();
 
-                for (FilePageStore partStore : holder.partStores)
+                for (PageStore partStore : holder.partStores)
                     partStore.finishRecover();
             }
         }
@@ -292,7 +292,8 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
                 new File(storeWorkDir, workingDir),
                 cacheId,
                 partitions,
-                tracker
+                tracker,
+                cctx.cacheContext(cacheId) != null && cctx.cacheContext(cacheId).config().isEncryptionEnabled()
             );
 
             CacheStoreHolder old = idxCacheStores.put(cacheId, holder);
@@ -321,9 +322,10 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
         if (!idxCacheStores.containsKey(grpId)) {
             CacheStoreHolder holder = initDir(
                 new File(storeWorkDir, META_STORAGE_NAME),
-                grpId,
-                1,
-                AllocatedPageTracker.NO_OP );
+                    grpId,
+                    1,
+                    AllocatedPageTracker.NO_OP,
+                    false);
 
             CacheStoreHolder old = idxCacheStores.put(grpId, holder);
 
@@ -400,9 +402,7 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
 
         PageStore store = getStore(grpId, partId);
 
-        assert store instanceof FilePageStore : store;
-
-        ((FilePageStore)store).truncate(tag);
+        store.truncate(tag);
     }
 
     /** {@inheritDoc} */
@@ -521,7 +521,8 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
             cacheWorkDir,
             grpDesc.groupId(),
             grpDesc.config().getAffinity().partitions(),
-            allocatedTracker
+            allocatedTracker,
+            ccfg.isEncryptionEnabled()
         );
     }
 
@@ -530,13 +531,15 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
      * @param grpId Group ID.
      * @param partitions Number of partitions.
      * @param allocatedTracker Metrics updater.
+     * @param encrypted {@code True} if this cache encrypted.
      * @return Cache store holder.
      * @throws IgniteCheckedException If failed.
      */
     private CacheStoreHolder initDir(File cacheWorkDir,
         int grpId,
         int partitions,
-        AllocatedPageTracker allocatedTracker) throws IgniteCheckedException {
+        AllocatedPageTracker allocatedTracker,
+        boolean encrypted) throws IgniteCheckedException {
         try {
             boolean dirExisted = checkAndInitCacheWorkDir(cacheWorkDir);
 
@@ -545,19 +548,48 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
             if (dirExisted && !idxFile.exists())
                 grpsWithoutIdx.add(grpId);
 
-            FilePageStoreFactory pageStoreFactory = new FileVersionCheckingFactory(
-                pageStoreFileIoFactory, pageStoreV1FileIoFactory, igniteCfg.getDataStorageConfiguration());
 
-            FilePageStore idxStore =
+            FileIOFactory pageStoreFileIoFactory = this.pageStoreFileIoFactory;
+            FileIOFactory pageStoreV1FileIoFactory = this.pageStoreV1FileIoFactory;
+
+            if (encrypted) {
+                pageStoreFileIoFactory = new EncryptedFileIOFactory(
+                    this.pageStoreFileIoFactory,
+                    grpId,
+                    pageSize(),
+                    cctx.kernalContext().encryption(),
+                    cctx.gridConfig().getEncryptionSpi());
+
+                pageStoreV1FileIoFactory = new EncryptedFileIOFactory(
+                    this.pageStoreV1FileIoFactory,
+                    grpId,
+                    pageSize(),
+                    cctx.kernalContext().encryption(),
+                    cctx.gridConfig().getEncryptionSpi());
+            }
+
+            FileVersionCheckingFactory pageStoreFactory = new FileVersionCheckingFactory(
+                pageStoreFileIoFactory,
+                pageStoreV1FileIoFactory,
+                igniteCfg.getDataStorageConfiguration());
+
+            if (encrypted) {
+                int headerSize = pageStoreFactory.headerSize(pageStoreFactory.latestVersion());
+
+                ((EncryptedFileIOFactory)pageStoreFileIoFactory).headerSize(headerSize);
+                ((EncryptedFileIOFactory)pageStoreV1FileIoFactory).headerSize(headerSize);
+            }
+
+            PageStore idxStore =
             pageStoreFactory.createPageStore(
                 PageMemory.FLAG_IDX,
                 idxFile,
                 allocatedTracker);
 
-            FilePageStore[] partStores = new FilePageStore[partitions];
+            PageStore[] partStores = new PageStore[partitions];
 
             for (int partId = 0; partId < partStores.length; partId++) {
-                FilePageStore partStore =
+                PageStore partStore =
                     pageStoreFactory.createPageStore(
                         PageMemory.FLAG_DATA,
                         getPartitionFile(cacheWorkDir, partId),
@@ -885,7 +917,7 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
         @Nullable IgniteCheckedException aggr) {
         aggr = shutdown(holder.idxStore, cleanFile, aggr);
 
-        for (FilePageStore store : holder.partStores) {
+        for (PageStore store : holder.partStores) {
             if (store != null)
                 aggr = shutdown(store, cleanFile, aggr);
         }
@@ -942,7 +974,7 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
      * @param aggr Aggregating exception.
      * @return Aggregating exception, if error occurred.
      */
-    private IgniteCheckedException shutdown(FilePageStore store, boolean cleanFile, IgniteCheckedException aggr) {
+    private IgniteCheckedException shutdown(PageStore store, boolean cleanFile, IgniteCheckedException aggr) {
         try {
             if (store != null)
                 store.stop(cleanFile);
@@ -978,7 +1010,7 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
         if (partId > PageIdAllocator.MAX_PARTITION_ID)
             throw new IgniteCheckedException("Partition ID is reserved: " + partId);
 
-        FilePageStore store = holder.partStores[partId];
+        PageStore store = holder.partStores[partId];
 
         if (store == null)
             throw new IgniteCheckedException("Failed to get page store for the given partition ID " +
@@ -1038,15 +1070,15 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
      */
     private static class CacheStoreHolder {
         /** Index store. */
-        private final FilePageStore idxStore;
+        private final PageStore idxStore;
 
         /** Partition stores. */
-        private final FilePageStore[] partStores;
+        private final PageStore[] partStores;
 
         /**
          *
          */
-        CacheStoreHolder(FilePageStore idxStore, FilePageStore[] partStores) {
+        public CacheStoreHolder(PageStore idxStore, PageStore[] partStores) {
             this.idxStore = idxStore;
             this.partStores = partStores;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
index bc938a5..af478de 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
@@ -62,14 +62,6 @@ public class FileVersionCheckingFactory implements FilePageStoreFactory {
         this.memCfg = memCfg;
     }
 
-    /**
-     * @param fileIOFactory File IO factory for V1 & V2 page store and for version checking.
-     * @param memCfg Memory configuration.
-     */
-    public FileVersionCheckingFactory(FileIOFactory fileIOFactory, DataStorageConfiguration memCfg) {
-        this(fileIOFactory, fileIOFactory, memCfg);
-    }
-
     /** {@inheritDoc} */
     @Override public FilePageStore createPageStore(
         byte type,
@@ -140,4 +132,21 @@ public class FileVersionCheckingFactory implements FilePageStoreFactory {
                 throw new IllegalArgumentException("Unknown version of file page store: " + ver + " for file [" + file.getAbsolutePath() + "]");
         }
     }
+
+    /**
+     * @param ver Version.
+     * @return Header size.
+     */
+    public int headerSize(int ver) {
+        switch (ver) {
+            case FilePageStore.VERSION:
+                return FilePageStore.HEADER_SIZE;
+
+            case FilePageStoreV2.VERSION:
+                return memCfg.getPageSize();
+
+            default:
+                throw new IllegalArgumentException("Unknown version of file page store.");
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
index 831465d..f1cc32a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
@@ -276,7 +276,9 @@ public abstract class PagesList extends DataStructure {
                     int tailIdx = 0;
 
                     while (tailIdx < tails.length) {
-                        int written = curPage != 0L ? curIo.addTails(pageMem.pageSize(), curAddr, bucket, tails, tailIdx) : 0;
+                        int written = curPage != 0L ?
+                            curIo.addTails(pageMem.realPageSize(grpId), curAddr, bucket, tails, tailIdx) :
+                            0;
 
                         if (written == 0) {
                             if (nextPageId == 0L) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java
index 556d997..3981d4d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/metastorage/MetaStorage.java
@@ -361,6 +361,7 @@ public class MetaStorage implements DbCheckpointListener, ReadOnlyMetastorage, R
                         // Initialize new page.
                         PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.latest();
 
+                        //MetaStorage never encrypted so realPageSize == pageSize.
                         io.initNewPage(pageAddr, partMetaId, pageMem.pageSize());
 
                         treeRoot = pageMem.allocatePage(METASTORAGE_CACHE_ID, partId, PageMemory.FLAG_DATA);
@@ -537,6 +538,7 @@ public class MetaStorage implements DbCheckpointListener, ReadOnlyMetastorage, R
                     try {
                         SimpleDataPageIO io = (SimpleDataPageIO)ioVersions().forPage(pageAddr);
 
+                        //MetaStorage never encrypted so realPageSize == pageSize.
                         DataPagePayload data = io.readPayload(pageAddr, itemId(nextLink), pageMem.pageSize());
 
                         nextLink = data.nextLink();


[2/6] ignite git commit: IGNITE-8485: TDE implementation. - Fixes #4167.

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/spi/encryption/KeystoreEncryptionSpiSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/encryption/KeystoreEncryptionSpiSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/encryption/KeystoreEncryptionSpiSelfTest.java
new file mode 100644
index 0000000..dd3b164
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/spi/encryption/KeystoreEncryptionSpiSelfTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.ignite.spi.encryption;
+
+import java.nio.ByteBuffer;
+import junit.framework.TestCase;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.jetbrains.annotations.NotNull;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.ignite.internal.encryption.AbstractEncryptionTest.KEYSTORE_PASSWORD;
+import static org.apache.ignite.internal.encryption.AbstractEncryptionTest.KEYSTORE_PATH;
+
+/** */
+public class KeystoreEncryptionSpiSelfTest extends TestCase {
+    /** @throws Exception If failed. */
+    public void testCantStartWithEmptyParam() throws Exception {
+        GridTestUtils.assertThrowsWithCause(() -> {
+            EncryptionSpi encSpi = new KeystoreEncryptionSpi();
+
+            encSpi.spiStart("default");
+        }, IgniteException.class);
+    }
+
+    /** @throws Exception If failed. */
+    public void testCantStartWithoutPassword() throws Exception {
+        GridTestUtils.assertThrowsWithCause(() -> {
+            KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi();
+
+            encSpi.setKeyStorePath("/ignite/is/cool/path/doesnt/exists");
+
+            encSpi.spiStart("default");
+        }, IgniteException.class);
+    }
+
+    /** @throws Exception If failed. */
+    public void testCantStartKeystoreDoesntExists() throws Exception {
+        GridTestUtils.assertThrowsWithCause(() -> {
+            KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi();
+
+            encSpi.setKeyStorePath("/ignite/is/cool/path/doesnt/exists");
+            encSpi.setKeyStorePassword(KEYSTORE_PASSWORD.toCharArray());
+
+            encSpi.spiStart("default");
+        }, IgniteException.class);
+    }
+
+    /** @throws Exception If failed. */
+    public void testEncryptDecrypt() throws Exception {
+        EncryptionSpi encSpi = spi();
+
+        KeystoreEncryptionKey k = GridTestUtils.getFieldValue(encSpi, "masterKey");
+        
+        assertNotNull(k);
+        assertNotNull(k.key());
+
+        byte[] plainText = "Just a test string to encrypt!".getBytes(UTF_8);
+        byte[] cipherText = new byte[spi().encryptedSize(plainText.length)];
+
+        encSpi.encrypt(ByteBuffer.wrap(plainText), k, ByteBuffer.wrap(cipherText));
+
+        assertNotNull(cipherText);
+        assertEquals(encSpi.encryptedSize(plainText.length), cipherText.length);
+        
+        byte[] decryptedText = encSpi.decrypt(cipherText, k);
+
+        assertNotNull(decryptedText);
+        assertEquals(plainText.length, decryptedText.length);
+
+        assertEquals(new String(plainText, UTF_8), new String(decryptedText, UTF_8));
+    }
+
+    /** @throws Exception If failed. */
+    public void testKeyEncryptDecrypt() throws Exception {
+        EncryptionSpi encSpi = spi();
+        
+        KeystoreEncryptionKey k = (KeystoreEncryptionKey)encSpi.create();
+
+        assertNotNull(k);
+        assertNotNull(k.key());
+
+        byte[] encGrpKey = encSpi.encryptKey(k);
+
+        assertNotNull(encGrpKey);
+        assertTrue(encGrpKey.length > 0);
+
+        KeystoreEncryptionKey k2 = (KeystoreEncryptionKey)encSpi.decryptKey(encGrpKey);
+
+        assertEquals(k.key(), k2.key());
+    }
+
+    /** */
+    @NotNull private EncryptionSpi spi() throws Exception {
+        KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi();
+
+        encSpi.setKeyStorePath(KEYSTORE_PATH);
+        encSpi.setKeyStorePassword(KEYSTORE_PASSWORD.toCharArray());
+
+        GridTestUtils.invoke(encSpi, "onBeforeStart");
+
+        encSpi.spiStart("default");
+
+        return encSpi;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
index caa292b..73293ce 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
@@ -1555,51 +1555,58 @@ public final class GridTestUtils {
      */
     @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
     @Nullable public static <T> T invoke(Object obj, String mtd, Object... params) throws Exception {
-        // We cannot resolve method by parameter classes due to some of parameters can be null.
-        // Search correct method among all methods collection.
-        for (Method m : obj.getClass().getDeclaredMethods()) {
-            // Filter methods by name.
-            if (!m.getName().equals(mtd))
-                continue;
-
-            if (!areCompatible(params, m.getParameterTypes()))
-                continue;
-
-            try {
-                synchronized (m) {
-                    // Backup accessible field state.
-                    boolean accessible = m.isAccessible();
+        Class<?> cls = obj.getClass();
+        
+        do {
+            // We cannot resolve method by parameter classes due to some of parameters can be null.
+            // Search correct method among all methods collection.
+            for (Method m : cls.getDeclaredMethods()) {
+                // Filter methods by name.
+                if (!m.getName().equals(mtd))
+                    continue;
 
-                    try {
-                        if (!accessible)
-                            m.setAccessible(true);
+                if (!areCompatible(params, m.getParameterTypes()))
+                    continue;
 
-                        return (T)m.invoke(obj, params);
-                    }
-                    finally {
-                        // Recover accessible field state.
-                        if (!accessible)
-                            m.setAccessible(false);
+                try {
+                    synchronized (m) {
+                        // Backup accessible field state.
+                        boolean accessible = m.isAccessible();
+
+                        try {
+                            if (!accessible)
+                                m.setAccessible(true);
+
+                            return (T)m.invoke(obj, params);
+                        }
+                        finally {
+                            // Recover accessible field state.
+                            if (!accessible)
+                                m.setAccessible(false);
+                        }
                     }
                 }
-            }
-            catch (IllegalAccessException e) {
-                throw new RuntimeException("Failed to access method" +
-                    " [obj=" + obj + ", mtd=" + mtd + ", params=" + Arrays.toString(params) + ']', e);
-            }
-            catch (InvocationTargetException e) {
-                Throwable cause = e.getCause();
+                catch (IllegalAccessException e) {
+                    throw new RuntimeException("Failed to access method" +
+                        " [obj=" + obj + ", mtd=" + mtd + ", params=" + Arrays.toString(params) + ']', e);
+                }
+                catch (InvocationTargetException e) {
+                    Throwable cause = e.getCause();
 
-                if (cause instanceof Error)
-                    throw (Error) cause;
+                    if (cause instanceof Error)
+                        throw (Error) cause;
 
-                if (cause instanceof Exception)
-                    throw (Exception) cause;
+                    if (cause instanceof Exception)
+                        throw (Exception) cause;
 
-                throw new RuntimeException("Failed to invoke method)" +
-                    " [obj=" + obj + ", mtd=" + mtd + ", params=" + Arrays.toString(params) + ']', e);
+                    throw new RuntimeException("Failed to invoke method)" +
+                        " [obj=" + obj + ", mtd=" + mtd + ", params=" + Arrays.toString(params) + ']', e);
+                }
             }
-        }
+
+            cls = cls.getSuperclass();
+        } while (cls != Object.class);
+
 
         throw new RuntimeException("Failed to find method" +
             " [obj=" + obj + ", mtd=" + mtd + ", params=" + Arrays.toString(params) + ']');

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index ee0dfa4..13387de 100755
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -839,8 +839,8 @@ public abstract class GridAbstractTest extends TestCase {
      * @return Started grid.
      * @throws Exception If failed.
      */
-    protected Ignite startGrid(String igniteInstanceName) throws Exception {
-        return startGrid(igniteInstanceName, (GridSpringResourceContext)null);
+    protected IgniteEx startGrid(String igniteInstanceName) throws Exception {
+        return (IgniteEx)startGrid(igniteInstanceName, (GridSpringResourceContext)null);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
index 7ce6209..e7876f8 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicWithPersistenceTestSuite.java
@@ -22,6 +22,13 @@ import junit.framework.TestSuite;
 import org.apache.ignite.failure.IoomFailureHandlerTest;
 import org.apache.ignite.failure.SystemWorkersTerminationTest;
 import org.apache.ignite.internal.ClusterBaselineNodesMetricsSelfTest;
+import org.apache.ignite.internal.encryption.EncryptedCacheBigEntryTest;
+import org.apache.ignite.internal.encryption.EncryptedCacheCreateTest;
+import org.apache.ignite.internal.encryption.EncryptedCacheDestroyTest;
+import org.apache.ignite.internal.encryption.EncryptedCacheGroupCreateTest;
+import org.apache.ignite.internal.encryption.EncryptedCacheNodeJoinTest;
+import org.apache.ignite.internal.encryption.EncryptedCachePreconfiguredRestartTest;
+import org.apache.ignite.internal.encryption.EncryptedCacheRestartTest;
 import org.apache.ignite.internal.GridNodeMetricsLogPdsSelfTest;
 import org.apache.ignite.internal.processors.service.ServiceDeploymentOnActivationTest;
 import org.apache.ignite.internal.processors.service.ServiceDeploymentOutsideBaselineTest;
@@ -62,6 +69,14 @@ public class IgniteBasicWithPersistenceTestSuite extends TestSuite {
 
         suite.addTestSuite(GridNodeMetricsLogPdsSelfTest.class);
 
+        suite.addTestSuite(EncryptedCacheBigEntryTest.class);
+        suite.addTestSuite(EncryptedCacheCreateTest.class);
+        suite.addTestSuite(EncryptedCacheDestroyTest.class);
+        suite.addTestSuite(EncryptedCacheGroupCreateTest.class);
+        suite.addTestSuite(EncryptedCacheNodeJoinTest.class);
+        suite.addTestSuite(EncryptedCacheRestartTest.class);
+        suite.addTestSuite(EncryptedCachePreconfiguredRestartTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
index b8ea850..ab2306e 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteKernalSelfTestSuite.java
@@ -53,7 +53,6 @@ import org.apache.ignite.internal.processors.port.GridPortProcessorSelfTest;
 import org.apache.ignite.internal.processors.service.GridServiceClientNodeTest;
 import org.apache.ignite.internal.processors.service.GridServiceContinuousQueryRedeployTest;
 import org.apache.ignite.internal.processors.service.GridServiceDeploymentCompoundFutureSelfTest;
-import org.apache.ignite.internal.processors.service.GridServiceDeploymentExceptionPropagationTest;
 import org.apache.ignite.internal.processors.service.GridServicePackagePrivateSelfTest;
 import org.apache.ignite.internal.processors.service.GridServiceProcessorBatchDeploySelfTest;
 import org.apache.ignite.internal.processors.service.GridServiceProcessorMultiNodeConfigSelfTest;

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiTestSuite.java
index 5de61ae..d5ded38 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiTestSuite.java
@@ -20,6 +20,7 @@ package org.apache.ignite.testsuites;
 import junit.framework.TestSuite;
 import org.apache.ignite.internal.managers.GridManagerLocalMessageListenerSelfTest;
 import org.apache.ignite.internal.managers.GridNoopManagerSelfTest;
+import org.apache.ignite.spi.encryption.KeystoreEncryptionSpiSelfTest;
 
 /**
  * Grid SPI test suite.
@@ -62,6 +63,8 @@ public class IgniteSpiTestSuite extends TestSuite {
         // Local Message Listener tests.
         suite.addTestSuite(GridManagerLocalMessageListenerSelfTest.class);
 
+        suite.addTestSuite(KeystoreEncryptionSpiSelfTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/resources/other_tde_keystore.jks
----------------------------------------------------------------------
diff --git a/modules/core/src/test/resources/other_tde_keystore.jks b/modules/core/src/test/resources/other_tde_keystore.jks
new file mode 100644
index 0000000..6b1f51b
Binary files /dev/null and b/modules/core/src/test/resources/other_tde_keystore.jks differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/test/resources/tde.jks
----------------------------------------------------------------------
diff --git a/modules/core/src/test/resources/tde.jks b/modules/core/src/test/resources/tde.jks
new file mode 100644
index 0000000..1bf532c
Binary files /dev/null and b/modules/core/src/test/resources/tde.jks differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
index 8688c4fbd9..5c2865a 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
@@ -72,7 +72,6 @@ import org.apache.ignite.internal.sql.command.SqlIndexColumn;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.plugin.security.SecurityPermission;
 import org.h2.command.Prepared;
 import org.h2.command.ddl.AlterTableAlterColumn;
@@ -358,7 +357,7 @@ public class DdlStatementsProcessor {
 
                     ctx.query().dynamicTableCreate(cmd.schemaName(), e, cmd.templateName(), cmd.cacheName(),
                         cmd.cacheGroup(), cmd.dataRegionName(), cmd.affinityKey(), cmd.atomicityMode(),
-                        cmd.writeSynchronizationMode(), cmd.backups(), cmd.ifNotExists());
+                        cmd.writeSynchronizationMode(), cmd.backups(), cmd.ifNotExists(), cmd.encrypted());
                 }
             }
             else if (stmt0 instanceof GridSqlDropTable) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
index de86d6a..0da77bb 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java
@@ -84,6 +84,9 @@ public class GridSqlCreateTable extends GridSqlStatement {
     /** Extra WITH-params. */
     private List<String> params;
 
+    /** Encrypted flag. */
+    private boolean encrypted;
+
     /**
      * @return Cache name upon which new cache configuration for this table must be based.
      */
@@ -336,6 +339,20 @@ public class GridSqlCreateTable extends GridSqlStatement {
         this.params = params;
     }
 
+    /**
+     * @return Encrypted flag.
+     */
+    public boolean encrypted() {
+        return encrypted;
+    }
+
+    /**
+     * @param encrypted Encrypted flag.
+     */
+    public void encrypted(boolean encrypted) {
+        this.encrypted = encrypted;
+    }
+
     /** {@inheritDoc} */
     @Override public String getSQL() {
         return null;

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
index a653e7f..856951f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
@@ -514,6 +514,9 @@ public class GridSqlQueryParser {
     public static final String PARAM_DATA_REGION = "DATA_REGION";
 
     /** */
+    private static final String PARAM_ENCRYPTED = "ENCRYPTED";
+
+    /** */
     private final IdentityHashMap<Object, Object> h2ObjToGridObj = new IdentityHashMap<>();
 
     /** */
@@ -1610,6 +1613,11 @@ public class GridSqlQueryParser {
 
                 break;
 
+            case PARAM_ENCRYPTED:
+                res.encrypted(F.isEmpty(val) || Boolean.parseBoolean(val));
+
+                break;
+
             default:
                 throw new IgniteSQLException("Unsupported parameter: " + name, IgniteQueryErrorCode.PARSING);
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/encryption/EncryptedSqlTableTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/encryption/EncryptedSqlTableTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/encryption/EncryptedSqlTableTest.java
new file mode 100644
index 0000000..4e0e3c3
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/encryption/EncryptedSqlTableTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.ignite.internal.processors.cache.encryption;
+
+import java.util.List;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.encryption.EncryptedCacheRestartTest;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** */
+public class EncryptedSqlTableTest extends EncryptedCacheRestartTest {
+    /** {@inheritDoc} */
+    @Override protected void createEncryptedCache(IgniteEx grid0, @Nullable IgniteEx grid1, String cacheName,
+        String cacheGroup, boolean putData) {
+
+        executeSql(grid0, "CREATE TABLE encrypted(ID BIGINT, NAME VARCHAR(10), PRIMARY KEY (ID)) " +
+            "WITH \"ENCRYPTED=true\"");
+        executeSql(grid0, "CREATE INDEX enc0 ON encrypted(NAME)");
+
+        if (putData) {
+            for (int i=0; i<100; i++)
+                executeSql(grid0, "INSERT INTO encrypted(ID, NAME) VALUES(?, ?)", i, "" + i);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void checkData(IgniteEx grid0) {
+        for (int i=0; i<100; i++) {
+            List<List<?>> res = executeSql(grid0, "SELECT NAME FROM encrypted WHERE ID = ?", i);
+
+            assertEquals(1, res.size());
+            assertEquals("" + i, res.get(0).get(0));
+        }
+    }
+
+    /** */
+    private List<List<?>> executeSql(IgniteEx grid, String qry, Object...args) {
+        return grid.context().query().querySqlFields(
+            new SqlFieldsQuery(qry).setSchema("PUBLIC").setArgs(args), true).getAll();
+    }
+
+    /** {@inheritDoc} */
+    @NotNull @Override protected String cacheName() {
+        return "SQL_PUBLIC_ENCRYPTED";
+    }
+
+    /** {@inheritDoc} */
+    @Override protected String keystorePath() {
+        return IgniteUtils.resolveIgnitePath("modules/indexing/src/test/resources/tde.jks").getAbsolutePath();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
index 6ed914c..c97d934 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java
@@ -34,7 +34,6 @@ import java.util.Random;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 import javax.cache.CacheException;
-import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.binary.BinaryObject;
@@ -44,7 +43,6 @@ import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.QueryIndex;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
-import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
 import org.apache.ignite.configuration.DataStorageConfiguration;
@@ -881,7 +879,7 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest {
                 e.setValueType("City");
 
                 queryProcessor(client()).dynamicTableCreate("PUBLIC", e, CacheMode.PARTITIONED.name(), null, null, null,
-                    null, CacheAtomicityMode.ATOMIC, null, 10, false);
+                    null, CacheAtomicityMode.ATOMIC, null, 10, false, false);
 
                 return null;
             }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
index 7c8b2f8..7633d2a 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
@@ -104,6 +104,7 @@ import org.apache.ignite.internal.processors.cache.distributed.replicated.Ignite
 import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQueryEvtsDisabledSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQueryP2PDisabledSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedQuerySelfTest;
+import org.apache.ignite.internal.processors.cache.encryption.EncryptedSqlTableTest;
 import org.apache.ignite.internal.processors.cache.index.BasicIndexTest;
 import org.apache.ignite.internal.processors.cache.index.DuplicateKeyValueClassesSelfTest;
 import org.apache.ignite.internal.processors.cache.index.DynamicIndexClientBasicSelfTest;
@@ -472,6 +473,7 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
         // User operation SQL
         suite.addTestSuite(SqlParserUserSelfTest.class);
         suite.addTestSuite(SqlUserCommandSelfTest.class);
+        suite.addTestSuite(EncryptedSqlTableTest.class);
 
         suite.addTestSuite(ThreadLocalObjectPoolSelfTest.class);
         suite.addTestSuite(H2StatementCacheSelfTest.class);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/indexing/src/test/resources/tde.jks
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/resources/tde.jks b/modules/indexing/src/test/resources/tde.jks
new file mode 100644
index 0000000..1bf532c
Binary files /dev/null and b/modules/indexing/src/test/resources/tde.jks differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/tde.jks
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/tde.jks b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/tde.jks
new file mode 100644
index 0000000..1bf532c
Binary files /dev/null and b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/tde.jks differ

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/IgniteConfigurationParityTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/IgniteConfigurationParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/IgniteConfigurationParityTest.cs
index 1fd8e72..71d2ba0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/IgniteConfigurationParityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/IgniteConfigurationParityTest.cs
@@ -64,7 +64,8 @@ namespace Apache.Ignite.Core.Tests.ApiParity
             "CacheStoreSessionListenerFactories",
             "PlatformConfiguration",
             "ExecutorConfiguration",
-            "CommunicationFailureResolver"
+            "CommunicationFailureResolver",
+            "EncryptionSpi"
         };
 
         /** Properties that are missing on .NET side. */
@@ -97,4 +98,4 @@ namespace Apache.Ignite.Core.Tests.ApiParity
                 KnownMappings);
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 2861c30..354a511 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -36,6 +36,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Discovery.Tcp;
     using Apache.Ignite.Core.Discovery.Tcp.Multicast;
     using Apache.Ignite.Core.Discovery.Tcp.Static;
+    using Apache.Ignite.Core.Encryption.Keystore;
     using Apache.Ignite.Core.Events;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.PersistentStore;
@@ -81,6 +82,7 @@ namespace Apache.Ignite.Core.Tests
             CheckDefaultValueAttributes(new IgniteConfiguration());
             CheckDefaultValueAttributes(new BinaryConfiguration());
             CheckDefaultValueAttributes(new TcpDiscoverySpi());
+            CheckDefaultValueAttributes(new KeystoreEncryptionSpi());
             CheckDefaultValueAttributes(new CacheConfiguration());
             CheckDefaultValueAttributes(new TcpDiscoveryMulticastIpFinder());
             CheckDefaultValueAttributes(new TcpCommunicationSpi());
@@ -132,6 +134,14 @@ namespace Apache.Ignite.Core.Tests
                 Assert.AreEqual(disco.ThreadPriority, resDisco.ThreadPriority);
                 Assert.AreEqual(disco.TopologyHistorySize, resDisco.TopologyHistorySize);
 
+                var enc = (KeystoreEncryptionSpi) cfg.EncryptionSpi;
+                var resEnc = (KeystoreEncryptionSpi) resCfg.EncryptionSpi;
+                
+                Assert.AreEqual(enc.MasterKeyName, resEnc.MasterKeyName);
+                Assert.AreEqual(enc.KeySize, resEnc.KeySize);
+                Assert.AreEqual(enc.KeyStorePath, resEnc.KeyStorePath);
+                Assert.AreEqual(enc.KeyStorePassword, resEnc.KeyStorePassword);
+
                 var ip = (TcpDiscoveryStaticIpFinder) disco.IpFinder;
                 var resIp = (TcpDiscoveryStaticIpFinder) resDisco.IpFinder;
 
@@ -684,6 +694,13 @@ namespace Apache.Ignite.Core.Tests
                     ThreadPriority = 6,
                     TopologyHistorySize = 1234567
                 },
+                EncryptionSpi = new KeystoreEncryptionSpi()
+                {
+                    KeySize = 192,
+                    KeyStorePassword = "love_sex_god",
+                    KeyStorePath = "tde.jks",
+                    MasterKeyName = KeystoreEncryptionSpi.DefaultMasterKeyName
+                },
                 IgniteInstanceName = "gridName1",
                 IgniteHome = IgniteHome.Resolve(null),
                 IncludedEventTypes = EventType.DiscoveryAll,

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 57357da..f5897c8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -161,6 +161,10 @@
     <Compile Include="Discovery\Tcp\Multicast\Package-Info.cs" />
     <Compile Include="Discovery\Tcp\Package-Info.cs" />
     <Compile Include="Discovery\Tcp\Static\Package-Info.cs" />
+    <Compile Include="Encryption\Package-Info.cs" />
+    <Compile Include="Encryption\IEncryptionSpi.cs" />
+    <Compile Include="Encryption\Keystore\Package-Info.cs" />
+    <Compile Include="Encryption\Keystore\KeystoreEncryptionSpi.cs" />
     <Compile Include="Impl\Binary\BinaryArrayEqualityComparer.cs" />
     <Compile Include="Impl\Binary\BinaryProcessor.cs" />
     <Compile Include="Impl\Binary\BinaryReflectiveSerializerInternal.cs" />
@@ -600,4 +604,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
\ No newline at end of file
+</Project>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
index a8925ad..2e0e1a3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs
@@ -161,6 +161,9 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /// <summary> Default value for <see cref="QueryParallelism"/>. </summary>
         public const int DefaultQueryParallelism = 1;
 
+        /// <summary> Default value for <see cref="EncryptionEnabled"/>. </summary>
+        public const bool DefaultEncryptionEnabled = false;
+
         /// <summary>
         /// Gets or sets the cache name.
         /// </summary>
@@ -214,6 +217,7 @@ namespace Apache.Ignite.Core.Cache.Configuration
             RebalanceBatchesPrefetchCount = DefaultRebalanceBatchesPrefetchCount;
             MaxQueryIteratorsCount = DefaultMaxQueryIteratorsCount;
             QueryParallelism = DefaultQueryParallelism;
+            EncryptionEnabled = DefaultEncryptionEnabled;
         }
 
         /// <summary>
@@ -329,6 +333,7 @@ namespace Apache.Ignite.Core.Cache.Configuration
             QueryDetailMetricsSize = reader.ReadInt();
             QueryParallelism = reader.ReadInt();
             SqlSchema = reader.ReadString();
+            EncryptionEnabled = reader.ReadBoolean();
 
             QueryEntities = reader.ReadCollectionRaw(r => new QueryEntity(r, srvVer));
 
@@ -427,6 +432,7 @@ namespace Apache.Ignite.Core.Cache.Configuration
             writer.WriteInt(QueryDetailMetricsSize);
             writer.WriteInt(QueryParallelism);
             writer.WriteString(SqlSchema);
+            writer.WriteBoolean(EncryptionEnabled);
 
             writer.WriteCollectionRaw(QueryEntities, srvVer);
 
@@ -919,5 +925,12 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /// </summary>
         [DefaultValue(DefaultQueryParallelism)]
         public int QueryParallelism { get; set; }
+
+        /// <summary>
+        /// Gets or sets encryption flag.
+        /// Default is false.
+        /// </summary>
+        [DefaultValue(DefaultEncryptionEnabled)]
+        public bool EncryptionEnabled { get; set; }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/IEncryptionSpi.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/IEncryptionSpi.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/IEncryptionSpi.cs
new file mode 100644
index 0000000..c0ea475
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/IEncryptionSpi.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Encryption
+{
+    using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Encryption.Keystore;
+
+    /// <summary>
+    /// Encryption SPI.
+    /// <para />
+    /// Only predefined implementations are supported: 
+    /// <see cref="KeystoreEncryptionSpi"/>
+    /// </summary>
+    [SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces")]
+    public interface IEncryptionSpi
+    {
+        // No-op.
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/KeystoreEncryptionSpi.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/KeystoreEncryptionSpi.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/KeystoreEncryptionSpi.cs
new file mode 100644
index 0000000..e1866f8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/KeystoreEncryptionSpi.cs
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Encryption.Keystore
+{
+    using System.ComponentModel;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// IEncryptionSPI implementation base on JDK provided cipher algorithm implementations.
+    /// </summary>
+    public class KeystoreEncryptionSpi : IEncryptionSpi
+    {
+        /// <summary>
+        /// Default master key name.
+        /// </summary>
+        public const string DefaultMasterKeyName = "ignite.master.key";
+
+        /// <summary>
+        /// Default encryption key size.
+        /// </summary>
+        public const int DefaultKeySize = 256;
+        
+        /// <summary>
+        /// Name of master key in key store.
+        /// </summary>
+        [DefaultValue(DefaultMasterKeyName)]
+        public string MasterKeyName { get; set; }
+        
+        /// <summary>
+        /// Size of encryption key.
+        /// </summary>
+        [DefaultValue(DefaultKeySize)]
+        public int KeySize { get; set; }
+        
+        /// <summary>
+        /// Path to key store.
+        /// </summary>
+        public string KeyStorePath { get; set; }
+
+        /// <summary>
+        /// Key store password.
+        /// </summary>
+        public string KeyStorePassword { get; set; }
+
+        /// <summary>
+        /// Empty constructor.
+        /// </summary>
+        public KeystoreEncryptionSpi()
+        {
+            MasterKeyName = DefaultMasterKeyName;
+            KeySize = DefaultKeySize;
+        }
+        
+        /// <summary>
+        /// Initializes a new instance of the <see cref="KeystoreEncryptionSpi"/> class.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        public KeystoreEncryptionSpi(IBinaryRawReader reader)
+        {
+            MasterKeyName = reader.ReadString();
+            KeySize = reader.ReadInt();
+            KeyStorePath = reader.ReadString();
+
+            var keyStorePassword = reader.ReadCharArray();
+
+            KeyStorePassword = keyStorePassword == null ? null : new string(keyStorePassword);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/Package-Info.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/Package-Info.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/Package-Info.cs
new file mode 100644
index 0000000..8df8b34
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Keystore/Package-Info.cs
@@ -0,0 +1,26 @@
+/*
+* 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.
+*/
+
+#pragma warning disable 1587   // invalid XML comment
+
+/// <summary>
+/// Encryption API based on standart java keystore.
+/// </summary>
+namespace Apache.Ignite.Core.Encryption.Keystore
+{
+    // No-op.
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Package-Info.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Package-Info.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Package-Info.cs
new file mode 100644
index 0000000..37cafdb
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Encryption/Package-Info.cs
@@ -0,0 +1,26 @@
+/*
+* 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.
+*/
+
+#pragma warning disable 1587   // invalid XML comment
+
+/// <summary>
+/// Encryption API.
+/// </summary>
+namespace Apache.Ignite.Core.Encryption
+{
+    // No-op.
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index 315b27d..fc6afb6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -39,6 +39,8 @@ namespace Apache.Ignite.Core
     using Apache.Ignite.Core.Deployment;
     using Apache.Ignite.Core.Discovery;
     using Apache.Ignite.Core.Discovery.Tcp;
+    using Apache.Ignite.Core.Encryption;
+    using Apache.Ignite.Core.Encryption.Keystore;
     using Apache.Ignite.Core.Events;
     using Apache.Ignite.Core.Failure;
     using Apache.Ignite.Core.Impl;
@@ -373,6 +375,26 @@ namespace Apache.Ignite.Core
             else
                 writer.WriteBoolean(false);
 
+            var enc = EncryptionSpi;
+
+            if (enc != null)
+            {
+                writer.WriteBoolean(true);
+
+                var keystoreEnc = enc as KeystoreEncryptionSpi;
+                
+                if (keystoreEnc == null)
+                    throw new InvalidOperationException("Unsupported encryption SPI: " + enc.GetType());
+
+                writer.WriteString(keystoreEnc.MasterKeyName);
+                writer.WriteInt(keystoreEnc.KeySize);
+                writer.WriteString(keystoreEnc.KeyStorePath);
+                writer.WriteCharArray(
+                    keystoreEnc.KeyStorePassword == null ? null : keystoreEnc.KeyStorePassword.ToCharArray());
+            }
+            else
+                writer.WriteBoolean(false);
+
             // Communication config
             var comm = CommunicationSpi;
 
@@ -727,6 +749,9 @@ namespace Apache.Ignite.Core
             // Discovery config
             DiscoverySpi = r.ReadBoolean() ? new TcpDiscoverySpi(r) : null;
 
+            EncryptionSpi = (srvVer.CompareTo(ClientSocket.Ver120) >= 0 && r.ReadBoolean()) ? 
+                new KeystoreEncryptionSpi(r) : null;
+
             // Communication config
             CommunicationSpi = r.ReadBoolean() ? new TcpCommunicationSpi(r) : null;
 
@@ -1055,6 +1080,12 @@ namespace Apache.Ignite.Core
         /// Null for default communication.
         /// </summary>
         public ICommunicationSpi CommunicationSpi { get; set; }
+        
+        /// <summary>
+        /// Gets or sets the encryption service provider.
+        /// Null for disabled encryption.
+        /// </summary>
+        public IEncryptionSpi EncryptionSpi { get; set; }
 
         /// <summary>
         /// Gets or sets a value indicating whether node should start in client mode.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
index 4040610..0a55095 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
@@ -862,6 +862,11 @@
                                             <xs:documentation>Desired query parallelism within a single node.</xs:documentation>
                                         </xs:annotation>
                                     </xs:attribute>
+                                    <xs:attribute name="encryptionEnabled" type="xs:boolean">
+                                        <xs:annotation>
+                                            <xs:documentation>Flag indicating whether cache encryption enabled.</xs:documentation>
+                                        </xs:annotation>
+                                    </xs:attribute>
                                 </xs:complexType>
                             </xs:element>
                         </xs:sequence>
@@ -905,6 +910,38 @@
                         </xs:sequence>
                     </xs:complexType>
                 </xs:element>
+                <xs:element name="encryptionSpi" minOccurs="0">
+                    <xs:annotation>
+                        <xs:documentation>Encryption spi. Null for disabled encryption.</xs:documentation>
+                    </xs:annotation>
+                    <xs:complexType>
+                        <xs:attribute name="masterKeyName" type="xs:string">
+                            <xs:annotation>
+                                <xs:documentation>Master key name</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                        <xs:attribute name="keySize" type="xs:int">
+                            <xs:annotation>
+                                <xs:documentation>Encryption key size.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                        <xs:attribute name="keyStorePath" type="xs:string">
+                            <xs:annotation>
+                                <xs:documentation>Key store path.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                        <xs:attribute name="keyStorePassword" type="xs:string">
+                            <xs:annotation>
+                                <xs:documentation>Key store password.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                        <xs:attribute name="type" type="xs:string" use="required">
+                            <xs:annotation>
+                                <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
+                    </xs:complexType>
+                </xs:element>
                 <xs:element name="discoverySpi" minOccurs="0">
                     <xs:annotation>
                         <xs:documentation>Discovery service provider. Null for default discovery.</xs:documentation>
@@ -999,7 +1036,7 @@
                         <xs:attribute name="forceServerMode" type="xs:boolean">
                             <xs:annotation>
                                 <xs:documentation>
-                                    Whether TcpDiscoverySpi is started in server mode regardless of IgniteConfiguration.ClientMode setting.
+                                    Whether TcpDiscoveryspi is started in server mode regardless of IgniteConfiguration.ClientMode setting.
                                 </xs:documentation>
                             </xs:annotation>
                         </xs:attribute>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/base-enc-cfg.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/base-enc-cfg.xml b/modules/spring/src/test/config/enc/base-enc-cfg.xml
new file mode 100644
index 0000000..ad17584
--- /dev/null
+++ b/modules/spring/src/test/config/enc/base-enc-cfg.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="peerClassLoadingEnabled" value="true"/>
+        <property name="clientMode" ref="clientMode"/>
+
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="ipFinder">
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
+                        <property name="shared" value="false"/>
+                        <property name="addresses">
+                            <list>
+                                <value>127.0.0.1:47500..47509</value>
+                            </list>
+                        </property>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+
+        <property name="dataStorageConfiguration">
+            <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
+                <property name="defaultDataRegionConfiguration">
+                    <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
+                        <property name="maxSize" value="#{10*1024*1024}"/>
+                        <property name="persistenceEnabled" value="true"/>
+                    </bean>
+                </property>
+                <property name="pageSize" value="#{4*1024}"/>
+                <property name="walMode" value="LOG_ONLY"/>
+            </bean>
+        </property>
+
+        <property name="encryptionSpi">
+            <bean class="org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi">
+                <property name="keyStorePath" value="tde.jks"/>
+                <property name="keyStorePassword" value="love_sex_god"/>
+            </bean>
+        </property>
+
+        <property name="cacheConfiguration">
+            <list>
+                <ref bean="cache.cfg" />
+            </list>
+        </property>
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/enc-cache-client.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/enc-cache-client.xml b/modules/spring/src/test/config/enc/enc-cache-client.xml
new file mode 100644
index 0000000..ba4068a
--- /dev/null
+++ b/modules/spring/src/test/config/enc/enc-cache-client.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="cache.cfg" class="org.apache.ignite.configuration.CacheConfiguration">
+        <property name="name" value="encrypted-client"/>
+        <property name="encryptionEnabled" value="true"/>
+    </bean>
+
+    <bean id="clientMode" class="java.lang.Boolean">
+        <constructor-arg value="true"/>
+    </bean>
+
+    <import resource="base-enc-cfg.xml"/>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/enc-cache.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/enc-cache.xml b/modules/spring/src/test/config/enc/enc-cache.xml
new file mode 100644
index 0000000..88b3ed0
--- /dev/null
+++ b/modules/spring/src/test/config/enc/enc-cache.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="cache.cfg" class="org.apache.ignite.configuration.CacheConfiguration">
+        <property name="name" value="encrypted"/>
+        <property name="encryptionEnabled" value="true"/>
+    </bean>
+
+    <bean id="clientMode" class="java.lang.Boolean">
+        <constructor-arg value="false"/>
+    </bean>
+
+    <import resource="base-enc-cfg.xml"/>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/enc-group-2.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/enc-group-2.xml b/modules/spring/src/test/config/enc/enc-group-2.xml
new file mode 100644
index 0000000..60f7031
--- /dev/null
+++ b/modules/spring/src/test/config/enc/enc-group-2.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="cache.cfg" class="org.apache.ignite.configuration.CacheConfiguration">
+        <property name="name" value="encrypted-2"/>
+        <property name="encryptionEnabled" value="true"/>
+        <property name="groupName" value="encrypted-group"/>
+    </bean>
+
+    <bean id="clientMode" class="java.lang.Boolean">
+        <constructor-arg value="false"/>
+    </bean>
+
+    <import resource="base-enc-cfg.xml"/>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/enc-group.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/enc-group.xml b/modules/spring/src/test/config/enc/enc-group.xml
new file mode 100644
index 0000000..33d4659
--- /dev/null
+++ b/modules/spring/src/test/config/enc/enc-group.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="cache.cfg" class="org.apache.ignite.configuration.CacheConfiguration">
+        <property name="name" value="encrypted"/>
+        <property name="encryptionEnabled" value="true"/>
+        <property name="groupName" value="encrypted-group"/>
+    </bean>
+
+    <bean id="clientMode" class="java.lang.Boolean">
+        <constructor-arg value="false"/>
+    </bean>
+
+    <import resource="base-enc-cfg.xml"/>
+</beans>
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/not-encrypted-cache-in-group.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/not-encrypted-cache-in-group.xml b/modules/spring/src/test/config/enc/not-encrypted-cache-in-group.xml
new file mode 100644
index 0000000..a49ddbd
--- /dev/null
+++ b/modules/spring/src/test/config/enc/not-encrypted-cache-in-group.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="cache.cfg" class="org.apache.ignite.configuration.CacheConfiguration">
+        <property name="name" value="encrypted-2"/>
+        <property name="encryptionEnabled" value="false"/>
+        <property name="groupName" value="encrypted-group"/>
+    </bean>
+
+    <bean id="clientMode" class="java.lang.Boolean">
+        <constructor-arg value="false"/>
+    </bean>
+
+    <import resource="base-enc-cfg.xml"/>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/config/enc/not-encrypted-cache.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/config/enc/not-encrypted-cache.xml b/modules/spring/src/test/config/enc/not-encrypted-cache.xml
new file mode 100644
index 0000000..a9478f6
--- /dev/null
+++ b/modules/spring/src/test/config/enc/not-encrypted-cache.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="cache.cfg" class="org.apache.ignite.configuration.CacheConfiguration">
+        <property name="name" value="encrypted"/>
+        <property name="encryptionEnabled" value="false"/>
+    </bean>
+
+    <bean id="clientMode" class="java.lang.Boolean">
+        <constructor-arg value="false"/>
+    </bean>
+
+    <import resource="base-enc-cfg.xml"/>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartClientTest.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartClientTest.java b/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartClientTest.java
new file mode 100644
index 0000000..fa6de21
--- /dev/null
+++ b/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartClientTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.ignite.encryption;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgnitionEx;
+import org.apache.ignite.internal.encryption.EncryptedCacheRestartTest;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.typedef.T2;
+
+/** */
+public class SpringEncryptedCacheRestartClientTest extends EncryptedCacheRestartTest {
+    /** {@inheritDoc} */
+    @Override protected void createEncryptedCache(IgniteEx grid0, IgniteEx grid1, String cacheName, String cacheGroup) {
+        IgniteCache<Long, String> cache = grid0.cache(cacheName());
+
+        for (long i = 0; i < 100; i++)
+            cache.put(i, "" + i);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected T2<IgniteEx, IgniteEx> startTestGrids(boolean clnPersDir) throws Exception {
+        if (clnPersDir)
+            cleanPersistenceDir();
+
+        IgniteEx g0 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-cache.xml").getAbsolutePath(), "grid-0");
+
+        IgniteEx g1 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-cache.xml").getAbsolutePath(), "grid-1");
+
+        IgniteEx client = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-cache-client.xml").getAbsolutePath(), "client");
+
+        g1.cluster().active(true);
+
+        awaitPartitionMapExchange();
+
+        return new T2<>(g1, client);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartTest.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartTest.java b/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartTest.java
new file mode 100644
index 0000000..6488527
--- /dev/null
+++ b/modules/spring/src/test/java/org/apache/ignite/encryption/SpringEncryptedCacheRestartTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.ignite.encryption;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgnitionEx;
+import org.apache.ignite.internal.encryption.EncryptedCacheRestartTest;
+import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionKey;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
+
+/** */
+public class SpringEncryptedCacheRestartTest extends EncryptedCacheRestartTest {
+    /** {@inheritDoc} */
+    @Override protected void createEncryptedCache(IgniteEx grid0, IgniteEx grid1, String cacheName, String cacheGroup) {
+        IgniteCache<Long, String> cache = grid0.cache(cacheName());
+
+        for (long i = 0; i < 100; i++)
+            cache.put(i, "" + i);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected T2<IgniteEx, IgniteEx> startTestGrids(boolean clnPersDir) throws Exception {
+        if (clnPersDir)
+            cleanPersistenceDir();
+
+        IgniteEx g0 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-cache.xml").getAbsolutePath(), "grid-0");
+
+        IgniteEx g1 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-cache.xml").getAbsolutePath(), "grid-1");
+
+        g1.cluster().active(true);
+
+        awaitPartitionMapExchange();
+
+        return new T2<>(g0, g1);
+    }
+
+    /** @throws Exception If failed. */
+    public void testEncryptionKeysEqualsOnThirdNodeJoin() throws Exception {
+        T2<IgniteEx, IgniteEx> g = startTestGrids(true);
+
+        IgniteEx g2 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-group-2.xml").getAbsolutePath(), "grid-2");
+
+        Collection<String> cacheNames = Arrays.asList("encrypted", "encrypted-2");
+
+        for (String cacheName : cacheNames) {
+            IgniteInternalCache<Object, Object> enc = g.get1().cachex(cacheName);
+
+            assertNotNull(enc);
+
+            int grpId = CU.cacheGroupId(enc.name(), enc.configuration().getGroupName());
+
+            KeystoreEncryptionKey key0 = (KeystoreEncryptionKey)g.get1().context().encryption().groupKey(grpId);
+            KeystoreEncryptionKey key1 = (KeystoreEncryptionKey)g.get2().context().encryption().groupKey(grpId);
+            KeystoreEncryptionKey key2 = (KeystoreEncryptionKey)g2.context().encryption().groupKey(grpId);
+
+            assertNotNull(cacheName, key0);
+            assertNotNull(cacheName, key1);
+            assertNotNull(cacheName, key2);
+
+            assertNotNull(cacheName, key0.key());
+            assertNotNull(cacheName, key1.key());
+            assertNotNull(cacheName, key2.key());
+
+            assertEquals(cacheName, key0.key(), key1.key());
+            assertEquals(cacheName, key1.key(), key2.key());
+        }
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateEncryptedCacheGroup() throws Exception {
+        IgniteEx g0 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-group.xml").getAbsolutePath(), "grid-0");
+
+        IgniteEx g1 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-group-2.xml").getAbsolutePath(), "grid-1");
+
+        g1.cluster().active(true);
+
+        awaitPartitionMapExchange();
+
+        IgniteInternalCache<Object, Object> encrypted = g0.cachex("encrypted");
+
+        assertNotNull(encrypted);
+
+        IgniteInternalCache<Object, Object> encrypted2 = g0.cachex("encrypted-2");
+
+        assertNotNull(encrypted2);
+
+        KeystoreEncryptionKey key = (KeystoreEncryptionKey)g0.context().encryption().groupKey(
+            CU.cacheGroupId(encrypted.name(), encrypted.configuration().getGroupName()));
+
+        assertNotNull(key);
+        assertNotNull(key.key());
+
+        KeystoreEncryptionKey key2 = (KeystoreEncryptionKey)g0.context().encryption().groupKey(
+            CU.cacheGroupId(encrypted2.name(), encrypted2.configuration().getGroupName()));
+
+        assertNotNull(key2);
+        assertNotNull(key2.key());
+
+        assertEquals(key.key(), key2.key());
+    }
+
+    /** @throws Exception If failed. */
+    public void testCreateNotEncryptedCacheInEncryptedGroupFails() throws Exception {
+        IgniteEx g0 = (IgniteEx)IgnitionEx.start(
+            IgniteUtils.resolveIgnitePath(
+                "modules/spring/src/test/config/enc/enc-group.xml").getAbsolutePath(), "grid-0");
+
+        assertThrowsWithCause(() -> {
+            try {
+                IgnitionEx.start(IgniteUtils.resolveIgnitePath(
+                    "modules/spring/src/test/config/enc/not-encrypted-cache-in-group.xml").getAbsolutePath(), "grid-1");
+            }
+            catch (IgniteCheckedException e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+
+    /** @throws Exception If failed. */
+    public void testStartWithEncryptedOnDiskPlainInCfg() throws Exception {
+        doTestDiffCfgAndPersistentFlagVal(
+            "modules/spring/src/test/config/enc/enc-cache.xml",
+            "modules/spring/src/test/config/enc/not-encrypted-cache.xml");
+    }
+
+    /** @throws Exception If failed. */
+    public void testStartWithPlainOnDiskEncryptedInCfg() throws Exception {
+        doTestDiffCfgAndPersistentFlagVal(
+            "modules/spring/src/test/config/enc/not-encrypted-cache.xml",
+            "modules/spring/src/test/config/enc/enc-cache.xml");
+    }
+
+    /** */
+    private void doTestDiffCfgAndPersistentFlagVal(String cfg1, String cfg2) throws Exception {
+        cleanPersistenceDir();
+
+        IgniteEx g = (IgniteEx)IgnitionEx.start(IgniteUtils.resolveIgnitePath(cfg1).getAbsolutePath(), "grid-0");
+
+        g.cluster().active(true);
+
+        IgniteCache c = g.cache("encrypted");
+
+        assertNotNull(c);
+
+        stopAllGrids(false);
+
+        assertThrowsWithCause(() -> {
+            try {
+                IgnitionEx.start(IgniteUtils.resolveIgnitePath(cfg2).getAbsolutePath(), "grid-0");
+            }
+            catch (IgniteCheckedException e) {
+                throw new RuntimeException(e);
+            }
+        }, IgniteCheckedException.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java b/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
index 0e590a7..0943d51 100644
--- a/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
+++ b/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
@@ -23,6 +23,8 @@ import org.apache.ignite.cache.spring.GridSpringCacheManagerSelfTest;
 import org.apache.ignite.cache.spring.GridSpringCacheManagerSpringBeanSelfTest;
 import org.apache.ignite.cache.spring.SpringCacheManagerContextInjectionTest;
 import org.apache.ignite.cache.spring.SpringCacheTest;
+import org.apache.ignite.encryption.SpringEncryptedCacheRestartClientTest;
+import org.apache.ignite.encryption.SpringEncryptedCacheRestartTest;
 import org.apache.ignite.spring.injection.IgniteSpringBeanSpringResourceInjectionTest;
 import org.apache.ignite.internal.IgniteSpringBeanTest;
 import org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactorySelfTest;
@@ -93,6 +95,10 @@ public class IgniteSpringTestSuite extends TestSuite {
 
         suite.addTestSuite(SpringCacheTest.class);
 
+        suite.addTestSuite(SpringEncryptedCacheRestartTest.class);
+        suite.addTestSuite(SpringEncryptedCacheRestartClientTest.class);
+
+        //suite.addTestSuite(GridSpringCacheManagerMultiJvmSelfTest.class);
         suite.addTestSuite(GridSpringCacheManagerMultiJvmSelfTest.class);
 
         suite.addTestSuite(GridCommandLineLoaderTest.class);

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/spring/src/test/resources/tde.jks
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/resources/tde.jks b/modules/spring/src/test/resources/tde.jks
new file mode 100644
index 0000000..1bf532c
Binary files /dev/null and b/modules/spring/src/test/resources/tde.jks differ


[4/6] ignite git commit: IGNITE-8485: TDE implementation. - Fixes #4167.

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java
index e49b7e2..55c5fb5 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/pagemem/PageMemoryImpl.java
@@ -81,6 +81,7 @@ import org.apache.ignite.internal.util.OffheapReadWriteLock;
 import org.apache.ignite.internal.util.future.CountDownFuture;
 import org.apache.ignite.internal.util.lang.GridInClosure3X;
 import org.apache.ignite.internal.util.offheap.GridOffHeapOutOfMemoryException;
+import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.jetbrains.annotations.NotNull;
@@ -190,6 +191,9 @@ public class PageMemoryImpl implements PageMemoryEx {
     /** Page size. */
     private final int sysPageSize;
 
+    /** Encrypted page size. */
+    private final int encPageSize;
+
     /** Shared context. */
     private final GridCacheSharedContext<?, ?> ctx;
 
@@ -316,6 +320,8 @@ public class PageMemoryImpl implements PageMemoryEx {
 
         sysPageSize = pageSize + PAGE_OVERHEAD;
 
+        encPageSize = CU.encryptedPageSize(pageSize, ctx.kernalContext().config().getEncryptionSpi());
+
         rwLock = new OffheapReadWriteLock(128);
 
         this.memMetrics = memMetrics;
@@ -484,7 +490,8 @@ public class PageMemoryImpl implements PageMemoryEx {
 
         seg.writeLock().lock();
 
-        boolean isTrackingPage = changeTracker != null && trackingIO.trackingPageFor(pageId, pageSize()) == pageId;
+        boolean isTrackingPage =
+            changeTracker != null && trackingIO.trackingPageFor(pageId, realPageSize(grpId)) == pageId;
 
         try {
             long relPtr = seg.loadedPages.get(
@@ -526,9 +533,9 @@ public class PageMemoryImpl implements PageMemoryEx {
                 // We are inside segment write lock, so no other thread can pin this tracking page yet.
                 // We can modify page buffer directly.
                 if (PageIO.getType(pageAddr) == 0) {
-                    trackingIO.initNewPage(pageAddr, pageId, pageSize());
+                    trackingIO.initNewPage(pageAddr, pageId, realPageSize(grpId));
 
-                    if (!ctx.wal().disabled(fullId.groupId()))
+                    if (!ctx.wal().disabled(fullId.groupId())) {
                         if (!ctx.wal().isAlwaysWriteFullPages())
                             ctx.wal().log(
                                 new InitNewPageRecord(
@@ -538,8 +545,11 @@ public class PageMemoryImpl implements PageMemoryEx {
                                     trackingIO.getVersion(), pageId
                                 )
                             );
-                        else
-                            ctx.wal().log(new PageSnapshot(fullId, absPtr + PAGE_OVERHEAD, pageSize()));
+                        else {
+                            ctx.wal().log(new PageSnapshot(fullId, absPtr + PAGE_OVERHEAD, pageSize(),
+                                realPageSize(fullId.groupId())));
+                        }
+                    }
                 }
             }
 
@@ -947,6 +957,14 @@ public class PageMemoryImpl implements PageMemoryEx {
     }
 
     /** {@inheritDoc} */
+    @Override public int realPageSize(int grpId) {
+        if (ctx.kernalContext().encryption().groupKey(grpId) == null)
+            return pageSize();
+
+        return encPageSize;
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean safeToUpdate() {
         if (segments != null) {
             for (Segment segment : segments)
@@ -1627,7 +1645,7 @@ public class PageMemoryImpl implements PageMemoryEx {
     void beforeReleaseWrite(FullPageId pageId, long ptr, boolean pageWalRec) {
         if (walMgr != null && (pageWalRec || walMgr.isAlwaysWriteFullPages()) && !walMgr.disabled(pageId.groupId())) {
             try {
-                walMgr.log(new PageSnapshot(pageId, ptr, pageSize()));
+                walMgr.log(new PageSnapshot(pageId, ptr, pageSize(), realPageSize(pageId.groupId())));
             }
             catch (IgniteCheckedException e) {
                 // TODO ignite-db.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusIO.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusIO.java
index 5e1cb81..349e877 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/BPlusIO.java
@@ -159,7 +159,7 @@ public abstract class BPlusIO<L> extends PageIO {
 
     /**
      * @param pageAddr Page address.
-     * @param pageSize Page size.
+     * @param pageSize Page size without encryption overhead.
      * @return Max items count.
      */
     public abstract int getMaxCount(long pageAddr, int pageSize);
@@ -331,7 +331,7 @@ public abstract class BPlusIO<L> extends PageIO {
      * @param leftPageAddr Left page address.
      * @param rightPageAddr Right page address.
      * @param emptyBranch We are merging an empty branch.
-     * @param pageSize Page size.
+     * @param pageSize Page size without encryption overhead.
      * @return {@code false} If we were not able to merge.
      * @throws IgniteCheckedException If failed.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java
index 22d2420..ee61e25 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PageIO.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.internal.pagemem.PageIdUtils;
 import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.pagemem.PageUtils;
@@ -293,7 +294,7 @@ public abstract class PageIO {
     }
 
     /**
-     * @param pageAddr Page addres.
+     * @param pageAddr Page address.
      * @return Page type.
      */
     public static int getType(long pageAddr) {
@@ -503,6 +504,8 @@ public abstract class PageIO {
      * @param pageAddr Page address.
      * @param pageId Page ID.
      * @param pageSize Page size.
+     *
+     * @see EncryptionSpi#encryptedSize(int)
      */
     public void initNewPage(long pageAddr, long pageId, int pageSize) {
         setType(pageAddr, getType());

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionCountersIO.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionCountersIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionCountersIO.java
index 68e6e2f..a3e92cf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionCountersIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/PagePartitionCountersIO.java
@@ -107,7 +107,7 @@ public class PagePartitionCountersIO extends PageIO {
     }
 
     /**
-     * @param pageSize Page size.
+     * @param pageSize Page size without encryption overhead.
      * @param pageAddr Page address.
      * @param cacheSizes Serialized cache size items (pairs of cache ID and its size).
      * @return Number of written pairs.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java
index 98c6f1f..1135868 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/util/PageHandler.java
@@ -23,8 +23,6 @@ import org.apache.ignite.internal.pagemem.PageMemory;
 import org.apache.ignite.internal.pagemem.PageSupport;
 import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
 import org.apache.ignite.internal.pagemem.wal.record.delta.InitNewPageRecord;
-import org.apache.ignite.internal.processors.cache.GridCacheSharedManager;
-import org.apache.ignite.internal.processors.cache.GridCacheSharedManagerAdapter;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
 import org.apache.ignite.internal.util.GridUnsafe;
 
@@ -211,7 +209,7 @@ public abstract class PageHandler<X, R> {
 
     /**
      * @param pageMem Page memory.
-     * @param cacheId Cache ID.
+     * @param grpId Group ID.
      * @param pageId Page ID.
      * @param init IO for new page initialization.
      * @param wal Write ahead log.
@@ -220,20 +218,20 @@ public abstract class PageHandler<X, R> {
      */
     public static void initPage(
         PageMemory pageMem,
-        int cacheId,
+        int grpId,
         long pageId,
         PageIO init,
         IgniteWriteAheadLogManager wal,
         PageLockListener lsnr
     ) throws IgniteCheckedException {
-        Boolean res = writePage(pageMem, cacheId, pageId, lsnr, PageHandler.NO_OP, init, wal, null, null, 0, FALSE);
+        Boolean res = writePage(pageMem, grpId, pageId, lsnr, PageHandler.NO_OP, init, wal, null, null, 0, FALSE);
 
         assert res != FALSE;
     }
 
     /**
      * @param pageMem Page memory.
-     * @param cacheId Cache ID.
+     * @param grpId Group ID.
      * @param pageId Page ID.
      * @param lsnr Lock listener.
      * @param h Handler.
@@ -248,7 +246,7 @@ public abstract class PageHandler<X, R> {
      */
     public static <X, R> R writePage(
         PageMemory pageMem,
-        int cacheId,
+        int grpId,
         final long pageId,
         PageLockListener lsnr,
         PageHandler<X, R> h,
@@ -260,9 +258,9 @@ public abstract class PageHandler<X, R> {
         R lockFailed
     ) throws IgniteCheckedException {
         boolean releaseAfterWrite = true;
-        long page = pageMem.acquirePage(cacheId, pageId);
+        long page = pageMem.acquirePage(grpId, pageId);
         try {
-            long pageAddr = writeLock(pageMem, cacheId, pageId, page, lsnr, false);
+            long pageAddr = writeLock(pageMem, grpId, pageId, page, lsnr, false);
 
             if (pageAddr == 0L)
                 return lockFailed;
@@ -272,13 +270,13 @@ public abstract class PageHandler<X, R> {
             try {
                 if (init != null) {
                     // It is a new page and we have to initialize it.
-                    doInitPage(pageMem, cacheId, pageId, page, pageAddr, init, wal);
+                    doInitPage(pageMem, grpId, pageId, page, pageAddr, init, wal);
                     walPlc = FALSE;
                 }
                 else
                     init = PageIO.getPageIO(pageAddr);
 
-                R res = h.run(cacheId, pageId, page, pageAddr, init, walPlc, arg, intArg);
+                R res = h.run(grpId, pageId, page, pageAddr, init, walPlc, arg, intArg);
 
                 ok = true;
 
@@ -287,19 +285,19 @@ public abstract class PageHandler<X, R> {
             finally {
                 assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480
 
-                if (releaseAfterWrite = h.releaseAfterWrite(cacheId, pageId, page, pageAddr, arg, intArg))
-                    writeUnlock(pageMem, cacheId, pageId, page, pageAddr, lsnr, walPlc, ok);
+                if (releaseAfterWrite = h.releaseAfterWrite(grpId, pageId, page, pageAddr, arg, intArg))
+                    writeUnlock(pageMem, grpId, pageId, page, pageAddr, lsnr, walPlc, ok);
             }
         }
         finally {
             if (releaseAfterWrite)
-                pageMem.releasePage(cacheId, pageId, page);
+                pageMem.releasePage(grpId, pageId, page);
         }
     }
 
     /**
      * @param pageMem Page memory.
-     * @param cacheId Cache ID.
+     * @param grpId Group ID.
      * @param pageId Page ID.
      * @param page Page pointer.
      * @param lsnr Lock listener.
@@ -315,7 +313,7 @@ public abstract class PageHandler<X, R> {
      */
     public static <X, R> R writePage(
         PageMemory pageMem,
-        int cacheId,
+        int grpId,
         long pageId,
         long page,
         PageLockListener lsnr,
@@ -327,7 +325,7 @@ public abstract class PageHandler<X, R> {
         int intArg,
         R lockFailed
     ) throws IgniteCheckedException {
-        long pageAddr = writeLock(pageMem, cacheId, pageId, page, lsnr, false);
+        long pageAddr = writeLock(pageMem, grpId, pageId, page, lsnr, false);
 
         if (pageAddr == 0L)
             return lockFailed;
@@ -337,13 +335,13 @@ public abstract class PageHandler<X, R> {
         try {
             if (init != null) {
                 // It is a new page and we have to initialize it.
-                doInitPage(pageMem, cacheId, pageId, page, pageAddr, init, wal);
+                doInitPage(pageMem, grpId, pageId, page, pageAddr, init, wal);
                 walPlc = FALSE;
             }
             else
                 init = PageIO.getPageIO(pageAddr);
 
-            R res = h.run(cacheId, pageId, page, pageAddr, init, walPlc, arg, intArg);
+            R res = h.run(grpId, pageId, page, pageAddr, init, walPlc, arg, intArg);
 
             ok = true;
 
@@ -352,8 +350,8 @@ public abstract class PageHandler<X, R> {
         finally {
             assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480
 
-            if (h.releaseAfterWrite(cacheId, pageId, page, pageAddr, arg, intArg))
-                writeUnlock(pageMem, cacheId, pageId, page, pageAddr, lsnr, walPlc, ok);
+            if (h.releaseAfterWrite(grpId, pageId, page, pageAddr, arg, intArg))
+                writeUnlock(pageMem, grpId, pageId, page, pageAddr, lsnr, walPlc, ok);
         }
     }
 
@@ -408,7 +406,7 @@ public abstract class PageHandler<X, R> {
 
     /**
      * @param pageMem Page memory.
-     * @param cacheId Cache ID.
+     * @param grpId Group ID.
      * @param pageId Page ID.
      * @param page Page pointer.
      * @param pageAddr Page address.
@@ -418,7 +416,7 @@ public abstract class PageHandler<X, R> {
      */
     private static void doInitPage(
         PageMemory pageMem,
-        int cacheId,
+        int grpId,
         long pageId,
         long page,
         long pageAddr,
@@ -427,11 +425,11 @@ public abstract class PageHandler<X, R> {
 
         assert PageIO.getCrc(pageAddr) == 0; //TODO GG-11480
 
-        init.initNewPage(pageAddr, pageId, pageMem.pageSize());
+        init.initNewPage(pageAddr, pageId, pageMem.realPageSize(grpId));
 
         // Here we should never write full page, because it is known to be new.
-        if (isWalDeltaRecordNeeded(pageMem, cacheId, pageId, page, wal, FALSE))
-            wal.log(new InitNewPageRecord(cacheId, pageId,
+        if (isWalDeltaRecordNeeded(pageMem, grpId, pageId, page, wal, FALSE))
+            wal.log(new InitNewPageRecord(grpId, pageId,
                 init.getType(), init.getVersion(), pageId));
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
index 3f35c5f..6d379a9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
@@ -41,6 +41,7 @@ import org.apache.ignite.internal.managers.collision.GridCollisionManager;
 import org.apache.ignite.internal.managers.communication.GridIoManager;
 import org.apache.ignite.internal.managers.deployment.GridDeploymentManager;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.managers.encryption.GridEncryptionManager;
 import org.apache.ignite.internal.managers.eventstorage.GridEventStorageManager;
 import org.apache.ignite.internal.managers.failover.GridFailoverManager;
 import org.apache.ignite.internal.managers.indexing.GridIndexingManager;
@@ -458,6 +459,11 @@ public class StandaloneGridKernalContext implements GridKernalContext {
     }
 
     /** {@inheritDoc} */
+    @Override public GridEncryptionManager encryption() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
     @Override public WorkersRegistry workersRegistry() {
         return null;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
index c33a45b..25432d3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
@@ -42,6 +42,7 @@ import org.apache.ignite.internal.processors.cache.persistence.wal.AbstractWalRe
 import org.apache.ignite.internal.processors.cache.persistence.wal.FileDescriptor;
 import org.apache.ignite.internal.processors.cache.persistence.wal.FileWALPointer;
 import org.apache.ignite.internal.processors.cache.persistence.wal.FileWriteAheadLogManager.ReadFileHandle;
+import org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordDataV1Serializer.EncryptedDataEntry;
 import org.apache.ignite.internal.processors.cache.persistence.wal.WalSegmentTailReachedException;
 import org.apache.ignite.internal.processors.cache.persistence.wal.io.FileInput;
 import org.apache.ignite.internal.processors.cache.persistence.wal.io.SegmentFileInputFactory;
@@ -375,6 +376,8 @@ class StandaloneWalRecordsIterator extends AbstractWalRecordsIterator {
         final IgniteCacheObjectProcessor processor,
         final CacheObjectContext fakeCacheObjCtx,
         final DataEntry dataEntry) throws IgniteCheckedException {
+        if(dataEntry instanceof EncryptedDataEntry)
+            return dataEntry;
 
         final KeyCacheObject key;
         final CacheObject val;

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
index 752777a..2c8f03f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.cache.persistence.wal.serializer;
 import java.io.DataInput;
 import java.io.EOFException;
 import java.io.IOException;
+import java.io.Serializable;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -28,17 +29,21 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.internal.pagemem.FullPageId;
 import org.apache.ignite.internal.pagemem.wal.record.CacheState;
 import org.apache.ignite.internal.pagemem.wal.record.CheckpointRecord;
 import org.apache.ignite.internal.pagemem.wal.record.DataEntry;
 import org.apache.ignite.internal.pagemem.wal.record.DataRecord;
+import org.apache.ignite.internal.pagemem.wal.record.EncryptedRecord;
 import org.apache.ignite.internal.pagemem.wal.record.LazyDataEntry;
 import org.apache.ignite.internal.pagemem.wal.record.MemoryRecoveryRecord;
 import org.apache.ignite.internal.pagemem.wal.record.MetastoreDataRecord;
 import org.apache.ignite.internal.pagemem.wal.record.PageSnapshot;
 import org.apache.ignite.internal.pagemem.wal.record.TxRecord;
 import org.apache.ignite.internal.pagemem.wal.record.WALRecord;
+import org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType;
+import org.apache.ignite.internal.pagemem.wal.record.WalRecordCacheGroupAware;
 import org.apache.ignite.internal.pagemem.wal.record.delta.DataPageInsertFragmentRecord;
 import org.apache.ignite.internal.pagemem.wal.record.delta.DataPageInsertRecord;
 import org.apache.ignite.internal.pagemem.wal.record.delta.DataPageMvccUpdateNewTxStateHintRecord;
@@ -82,6 +87,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.SplitForwardPageRecor
 import org.apache.ignite.internal.pagemem.wal.record.delta.TrackingPageDeltaRecord;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
+import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheOperation;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
@@ -91,11 +97,23 @@ import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusInnerIO;
 import org.apache.ignite.internal.processors.cache.persistence.tree.io.CacheVersionIO;
 import org.apache.ignite.internal.processors.cache.persistence.wal.ByteBufferBackedDataInput;
+import org.apache.ignite.internal.processors.cache.persistence.wal.ByteBufferBackedDataInputImpl;
 import org.apache.ignite.internal.processors.cache.persistence.wal.FileWALPointer;
 import org.apache.ignite.internal.processors.cache.persistence.wal.record.HeaderRecord;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.T3;
+import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType.DATA_RECORD;
+import static org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType.ENCRYPTED_DATA_RECORD;
+import static org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType.ENCRYPTED_RECORD;
+import static org.apache.ignite.internal.processors.cache.GridCacheOperation.READ;
+import static org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.REC_TYPE_SIZE;
+import static org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.putRecordType;
 
 /**
  * Record data V1 serializer.
@@ -107,15 +125,27 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
     /** Cache shared context */
     private final GridCacheSharedContext cctx;
 
-    /** Size of page used for PageMemory regions */
+    /** Size of page used for PageMemory regions. */
     private final int pageSize;
 
+    /** Size of page without encryption overhead. */
+    private final int realPageSize;
+
     /** Cache object processor to reading {@link DataEntry DataEntries} */
     private final IgniteCacheObjectProcessor co;
 
     /** Serializer of {@link TxRecord} records. */
     private TxRecordSerializer txRecordSerializer;
 
+    /** Encryption SPI instance. */
+    private final EncryptionSpi encSpi;
+
+    /** */
+    private static final byte ENCRYPTED = 1;
+
+    /** */
+    private static final byte PLAIN = 0;
+
     /**
      * @param cctx Cache shared context.
      */
@@ -124,10 +154,174 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
         this.txRecordSerializer = new TxRecordSerializer();
         this.co = cctx.kernalContext().cacheObjects();
         this.pageSize = cctx.database().pageSize();
+        this.encSpi = cctx.gridConfig().getEncryptionSpi();
+
+        //This happen on offline WAL iteration(we don't have encryption keys available).
+        if (encSpi != null)
+            this.realPageSize = CU.encryptedPageSize(pageSize, encSpi);
+        else
+            this.realPageSize = pageSize;
     }
 
     /** {@inheritDoc} */
     @Override public int size(WALRecord record) throws IgniteCheckedException {
+        int clSz = plainSize(record);
+
+        if (needEncryption(record))
+            return encSpi.encryptedSize(clSz) + 4 /* groupId */ + 4 /* data size */ + REC_TYPE_SIZE;
+
+        return clSz;
+    }
+
+    /** {@inheritDoc} */
+    @Override public WALRecord readRecord(RecordType type, ByteBufferBackedDataInput in)
+        throws IOException, IgniteCheckedException {
+        if (type == ENCRYPTED_RECORD) {
+            if (encSpi == null) {
+                T2<Integer, RecordType> knownData = skipEncryptedRecord(in, true);
+
+                //This happen on offline WAL iteration(we don't have encryption keys available).
+                return new EncryptedRecord(knownData.get1(), knownData.get2());
+            }
+
+            T3<ByteBufferBackedDataInput, Integer, RecordType> clData = readEncryptedData(in, true);
+
+            //This happen during startup. On first WAL iteration we restore only metastore.
+            //So, no encryption keys available. See GridCacheDatabaseSharedManager#readMetastore
+            if (clData.get1() == null)
+                return new EncryptedRecord(clData.get2(), clData.get3());
+
+            return readPlainRecord(clData.get3(), clData.get1(), true);
+        }
+
+        return readPlainRecord(type, in, false);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
+        if (needEncryption(rec)) {
+            int clSz = plainSize(rec);
+
+            ByteBuffer clData = ByteBuffer.allocate(clSz);
+
+            writePlainRecord(rec, clData);
+
+            clData.rewind();
+
+            writeEncryptedData(((WalRecordCacheGroupAware)rec).groupId(), rec.type(), clData, buf);
+
+            return;
+        }
+
+        writePlainRecord(rec, buf);
+    }
+
+    /**
+     * @param rec Record to check.
+     * @return {@code True} if this record should be encrypted.
+     */
+    private boolean needEncryption(WALRecord rec) {
+        if (!(rec instanceof WalRecordCacheGroupAware))
+            return false;
+
+        return needEncryption(((WalRecordCacheGroupAware)rec).groupId());
+    }
+
+    /**
+     * @param grpId Group id.
+     * @return {@code True} if this record should be encrypted.
+     */
+    private boolean needEncryption(int grpId) {
+        return cctx.kernalContext().encryption().groupKey(grpId) != null;
+    }
+
+    /**
+     * Reads and decrypt data from {@code in} stream.
+     *
+     * @param in Input stream.
+     * @param readType If {@code true} plain record type will be read from {@code in}.
+     * @return Plain data stream, group id, plain record type,
+     * @throws IOException If failed.
+     * @throws IgniteCheckedException If failed.
+     */
+    private T3<ByteBufferBackedDataInput, Integer, RecordType> readEncryptedData(ByteBufferBackedDataInput in,
+        boolean readType)
+        throws IOException, IgniteCheckedException {
+        int grpId = in.readInt();
+        int encRecSz = in.readInt();
+        RecordType plainRecType = null;
+
+        if (readType)
+            plainRecType = RecordV1Serializer.readRecordType(in);
+
+        byte[] encData = new byte[encRecSz];
+
+        in.readFully(encData);
+
+        Serializable key = cctx.kernalContext().encryption().groupKey(grpId);
+
+        if (key == null)
+            return new T3<>(null, grpId, plainRecType);
+
+        byte[] clData = encSpi.decrypt(encData, key);
+
+        return new T3<>(new ByteBufferBackedDataInputImpl().buffer(ByteBuffer.wrap(clData)), grpId, plainRecType);
+    }
+
+    /**
+     * Reads encrypted record without decryption.
+     * Should be used only for a offline WAL iteration.
+     *
+     * @param in Data stream.
+     * @param readType If {@code true} plain record type will be read from {@code in}.
+     * @return Group id and type of skipped record.
+     */
+    private T2<Integer, RecordType> skipEncryptedRecord(ByteBufferBackedDataInput in, boolean readType)
+        throws IOException, IgniteCheckedException {
+        int grpId = in.readInt();
+        int encRecSz = in.readInt();
+        RecordType plainRecType = null;
+
+        if (readType)
+            plainRecType = RecordV1Serializer.readRecordType(in);
+
+        int skipped = in.skipBytes(encRecSz);
+
+        assert skipped == encRecSz;
+
+        return new T2<>(grpId, plainRecType);
+    }
+
+    /**
+     * Writes encrypted {@code clData} to {@code dst} stream.
+     *
+     * @param grpId Group id;
+     * @param plainRecType Plain record type
+     * @param clData Plain data.
+     * @param dst Destination buffer.
+     */
+    private void writeEncryptedData(int grpId, @Nullable RecordType plainRecType, ByteBuffer clData, ByteBuffer dst) {
+        int dtSz = encSpi.encryptedSize(clData.capacity());
+
+        dst.putInt(grpId);
+        dst.putInt(dtSz);
+
+        if (plainRecType != null)
+            putRecordType(dst, plainRecType);
+
+        Serializable key = cctx.kernalContext().encryption().groupKey(grpId);
+
+        assert key != null;
+
+        encSpi.encrypt(clData, key, dst);
+    }
+
+    /**
+     * @param record Record to measure.
+     * @return Plain(without encryption) size of serialized rec in bytes.
+     * @throws IgniteCheckedException If failed.
+     */
+    int plainSize(WALRecord record) throws IgniteCheckedException {
         switch (record.type()) {
             case PAGE_RECORD:
                 assert record instanceof PageSnapshot;
@@ -313,8 +507,19 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
         }
     }
 
-    /** {@inheritDoc} */
-    @Override public WALRecord readRecord(WALRecord.RecordType type, ByteBufferBackedDataInput in) throws IOException, IgniteCheckedException {
+    /**
+     * Reads {@code WalRecord} of {@code type} from input.
+     * Input should be plain(not encrypted).
+     *
+     * @param type Record type.
+     * @param in Input
+     * @param encrypted Record was encrypted.
+     * @return Deserialized record.
+     * @throws IOException If failed.
+     * @throws IgniteCheckedException If failed.
+     */
+    WALRecord readPlainRecord(RecordType type, ByteBufferBackedDataInput in,
+        boolean encrypted) throws IOException, IgniteCheckedException {
         WALRecord res;
 
         switch (type) {
@@ -326,7 +531,7 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
 
                 in.readFully(arr);
 
-                res = new PageSnapshot(new FullPageId(pageId, cacheId), arr);
+                res = new PageSnapshot(new FullPageId(pageId, cacheId), arr, encrypted ? realPageSize : pageSize);
 
                 break;
 
@@ -401,7 +606,19 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
                 List<DataEntry> entries = new ArrayList<>(entryCnt);
 
                 for (int i = 0; i < entryCnt; i++)
-                    entries.add(readDataEntry(in));
+                    entries.add(readPlainDataEntry(in));
+
+                res = new DataRecord(entries, 0L);
+
+                break;
+
+            case ENCRYPTED_DATA_RECORD:
+                entryCnt = in.readInt();
+
+                entries = new ArrayList<>(entryCnt);
+
+                for (int i = 0; i < entryCnt; i++)
+                    entries.add(readEncryptedDataEntry(in));
 
                 res = new DataRecord(entries, 0L);
 
@@ -911,8 +1128,14 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
         return res;
     }
 
-    /** {@inheritDoc} */
-    @Override public void writeRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
+    /**
+     * Write {@code rec} to {@code buf} without encryption.
+     *
+     * @param rec Record to serialize.
+     * @param buf Output buffer.
+     * @throws IgniteCheckedException If failed.
+     */
+    void writePlainRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
         switch (rec.type()) {
             case PAGE_RECORD:
                 PageSnapshot snap = (PageSnapshot)rec;
@@ -997,8 +1220,14 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
 
                 buf.putInt(dataRec.writeEntries().size());
 
-                for (DataEntry dataEntry : dataRec.writeEntries())
-                    putDataEntry(buf, dataEntry);
+                boolean encrypted = isDataRecordEncrypted(dataRec);
+
+                for (DataEntry dataEntry : dataRec.writeEntries()) {
+                    if (encrypted)
+                        putEncryptedDataEntry(buf, dataEntry);
+                    else
+                        putPlainDataEntry(buf, dataEntry);
+                }
 
                 break;
 
@@ -1482,8 +1711,36 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
     /**
      * @param buf Buffer to write to.
      * @param entry Data entry.
+     * @throws IgniteCheckedException If failed.
+     */
+    void putEncryptedDataEntry(ByteBuffer buf, DataEntry entry) throws IgniteCheckedException {
+        DynamicCacheDescriptor desc = cctx.cache().cacheDescriptor(entry.cacheId());
+
+        if (desc != null && needEncryption(desc.groupId())) {
+            int clSz = entrySize(entry);
+
+            ByteBuffer clData = ByteBuffer.allocate(clSz);
+
+            putPlainDataEntry(clData, entry);
+
+            clData.rewind();
+
+            buf.put(ENCRYPTED);
+
+            writeEncryptedData(desc.groupId(), null, clData, buf);
+        }
+        else {
+            buf.put(PLAIN);
+
+            putPlainDataEntry(buf, entry);
+        }
+    }
+
+    /**
+     * @param buf Buffer to write to.
+     * @param entry Data entry.
      */
-    static void putDataEntry(ByteBuffer buf, DataEntry entry) throws IgniteCheckedException {
+    void putPlainDataEntry(ByteBuffer buf, DataEntry entry) throws IgniteCheckedException {
         buf.putInt(entry.cacheId());
 
         if (!entry.key().putValue(buf))
@@ -1550,8 +1807,35 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
     /**
      * @param in Input to read from.
      * @return Read entry.
+     * @throws IOException If failed.
+     * @throws IgniteCheckedException If failed.
+     */
+    DataEntry readEncryptedDataEntry(ByteBufferBackedDataInput in) throws IOException, IgniteCheckedException {
+        boolean needDecryption = in.readByte() == ENCRYPTED;
+
+        if (needDecryption) {
+            if (encSpi == null) {
+                skipEncryptedRecord(in, false);
+
+                return new EncryptedDataEntry();
+            }
+
+            T3<ByteBufferBackedDataInput, Integer, RecordType> clData = readEncryptedData(in, false);
+
+            if (clData.get1() == null)
+                return null;
+
+            return readPlainDataEntry(clData.get1());
+        }
+
+        return readPlainDataEntry(in);
+    }
+
+    /**
+     * @param in Input to read from.
+     * @return Read entry.
      */
-    DataEntry readDataEntry(ByteBufferBackedDataInput in) throws IOException, IgniteCheckedException {
+    DataEntry readPlainDataEntry(ByteBufferBackedDataInput in) throws IOException, IgniteCheckedException {
         int cacheId = in.readInt();
 
         int keySize = in.readInt();
@@ -1622,6 +1906,33 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
     }
 
     /**
+     * @param rec Record.
+     * @return Real record type.
+     */
+    RecordType recordType(WALRecord rec) {
+        if (needEncryption(rec))
+            return ENCRYPTED_RECORD;
+
+        if (rec.type() != DATA_RECORD)
+            return rec.type();
+
+        return isDataRecordEncrypted((DataRecord)rec) ? ENCRYPTED_DATA_RECORD : DATA_RECORD;
+    }
+
+    /**
+     * @param rec Data record.
+     * @return {@code True} if this data record should be encrypted.
+     */
+    boolean isDataRecordEncrypted(DataRecord rec) {
+        for (DataEntry e : rec.writeEntries()) {
+            if(needEncryption(cctx.cacheContext(e.cacheId()).groupId()))
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
      * @param buf Buffer to read from.
      * @return Read map.
      */
@@ -1683,10 +1994,22 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
      * @throws IgniteCheckedException If failed to obtain the length of one of the entries.
      */
     private int dataSize(DataRecord dataRec) throws IgniteCheckedException {
+        boolean encrypted = isDataRecordEncrypted(dataRec);
+
         int sz = 0;
 
-        for (DataEntry entry : dataRec.writeEntries())
-            sz += entrySize(entry);
+        for (DataEntry entry : dataRec.writeEntries()) {
+            int clSz = entrySize(entry);
+
+            if (needEncryption(cctx.cacheContext(entry.cacheId()).groupId()))
+                sz += encSpi.encryptedSize(clSz) + 1 /* encrypted flag */ + 4 /* groupId */ + 4 /* data size */;
+            else {
+                sz += clSz;
+
+                if (encrypted)
+                    sz += 1 /* encrypted flag */;
+            }
+        }
 
         return sz;
     }
@@ -1735,4 +2058,10 @@ public class RecordDataV1Serializer implements RecordDataSerializer {
 
         return size;
     }
+
+    public static class EncryptedDataEntry extends DataEntry {
+        EncryptedDataEntry() {
+            super(0, null, null, READ, null, null, 0, 0, 0);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
index b760547..5f29dd5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
@@ -35,6 +35,8 @@ import org.apache.ignite.internal.pagemem.wal.record.ExchangeRecord;
 import org.apache.ignite.internal.pagemem.wal.record.SnapshotRecord;
 import org.apache.ignite.internal.pagemem.wal.record.TxRecord;
 import org.apache.ignite.internal.pagemem.wal.record.WALRecord;
+import org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.persistence.wal.ByteBufferBackedDataInput;
 import org.apache.ignite.internal.processors.cache.persistence.wal.FileWALPointer;
 import org.apache.ignite.internal.processors.cache.persistence.wal.record.HeaderRecord;
@@ -42,12 +44,9 @@ import org.apache.ignite.internal.processors.cache.persistence.wal.record.Header
 /**
  * Record data V2 serializer.
  */
-public class RecordDataV2Serializer implements RecordDataSerializer {
+public class RecordDataV2Serializer extends RecordDataV1Serializer implements RecordDataSerializer {
     /** Length of HEADER record data. */
-    static final int HEADER_RECORD_DATA_SIZE = /*Magic*/8 + /*Version*/4;
-
-    /** V1 data serializer delegate. */
-    private final RecordDataV1Serializer delegateSerializer;
+    private static final int HEADER_RECORD_DATA_SIZE = /*Magic*/8 + /*Version*/4;
 
     /** Serializer of {@link TxRecord} records. */
     private final TxRecordSerializer txRecordSerializer;
@@ -55,15 +54,16 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
     /**
      * Create an instance of V2 data serializer.
      *
-     * @param delegateSerializer V1 data serializer.
+     * @param cctx Cache shared context.
      */
-    public RecordDataV2Serializer(RecordDataV1Serializer delegateSerializer) {
-        this.delegateSerializer = delegateSerializer;
+    public RecordDataV2Serializer(GridCacheSharedContext cctx) {
+        super(cctx);
+
         this.txRecordSerializer = new TxRecordSerializer();
     }
 
     /** {@inheritDoc} */
-    @Override public int size(WALRecord rec) throws IgniteCheckedException {
+    @Override protected int plainSize(WALRecord rec) throws IgniteCheckedException {
         switch (rec.type()) {
             case HEADER_RECORD:
                 return HEADER_RECORD_DATA_SIZE;
@@ -81,7 +81,7 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
                 return 18 + cacheStatesSize + (walPtr == null ? 0 : 16);
 
             case DATA_RECORD:
-                return delegateSerializer.size(rec) + 8/*timestamp*/;
+                return super.plainSize(rec) + 8/*timestamp*/;
 
             case SNAPSHOT:
                 return 8 + 1;
@@ -93,14 +93,15 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
                 return txRecordSerializer.size((TxRecord)rec);
 
             default:
-                return delegateSerializer.size(rec);
+                return super.plainSize(rec);
         }
     }
 
     /** {@inheritDoc} */
-    @Override public WALRecord readRecord(
-        WALRecord.RecordType type,
-        ByteBufferBackedDataInput in
+    @Override WALRecord readPlainRecord(
+        RecordType type,
+        ByteBufferBackedDataInput in,
+        boolean encrypted
     ) throws IOException, IgniteCheckedException {
         switch (type) {
             case CHECKPOINT_RECORD:
@@ -130,9 +131,21 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
                 List<DataEntry> entries = new ArrayList<>(entryCnt);
 
                 for (int i = 0; i < entryCnt; i++)
-                    entries.add(delegateSerializer.readDataEntry(in));
+                    entries.add(readPlainDataEntry(in));
+
+                return new DataRecord(entries, timeStamp);
+
+            case ENCRYPTED_DATA_RECORD:
+                entryCnt = in.readInt();
+                timeStamp = in.readLong();
+
+                entries = new ArrayList<>(entryCnt);
+
+                for (int i = 0; i < entryCnt; i++)
+                    entries.add(readEncryptedDataEntry(in));
 
                 return new DataRecord(entries, timeStamp);
+
             case SNAPSHOT:
                 long snpId = in.readLong();
                 byte full = in.readByte();
@@ -150,13 +163,12 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
                 return txRecordSerializer.read(in);
 
             default:
-                return delegateSerializer.readRecord(type, in);
+                return super.readPlainRecord(type, in, encrypted);
         }
-
     }
 
     /** {@inheritDoc} */
-    @Override public void writeRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
+    @Override protected void writePlainRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
         if (rec instanceof HeaderRecord)
             throw new UnsupportedOperationException("Writing header records is forbidden since version 2 of serializer");
 
@@ -193,8 +205,14 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
                 buf.putInt(dataRec.writeEntries().size());
                 buf.putLong(dataRec.timestamp());
 
-                for (DataEntry dataEntry : dataRec.writeEntries())
-                    RecordDataV1Serializer.putDataEntry(buf, dataEntry);
+                boolean encrypted = isDataRecordEncrypted(dataRec);
+
+                for (DataEntry dataEntry : dataRec.writeEntries()) {
+                    if (encrypted)
+                        putEncryptedDataEntry(buf, dataEntry);
+                    else
+                        putPlainDataEntry(buf, dataEntry);
+                }
 
                 break;
 
@@ -221,7 +239,7 @@ public class RecordDataV2Serializer implements RecordDataSerializer {
                 break;
 
             default:
-                delegateSerializer.writeRecord(rec, buf);
+                super.writePlainRecord(rec, buf);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordSerializerFactoryImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordSerializerFactoryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordSerializerFactoryImpl.java
index 2e2e2f8..c149817 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordSerializerFactoryImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordSerializerFactoryImpl.java
@@ -77,11 +77,8 @@ public class RecordSerializerFactoryImpl implements RecordSerializerFactory {
                     recordDeserializeFilter);
 
             case 2:
-                RecordDataV2Serializer dataV2Serializer = new RecordDataV2Serializer(
-                    new RecordDataV1Serializer(cctx));
-
                 return new RecordV2Serializer(
-                    dataV2Serializer,
+                    new RecordDataV2Serializer(cctx),
                     needWritePointer,
                     marshalledMode,
                     skipPositionCheck,

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
index afd770d..c65f37c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
@@ -170,7 +170,7 @@ public class RecordV1Serializer implements RecordSerializer {
         /** {@inheritDoc} */
         @Override public void writeWithHeaders(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
             // Write record type.
-            putRecordType(buf, rec);
+            putRecordType(buf, dataSerializer.recordType(rec));
 
             // SWITCH_SEGMENT_RECORD should have only type, no need to write pointer.
             if (rec.type() == SWITCH_SEGMENT_RECORD)
@@ -326,10 +326,10 @@ public class RecordV1Serializer implements RecordSerializer {
      * Writes record type to given {@code buf}.
      *
      * @param buf Buffer to write record type.
-     * @param rec WAL record.
+     * @param type WAL record type.
      */
-    static void putRecordType(ByteBuffer buf, WALRecord rec) {
-        buf.put((byte)(rec.type().ordinal() + 1));
+    static void putRecordType(ByteBuffer buf, RecordType type) {
+        buf.put((byte)(type.ordinal() + 1));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
index e112522..d27a331 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
@@ -174,7 +174,7 @@ public class RecordV2Serializer implements RecordSerializer {
             ByteBuffer buf
         ) throws IgniteCheckedException {
             // Write record type.
-            RecordV1Serializer.putRecordType(buf, record);
+            RecordV1Serializer.putRecordType(buf, dataSerializer.recordType(record));
 
             // SWITCH_SEGMENT_RECORD should have only type, no need to write pointer.
             if (record.type() == SWITCH_SEGMENT_RECORD)

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java
index 81855fc..51a65bb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java
@@ -70,6 +70,9 @@ public class ChangeGlobalStateMessage implements DiscoveryCustomMessage {
      * @param initiatingNodeId Node initiated state change.
      * @param storedCfgs Configurations read from persistent store.
      * @param activate New cluster state.
+     * @param baselineTopology Baseline topology.
+     * @param forceChangeBaselineTopology Force change baseline topology flag.
+     * @param timestamp Timestamp.
      */
     public ChangeGlobalStateMessage(
         UUID reqId,
@@ -78,8 +81,7 @@ public class ChangeGlobalStateMessage implements DiscoveryCustomMessage {
         boolean activate,
         BaselineTopology baselineTopology,
         boolean forceChangeBaselineTopology,
-        long timestamp
-    ) {
+        long timestamp) {
         assert reqId != null;
         assert initiatingNodeId != null;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
index 2b70998..d52d388 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
@@ -1170,6 +1170,8 @@ public class GridClusterStateProcessor extends GridProcessorAdapter implements I
 
                     ctx.task().onActivate(ctx);
 
+                    ctx.encryption().onActivate(ctx);
+
                     if (log.isInfoEnabled())
                         log.info("Successfully performed final activation steps [nodeId="
                             + ctx.localNodeId() + ", client=" + client + ", topVer=" + req.topologyVersion() + "]");

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
index 8e66102..25b9cb8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
@@ -69,6 +69,7 @@ import org.apache.ignite.configuration.PersistentStoreConfiguration;
 import org.apache.ignite.configuration.SqlConnectorConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
 import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.failure.FailureHandler;
 import org.apache.ignite.failure.NoOpFailureHandler;
@@ -99,6 +100,8 @@ import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.spi.encryption.noop.NoopEncryptionSpi;
+import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi;
 import org.apache.ignite.spi.eventstorage.EventStorageSpi;
 import org.apache.ignite.spi.eventstorage.NoopEventStorageSpi;
 import org.apache.ignite.spi.eventstorage.memory.MemoryEventStorageSpi;
@@ -220,6 +223,7 @@ public class PlatformConfigurationUtils {
         ccfg.setQueryDetailMetricsSize(in.readInt());
         ccfg.setQueryParallelism(in.readInt());
         ccfg.setSqlSchema(in.readString());
+        ccfg.setEncryptionEnabled(in.readBoolean());
 
         int qryEntCnt = in.readInt();
 
@@ -702,6 +706,7 @@ public class PlatformConfigurationUtils {
 
         readCacheConfigurations(in, cfg, ver);
         readDiscoveryConfiguration(in, cfg);
+        readEncryptionConfiguration(in, cfg, ver);
 
         if (in.readBoolean()) {
             TcpCommunicationSpi comm = new TcpCommunicationSpi();
@@ -943,6 +948,30 @@ public class PlatformConfigurationUtils {
     }
 
     /**
+     * Reads encryption configuration
+     * @param in Reader.
+     * @param cfg Configuration.
+     * @param ver Client version.
+     */
+    private static void readEncryptionConfiguration(BinaryRawReaderEx in, IgniteConfiguration cfg,
+        ClientListenerProtocolVersion ver) {
+        if (ver.compareTo(VER_1_2_0) < 0 || !in.readBoolean()) {
+            cfg.setEncryptionSpi(new NoopEncryptionSpi());
+
+            return;
+        }
+
+        KeystoreEncryptionSpi enc = new KeystoreEncryptionSpi();
+
+        enc.setMasterKeyName(in.readString());
+        enc.setKeySize(in.readInt());
+        enc.setKeyStorePath(in.readString());
+        enc.setKeyStorePassword(in.readCharArray());
+
+        cfg.setEncryptionSpi(enc);
+    }
+
+    /**
      * Writes cache configuration.
      *
      * @param writer Writer.
@@ -1003,6 +1032,7 @@ public class PlatformConfigurationUtils {
         writer.writeInt(ccfg.getQueryDetailMetricsSize());
         writer.writeInt(ccfg.getQueryParallelism());
         writer.writeString(ccfg.getSqlSchema());
+        writer.writeBoolean(ccfg.isEncryptionEnabled());
 
         Collection<QueryEntity> qryEntities = ccfg.getQueryEntities();
 
@@ -1253,6 +1283,7 @@ public class PlatformConfigurationUtils {
             w.writeInt(0);
 
         writeDiscoveryConfiguration(w, cfg.getDiscoverySpi());
+        writeEncryptionConfiguration(w, cfg.getEncryptionSpi(), ver);
 
         CommunicationSpi comm = cfg.getCommunicationSpi();
 
@@ -1462,6 +1493,34 @@ public class PlatformConfigurationUtils {
     }
 
     /**
+     * Writes encryption configuration.
+     *
+     * @param w Writer.
+     * @param enc Encryption Spi.
+     * @param ver Client version.
+     */
+    private static void writeEncryptionConfiguration(BinaryRawWriter w, EncryptionSpi enc,
+        ClientListenerProtocolVersion ver) {
+        if (ver.compareTo(VER_1_2_0) < 0)
+            return;
+
+        if (enc instanceof NoopEncryptionSpi) {
+            w.writeBoolean(false);
+
+            return;
+        }
+
+        KeystoreEncryptionSpi keystoreEnc = (KeystoreEncryptionSpi)enc;
+
+        w.writeBoolean(true);
+
+        w.writeString(keystoreEnc.getMasterKeyName());
+        w.writeInt(keystoreEnc.getKeySize());
+        w.writeString(keystoreEnc.getKeyStorePath());
+        w.writeCharArray(keystoreEnc.getKeyStorePwd());
+    }
+
+    /**
      * Writes enum as byte.
      *
      * @param w Writer.

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index eb3f2a7..b5b104d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -1484,13 +1484,14 @@ public class GridQueryProcessor extends GridProcessorAdapter {
      * @param writeSyncMode Write synchronization mode.
      * @param backups Backups.
      * @param ifNotExists Quietly ignore this command if table already exists.
+     * @param encrypted Encrypted flag.
      * @throws IgniteCheckedException If failed.
      */
     @SuppressWarnings("unchecked")
     public void dynamicTableCreate(String schemaName, QueryEntity entity, String templateName, String cacheName,
         String cacheGroup, @Nullable String dataRegion, String affinityKey, @Nullable CacheAtomicityMode atomicityMode,
-        @Nullable CacheWriteSynchronizationMode writeSyncMode, @Nullable Integer backups, boolean ifNotExists)
-        throws IgniteCheckedException {
+        @Nullable CacheWriteSynchronizationMode writeSyncMode, @Nullable Integer backups, boolean ifNotExists,
+        boolean encrypted) throws IgniteCheckedException {
         assert !F.isEmpty(templateName);
         assert backups == null || backups >= 0;
 
@@ -1534,6 +1535,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
         if (backups != null)
             ccfg.setBackups(backups);
 
+        ccfg.setEncryptionEnabled(encrypted);
         ccfg.setSqlSchema(schemaName);
         ccfg.setSqlEscapeAll(true);
         ccfg.setQueryEntities(Collections.singleton(entity));

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index b8ba742..3ffbb00 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -32,10 +32,13 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.ObjectInput;
+import java.io.ObjectInputStream;
 import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.Reader;
+import java.io.Serializable;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.lang.annotation.Annotation;
@@ -107,6 +110,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Random;
 import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -477,6 +481,9 @@ public abstract class IgniteUtils {
     /** Ignite Work Directory. */
     public static final String IGNITE_WORK_DIR = System.getenv(IgniteSystemProperties.IGNITE_WORK_DIR);
 
+    /** Random is used to get random server node to authentication from client node. */
+    private static final Random RND = new Random(System.currentTimeMillis());
+
     /** Clock timer. */
     private static Thread timer;
 
@@ -10339,6 +10346,43 @@ public abstract class IgniteUtils {
     }
 
     /**
+     * Serialize object to byte array.
+     *
+     * @param obj Object.
+     * @return Serialized object.
+     */
+    public static byte[] toBytes(Serializable obj) {
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+            
+            oos.writeObject(obj);
+            oos.flush();
+
+            return bos.toByteArray();
+        }
+        catch (IOException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /**
+     * Deserialize object from byte array.
+     *
+     * @param data Serialized object.
+     * @return Object.
+     */
+    public static <T> T fromBytes(byte[] data) {
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
+             ObjectInputStream ois = new ObjectInputStream(bis)) {
+
+            return (T)ois.readObject();
+        }
+        catch (IOException | ClassNotFoundException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /**
      * Return count of regular file in the directory (including in sub-directories)
      *
      * @param dir path to directory
@@ -10580,6 +10624,27 @@ public abstract class IgniteUtils {
     }
 
     /**
+     * @param ctx Kernel context.
+     * @return Random alive server node.
+     */
+    public static ClusterNode randomServerNode(GridKernalContext ctx) {
+        Collection<ClusterNode> aliveNodes = ctx.discovery().aliveServerNodes();
+
+        int rndIdx = RND.nextInt(aliveNodes.size()) + 1;
+
+        int i = 0;
+        ClusterNode rndNode = null;
+
+        for (Iterator<ClusterNode> it = aliveNodes.iterator(); i < rndIdx && it.hasNext(); i++)
+            rndNode = it.next();
+
+        if (rndNode == null)
+            assert rndNode != null;
+
+        return rndNode;
+    }
+
+    /**
      *
      */
     public static class ReentrantReadWriteLockTracer implements ReadWriteLock {

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java b/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java
index f9c4d9d..ce5076b 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java
@@ -298,13 +298,13 @@ public class GridFunc {
      * @param delim Delimiter (optional).
      * @return Concatenated string.
      */
-    public static String concat(Iterable<String> c, @Nullable String delim) {
+    public static String concat(Iterable<?> c, @Nullable String delim) {
         A.notNull(c, "c");
 
         IgniteReducer<? super String, String> f = new StringConcatReducer(delim);
 
-        for (String x : c)
-            if (!f.collect(x))
+        for (Object x : c)
+            if (!f.collect(x == null ? null : x.toString()))
                 break;
 
         return f.reduce();

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/spi/encryption/EncryptionSpi.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/EncryptionSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/EncryptionSpi.java
new file mode 100644
index 0000000..693cefd
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/EncryptionSpi.java
@@ -0,0 +1,113 @@
+/*
+ * 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.ignite.spi.encryption;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.spi.IgniteSpi;
+
+/**
+ * SPI provides encryption features for an Ignite.
+ */
+public interface EncryptionSpi extends IgniteSpi {
+    /**
+     * Returns master key digest.
+     * Should always return same digest for a same key.
+     * Digest used for a configuration consistency check.
+     *
+     * @return Master key digest.
+     */
+    byte[] masterKeyDigest();
+
+    /**
+     * Creates new key for an encryption/decryption of cache persistent data: pages, WAL records.
+     *
+     * @return Newly created encryption key.
+     * @throws IgniteException If key creation failed.
+     */
+    Serializable create() throws IgniteException;
+
+    /**
+     * Encrypts data.
+     * 
+     * @param data Data to encrypt.
+     * @param key Encryption key.
+     * @param res Destination buffer.
+     */
+    void encrypt(ByteBuffer data, Serializable key, ByteBuffer res);
+
+    /**
+     * Encrypts data without padding info.
+     *
+     * @param data Data to encrypt.
+     * @param key Encryption key.
+     * @param res Destination buffer.
+     */
+    void encryptNoPadding(ByteBuffer data, Serializable key, ByteBuffer res);
+
+    /**
+     * Decrypts data encrypted with {@link #encrypt(ByteBuffer, Serializable, ByteBuffer)}
+     * 
+     * @param data Data to decrypt.
+     * @param key Encryption key.
+     */
+     byte[] decrypt(byte[] data, Serializable key);
+
+    /**
+     * Decrypts data encrypted with {@link #encryptNoPadding(ByteBuffer, Serializable, ByteBuffer)}
+     *
+     * @param data Data to decrypt.
+     * @param key Encryption key.
+     */
+    void decryptNoPadding(ByteBuffer data, Serializable key, ByteBuffer res);
+
+    /**
+     * Encrypts key.
+     * Adds some info to check key integrity on decryption.
+     *
+     * @param key Key to encrypt.
+     * @return Encrypted key.
+     */
+    byte[] encryptKey(Serializable key);
+
+    /**
+     * Decrypts key and checks it integrity.
+     * 
+     * @param key Key to decrypt.
+     * @return Encrypted key.
+     */
+    Serializable decryptKey(byte[] key);
+
+    /**
+     * @param dataSize Size of plain data in bytes.
+     * @return Size of encrypted data in bytes for padding encryption mode.
+     */
+    int encryptedSize(int dataSize);
+
+    /**
+     * @param dataSize Size of plain data in bytes.
+     * @return Size of encrypted data in bytes for nopadding encryption mode.
+     */
+    int encryptedSizeNoPadding(int dataSize);
+
+    /**
+     * @return Encrypted data block size.
+     */
+    int blockSize();
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionKey.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionKey.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionKey.java
new file mode 100644
index 0000000..c2577c7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionKey.java
@@ -0,0 +1,84 @@
+/*
+ * 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.ignite.spi.encryption.keystore;
+
+import java.io.Serializable;
+import java.security.Key;
+import java.util.Arrays;
+import java.util.Objects;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * {@code EncryptionKey} implementation based on java security.
+ *
+ * @see Key
+ * @see KeystoreEncryptionSpi
+ */
+public final class KeystoreEncryptionKey implements Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Encryption key.
+     */
+    private final Key k;
+
+    /**
+     * Key digest.
+     */
+    @Nullable final byte[] digest;
+
+    /**
+     * @param k Encryption key.
+     * @param digest Message digest.
+     */
+    KeystoreEncryptionKey(Key k, @Nullable byte[] digest) {
+        this.k = k;
+        this.digest = digest;
+    }
+
+    /**
+     * Encryption key.
+     */
+    public Key key() {
+        return k;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        KeystoreEncryptionKey key = (KeystoreEncryptionKey)o;
+
+        return Objects.equals(k, key.k) &&
+            Arrays.equals(digest, key.digest);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int result = Objects.hash(k);
+
+        result = 31 * result + Arrays.hashCode(digest);
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/aabacfa0/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java
new file mode 100644
index 0000000..beba015
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/encryption/keystore/KeystoreEncryptionSpi.java
@@ -0,0 +1,501 @@
+/*
+ * 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.ignite.spi.encryption.keystore;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.concurrent.ThreadLocalRandom;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.spi.encryption.EncryptionSpi;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.resources.IgniteInstanceResource;
+import org.apache.ignite.resources.LoggerResource;
+import org.apache.ignite.spi.IgniteSpiAdapter;
+import org.apache.ignite.spi.IgniteSpiException;
+import org.jetbrains.annotations.Nullable;
+
+import static javax.crypto.Cipher.DECRYPT_MODE;
+import static javax.crypto.Cipher.ENCRYPT_MODE;
+
+/**
+ * EncryptionSPI implementation base on JDK provided cipher algorithm implementations.
+ *
+ * @see EncryptionSpi
+ * @see KeystoreEncryptionKey
+ */
+public class KeystoreEncryptionSpi extends IgniteSpiAdapter implements EncryptionSpi {
+    /**
+     * Default key store entry name to store Encryption master key.
+     */
+    public static final String DEFAULT_MASTER_KEY_NAME = "ignite.master.key";
+
+    /**
+     * Algorithm supported by implementation.
+     */
+    public static final String CIPHER_ALGO = "AES";
+
+    /**
+     * Default encryption key size;
+     */
+    public static final int DEFAULT_KEY_SIZE = 256;
+
+    /**
+     * Full name of cipher algorithm.
+     */
+    private static final String AES_WITH_PADDING = "AES/CBC/PKCS5Padding";
+
+    /**
+     * Full name of cipher algorithm without padding.
+     */
+    private static final String AES_WITHOUT_PADDING = "AES/CBC/NoPadding";
+
+    /**
+     * Algorithm used for digest calculation.
+     */
+    private static final String DIGEST_ALGO = "SHA-512";
+
+    /**
+     * Data block size.
+     */
+    private static final int BLOCK_SZ = 16;
+
+    /**
+     * Path to master key store.
+     */
+    private String keyStorePath;
+
+    /**
+     * Key store password.
+     */
+    private char[] keyStorePwd;
+
+    /**
+     * Key size.
+     */
+    private int keySize = DEFAULT_KEY_SIZE;
+
+    /**
+     * Master key name.
+     */
+    private String masterKeyName = DEFAULT_MASTER_KEY_NAME;
+
+    /**
+     * Master key.
+     */
+    private KeystoreEncryptionKey masterKey;
+
+    /** Logger. */
+    @LoggerResource
+    protected IgniteLogger log;
+
+    /** Ignite */
+    @IgniteInstanceResource
+    protected Ignite ignite;
+
+    /** */
+    private ThreadLocal<Cipher> aesWithPadding = ThreadLocal.withInitial(() -> {
+        try {
+            return Cipher.getInstance(AES_WITH_PADDING);
+        }
+        catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+            throw new IgniteException(e);
+        }
+    });
+
+    /** */
+    private ThreadLocal<Cipher> aesWithoutPadding = ThreadLocal.withInitial(() -> {
+        try {
+            return Cipher.getInstance(AES_WITHOUT_PADDING);
+        }
+        catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+            throw new IgniteException(e);
+        }
+    });
+
+    /** {@inheritDoc} */
+    @Override public void spiStart(@Nullable String igniteInstanceName) throws IgniteSpiException {
+        assertParameter(!F.isEmpty(keyStorePath), "KeyStorePath shouldn't be empty");
+        assertParameter(keyStorePwd != null && keyStorePwd.length > 0,
+            "KeyStorePassword shouldn't be empty");
+
+        try (InputStream keyStoreFile = keyStoreFile()) {
+            assertParameter(keyStoreFile != null, keyStorePath + " doesn't exists!");
+
+            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+
+            ks.load(keyStoreFile, keyStorePwd);
+
+            if (log != null)
+                log.info("Successfully load keyStore [path=" + keyStorePath + "]");
+
+            masterKey = new KeystoreEncryptionKey(ks.getKey(masterKeyName, keyStorePwd), null);
+        }
+        catch (GeneralSecurityException | IOException e) {
+            throw new IgniteSpiException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void spiStop() throws IgniteSpiException {
+        ensureStarted();
+
+        //empty.
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] masterKeyDigest() {
+        ensureStarted();
+
+        return makeDigest(masterKey.key().getEncoded());
+    }
+
+    /** {@inheritDoc} */
+    @Override public KeystoreEncryptionKey create() throws IgniteException {
+        ensureStarted();
+
+        try {
+            KeyGenerator gen = KeyGenerator.getInstance(CIPHER_ALGO);
+
+            gen.init(keySize);
+
+            SecretKey key = gen.generateKey();
+
+            return new KeystoreEncryptionKey(key, makeDigest(key.getEncoded()));
+        }
+        catch (NoSuchAlgorithmException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void encrypt(ByteBuffer data, Serializable key, ByteBuffer res) {
+        doEncryption(data, aesWithPadding.get(), key, res);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void encryptNoPadding(ByteBuffer data, Serializable key, ByteBuffer res) {
+        doEncryption(data, aesWithoutPadding.get(), key, res);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] decrypt(byte[] data, Serializable key) {
+        assert key instanceof KeystoreEncryptionKey;
+
+        ensureStarted();
+
+        try {
+            SecretKeySpec keySpec = new SecretKeySpec(((KeystoreEncryptionKey)key).key().getEncoded(), CIPHER_ALGO);
+
+            Cipher cipher = aesWithPadding.get();
+
+            cipher.init(DECRYPT_MODE, keySpec, new IvParameterSpec(data, 0, cipher.getBlockSize()));
+
+            return cipher.doFinal(data, cipher.getBlockSize(), data.length - cipher.getBlockSize());
+        }
+        catch (InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException |
+            BadPaddingException e) {
+            throw new IgniteSpiException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void decryptNoPadding(ByteBuffer data, Serializable key, ByteBuffer res) {
+        assert key instanceof KeystoreEncryptionKey;
+
+        ensureStarted();
+
+        try {
+            SecretKeySpec keySpec = new SecretKeySpec(((KeystoreEncryptionKey)key).key().getEncoded(), CIPHER_ALGO);
+
+            Cipher cipher = aesWithoutPadding.get();
+
+            byte[] iv = new byte[cipher.getBlockSize()];
+
+            data.get(iv);
+
+            cipher.init(DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
+
+            cipher.doFinal(data, res);
+        }
+        catch (InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException |
+            ShortBufferException | BadPaddingException e) {
+            throw new IgniteSpiException(e);
+        }
+    }
+
+    /**
+     * @param data Plain data.
+     * @param cipher Cipher.
+     * @param key Encryption key.
+     */
+    private void doEncryption(ByteBuffer data, Cipher cipher, Serializable key, ByteBuffer res) {
+        assert key instanceof KeystoreEncryptionKey;
+
+        ensureStarted();
+
+        try {
+            SecretKeySpec keySpec = new SecretKeySpec(((KeystoreEncryptionKey)key).key().getEncoded(), CIPHER_ALGO);
+
+            byte[] iv = initVector(cipher);
+
+            res.put(iv);
+
+            cipher.init(ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
+
+            cipher.doFinal(data, res);
+        }
+        catch (ShortBufferException | InvalidAlgorithmParameterException | InvalidKeyException |
+            IllegalBlockSizeException | BadPaddingException e) {
+            throw new IgniteSpiException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] encryptKey(Serializable key) {
+        assert key instanceof KeystoreEncryptionKey;
+
+        byte[] serKey = U.toBytes(key);
+
+        byte[] res = new byte[encryptedSize(serKey.length)];
+
+        encrypt(ByteBuffer.wrap(serKey), masterKey, ByteBuffer.wrap(res));
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public KeystoreEncryptionKey decryptKey(byte[] data) {
+        byte[] serKey = decrypt(data, masterKey);
+
+        KeystoreEncryptionKey key = U.fromBytes(serKey);
+
+        byte[] digest = makeDigest(key.key().getEncoded());
+
+        if (!Arrays.equals(key.digest, digest))
+            throw new IgniteException("Key is broken!");
+
+        return key;
+
+    }
+
+    /** {@inheritDoc} */
+    @Override public int encryptedSize(int dataSize) {
+        return encryptedSize(dataSize, AES_WITH_PADDING);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int encryptedSizeNoPadding(int dataSize) {
+        return encryptedSize(dataSize, AES_WITHOUT_PADDING);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int blockSize() {
+        return BLOCK_SZ;
+    }
+
+    /**
+     * @param dataSize Data size.
+     * @param algo Encryption algorithm
+     * @return Encrypted data size.
+     */
+    private int encryptedSize(int dataSize, String algo) {
+        int cntBlocks;
+
+        switch (algo) {
+            case AES_WITH_PADDING:
+                cntBlocks = 2;
+                break;
+
+            case AES_WITHOUT_PADDING:
+                cntBlocks = 1;
+                break;
+
+            default:
+                throw new IllegalStateException("Unknown algorithm: " + algo);
+        }
+
+        return (dataSize/BLOCK_SZ + cntBlocks)*BLOCK_SZ;
+    }
+
+    /**
+     * Calculates message digest.
+     *
+     * @param msg Message.
+     * @return Digest.
+     */
+    private byte[] makeDigest(byte[] msg) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(DIGEST_ALGO);
+
+            return md.digest(msg);
+        }
+        catch (NoSuchAlgorithmException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /**
+     * @param cipher Cipher.
+     * @return Init vector for encryption.
+     * @see <a href="https://en.wikipedia.org/wiki/Initialization_vector">Initialization vector</a>
+     */
+    private byte[] initVector(Cipher cipher) {
+        byte[] iv = new byte[cipher.getBlockSize()];
+
+        ThreadLocalRandom.current().nextBytes(iv);
+
+        return iv;
+    }
+
+    /**
+     * {@code keyStorePath} could be absolute path or path to classpath resource.
+     *
+     * @return File for {@code keyStorePath}.
+     */
+    private InputStream keyStoreFile() throws IOException {
+        File abs = new File(keyStorePath);
+
+        if (abs.exists())
+            return new FileInputStream(abs);
+
+        URL clsPthRes = KeystoreEncryptionSpi.class.getClassLoader().getResource(keyStorePath);
+
+        if (clsPthRes != null)
+            return clsPthRes.openStream();
+
+        return null;
+    }
+
+    /**
+     * Ensures spi started.
+     * 
+     * @throws IgniteException If spi not started.
+     */
+    private void ensureStarted() throws IgniteException {
+        if (started())
+            return;
+
+        throw new IgniteException("EncryptionSpi is not started!");
+    }
+
+    /**
+     * Gets path to jdk keyStore that stores master key.
+     *
+     * @return Key store path.
+     */
+    public String getKeyStorePath() {
+        return keyStorePath;
+    }
+
+    /**
+     * Sets path to jdk keyStore that stores master key.
+     *
+     * @param keyStorePath Path to JDK KeyStore.
+     */
+    public void setKeyStorePath(String keyStorePath) {
+        assert !F.isEmpty(keyStorePath) : "KeyStore path shouldn't be empty";
+        assert !started() : "Spi already started";
+
+        this.keyStorePath = keyStorePath;
+    }
+
+    /**
+     * Gets key store password.
+     *
+     * @return Key store password.
+     */
+    public char[] getKeyStorePwd() {
+        return keyStorePwd;
+    }
+
+    /**
+     * Sets password to access KeyStore.
+     *
+     * @param keyStorePassword Password for Key Store.
+     */
+    public void setKeyStorePassword(char[] keyStorePassword) {
+        assert keyStorePassword != null && keyStorePassword.length > 0;
+        assert !started() : "Spi already started";
+
+        this.keyStorePwd = keyStorePassword;
+    }
+
+    /**
+     * Gets encryption key size.
+     *
+     * @return Encryption key size.
+     */
+    public int getKeySize() {
+        return keySize;
+    }
+
+    /**
+     * Sets encryption key size.
+     *
+     * @param keySize Key size.
+     */
+    public void setKeySize(int keySize) {
+        assert !started() : "Spi already started";
+
+        this.keySize = keySize;
+    }
+
+    /**
+     * Gets master key name.
+     *
+     * @return Master key name.
+     */
+    public String getMasterKeyName() {
+        return masterKeyName;
+    }
+
+    /**
+     * Sets mater key name.
+     *
+     * @param masterKeyName Master key name.
+     */
+    public void setMasterKeyName(String masterKeyName) {
+        assert !started() : "Spi already started";
+
+        this.masterKeyName = masterKeyName;
+    }
+}