Repository: drill
Updated Branches:
  refs/heads/master 8d659ff70 -> 07346c782


DRILL-5634: Add Crypto Functions

closes #865


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

Branch: refs/heads/master
Commit: a3f9dff0a00f5ed8b87c0802ea7cc069c6407bcd
Parents: 8d659ff
Author: cgivre <cgi...@gmail.com>
Authored: Sun Jul 2 23:13:02 2017 -0400
Committer: Arina Ielchiieva <arina.yelchiy...@gmail.com>
Committed: Fri Jul 21 15:48:06 2017 +0300

----------------------------------------------------------------------
 exec/java-exec/pom.xml                          |   5 +
 .../exec/expr/fn/impl/CryptoFunctions.java      | 388 +++++++++++++++++++
 .../drill/exec/fn/impl/TestCryptoFunctions.java |  92 +++++
 exec/jdbc-all/pom.xml                           |   4 +
 4 files changed, 489 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/drill/blob/a3f9dff0/exec/java-exec/pom.xml
----------------------------------------------------------------------
diff --git a/exec/java-exec/pom.xml b/exec/java-exec/pom.xml
index cd287aa..c275303 100644
--- a/exec/java-exec/pom.xml
+++ b/exec/java-exec/pom.xml
@@ -94,6 +94,11 @@
       <version>2.2</version>
     </dependency>
     <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.10</version>
+    </dependency>
+    <dependency>
       <groupId>com.thoughtworks.paranamer</groupId>
       <artifactId>paranamer</artifactId>
       <version>2.5.6</version>

http://git-wip-us.apache.org/repos/asf/drill/blob/a3f9dff0/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/CryptoFunctions.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/CryptoFunctions.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/CryptoFunctions.java
new file mode 100644
index 0000000..65e5fb5
--- /dev/null
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/CryptoFunctions.java
@@ -0,0 +1,388 @@
+/*
+ * 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.drill.exec.expr.fn.impl;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.annotations.Workspace;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+
+import javax.crypto.Cipher;
+import javax.inject.Inject;
+
+public class CryptoFunctions {
+  static final org.slf4j.Logger logger = 
org.slf4j.LoggerFactory.getLogger(CryptoFunctions.class);
+
+  private CryptoFunctions() {
+  }
+
+  /**
+   * This class returns the md2 digest of a given input string.
+   *  Usage is SELECT md2( <input string> ) FROM ...
+   */
+
+  @FunctionTemplate(name = "md2", scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class MD2Function implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Override
+    public void setup() {
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+      String outputString = 
org.apache.commons.codec.digest.DigestUtils.md2Hex(input).toLowerCase();
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = outputString.getBytes().length;
+      buffer.setBytes(0, outputString.getBytes());
+    }
+
+  }
+
+  /**
+   * This function returns the MD5 digest of a given input string.
+   *  Usage is shown below:
+   *  select md5( 'testing' ) from (VALUES(1));
+   */
+
+  @FunctionTemplate(name = "md5", scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class MD5Function implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Override
+    public void setup() {
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+      String outputString = 
org.apache.commons.codec.digest.DigestUtils.md5Hex(input).toLowerCase();
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = outputString.getBytes().length;
+      buffer.setBytes(0, outputString.getBytes());
+    }
+
+  }
+
+  /**
+   * sha(<text>) / sha1(<text>): Calculates an SHA-1 160-bit checksum for the 
string, as described in RFC 3174 (Secure Hash Algorithm).
+   * (https://en.wikipedia.org/wiki/SHA-1) The value is returned as a string 
of 40 hexadecimal digits, or NULL if the argument was NULL.
+   * Note that sha() and sha1() are aliases for the same function.
+   *
+   * > select sha1( 'testing' ) from (VALUES(1));
+   */
+
+  @FunctionTemplate(names = {"sha", "sha1"}, scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class SHA1Function implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Override
+    public void setup() {
+
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+
+      String sha1 = org.apache.commons.codec.digest.DigestUtils.sha1Hex(input);
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = sha1.getBytes().length;
+      buffer.setBytes(0, sha1.getBytes());
+    }
+
+  }
+
+  /**
+   * sha2(<text>) / sha256(<text>): Calculates an SHA-2 256-bit checksum for 
the string.  The value is returned as a string of hexadecimal digits,
+   * or NULL if the argument was NULL. Note that sha2() and sha256() are 
aliases for the same function.
+   * > select sha2( 'testing' ) from (VALUES(1));
+   */
+
+  @FunctionTemplate(names = {"sha256", "sha2"}, scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class SHA256Function implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+
+    @Override
+    public void setup() {
+
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+
+      String sha2 = 
org.apache.commons.codec.digest.DigestUtils.sha256Hex(input);
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = sha2.getBytes().length;
+      buffer.setBytes(0, sha2.getBytes());
+    }
+
+  }
+
+  /**
+   * This function returns the SHA384 digest of a given input string.
+   *  Usage is shown below:
+   *  select sha384( 'testing' ) from (VALUES(1));
+   */
+
+  @FunctionTemplate(name = "sha384", scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class SHA384Function implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Override
+    public void setup() {
+
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+
+      String sha384 = 
org.apache.commons.codec.digest.DigestUtils.sha384Hex(input);
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = sha384.getBytes().length;
+      buffer.setBytes(0, sha384.getBytes());
+    }
+
+  }
+
+  /**
+   * This function returns the SHA512 digest of a given input string.
+   *  Usage is shown below:
+   *  select sha512( 'testing' ) from (VALUES(1));
+   */
+
+
+  @FunctionTemplate(name = "sha512", scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class SHA512Function implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Override
+    public void setup() {
+
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+
+      String sha512 = 
org.apache.commons.codec.digest.DigestUtils.sha512Hex(input);
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = sha512.getBytes().length;
+      buffer.setBytes(0, sha512.getBytes());
+    }
+
+  }
+
+  /**
+   * aes_encrypt()/ aes_decrypt(): implement encryption and decryption of data 
using the official AES (Advanced Encryption Standard) algorithm,
+   * previously known as “Rijndael.” AES_ENCRYPT() encrypts the string str 
using the key string key_str and returns a
+   * binary string containing the encrypted output.
+   * Usage:  SELECT aes_encrypt( 'encrypted_text', 'my_secret_key' ) AS aes 
FROM (VALUES(1));
+   */
+
+
+  @FunctionTemplate(name = "aes_encrypt", scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class AESEncryptFunction implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Param
+    VarCharHolder rawKey;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Workspace
+    Cipher cipher;
+
+    @Override
+    public void setup() {
+      String key = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawKey.start,
 rawKey.end, rawKey.buffer);
+
+      try {
+        byte[] keyByteArray = key.getBytes("UTF-8");
+        java.security.MessageDigest sha = 
java.security.MessageDigest.getInstance("SHA-1");
+        keyByteArray = sha.digest(keyByteArray);
+        keyByteArray = java.util.Arrays.copyOf(keyByteArray, 16);
+        javax.crypto.spec.SecretKeySpec secretKey = new 
javax.crypto.spec.SecretKeySpec(keyByteArray, "AES");
+
+        cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+      } catch (Exception e) {
+        //Exceptions are ignored
+      }
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+      String encryptedText = "";
+      try {
+        encryptedText = 
javax.xml.bind.DatatypeConverter.printBase64Binary(cipher.doFinal(input.getBytes("UTF-8")));
+      } catch (Exception e) {
+        //Exceptions are ignored
+      }
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = encryptedText.getBytes().length;
+      buffer.setBytes(0, encryptedText.getBytes());
+    }
+
+  }
+
+  /**
+   *  AES_DECRYPT() decrypts the encrypted string crypt_str using the key 
string key_str and returns the original cleartext string.
+   *  If either function argument is NULL, the function returns NULL.
+   *  Usage:  SELECT aes_decrypt( <encrypted_text>, <key> ) FROM ...
+   */
+
+  @FunctionTemplate(name = "aes_decrypt", scope = 
FunctionTemplate.FunctionScope.SIMPLE, nulls = 
FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class AESDecryptFunction implements DrillSimpleFunc {
+
+    @Param
+    VarCharHolder rawInput;
+
+    @Param
+    VarCharHolder rawKey;
+
+    @Output
+    VarCharHolder out;
+
+    @Inject
+    DrillBuf buffer;
+
+    @Workspace
+    Cipher cipher;
+
+    @Override
+    public void setup() {
+      String key = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawKey.start,
 rawKey.end, rawKey.buffer);
+
+      try {
+        byte[] keyByteArray = key.getBytes("UTF-8");
+        java.security.MessageDigest sha = 
java.security.MessageDigest.getInstance("SHA-1");
+        keyByteArray = sha.digest(keyByteArray);
+        keyByteArray = java.util.Arrays.copyOf(keyByteArray, 16);
+        javax.crypto.spec.SecretKeySpec secretKey = new 
javax.crypto.spec.SecretKeySpec(keyByteArray, "AES");
+
+        cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+        cipher.init(Cipher.DECRYPT_MODE, secretKey);
+      } catch (Exception e) {
+        //Exceptions are ignored
+      }
+    }
+
+    @Override
+    public void eval() {
+
+      String input = 
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawInput.start,
 rawInput.end, rawInput.buffer);
+      String decryptedText = "";
+      try {
+        decryptedText = new 
String(cipher.doFinal(javax.xml.bind.DatatypeConverter.parseBase64Binary(input)));
+      } catch (Exception e) {
+        //Exceptions are ignored
+      }
+
+      out.buffer = buffer;
+      out.start = 0;
+      out.end = decryptedText.getBytes().length;
+      buffer.setBytes(0, decryptedText.getBytes());
+    }
+
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/drill/blob/a3f9dff0/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestCryptoFunctions.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestCryptoFunctions.java
 
b/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestCryptoFunctions.java
new file mode 100644
index 0000000..4dc6284
--- /dev/null
+++ 
b/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestCryptoFunctions.java
@@ -0,0 +1,92 @@
+/*
+ * 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.drill.exec.fn.impl;
+
+import org.apache.drill.BaseTestQuery;
+import org.junit.Test;
+
+public class TestCryptoFunctions extends BaseTestQuery {
+
+  @Test
+  public void testMD5() throws Exception {
+    final String query = "select md5('testing') as md5Hash from (values(1))";
+    
testBuilder().sqlQuery(query).ordered().baselineColumns("md5Hash").baselineValues("ae2b1fca515949e5d54fb22b8ed95575").go();
+  }
+
+  @Test
+  public void testMD2() throws Exception {
+    final String query = "select md2('testing') as md2Hash from (values(1))";
+    
testBuilder().sqlQuery(query).ordered().baselineColumns("md2Hash").baselineValues("fc134df10d6ecafceb5c75861d01b41f").go();
+  }
+
+
+  @Test
+  public void testSHA1() throws Exception {
+    final String query = "select sha('testing') as shaHash from (values(1))";
+    testBuilder()
+      .sqlQuery(query)
+      .ordered()
+      .baselineColumns("shaHash")
+      .baselineValues("dc724af18fbdd4e59189f5fe768a5f8311527050")
+      .go();
+  }
+
+  @Test
+  public void testSHA384() throws Exception {
+    final String query = "select sha384('testing') as shaHash from 
(values(1))";
+    testBuilder()
+      .sqlQuery(query)
+      .ordered()
+      .baselineColumns("shaHash")
+      
.baselineValues("cf4811d74fd40504674fc3273f824fa42f755b9660a2e902b57f1df74873db1a91a037bcee65f1a88ecd1ef57ff254c9")
+      .go();
+  }
+
+  @Test
+  public void testSHA512() throws Exception {
+    final String query = "select sha512('testing') as shaHash from 
(values(1))";
+    testBuilder()
+      .sqlQuery(query)
+      .ordered()
+      .baselineColumns("shaHash")
+      
.baselineValues("521b9ccefbcd14d179e7a1bb877752870a6d620938b28a66a107eac6e6805b9d0989f45b5730508041aa5e710847d439ea74cd312c9355f1f2dae08d40e41d50")
+      .go();
+  }
+
+  @Test
+  public void testAESEncrypt() throws Exception {
+    final String query = "select aes_encrypt('testing', 'secret_key') as 
encrypted FROM (VALUES(1))";
+    testBuilder()
+      .sqlQuery(query)
+      .ordered()
+      .baselineColumns("encrypted")
+      .baselineValues("ICf+zdOrLitogB8HUDru0w==")
+      .go();
+  }
+
+  @Test
+  public void testAESDecrypt() throws Exception {
+    final String query = "select aes_decrypt('ICf+zdOrLitogB8HUDru0w==', 
'secret_key') as decrypt from (values(1))";
+    testBuilder()
+      .sqlQuery(query)
+      .ordered()
+      .baselineColumns("decrypt")
+      .baselineValues("testing")
+      .go();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/drill/blob/a3f9dff0/exec/jdbc-all/pom.xml
----------------------------------------------------------------------
diff --git a/exec/jdbc-all/pom.xml b/exec/jdbc-all/pom.xml
index 238288e..56389be 100644
--- a/exec/jdbc-all/pom.xml
+++ b/exec/jdbc-all/pom.xml
@@ -68,6 +68,10 @@
           <artifactId>bcpkix-jdk15on</artifactId>
         </exclusion>
         <exclusion>
+          <groupId>commons-codec</groupId>
+          <artifactId>commons-codec</artifactId>
+        </exclusion>
+        <exclusion>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk15on</artifactId>
         </exclusion>

Reply via email to