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 2ca992e  Add the exposed password checking function (#447)
2ca992e is described below

commit 2ca992e818da86a22b76bc9d4c5a9099d959e50e
Author: Mingshen Sun <[email protected]>
AuthorDate: Fri Dec 18 11:00:24 2020 -0800

    Add the exposed password checking function (#447)
---
 cli/src/main.rs                                    |   2 +-
 cmake/scripts/test.sh                              |   1 +
 examples/python/builtin_password_check.py          | 194 +++++++++++++++++++++
 executor/Cargo.toml                                |  14 +-
 executor/src/builtin.rs                            |   6 +-
 file_agent/Cargo.toml                              |   1 +
 file_agent/src/agent.rs                            |  23 +++
 function/README.md                                 |   2 +
 function/src/lib.rs                                |  13 +-
 function/src/password_check.rs                     | 103 +++++++++++
 .../functions/password_check/exposed_passwords.txt |  20 +++
 .../password_check/exposed_passwords.txt.enc       | Bin 0 -> 4096 bytes
 .../fixtures/functions/password_check/password.txt |   1 +
 tests/scripts/simple_http_server.py                |   2 +-
 14 files changed, 367 insertions(+), 15 deletions(-)

diff --git a/cli/src/main.rs b/cli/src/main.rs
index 372443e..1c672ed 100644
--- a/cli/src/main.rs
+++ b/cli/src/main.rs
@@ -260,7 +260,7 @@ fn attest(opt: AttestOpt) -> Result<()> {
 
     let mut session = rustls::ClientSession::new(&rc_config, hostname);
     let mut tls_stream = rustls::Stream::new(&mut session, &mut stream);
-    tls_stream.write(&[0]).unwrap();
+    tls_stream.write_all(&[0]).unwrap();
 
     Ok(())
 }
diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index 5388371..ab3a5df 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -191,6 +191,7 @@ run_examples() {
   python3 builtin_ordered_set_intersect.py
   python3 builtin_rsa_sign.py
   python3 builtin_face_detection.py
+  python3 builtin_password_check.py
   popd
 
   # kill all background services
diff --git a/examples/python/builtin_password_check.py 
b/examples/python/builtin_password_check.py
new file mode 100644
index 0000000..fb87d42
--- /dev/null
+++ b/examples/python/builtin_password_check.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python3
+
+# 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.
+
+import sys
+
+from teaclave import (AuthenticationService, FrontendService,
+                      AuthenticationClient, FrontendClient, FunctionInput,
+                      FunctionOutput, OwnerList, DataMap)
+from utils import (AUTHENTICATION_SERVICE_ADDRESS, FRONTEND_SERVICE_ADDRESS,
+                   AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, USER_ID,
+                   USER_PASSWORD)
+
+# In the example, user 0 creates the task and user 0, 1, upload their private 
data.
+# Then user 0 invokes the task and user 0, 1 get the result.
+
+
+class UserData:
+    def __init__(self,
+                 user_id,
+                 password,
+                 input_url="",
+                 encryption_algorithm="teaclave-file-128",
+                 input_cmac="",
+                 iv=[],
+                 key=[]):
+        self.user_id = user_id
+        self.password = password
+        self.input_url = input_url
+        self.encryption_algorithm = encryption_algorithm
+        self.input_cmac = input_cmac
+        self.iv = iv
+        self.key = key
+
+
+INPUT_FILE_URL_PREFIX = 
"http://localhost:6789/fixtures/functions/password_check/";
+
+# Client
+USER_DATA_0 = UserData(
+    "user0",
+    "password",
+    "data:text/plain;base64,c+mpvRfZ0fboR0j3rTgOGDBiubSzlCt9",  # base64 of 
encrypted string "password"
+    "aes-gcm-128",
+    "e84748f7ad380e183062b9b4b3942b7d",
+    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+
+# Data provider
+USER_DATA_1 = UserData("user1", "password",
+                       INPUT_FILE_URL_PREFIX + "exposed_passwords.txt.enc",
+                       "teaclave-file-128", "42b16c29edeb9ee0e4d219f3b5395946",
+                       [], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+
+
+class DataList:
+    def __init__(self, data_name, data_id):
+        self.data_name = data_name
+        self.data_id = data_id
+
+
+class Client:
+    def __init__(self, user_id, user_password):
+        self.user_id = user_id
+        self.user_password = user_password
+        self.client = AuthenticationService(
+            AUTHENTICATION_SERVICE_ADDRESS, AS_ROOT_CA_CERT_PATH,
+            ENCLAVE_INFO_PATH).connect().get_client()
+        print(f"[+] {self.user_id} registering user")
+        self.client.user_register(self.user_id, self.user_password)
+        print(f"[+] {self.user_id} login")
+        token = self.client.user_login(self.user_id, self.user_password)
+        self.client = FrontendService(
+            FRONTEND_SERVICE_ADDRESS, AS_ROOT_CA_CERT_PATH,
+            ENCLAVE_INFO_PATH).connect().get_client()
+        metadata = {"id": self.user_id, "token": token}
+        self.client.metadata = metadata
+
+    def set_task(self):
+        client = self.client
+
+        print(f"[+] {self.user_id} registering function")
+
+        function_id = client.register_function(
+            name="builtin-password-check",
+            description="Check whether a password is exposed.",
+            executor_type="builtin",
+            arguments=[],
+            inputs=[
+                FunctionInput("password", "Client 0 data."),
+                FunctionInput("exposed_passwords", "Client 1 data.")
+            ],
+            outputs=[])
+
+        print(f"[+] {self.user_id} creating task")
+        task_id = client.create_task(
+            function_id=function_id,
+            function_arguments={},
+            executor="builtin",
+            inputs_ownership=[
+                OwnerList("password", [USER_DATA_0.user_id]),
+                OwnerList("exposed_passwords", [USER_DATA_1.user_id])
+            ],
+        )
+
+        return task_id
+
+    def run_task(self, task_id):
+        client = self.client
+        print(f"[+] {self.user_id} invoking task")
+        client.invoke_task(task_id)
+
+    def register_data(self, task_id, input_url, algorithm, input_cmac,
+                      file_key, iv, input_label):
+        client = self.client
+
+        print(f"[+] {self.user_id} registering input file")
+        url = input_url
+        cmac = input_cmac
+        schema = algorithm
+        key = file_key
+        input_id = client.register_input_file(url, schema, key, iv, cmac)
+
+        print(f"[+] {self.user_id} assigning data to task")
+        client.assign_data_to_task(task_id, [DataList(input_label, input_id)],
+                                   [])
+
+    def approve_task(self, task_id):
+        client = self.client
+        print(f"[+] {self.user_id} approving task")
+        client.approve_task(task_id)
+
+    def get_task_result(self, task_id):
+        client = self.client
+        print(f"[+] {self.user_id} getting task result")
+        return bytes(client.get_task_result(task_id))
+
+
+def main():
+    user0 = Client(USER_DATA_0.user_id, USER_DATA_0.password)
+    user1 = Client(USER_DATA_1.user_id, USER_DATA_1.password)
+
+    task_id = user0.set_task()
+
+    user0.register_data(
+        task_id,
+        USER_DATA_0.input_url,
+        USER_DATA_0.encryption_algorithm,
+        USER_DATA_0.input_cmac,
+        USER_DATA_0.key,
+        USER_DATA_0.iv,
+        "password",
+    )
+
+    user1.register_data(
+        task_id,
+        USER_DATA_1.input_url,
+        USER_DATA_1.encryption_algorithm,
+        USER_DATA_1.input_cmac,
+        USER_DATA_1.key,
+        USER_DATA_1.iv,
+        "exposed_passwords",
+    )
+
+    user0.approve_task(task_id)
+    user1.approve_task(task_id)
+
+    ## USER 0 start the computation
+    user0.run_task(task_id)
+
+    ## USER 0, 1 get the result
+    result_user0 = user0.get_task_result(task_id)
+    result_user1 = user1.get_task_result(task_id)
+
+    print("[+] User 0 result: " + result_user0.decode("utf-8"))
+    print("[+] User 1 result: " + result_user1.decode("utf-8"))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/executor/Cargo.toml b/executor/Cargo.toml
index 76ea1a9..7f88450 100644
--- a/executor/Cargo.toml
+++ b/executor/Cargo.toml
@@ -29,29 +29,31 @@ enclave_unit_test = [
 
 full_builtin_function = [
   "builtin_echo",
+  "builtin_face_detection",
   "builtin_gbdt_predict",
   "builtin_gbdt_train",
   "builtin_logistic_regression_predict",
   "builtin_logistic_regression_train",
+  "builtin_password_check",
   "builtin_online_decrypt",
-  "builtin_private_join_and_compute",
   "builtin_ordered_set_intersect",
-  "builtin_rsa_sign",
-  "builtin_face_detection",
   "builtin_principal_components_analysis",
+  "builtin_private_join_and_compute",
+  "builtin_rsa_sign",
 ]
 
 builtin_echo = []
+builtin_face_detection = []
 builtin_gbdt_predict = []
 builtin_gbdt_train = []
 builtin_logistic_regression_predict = []
 builtin_logistic_regression_train = []
+builtin_password_check = []
 builtin_online_decrypt = []
-builtin_private_join_and_compute = []
 builtin_ordered_set_intersect = []
-builtin_rsa_sign = []
-builtin_face_detection = []
 builtin_principal_components_analysis = []
+builtin_private_join_and_compute = []
+builtin_rsa_sign = []
 
 [dependencies]
 log           = { version = "0.4.6", features = ["release_max_level_info"] }
diff --git a/executor/src/builtin.rs b/executor/src/builtin.rs
index afc9862..070bd88 100644
--- a/executor/src/builtin.rs
+++ b/executor/src/builtin.rs
@@ -20,8 +20,8 @@ use std::prelude::v1::*;
 
 use teaclave_function::{
     Echo, FaceDetection, GbdtPredict, GbdtTrain, LogisticRegressionPredict,
-    LogisticRegressionTrain, OnlineDecrypt, OrderedSetIntersect, 
PrincipalComponentsAnalysis,
-    PrivateJoinAndCompute, RsaSign,
+    LogisticRegressionTrain, OnlineDecrypt, OrderedSetIntersect, PasswordCheck,
+    PrincipalComponentsAnalysis, PrivateJoinAndCompute, RsaSign,
 };
 use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveExecutor};
 
@@ -65,6 +65,8 @@ impl TeaclaveExecutor for BuiltinFunctionExecutor {
             }
             #[cfg(feature = "builtin_face_detection")]
             FaceDetection::NAME => FaceDetection::new().run(arguments, 
runtime),
+            #[cfg(feature = "builtin_password_check")]
+            PasswordCheck::NAME => PasswordCheck::new().run(arguments, 
runtime),
             _ => bail!("Function not found."),
         }
     }
diff --git a/file_agent/Cargo.toml b/file_agent/Cargo.toml
index ee888f0..c40c206 100644
--- a/file_agent/Cargo.toml
+++ b/file_agent/Cargo.toml
@@ -16,6 +16,7 @@ default = []
 [dependencies]
 log           = { version = "0.4.6", features = ["release_max_level_info"] }
 anyhow        = { version = "1.0.26" }
+base64        = { version = "0.10.1" }
 serde_json    = { version = "1.0.39" }
 serde         = { version = "1.0.92", features = ["derive"] }
 thiserror     = { version = "1.0.9" }
diff --git a/file_agent/src/agent.rs b/file_agent/src/agent.rs
index 3754e65..caa0d45 100644
--- a/file_agent/src/agent.rs
+++ b/file_agent/src/agent.rs
@@ -129,6 +129,15 @@ async fn handle_download(
             );
             copy_file(src, dst).await?;
         }
+        "data" => {
+            let data = remote.path().split(',').collect::<Vec<&str>>();
+            if data.len() == 2 && data[0] == "text/plain;base64" {
+                let bytes = base64::decode(data[1])?;
+                tokio::fs::write(dst, bytes).await?;
+            } else {
+                anyhow::bail!("Scheme format not supported")
+            }
+        }
         _ => anyhow::bail!("Scheme not supported"),
     }
     Ok(())
@@ -376,4 +385,18 @@ mod tests {
 
         std::fs::remove_dir_all(&base).unwrap();
     }
+
+    #[test]
+    fn test_data_scheme() {
+        let url = 
Url::parse("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==").unwrap();
+        let dest = PathBuf::from("/tmp/input_test.txt");
+        let info = HandleFileInfo::new(&dest, &url);
+        let req = FileAgentRequest::new(HandleFileCommand::Download, 
vec![info], "");
+
+        let bytes = serde_json::to_vec(&req).unwrap();
+        handle_file_request(&bytes).unwrap();
+        assert_eq!(std::fs::read_to_string(&dest).unwrap(), "Hello, World!");
+
+        std::fs::remove_file(&dest).unwrap();
+    }
 }
diff --git a/function/README.md b/function/README.md
index d1bbe01..c27adc0 100644
--- a/function/README.md
+++ b/function/README.md
@@ -28,6 +28,8 @@ Currently, we have these built-in functions:
   - `builtin-face-detection`: An implementation of Funnel-Structured cascade,
     which is designed for real-time multi-view face detection.
   - `builtin-principal-components-analysis`: Example to calculate PCA.
+  - `builtin-password-check`: Given a password, check whether it is in the
+    exposed password list.
   
 The function arguments are in JSON format and can be serialized to a Rust 
struct
 very easily. You can learn more about supported arguments in the implementation
diff --git a/function/src/lib.rs b/function/src/lib.rs
index 6bb6ce1..641512c 100644
--- a/function/src/lib.rs
+++ b/function/src/lib.rs
@@ -30,6 +30,7 @@ mod logistic_regression_predict;
 mod logistic_regression_train;
 mod online_decrypt;
 mod ordered_set_intersect;
+mod password_check;
 mod principal_components_analysis;
 mod private_join_and_compute;
 mod rsa_sign;
@@ -42,6 +43,7 @@ pub use 
logistic_regression_predict::LogisticRegressionPredict;
 pub use logistic_regression_train::LogisticRegressionTrain;
 pub use online_decrypt::OnlineDecrypt;
 pub use ordered_set_intersect::OrderedSetIntersect;
+pub use password_check::PasswordCheck;
 pub use principal_components_analysis::PrincipalComponentsAnalysis;
 pub use private_join_and_compute::PrivateJoinAndCompute;
 pub use rsa_sign::RsaSign;
@@ -54,16 +56,17 @@ pub mod tests {
     pub fn run_tests() -> bool {
         check_all_passed!(
             echo::tests::run_tests(),
-            gbdt_train::tests::run_tests(),
+            face_detection::tests::run_tests(),
             gbdt_predict::tests::run_tests(),
-            logistic_regression_train::tests::run_tests(),
+            gbdt_train::tests::run_tests(),
             logistic_regression_predict::tests::run_tests(),
+            logistic_regression_train::tests::run_tests(),
+            password_check::tests::run_tests(),
             online_decrypt::tests::run_tests(),
-            private_join_and_compute::tests::run_tests(),
             ordered_set_intersect::tests::run_tests(),
-            rsa_sign::tests::run_tests(),
-            face_detection::tests::run_tests(),
             principal_components_analysis::tests::run_tests(),
+            private_join_and_compute::tests::run_tests(),
+            rsa_sign::tests::run_tests(),
         )
     }
 }
diff --git a/function/src/password_check.rs b/function/src/password_check.rs
new file mode 100644
index 0000000..10d4652
--- /dev/null
+++ b/function/src/password_check.rs
@@ -0,0 +1,103 @@
+// 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.
+
+use std::io::prelude::*;
+use std::prelude::v1::*;
+
+use std::collections::HashSet;
+use std::convert::TryFrom;
+use std::io::BufReader;
+use teaclave_types::{FunctionArguments, FunctionRuntime};
+
+#[derive(Default)]
+pub struct PasswordCheck;
+
+#[derive(serde::Deserialize)]
+struct PasswordCheckArguments;
+
+impl TryFrom<FunctionArguments> for PasswordCheckArguments {
+    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")
+    }
+}
+
+impl PasswordCheck {
+    pub const NAME: &'static str = "builtin-password-check";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(&self, _: FunctionArguments, runtime: FunctionRuntime) -> 
anyhow::Result<String> {
+        let password_file = runtime.open_input("password")?;
+        let password = BufReader::new(password_file)
+            .lines()
+            .next()
+            .unwrap()
+            .unwrap()
+            .trim()
+            .to_owned();
+        let exposed_passwords_file = runtime.open_input("exposed_passwords")?;
+        let exposed_passwords: HashSet<String> = 
BufReader::new(exposed_passwords_file)
+            .lines()
+            .map(|l| l.expect("Could not parse line").trim().to_string())
+            .collect::<Vec<String>>()
+            .iter()
+            .cloned()
+            .collect();
+        if exposed_passwords.contains(&password) {
+            Ok("true".to_string())
+        } else {
+            Ok("false".to_string())
+        }
+    }
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use super::*;
+    use std::path::Path;
+    use teaclave_crypto::*;
+    use teaclave_runtime::*;
+    use teaclave_test_utils::*;
+    use teaclave_types::*;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_password_check)
+    }
+
+    fn test_password_check() {
+        let password_input = 
Path::new("fixtures/functions/password_check/password.txt");
+        let exposed_passwords_input =
+            
Path::new("fixtures/functions/password_check/exposed_passwords.txt");
+        let arguments = FunctionArguments::default();
+
+        let input_files = StagedFiles::new(hashmap!(
+            "password" => StagedFileInfo::new(&password_input, 
TeaclaveFile128Key::random(), FileAuthTag::mock()),
+            "exposed_passwords" => 
StagedFileInfo::new(&exposed_passwords_input, TeaclaveFile128Key::random(), 
FileAuthTag::mock()),
+        ));
+        let output_files = StagedFiles::new(hashmap!());
+        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
+
+        let result = PasswordCheck::new().run(arguments, runtime).unwrap();
+
+        assert_eq!(result, "true");
+    }
+}
diff --git a/tests/fixtures/functions/password_check/exposed_passwords.txt 
b/tests/fixtures/functions/password_check/exposed_passwords.txt
new file mode 100644
index 0000000..48ee889
--- /dev/null
+++ b/tests/fixtures/functions/password_check/exposed_passwords.txt
@@ -0,0 +1,20 @@
+123456
+123456789
+qwerty
+password
+1111111
+12345678
+abc123
+1234567
+password1
+12345
+1234567890
+123123
+000000
+Iloveyou
+1234
+1q2w3e4r5t
+Qwertyuiop
+123
+Monkey
+Dragon
diff --git a/tests/fixtures/functions/password_check/exposed_passwords.txt.enc 
b/tests/fixtures/functions/password_check/exposed_passwords.txt.enc
new file mode 100644
index 0000000..af31d20
Binary files /dev/null and 
b/tests/fixtures/functions/password_check/exposed_passwords.txt.enc differ
diff --git a/tests/fixtures/functions/password_check/password.txt 
b/tests/fixtures/functions/password_check/password.txt
new file mode 100644
index 0000000..f3097ab
--- /dev/null
+++ b/tests/fixtures/functions/password_check/password.txt
@@ -0,0 +1 @@
+password
diff --git a/tests/scripts/simple_http_server.py 
b/tests/scripts/simple_http_server.py
old mode 100644
new mode 100755
index 5a0cd01..709285b
--- a/tests/scripts/simple_http_server.py
+++ b/tests/scripts/simple_http_server.py
@@ -23,7 +23,7 @@ if __name__ == '__main__':
     else:
         port = 6789
     socketserver.TCPServer.allow_reuse_address = True
-    with socketserver.TCPServer(("localhost", port),
+    with socketserver.TCPServer(("0.0.0.0", port),
                                 HTTPRequestHandler) as httpd:
         print("serving at port", port)
         httpd.serve_forever()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to