You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2020/06/02 03:57:05 UTC

[incubator-teaclave] branch master updated: [function] Add a OnlineDecrypt built-in function (#325)

This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/master by this push:
     new 7bd059a  [function] Add a OnlineDecrypt built-in function (#325)
7bd059a is described below

commit 7bd059a1173f418e1e218d78a9b9cd5a582a601c
Author: Qinkun Bao <qi...@gmail.com>
AuthorDate: Mon Jun 1 23:56:55 2020 -0400

    [function] Add a OnlineDecrypt built-in function (#325)
---
 cmake/scripts/test.sh                     |   1 +
 examples/python/builtin_online_decrypt.py |  84 +++++++++++++++++
 executor/Cargo.toml                       |   5 +-
 executor/src/builtin.rs                   |   4 +-
 function/Cargo.toml                       |   2 +
 function/src/lib.rs                       |   3 +
 function/src/online_decrypt.rs            | 148 ++++++++++++++++++++++++++++++
 7 files changed, 245 insertions(+), 2 deletions(-)

diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index 7e6119c..c2b2fa9 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -160,6 +160,7 @@ run_examples() {
   python3 builtin_echo.py
   python3 mesapy_echo.py
   python3 builtin_gbdt_train.py
+  python3 builtin_online_decrypt.py
   popd
 
   # kill all background services
diff --git a/examples/python/builtin_online_decrypt.py b/examples/python/builtin_online_decrypt.py
new file mode 100644
index 0000000..6bad1bf
--- /dev/null
+++ b/examples/python/builtin_online_decrypt.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+
+import sys
+import base64
+
+from teaclave import (AuthenticationService, FrontendService,
+                      AuthenticationClient, FrontendClient)
+from utils import (AUTHENTICATION_SERVICE_ADDRESS, FRONTEND_SERVICE_ADDRESS,
+                   AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, USER_ID,
+                   USER_PASSWORD)
+
+
+class BuiltinOnlineDecryptExample:
+    def __init__(self, user_id, user_password):
+        self.user_id = user_id
+        self.user_password = user_password
+
+    def decrypt(self, key, nonce, encrypted_data, algorithm):
+        channel = AuthenticationService(AUTHENTICATION_SERVICE_ADDRESS,
+                                        AS_ROOT_CA_CERT_PATH,
+                                        ENCLAVE_INFO_PATH).connect()
+        client = AuthenticationClient(channel)
+
+        print("[+] registering user")
+        client.user_register(self.user_id, self.user_password)
+
+        print("[+] login")
+        token = client.user_login(self.user_id, self.user_password)
+
+        channel = FrontendService(FRONTEND_SERVICE_ADDRESS,
+                                  AS_ROOT_CA_CERT_PATH,
+                                  ENCLAVE_INFO_PATH).connect()
+        metadata = {"id": self.user_id, "token": token}
+        client = FrontendClient(channel, metadata)
+
+        print("[+] registering function")
+        function_id = client.register_function(
+            name="builtin_online_decrypt",
+            description="Native Echo Function",
+            executor_type="builtin",
+            arguments=["key", "nonce", "encrypted_data", "algorithm"])
+
+        print("[+] creating task")
+        task_id = client.create_task(
+            function_id=function_id,
+            function_arguments={
+                "key": dataToBase64(key),
+                "nonce": dataToBase64(nonce),
+                "encrypted_data":
+                "CaZd8qSMMlBp8SjSXj2I4dQIuC9KkZ5DI/ATo1sWJw==",
+                "algorithm": algorithm
+            },
+            executor="builtin")
+
+        print("[+] invoking task")
+        client.invoke_task(task_id)
+
+        print("[+] getting result")
+        result = client.get_task_result(task_id)
+        print("[+] done")
+
+        return bytes(result)
+
+
+def dataToBase64(data):
+    return base64.standard_b64encode(bytes(data)).decode("utf-8")
+
+
+def main():
+    example = BuiltinOnlineDecryptExample(USER_ID, USER_PASSWORD)
+    key = [
+        106, 165, 29, 129, 157, 37, 38, 123, 179, 247, 40, 143, 146, 128, 241,
+        51, 166, 92, 77, 197, 85, 165, 222, 10, 40, 186, 179, 108, 112, 252,
+        240, 184
+    ]
+    nonce = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
+    encrypted_data = "CaZd8qSMMlBp8SjSXj2I4dQIuC9KkZ5DI/ATo1sWJw=="
+    algorithm = "aes256gcm" # Alogorithm can be "aes256gcm" or "aes128gcm"
+    rt = example.decrypt(key, nonce, encrypted_data, algorithm)
+    print("[+] function return: ", rt)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/executor/Cargo.toml b/executor/Cargo.toml
index cc18df0..19c0e7e 100644
--- a/executor/Cargo.toml
+++ b/executor/Cargo.toml
@@ -30,13 +30,16 @@ full_builtin_function = [
   "builtin_gbdt_predict",
   "builtin_gbdt_train",
   "builtin_logistic_regression_predict",
-  "builtin_logistic_regression_train"
+  "builtin_logistic_regression_train",
+  "builtin_online_decrypt",
 ]
+
 builtin_echo = []
 builtin_gbdt_predict = []
 builtin_gbdt_train = []
 builtin_logistic_regression_predict = []
 builtin_logistic_regression_train = []
+builtin_online_decrypt = []
 
 [dependencies]
 log           = { version = "0.4.6" }
diff --git a/executor/src/builtin.rs b/executor/src/builtin.rs
index 9e9941f..990d014 100644
--- a/executor/src/builtin.rs
+++ b/executor/src/builtin.rs
@@ -19,7 +19,7 @@
 use std::prelude::v1::*;
 
 use teaclave_function::{
-    Echo, GbdtPredict, GbdtTrain, LogisticRegressionPredict, LogisticRegressionTrain,
+    Echo, GbdtPredict, GbdtTrain, LogisticRegressionPredict, LogisticRegressionTrain, OnlineDecrypt,
 };
 use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveExecutor};
 
@@ -49,6 +49,8 @@ impl TeaclaveExecutor for BuiltinFunctionExecutor {
             LogisticRegressionPredict::NAME => {
                 LogisticRegressionPredict::new().run(arguments, runtime)
             }
+            #[cfg(feature = "builtin_online_decrypt")]
+            OnlineDecrypt::NAME => OnlineDecrypt::new().run(arguments, runtime),
             _ => bail!("Function not found."),
         }
     }
diff --git a/function/Cargo.toml b/function/Cargo.toml
index 9fcf244..b0b761f 100644
--- a/function/Cargo.toml
+++ b/function/Cargo.toml
@@ -31,6 +31,8 @@ thiserror     = { version = "1.0.9" }
 gbdt          = { version = "0.1.0", features = ["input", "enable_training"] }
 rusty-machine = { version = "0.5.4" }
 itertools     = { version = "0.8.0", default-features = false }
+ring          = { version = "0.16.5" }
+base64        = { version = "0.10.1" }
 teaclave_types = { path = "../types" }
 teaclave_crypto = { path = "../crypto" }
 teaclave_runtime = { path = "../runtime", optional = true }
diff --git a/function/src/lib.rs b/function/src/lib.rs
index a2c0c56..43189b6 100644
--- a/function/src/lib.rs
+++ b/function/src/lib.rs
@@ -27,12 +27,14 @@ mod gbdt_predict;
 mod gbdt_train;
 mod logistic_regression_predict;
 mod logistic_regression_train;
+mod online_decrypt;
 
 pub use echo::Echo;
 pub use gbdt_predict::GbdtPredict;
 pub use gbdt_train::GbdtTrain;
 pub use logistic_regression_predict::LogisticRegressionPredict;
 pub use logistic_regression_train::LogisticRegressionTrain;
+pub use online_decrypt::OnlineDecrypt;
 
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
@@ -46,6 +48,7 @@ pub mod tests {
             gbdt_predict::tests::run_tests(),
             logistic_regression_train::tests::run_tests(),
             logistic_regression_predict::tests::run_tests(),
+            online_decrypt::tests::run_tests(),
         )
     }
 }
diff --git a/function/src/online_decrypt.rs b/function/src/online_decrypt.rs
new file mode 100644
index 0000000..a495bf4
--- /dev/null
+++ b/function/src/online_decrypt.rs
@@ -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.
+
+#[cfg(feature = "mesalock_sgx")]
+use std::prelude::v1::*;
+extern crate base64;
+use anyhow::{anyhow, bail, Result};
+use ring::aead::*;
+use std::convert::TryFrom;
+use std::str;
+use teaclave_types::{FunctionArguments, FunctionRuntime};
+
+#[derive(Default)]
+pub struct OnlineDecrypt;
+
+#[derive(serde::Deserialize)]
+struct OnlineDecryptArguments {
+    key: String,
+    nonce: String,
+    encrypted_data: String,
+    algorithm: String,
+}
+
+impl TryFrom<FunctionArguments> for OnlineDecryptArguments {
+    type Error = anyhow::Error;
+
+    fn try_from(arguments: FunctionArguments) -> Result<Self, Self::Error> {
+        use anyhow::Context;
+        serde_json::from_str(&arguments.into_string()).context("Cannot deserialize arguments")
+    }
+}
+
+fn decrypt(
+    key: &[u8],
+    nonce_data: &[u8],
+    data: &mut Vec<u8>,
+    alg: &'static ring::aead::Algorithm,
+) -> anyhow::Result<()> {
+    let key =
+        LessSafeKey::new(UnboundKey::new(&alg, &key).map_err(|_| anyhow!("decryption error"))?);
+    let nonce = Nonce::try_assume_unique_for_key(&nonce_data[0..12])
+        .map_err(|_| anyhow!("decryption error"))?;
+    key.open_in_place(nonce, Aad::empty(), data)
+        .map_err(|_| anyhow!("decryption error"))?;
+    data.truncate(data.len() - alg.tag_len());
+    Ok(())
+}
+
+fn decrypt_string_base64(
+    key: &str,
+    nonce_str: &str,
+    encrypted: &str,
+    alg: &'static ring::aead::Algorithm,
+) -> anyhow::Result<String> {
+    let decoded_key = base64::decode(&key)?;
+    let nonce = base64::decode(&nonce_str)?;
+    let mut data_vec = base64::decode(&encrypted)?;
+
+    decrypt(&decoded_key, &nonce, &mut data_vec, &alg).map_err(|_| anyhow!("decryption error"))?;
+    let string = str::from_utf8(&data_vec).map_err(|_| anyhow!("base64 decoded error"))?;
+
+    Ok(string.to_string())
+}
+
+impl OnlineDecrypt {
+    pub const NAME: &'static str = "builtin_online_decrypt";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
+        &self,
+        arguments: FunctionArguments,
+        _runtime: FunctionRuntime,
+    ) -> anyhow::Result<String> {
+        let args = OnlineDecryptArguments::try_from(arguments)?;
+        let key = args.key;
+        let nonce = args.nonce;
+        let encrypted_data = args.encrypted_data;
+        let algorithm = &args.algorithm[..];
+
+        let alg = match algorithm {
+            "aes128gcm" => &AES_128_GCM,
+            "aes256gcm" => &AES_256_GCM,
+            _ => bail!("Invalid algorithm"),
+        };
+
+        let result = decrypt_string_base64(&key, &nonce, &encrypted_data, alg)?;
+        Ok(result)
+    }
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use super::*;
+    use serde_json::json;
+    use teaclave_runtime::*;
+    use teaclave_test_utils::*;
+    use teaclave_types::*;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_online_decrypt)
+    }
+
+    fn test_subroutine(args: FunctionArguments, result: &str) {
+        let input_files = StagedFiles::default();
+        let output_files = StagedFiles::default();
+        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
+        let function = OnlineDecrypt;
+        let summary = function.run(args, runtime).unwrap();
+        assert_eq!(summary, result);
+    }
+
+    fn test_online_decrypt() {
+        let args1 = FunctionArguments::from_json(json!({
+            "key": "aqUdgZ0lJnuz9yiPkoDxM6ZcTcVVpd4KKLqzbHD88Lg=",
+            "nonce": "AAECAwQFBgcICQoL",
+            "encrypted_data": "CaZd8qSMMlBp8SjSXj2I4dQIuC9KkZ5DI/ATo1sWJw==",
+            "algorithm": "aes256gcm"
+        }))
+        .unwrap();
+        test_subroutine(args1, "Hello Teaclave!");
+
+        let args2 = FunctionArguments::from_json(json!({
+            "key": "aqUdgZ0lJnuz9yiPkoDxMw==",
+            "nonce": "AAECAwQFBgcICQoL",
+            "encrypted_data": "OqMscYqxk1CshHQZulTrrDlJjS/v6BE/clWJyTerUw==",
+            "algorithm": "aes128gcm"
+        }))
+        .unwrap();
+        test_subroutine(args2, "Hello Teaclave!");
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org