[function] Add a OnlineDecrypt built-in function (#325)
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 @@
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 @@
"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 @@
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 @@
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_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 @@
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!");
+ }
+}