();
+ for (String key : keyNames.split(",")) {
+ keys.add(key.trim());
+ }
+ return keys;
+ }
+}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/aes/CipherFactory.java b/serde/src/java/org/apache/hadoop/hive/serde2/aes/CipherFactory.java
new file mode 100644
index 0000000..237232d
--- /dev/null
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/aes/CipherFactory.java
@@ -0,0 +1,56 @@
+package org.apache.hadoop.hive.serde2.aes;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+public class CipherFactory {
+
+ /**
+ * Create an instance of this Cipher class, according to the algorithm string
+ *
+ * @param transformation
+ * @return cipher instance
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws NoSuchPaddingException
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ */
+ public static Cipher getInstance(String transformation)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ NoSuchPaddingException, InstantiationException, IllegalAccessException {
+ return getInstance(transformation, null);
+ }
+
+ /**
+ * Create an instance of this Cipher class, according to the algorithm string
+ * and provider.
+ *
+ * @param transformation
+ * @param provider
+ * @return
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws NoSuchPaddingException
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ */
+ public static Cipher getInstance(String transformation, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ NoSuchPaddingException, InstantiationException, IllegalAccessException {
+ Cipher cipher = null;
+ try {
+ if (provider == null || provider.isEmpty()) {
+ cipher = Cipher.getInstance(transformation);
+ } else {
+ cipher = Cipher.getInstance(transformation, provider);
+ }
+ } catch (NoSuchProviderException e) {
+ cipher = Cipher.getInstance(transformation);
+ }
+ return cipher;
+ }
+}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/aes/CryptoException.java b/serde/src/java/org/apache/hadoop/hive/serde2/aes/CryptoException.java
new file mode 100644
index 0000000..7007ff2
--- /dev/null
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/aes/CryptoException.java
@@ -0,0 +1,86 @@
+/**
+ * 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.hadoop.hive.serde2.aes;
+
+/**
+ * CryptoException is the base exception class for cryptographic related classes.
+ */
+public class CryptoException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a new exception with null as its detail message.
+ * The cause is not initialized, and may subsequently be initialized by a
+ * call to {@link #initCause}.
+ */
+ public CryptoException() {
+ super();
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message. The
+ * cause is not initialized, and may subsequently be initialized by
+ * a call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public CryptoException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and cause.
+ *
+ * Note that the detail message associated with cause is
+ * not automatically incorporated in this exception's detail message.
+ *
+ * @param message
+ * the detail message (which is saved for later retrieval by the
+ * {@link #getMessage()} method).
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public CryptoException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail message
+ * of (cause==null ? null : cause.toString()) (which typically
+ * contains the class and detail message of cause). This
+ * constructor is useful for exceptions that are little more than wrappers
+ * for other throwables (for example,
+ * {@link java.security.PrivilegedActionException}).
+ *
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public CryptoException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/aes/HiveSerdeKeyManagement.java b/serde/src/java/org/apache/hadoop/hive/serde2/aes/HiveSerdeKeyManagement.java
new file mode 100644
index 0000000..0596794
--- /dev/null
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/aes/HiveSerdeKeyManagement.java
@@ -0,0 +1,88 @@
+/**
+ * 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.hadoop.hive.serde2.aes;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.crypto.key.KeyProvider;
+import org.apache.hadoop.crypto.key.KeyProvider.KeyVersion;
+import org.apache.hadoop.crypto.key.kms.KMSClientProvider;
+import org.apache.hadoop.security.authorize.AuthorizationException;
+
+public class HiveSerdeKeyManagement {
+ public static final String HIVE_ENCRYPT_KEYNAMES = "hive.encrypt.keynames";
+ public static final String HIVE_ENCRYPT_IV = "hive.encrypt.iv";
+ public static final String KMS_URI = "hadoop.security.kms.uri";
+
+ private static Log LOG = LogFactory.getLog(HiveSerdeKeyManagement.class);
+
+ public static void setupTableForEncryption(Configuration conf, Map tblProps)
+ throws IOException {
+ if(tblProps == null) {
+ return;
+ }
+
+ String keyNames = tblProps.get(HIVE_ENCRYPT_KEYNAMES);
+ if (keyNames == null || keyNames.isEmpty()) {
+ return;
+ }
+
+ String kmsUri = conf.get(KMS_URI);
+ if (kmsUri == null) {
+ LOG.warn("Please set " + KMS_URI + " if you want to enable encryption");
+ return;
+ }
+
+ // 1. create key using kms
+ try {
+ URL url = new URL(kmsUri);
+ URI uri = createKMSUri(url);
+ KMSClientProvider kp = new KMSClientProvider(uri, conf);
+ for (String keyName : AESUtil.getKeys(keyNames)) {
+ KeyVersion kv = kp.getCurrentKey(keyName);
+ if (kv == null) {
+ kv = kp.createKey(keyName, new KeyProvider.Options(conf));
+ }
+ }
+ } catch (URISyntaxException e) {
+ throw new IOException("Bad configuration of " + KMS_URI + " at " + kmsUri, e);
+ } catch (AuthorizationException e) {
+ throw new IOException("Current user has no permission to get/create key", e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException("No such algorithm when create key", e);
+ }
+
+ // 2. generate iv and set to table properties
+ byte[] ivBytes = AESUtil.randomBytes(AESConstants.IV_LENGTH);
+ tblProps.put(HIVE_ENCRYPT_IV, AESUtil.encodeBytes(ivBytes));
+ }
+
+ public static URI createKMSUri(URL kmsUrl) throws URISyntaxException {
+ String str = kmsUrl.toString();
+ str = str.replaceFirst("://", "@");
+ return new URI("kms://" + str);
+ }
+}
diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/lazy/LazySimpleSerDe.java b/serde/src/java/org/apache/hadoop/hive/serde2/lazy/LazySimpleSerDe.java
index edea98d..5dca32c 100644
--- a/serde/src/java/org/apache/hadoop/hive/serde2/lazy/LazySimpleSerDe.java
+++ b/serde/src/java/org/apache/hadoop/hive/serde2/lazy/LazySimpleSerDe.java
@@ -390,7 +390,7 @@ private static FieldRewriter createRewriter(String encoderClass, Properties prop
try {
FieldRewriter rewriter =
(FieldRewriter) ReflectionUtils.newInstance(Class.forName(encoderClass), job);
- rewriter.init(parameters.columnNames, parameters.columnTypes, properties);
+ rewriter.init(parameters.columnNames, parameters.columnTypes, properties, job);
return rewriter;
} catch (Exception e) {
throw new SerDeException(e);
diff --git a/shims/common/src/main/java/org/apache/hadoop/hive/shims/ShimLoader.java b/shims/common/src/main/java/org/apache/hadoop/hive/shims/ShimLoader.java
index f354fb7..ecc81fb 100644
--- a/shims/common/src/main/java/org/apache/hadoop/hive/shims/ShimLoader.java
+++ b/shims/common/src/main/java/org/apache/hadoop/hive/shims/ShimLoader.java
@@ -163,6 +163,7 @@ public static String getMajorVersion() {
case 1:
return "0.20S";
case 2:
+ case 3:
return "0.23";
default:
throw new IllegalArgumentException("Unrecognized Hadoop major version number: " + vers);