├── .clang-format ├── .gitignore ├── Makefile ├── README.md ├── benchmark ├── README.md ├── bin │ ├── oltp.jar │ └── tpch.jar ├── config │ ├── config.xml │ ├── plugin.xml │ ├── tpcc_config.xml │ └── tpch_postgres.xml ├── db_schemas │ ├── tpcc-schema.sql │ ├── tpcc-schema_encrypted.sql │ ├── tpch-index.sql │ ├── tpch-schema-encrypted.sql │ └── tpch-schema.sql ├── log4j.properties ├── patches │ └── oltpbenchmark.patch └── tools │ ├── README │ ├── dbgen │ └── dists.dss ├── docker ├── Dockerfile └── sgx-deps.mk ├── docs ├── developer │ └── dirlayout.md └── user │ ├── README.md │ ├── character.md │ ├── datetime.md │ ├── install.md │ ├── numeric.md │ ├── oblvs.md │ └── utils.md ├── src ├── enclave.mk ├── enclave │ ├── enc_float32_ops.cpp │ ├── enc_int32_ops.cpp │ ├── enc_oblvs_int32_ops.cpp │ ├── enc_text_ops.cpp │ ├── enc_timestamp_ops.cpp │ ├── enclave.config.xml │ ├── enclave.cpp │ ├── enclave.edl │ └── enclave.lds ├── include │ ├── defs.h │ ├── enclave │ │ ├── Queue.hpp │ │ ├── enc_float32_ops.hpp │ │ ├── enc_int32_ops.hpp │ │ ├── enc_text_ops.hpp │ │ ├── enc_timestamp_ops.hpp │ │ └── enclave.hpp │ ├── tools │ │ ├── base64.hpp │ │ ├── bytes.hpp │ │ ├── like_match.h │ │ ├── oblvs_int32_ops.h │ │ ├── sync_utils.hpp │ │ └── timestamp.h │ └── untrusted │ │ ├── extensions │ │ └── stdafx.h │ │ └── interface │ │ ├── interface.h │ │ └── stdafx.h ├── tools │ ├── Queue.cpp │ ├── base64.cpp │ ├── bytes.cpp │ ├── like_match.c │ ├── oblvs_int32_ops.S │ ├── sync_utils.cpp │ └── timestamp.c ├── untrusted.mk ├── untrusted │ ├── Makefile │ ├── extensions │ │ ├── enc_float4.c │ │ ├── enc_int4.c │ │ ├── enc_text.c │ │ ├── enc_timestamp.c │ │ ├── encdb--0.0.1.sql │ │ ├── encdb.c │ │ └── encdb.control │ └── interface │ │ ├── enc_float32.cpp │ │ ├── enc_int32.cpp │ │ ├── enc_text.cpp │ │ ├── enc_timestamp.cpp │ │ └── interface.cpp └── vars.mk └── test ├── README.md ├── encdb └── run_test.sql └── sql ├── pgtap--0.90.0--0.91.0.sql ├── pgtap--0.91.0--0.92.0.sql ├── pgtap--0.92.0--0.93.0.sql ├── pgtap--0.93.0--0.94.0.sql ├── pgtap--0.94.0--0.95.0.sql ├── pgtap--0.95.0--0.96.0.sql ├── pgtap--unpackaged--0.91.0.sql ├── pgtap.sql ├── pgtap.sql.bak ├── pgtap.sql.in └── setup.sql /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -1 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlines: Right 8 | AlignOperands: true 9 | AlignTrailingComments: false 10 | AllowAllParametersOfDeclarationOnNextLine: false 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: All 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: true 19 | AlwaysBreakTemplateDeclarations: true 20 | BinPackArguments: true 21 | BinPackParameters: false 22 | BreakBeforeBinaryOperators: All 23 | BreakBeforeBraces: Allman 24 | BreakBeforeInheritanceComma: false 25 | BreakBeforeTernaryOperators: true 26 | BreakConstructorInitializersBeforeComma: false 27 | BreakConstructorInitializers: BeforeComma 28 | BreakAfterJavaFieldAnnotations: false 29 | BreakStringLiterals: true 30 | ColumnLimit: 0 31 | CommentPragmas: '^ IWYU pragma:' 32 | CompactNamespaces: false 33 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 34 | ConstructorInitializerIndentWidth: 4 35 | ContinuationIndentWidth: 4 36 | Cpp11BracedListStyle: false 37 | DerivePointerAlignment: false 38 | DisableFormat: false 39 | ExperimentalAutoDetectBinPacking: false 40 | FixNamespaceComments: false 41 | ForEachMacros: 42 | - foreach 43 | - Q_FOREACH 44 | - BOOST_FOREACH 45 | IncludeBlocks: Preserve 46 | IncludeCategories: 47 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 48 | Priority: 2 49 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 50 | Priority: 3 51 | - Regex: '.*' 52 | Priority: 1 53 | IncludeIsMainRegex: '(Test)?$' 54 | IndentCaseLabels: false 55 | IndentPPDirectives: None 56 | IndentWidth: 4 57 | IndentWrappedFunctionNames: false 58 | JavaScriptQuotes: Leave 59 | JavaScriptWrapImports: true 60 | KeepEmptyLinesAtTheStartOfBlocks: true 61 | MacroBlockBegin: '' 62 | MacroBlockEnd: '' 63 | MaxEmptyLinesToKeep: 1 64 | NamespaceIndentation: Inner 65 | ObjCBlockIndentWidth: 4 66 | ObjCSpaceAfterProperty: true 67 | ObjCSpaceBeforeProtocolList: true 68 | PenaltyBreakAssignment: 2 69 | PenaltyBreakBeforeFirstCallParameter: 19 70 | PenaltyBreakComment: 300 71 | PenaltyBreakFirstLessLess: 120 72 | PenaltyBreakString: 1000 73 | PenaltyExcessCharacter: 1000000 74 | PenaltyReturnTypeOnItsOwnLine: 60 75 | PointerAlignment: Left 76 | RawStringFormats: 77 | - Delimiter: pb 78 | Language: TextProto 79 | BasedOnStyle: google 80 | ReflowComments: false 81 | SortIncludes: true 82 | SortUsingDeclarations: true 83 | SpaceAfterCStyleCast: false 84 | SpaceAfterTemplateKeyword: true 85 | SpaceBeforeAssignmentOperators: true 86 | SpaceBeforeParens: ControlStatements 87 | SpaceInEmptyParentheses: false 88 | SpacesBeforeTrailingComments: 1 89 | SpacesInAngles: false 90 | SpacesInContainerLiterals: true 91 | SpacesInCStyleCastParentheses: false 92 | SpacesInParentheses: false 93 | SpacesInSquareBrackets: false 94 | Standard: Cpp11 95 | TabWidth: 8 96 | UseTab: Never 97 | ... 98 | 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | #ctags 26 | tags 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | # Debug files 43 | *.dSYM/ 44 | *.su 45 | *.idb 46 | *.pdb 47 | 48 | #SGX 49 | enclave_t.* 50 | enclave_u.* 51 | enclave.debug.* 52 | 53 | #Swap 54 | .Makefile.* 55 | *.swp 56 | 57 | #Vim 58 | .vimrc 59 | 60 | #Project Artifacts 61 | status.mk 62 | build 63 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UNTRUSTED_MK:= src/untrusted.mk 2 | ENCLAVE_MK:= src/enclave.mk 3 | 4 | .PHONY: all 5 | all: 6 | $(MAKE) -C $(shell dirname $(UNTRUSTED_MK)) -f $(shell basename $(UNTRUSTED_MK)) $@ 7 | $(MAKE) -C $(shell dirname $(ENCLAVE_MK)) -f $(shell basename $(ENCLAVE_MK)) $@ 8 | 9 | .PHONY: docker 10 | docker: 11 | docker build -f docker/Dockerfile -t stealthdb:1.0 docker/ 12 | docker run -it -d --rm --device=/dev/isgx --volume=/var/run/aesmd/aesm.socket:/var/run/aesmd/aesm.socket -p 5432:5432 --name sdb stealthdb:1.0 13 | 14 | .PHONY: install 15 | install: 16 | $(MAKE) -C $(shell dirname $(UNTRUSTED_MK)) -f $(shell basename $(UNTRUSTED_MK)) $@ 17 | $(MAKE) -C $(shell dirname $(ENCLAVE_MK)) -f $(shell basename $(ENCLAVE_MK)) $@ 18 | 19 | .PHONY: clean 20 | clean: 21 | $(MAKE) -C $(shell dirname $(UNTRUSTED_MK)) -f $(shell basename $(UNTRUSTED_MK)) $@ 22 | $(MAKE) -C $(shell dirname $(ENCLAVE_MK)) -f $(shell basename $(ENCLAVE_MK)) $@ 23 | $(RM) -r build 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | StealthDB 2 | ======================================================================= 3 | 4 | StealthDB is an extension to PostgreSQL, leveraging Intel SGX, that endows it with encrypted database functionality (i.e. encrypted values can be persisted in tables, and queries with encrypted expressions and predicates can be specified). The database's integrity and confidentiality is guaranteed under a threat model in which only the CPU is trusted. Further information can be found [here](https://arxiv.org/pdf/1711.02279.pdf). 5 | 6 | ## Status 7 | 8 | StealthDB is a research project and is **not** suitable for production use. 9 | 10 | ## Requirements 11 | 12 | * An Intel:registered: SGX-enabled CPU. In addition: 13 | * The [Intel:registered: SGX PSW and SDK](https://github.com/01org/linux-sgx#build-the-intelr-sgx-sdk-and-intelr-sgx-psw-package) installed in the `/opt` directory 14 | * Version 2.0 of the [Intel:registered: SGX Driver](https://github.com/01org/linux-sgx-driver#build-and-install-the-intelr-sgx-driver) 15 | 16 | * The NASM assembler. 17 | 18 | ## Quickstart 19 | 20 | ### Installing on 64-bit Ubuntu Desktop-16.04 21 | 22 | 0. Install PostgreSQL server and the PostgreSQL extension build tool: 23 | 24 | ``` 25 | sudo apt-get install postgresql postgresql-server-dev-all 26 | ``` 27 | 28 | 1. Run: 29 | 30 | ``` 31 | make 32 | sudo make install 33 | ``` 34 | 35 | ### Creating a Debian-based Docker Container 36 | 37 | 1. If you have a PostgreSQL service already running, be sure to stop it with `sudo service postgresql stop`. 38 | 39 | 2. Run 40 | 41 | ``` 42 | make docker 43 | ``` 44 | 45 | ### Running Queries 46 | 47 | 0. Run the PostgreSQL client. 48 | 49 | 1. Load the extension into the database, generate the default master key, and load the key. 50 | 51 | ``` 52 | CREATE EXTENSION encdb; 53 | SELECT generate_key(); 54 | SELECT load_key(0); 55 | ``` 56 | 57 | 2. Try some examples 58 | 59 | ``` 60 | SELECT pg_enc_int4_encrypt(1) + pg_enc_int4_encrypt(2); 61 | SELECT pg_enc_int4_decrypt(pg_enc_int4_encrypt(1) + pg_enc_int4_encrypt(2)); 62 | ``` 63 | 64 | `pg_enc_int4_decrypt` and `pg_enc_int4_encrypt` are wrappers around the `enc_int4` data type, which in turn corresponds to the `int4` type offered by PostgreSQL. 65 | 66 | `pg_enc_int4_encrypt(x)` encrypts the number `x` and stores it as an `enc_int4` value. `pg_enc_int4_decrypt(x)` takes an `enc_int4` value `x` and decrypts it. Further information can be found [here](https://github.com/cryptograph/stealthdb/blob/master/docs/user/README.md). 67 | 68 | Consult the [manual](https://github.com/cryptograph/stealthdb/blob/master/docs/user/install.md) for further information. 69 | -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarking suite 2 | 3 | We use modified open-source OLTP Benchmarking Framework (http://oltpbenchmark.com) to measure TPC-C and TPC-H performance. One can clone the source code of the framework and apply the patch or just use jar executable file to get numbers. 4 | 5 | ## Build from the source code. 6 | 7 | ``` 8 | git clone https://github.com/oltpbenchmark/oltpbench.git 9 | git checkout 51f9aa011defb33cfe4c8ebd902c495830c2824f 10 | git apply patches/oltpbenchmark.patch 11 | ``` 12 | 13 | ## Configuration 14 | 15 | * setup database credentials in configuration file config/tpcc_config_postgres.xml 16 | * setup logger configuration in log4j.properties 17 | * create TPC-C database schema, select which columns to encrypt 18 | (ex. ol_number int NOT NULL --> ol_number enc_int4 NOT NULL) 19 | 20 | See more information in the [original repository](https://github.com/oltpbenchmark/oltpbench/wiki/Quickstart) 21 | 22 | ## How to start 23 | 24 | 0. Create the user and the database 25 | 26 | ``` 27 | psql 28 | postgres> CREATE USER test WITH PASSWORD 'password'; 29 | postgres> CREATE DATABASE test; 30 | postgres> \c test; 31 | postgres> CREATE EXTENSION encdb; 32 | ``` 33 | 34 | ### TPC-C 35 | 1. Create tables and relations 36 | 37 | ``` 38 | psql -U test -d test -f db_schemas/tpcc-schema.sql 39 | (or psql -U test -d test -f db_schemas/tpcc-schema_encrypted.sql) 40 | ``` 41 | 42 | 2. Run experiments 43 | 44 | ``` 45 | java -Dlog4j.configuration=log4j.properties -jar bin/oltp.jar -b tpcc -o output -s 10 --config config/tpcc_config.xml --load true --execute true 46 | ``` 47 | 48 | 3. The output will be in the folder results/ containing files with the listing of start time and duration for each transaction type (output.raw), the throughput and different latency measures in milliseconds (output.res) 49 | 50 | ### TPC-H 51 | 1. Create tables and relations between them 52 | 53 | ``` 54 | psql -U test -d test -f db_schemas/tpch-schema.sql 55 | (or psql -U test -d test -f db_schemas/tpch-schema_encrypted.sql) 56 | psql -U test -d test -f db_schemas/tpch-index.sql 57 | ``` 58 | 59 | 2. Generate tables 60 | 61 | ``` 62 | tool/dbgen -s 2 63 | ``` 64 | 65 | 3. Run experiments 66 | 67 | ``` 68 | java -Dlog4j.configuration=log4j.properties -jar bin/tpch.jar -b tpch -o output -s 10 --config config/tpch_config.xml --load true --execute true 69 | ``` 70 | 71 | 4. The output will be in the folder results/ containing files with the listing of start time and duration for each transaction type (output.csv), the throughput and different latency measures in milliseconds (output.res) 72 | 73 | -------------------------------------------------------------------------------- /benchmark/bin/oltp.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptograph/stealthdb/1ca645ae1613c146d59900ce50abc873dc8a6d01/benchmark/bin/oltp.jar -------------------------------------------------------------------------------- /benchmark/bin/tpch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptograph/stealthdb/1ca645ae1613c146d59900ce50abc873dc8a6d01/benchmark/bin/tpch.jar -------------------------------------------------------------------------------- /benchmark/config/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.mysql.jdbc.Driver 4 | jdbc:mysql://127.0.0.1:3500/wiki1k 5 | wiki1k 6 | root 7 | 8 | 9 | 10 | 11 | 10 12 | 5,5,5,5 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /benchmark/config/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.oltpbenchmark.benchmarks.tpcc.TPCCBenchmark 4 | com.oltpbenchmark.benchmarks.tpch.TPCHBenchmark 5 | com.oltpbenchmark.benchmarks.tatp.TATPBenchmark 6 | com.oltpbenchmark.benchmarks.wikipedia.WikipediaBenchmark 7 | com.oltpbenchmark.benchmarks.resourcestresser.ResourceStresserBenchmark 8 | com.oltpbenchmark.benchmarks.twitter.TwitterBenchmark 9 | com.oltpbenchmark.benchmarks.epinions.EpinionsBenchmark 10 | com.oltpbenchmark.benchmarks.ycsb.YCSBBenchmark 11 | com.oltpbenchmark.benchmarks.jpab.JPABBenchmark 12 | com.oltpbenchmark.benchmarks.seats.SEATSBenchmark 13 | com.oltpbenchmark.benchmarks.auctionmark.AuctionMarkBenchmark 14 | com.oltpbenchmark.benchmarks.chbenchmark.CHBenCHmark 15 | com.oltpbenchmark.benchmarks.voter.VoterBenchmark 16 | com.oltpbenchmark.benchmarks.linkbench.LinkBenchBenchmark 17 | com.oltpbenchmark.benchmarks.sibench.SIBenchmark 18 | com.oltpbenchmark.benchmarks.noop.NoOpBenchmark 19 | com.oltpbenchmark.benchmarks.smallbank.SmallBankBenchmark 20 | com.oltpbenchmark.benchmarks.hyadapt.HYADAPTBenchmark 21 | 22 | -------------------------------------------------------------------------------- /benchmark/config/tpcc_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgres 6 | org.postgresql.Driver 7 | jdbc:postgresql://localhost:5432/test 8 | test 9 | password 10 | TRANSACTION_READ_COMMITTED 11 | 12 | 13 | 1 14 | 15 | 16 | 1 17 | 18 | 19 | 20 | 10000 21 | true 22 | 45,43,4,4,4 23 | 24 | 25 | 26 | 27 | 28 | 29 | NewOrder 30 | 31 | 32 | Payment 33 | 34 | 35 | OrderStatus 36 | 37 | 38 | Delivery 39 | 40 | 41 | StockLevel 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /benchmark/config/tpch_postgres.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgres 6 | org.postgresql.Driver 7 | jdbc:postgresql://localhost:5432/test 8 | test_user 9 | test_password 10 | TRANSACTION_READ_COMMITTED 11 | tools/ 12 | tbl 13 | 14 | 15 | 1 16 | 17 | 18 | 1 19 | 20 | 21 | 22 | false 23 | 10000 24 | 3, 2, 3, 2 , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 25 | 26 | 27 | 28 | 29 | 30 | 31 | Q1 32 | 33 | 34 | Q2 35 | 36 | 37 | Q3 38 | 39 | 40 | Q4 41 | 42 | 43 | Q5 44 | 45 | 46 | Q6 47 | 48 | 49 | Q7 50 | 51 | 52 | Q8 53 | 54 | 55 | Q9 56 | 57 | 58 | Q10 59 | 60 | 61 | Q11 62 | 63 | 64 | Q12 65 | 66 | 67 | Q13 68 | 69 | 70 | Q14 71 | 72 | 73 | 74 | Q15 75 | 76 | 77 | Q16 78 | 79 | 80 | Q17 81 | 82 | 83 | Q18 84 | 85 | 86 | Q19 87 | 88 | 89 | Q20 90 | 91 | 92 | Q21 93 | 94 | 95 | Q22 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /benchmark/db_schemas/tpcc-schema.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION IF NOT EXISTS encdb; 2 | 3 | DROP TABLE IF EXISTS order_line; 4 | CREATE TABLE order_line ( 5 | ol_w_id int NOT NULL, 6 | ol_d_id int NOT NULL, 7 | ol_o_id int NOT NULL, 8 | ol_number int NOT NULL, 9 | ol_i_id int NOT NULL, 10 | ol_delivery_d timestamp NULL DEFAULT NULL, 11 | ol_amount decimal(6,2) NOT NULL, 12 | ol_supply_w_id int NOT NULL, 13 | ol_quantity decimal(2,0) NOT NULL, 14 | ol_dist_info char(24) NOT NULL, 15 | PRIMARY KEY (ol_w_id,ol_d_id,ol_o_id,ol_number) 16 | ); 17 | 18 | DROP TABLE IF EXISTS new_order; 19 | CREATE TABLE new_order ( 20 | no_w_id int NOT NULL, 21 | no_d_id int NOT NULL, 22 | no_o_id int NOT NULL, 23 | PRIMARY KEY (no_w_id,no_d_id,no_o_id) 24 | ); 25 | 26 | DROP TABLE IF EXISTS stock; 27 | CREATE TABLE stock ( 28 | s_w_id int NOT NULL, 29 | s_i_id int NOT NULL, 30 | s_quantity decimal(4,0) NOT NULL, 31 | s_ytd decimal(8,2) NOT NULL, 32 | s_order_cnt int NOT NULL, 33 | s_remote_cnt int NOT NULL, 34 | s_data varchar(50) NOT NULL, 35 | s_dist_01 char(24) NOT NULL, 36 | s_dist_02 char(24) NOT NULL, 37 | s_dist_03 char(24) NOT NULL, 38 | s_dist_04 char(24) NOT NULL, 39 | s_dist_05 char(24) NOT NULL, 40 | s_dist_06 char(24) NOT NULL, 41 | s_dist_07 char(24) NOT NULL, 42 | s_dist_08 char(24) NOT NULL, 43 | s_dist_09 char(24) NOT NULL, 44 | s_dist_10 char(24) NOT NULL, 45 | PRIMARY KEY (s_w_id,s_i_id) 46 | ); 47 | 48 | DROP TABLE IF EXISTS oorder; 49 | CREATE TABLE oorder ( 50 | o_w_id int NOT NULL, 51 | o_d_id int NOT NULL, 52 | o_id int NOT NULL, 53 | o_c_id int NOT NULL, 54 | o_carrier_id int DEFAULT NULL, 55 | o_ol_cnt decimal(2,0) NOT NULL, 56 | o_all_local decimal(1,0) NOT NULL, 57 | o_entry_d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 58 | PRIMARY KEY (o_w_id,o_d_id,o_id), 59 | UNIQUE (o_w_id,o_d_id,o_c_id,o_id) 60 | ); 61 | 62 | DROP TABLE IF EXISTS history; 63 | CREATE TABLE history ( 64 | h_c_id int NOT NULL, 65 | h_c_d_id int NOT NULL, 66 | h_c_w_id int NOT NULL, 67 | h_d_id int NOT NULL, 68 | h_w_id int NOT NULL, 69 | h_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 70 | h_amount decimal(6,2) NOT NULL, 71 | h_data varchar(24) NOT NULL 72 | ); 73 | 74 | DROP TABLE IF EXISTS customer; 75 | CREATE TABLE customer ( 76 | c_w_id int NOT NULL, 77 | c_d_id int NOT NULL, 78 | c_id int NOT NULL, 79 | c_discount decimal(4,4) NOT NULL, 80 | c_credit char(2) NOT NULL, 81 | c_last varchar(16) NOT NULL, 82 | c_first varchar(16) NOT NULL, 83 | c_credit_lim decimal(12,2) NOT NULL, 84 | c_balance decimal(12,2) NOT NULL, 85 | c_ytd_payment float NOT NULL, 86 | c_payment_cnt int NOT NULL, 87 | c_delivery_cnt int NOT NULL, 88 | c_street_1 varchar(20) NOT NULL, 89 | c_street_2 varchar(20) NOT NULL, 90 | c_city varchar(20) NOT NULL, 91 | c_state char(2) NOT NULL, 92 | c_zip char(9) NOT NULL, 93 | c_phone char(16) NOT NULL, 94 | c_since timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 95 | c_middle char(2) NOT NULL, 96 | c_data varchar(500) NOT NULL, 97 | PRIMARY KEY (c_w_id,c_d_id,c_id) 98 | ); 99 | 100 | DROP TABLE IF EXISTS district; 101 | CREATE TABLE district ( 102 | d_w_id int NOT NULL, 103 | d_id int NOT NULL, 104 | d_ytd decimal(12,2) NOT NULL, 105 | d_tax decimal(4,4) NOT NULL, 106 | d_next_o_id int NOT NULL, 107 | d_name varchar(10) NOT NULL, 108 | d_street_1 varchar(20) NOT NULL, 109 | d_street_2 varchar(20) NOT NULL, 110 | d_city varchar(20) NOT NULL, 111 | d_state char(2) NOT NULL, 112 | d_zip char(9) NOT NULL, 113 | PRIMARY KEY (d_w_id,d_id) 114 | ); 115 | 116 | 117 | DROP TABLE IF EXISTS item; 118 | CREATE TABLE item ( 119 | i_id int NOT NULL, 120 | i_name varchar(24) NOT NULL, 121 | i_price decimal(5,2) NOT NULL, 122 | i_data varchar(50) NOT NULL, 123 | i_im_id int NOT NULL, 124 | PRIMARY KEY (i_id) 125 | ); 126 | 127 | 128 | DROP TABLE IF EXISTS warehouse; 129 | CREATE TABLE warehouse ( 130 | w_id int NOT NULL, 131 | w_ytd decimal(12,2) NOT NULL, 132 | w_tax decimal(4,4) NOT NULL, 133 | w_name varchar(10) NOT NULL, 134 | w_street_1 varchar(20) NOT NULL, 135 | w_street_2 varchar(20) NOT NULL, 136 | w_city varchar(20) NOT NULL, 137 | w_state char(2) NOT NULL, 138 | w_zip char(9) NOT NULL, 139 | PRIMARY KEY (w_id) 140 | ); 141 | 142 | 143 | --add constraints and indexes 144 | CREATE INDEX idx_customer_name ON customer (c_w_id,c_d_id,c_last,c_first); 145 | CREATE INDEX idx_order ON oorder (o_w_id,o_d_id,o_c_id,o_id); 146 | -- tpcc-mysql create two indexes for the foreign key constraints, Is it really necessary? 147 | -- CREATE INDEX FKEY_STOCK_2 ON STOCK (S_I_ID); 148 | -- CREATE INDEX FKEY_ORDER_LINE_2 ON ORDER_LINE (OL_SUPPLY_W_ID,OL_I_ID); 149 | 150 | --add 'ON DELETE CASCADE' to clear table work correctly 151 | 152 | ALTER TABLE district ADD CONSTRAINT fkey_district_1 FOREIGN KEY(d_w_id) REFERENCES warehouse(w_id) ON DELETE CASCADE; 153 | ALTER TABLE customer ADD CONSTRAINT fkey_customer_1 FOREIGN KEY(c_w_id,c_d_id) REFERENCES district(d_w_id,d_id) ON DELETE CASCADE ; 154 | ALTER TABLE history ADD CONSTRAINT fkey_history_1 FOREIGN KEY(h_c_w_id,h_c_d_id,h_c_id) REFERENCES customer(c_w_id,c_d_id,c_id) ON DELETE CASCADE; 155 | ALTER TABLE history ADD CONSTRAINT fkey_history_2 FOREIGN KEY(h_w_id,h_d_id) REFERENCES district(d_w_id,d_id) ON DELETE CASCADE; 156 | ALTER TABLE new_order ADD CONSTRAINT fkey_new_order_1 FOREIGN KEY(no_w_id,no_d_id,no_o_id) REFERENCES oorder(o_w_id,o_d_id,o_id) ON DELETE CASCADE; 157 | ALTER TABLE oorder ADD CONSTRAINT fkey_order_1 FOREIGN KEY(o_w_id,o_d_id,o_c_id) REFERENCES customer(c_w_id,c_d_id,c_id) ON DELETE CASCADE; 158 | ALTER TABLE order_line ADD CONSTRAINT fkey_order_line_1 FOREIGN KEY(ol_w_id,ol_d_id,ol_o_id) REFERENCES oorder(o_w_id,o_d_id,o_id) ON DELETE CASCADE; 159 | ALTER TABLE order_line ADD CONSTRAINT fkey_order_line_2 FOREIGN KEY(ol_supply_w_id,ol_i_id) REFERENCES stock(s_w_id,s_i_id) ON DELETE CASCADE; 160 | ALTER TABLE stock ADD CONSTRAINT fkey_stock_1 FOREIGN KEY(s_w_id) REFERENCES warehouse(w_id) ON DELETE CASCADE; 161 | ALTER TABLE stock ADD CONSTRAINT fkey_stock_2 FOREIGN KEY(s_i_id) REFERENCES item(i_id) ON DELETE CASCADE; 162 | 163 | -------------------------------------------------------------------------------- /benchmark/db_schemas/tpcc-schema_encrypted.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION IF NOT EXISTS encdb; 2 | 3 | DROP TABLE IF EXISTS order_line; 4 | CREATE TABLE order_line ( 5 | ol_w_id int NOT NULL, 6 | ol_d_id int NOT NULL, 7 | ol_o_id int NOT NULL, 8 | ol_number enc_int4 NOT NULL, 9 | ol_i_id int NOT NULL, 10 | ol_delivery_d enc_timestamp NULL DEFAULT NULL, 11 | ol_amount enc_float4 NOT NULL, 12 | ol_supply_w_id int NOT NULL, 13 | ol_quantity enc_float4 NOT NULL, 14 | ol_dist_info char(24) NOT NULL, 15 | PRIMARY KEY (ol_w_id,ol_d_id,ol_o_id,ol_number) 16 | ); 17 | 18 | DROP TABLE IF EXISTS new_order; 19 | CREATE TABLE new_order ( 20 | no_w_id int NOT NULL, 21 | no_d_id int NOT NULL, 22 | no_o_id int NOT NULL, 23 | PRIMARY KEY (no_w_id,no_d_id,no_o_id) 24 | ); 25 | 26 | DROP TABLE IF EXISTS stock; 27 | CREATE TABLE stock ( 28 | s_w_id int NOT NULL, 29 | s_i_id int NOT NULL, 30 | s_quantity enc_float4 NOT NULL, 31 | s_ytd enc_float4 NOT NULL, 32 | s_order_cnt enc_int4 NOT NULL, 33 | s_remote_cnt enc_int4 NOT NULL, 34 | s_data varchar(50) NOT NULL, 35 | s_dist_01 char(24) NOT NULL, 36 | s_dist_02 char(24) NOT NULL, 37 | s_dist_03 char(24) NOT NULL, 38 | s_dist_04 char(24) NOT NULL, 39 | s_dist_05 char(24) NOT NULL, 40 | s_dist_06 char(24) NOT NULL, 41 | s_dist_07 char(24) NOT NULL, 42 | s_dist_08 char(24) NOT NULL, 43 | s_dist_09 char(24) NOT NULL, 44 | s_dist_10 char(24) NOT NULL, 45 | PRIMARY KEY (s_w_id,s_i_id) 46 | ); 47 | 48 | DROP TABLE IF EXISTS oorder; 49 | CREATE TABLE oorder ( 50 | o_w_id int NOT NULL, 51 | o_d_id int NOT NULL, 52 | o_id int NOT NULL, 53 | o_c_id int NOT NULL, 54 | o_carrier_id int DEFAULT NULL, 55 | o_ol_cnt enc_float4 NOT NULL, 56 | o_all_local enc_float4 NOT NULL, 57 | o_entry_d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 58 | PRIMARY KEY (o_w_id,o_d_id,o_id), 59 | UNIQUE (o_w_id,o_d_id,o_c_id,o_id) 60 | ); 61 | 62 | DROP TABLE IF EXISTS history; 63 | CREATE TABLE history ( 64 | h_c_id int NOT NULL, 65 | h_c_d_id int NOT NULL, 66 | h_c_w_id int NOT NULL, 67 | h_d_id int NOT NULL, 68 | h_w_id int NOT NULL, 69 | h_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 70 | h_amount enc_float4 NOT NULL, 71 | h_data varchar(24) NOT NULL 72 | ); 73 | 74 | DROP TABLE IF EXISTS customer; 75 | CREATE TABLE customer ( 76 | c_w_id int NOT NULL, 77 | c_d_id int NOT NULL, 78 | c_id int NOT NULL, 79 | c_discount enc_float4 NOT NULL, 80 | c_credit char(2) NOT NULL, 81 | c_last varchar(16) NOT NULL, 82 | c_first varchar(16) NOT NULL, 83 | c_credit_lim enc_float4 NOT NULL, 84 | c_balance enc_float4 NOT NULL, 85 | c_ytd_payment enc_float4 NOT NULL, 86 | c_payment_cnt enc_int4 NOT NULL, 87 | c_delivery_cnt enc_int4 NOT NULL, 88 | c_street_1 varchar(20) NOT NULL, 89 | c_street_2 varchar(20) NOT NULL, 90 | c_city varchar(20) NOT NULL, 91 | c_state char(2) NOT NULL, 92 | c_zip char(9) NOT NULL, 93 | c_phone char(16) NOT NULL, 94 | c_since timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 95 | c_middle char(2) NOT NULL, 96 | c_data varchar(500) NOT NULL, 97 | PRIMARY KEY (c_w_id,c_d_id,c_id) 98 | ); 99 | 100 | DROP TABLE IF EXISTS district; 101 | CREATE TABLE district ( 102 | d_w_id int NOT NULL, 103 | d_id int NOT NULL, 104 | d_ytd enc_float4 NOT NULL, 105 | d_tax enc_float4 NOT NULL, 106 | d_next_o_id int NOT NULL, 107 | d_name varchar(10) NOT NULL, 108 | d_street_1 varchar(20) NOT NULL, 109 | d_street_2 varchar(20) NOT NULL, 110 | d_city varchar(20) NOT NULL, 111 | d_state char(2) NOT NULL, 112 | d_zip char(9) NOT NULL, 113 | PRIMARY KEY (d_w_id,d_id) 114 | ); 115 | 116 | 117 | DROP TABLE IF EXISTS item; 118 | CREATE TABLE item ( 119 | i_id int NOT NULL, 120 | i_name varchar(24) NOT NULL, 121 | i_price enc_float4 NOT NULL, 122 | i_data varchar(50) NOT NULL, 123 | i_im_id int NOT NULL, 124 | PRIMARY KEY (i_id) 125 | ); 126 | 127 | 128 | DROP TABLE IF EXISTS warehouse; 129 | CREATE TABLE warehouse ( 130 | w_id int NOT NULL, 131 | w_ytd enc_float4 NOT NULL, 132 | w_tax enc_float4 NOT NULL, 133 | w_name enc_text NOT NULL, 134 | w_street_1 varchar(20) NOT NULL, 135 | w_street_2 varchar(20) NOT NULL, 136 | w_city varchar(20) NOT NULL, 137 | w_state char(2) NOT NULL, 138 | w_zip char(9) NOT NULL, 139 | PRIMARY KEY (w_id) 140 | ); 141 | 142 | 143 | --add constraints and indexes 144 | CREATE INDEX idx_customer_name ON customer (c_w_id,c_d_id,c_last,c_first); 145 | CREATE INDEX idx_order ON oorder (o_w_id,o_d_id,o_c_id,o_id); 146 | -- tpcc-mysql create two indexes for the foreign key constraints, Is it really necessary? 147 | -- CREATE INDEX FKEY_STOCK_2 ON STOCK (S_I_ID); 148 | -- CREATE INDEX FKEY_ORDER_LINE_2 ON ORDER_LINE (OL_SUPPLY_W_ID,OL_I_ID); 149 | 150 | --add 'ON DELETE CASCADE' to clear table work correctly 151 | 152 | ALTER TABLE district ADD CONSTRAINT fkey_district_1 FOREIGN KEY(d_w_id) REFERENCES warehouse(w_id) ON DELETE CASCADE; 153 | ALTER TABLE customer ADD CONSTRAINT fkey_customer_1 FOREIGN KEY(c_w_id,c_d_id) REFERENCES district(d_w_id,d_id) ON DELETE CASCADE ; 154 | ALTER TABLE history ADD CONSTRAINT fkey_history_1 FOREIGN KEY(h_c_w_id,h_c_d_id,h_c_id) REFERENCES customer(c_w_id,c_d_id,c_id) ON DELETE CASCADE; 155 | ALTER TABLE history ADD CONSTRAINT fkey_history_2 FOREIGN KEY(h_w_id,h_d_id) REFERENCES district(d_w_id,d_id) ON DELETE CASCADE; 156 | ALTER TABLE new_order ADD CONSTRAINT fkey_new_order_1 FOREIGN KEY(no_w_id,no_d_id,no_o_id) REFERENCES oorder(o_w_id,o_d_id,o_id) ON DELETE CASCADE; 157 | ALTER TABLE oorder ADD CONSTRAINT fkey_order_1 FOREIGN KEY(o_w_id,o_d_id,o_c_id) REFERENCES customer(c_w_id,c_d_id,c_id) ON DELETE CASCADE; 158 | ALTER TABLE order_line ADD CONSTRAINT fkey_order_line_1 FOREIGN KEY(ol_w_id,ol_d_id,ol_o_id) REFERENCES oorder(o_w_id,o_d_id,o_id) ON DELETE CASCADE; 159 | ALTER TABLE order_line ADD CONSTRAINT fkey_order_line_2 FOREIGN KEY(ol_supply_w_id,ol_i_id) REFERENCES stock(s_w_id,s_i_id) ON DELETE CASCADE; 160 | ALTER TABLE stock ADD CONSTRAINT fkey_stock_1 FOREIGN KEY(s_w_id) REFERENCES warehouse(w_id) ON DELETE CASCADE; 161 | ALTER TABLE stock ADD CONSTRAINT fkey_stock_2 FOREIGN KEY(s_i_id) REFERENCES item(i_id) ON DELETE CASCADE; 162 | 163 | -------------------------------------------------------------------------------- /benchmark/db_schemas/tpch-index.sql: -------------------------------------------------------------------------------- 1 | create unique index c_ck on customer (c_custkey asc) ; 2 | create index c_nk on customer (c_nationkey asc) ; 3 | create unique index p_pk on part (p_partkey asc) ; 4 | create unique index s_sk on supplier (s_suppkey asc) ; 5 | create index s_nk on supplier (s_nationkey asc) ; 6 | create index ps_pk on partsupp (ps_partkey asc) ; 7 | create index ps_sk on partsupp (ps_suppkey asc) ; 8 | create unique index ps_pk_sk on partsupp (ps_partkey asc, ps_suppkey asc) ; 9 | create unique index ps_sk_pk on partsupp (ps_suppkey asc, ps_partkey asc) ; 10 | create unique index o_ok on orders (o_orderkey asc) ; 11 | create index o_ck on orders (o_custkey asc) ; 12 | create index o_od on orders (o_orderdate asc) ; 13 | create index l_ok on lineitem (l_orderkey asc) ; 14 | create index l_pk on lineitem (l_partkey asc) ; 15 | create index l_sk on lineitem (l_suppkey asc) ; 16 | --create index l_ln on lineitem (l_linenumber asc) ; 17 | create index l_sd on lineitem (l_shipdate asc) ; 18 | create index l_cd on lineitem (l_commitdate asc) ; 19 | create index l_rd on lineitem (l_receiptdate asc) ; 20 | --create unique index l_ok_ln on lineitem (l_orderkey asc, l_linenumber asc) ; 21 | --create unique index l_ln_ok on lineitem (l_linenumber asc, l_orderkey asc) ; 22 | create index l_pk_sk on lineitem (l_partkey asc, l_suppkey asc) ; 23 | create index l_sk_pk on lineitem (l_suppkey asc, l_partkey asc) ; 24 | create unique index n_nk on nation (n_nationkey asc) ; 25 | create index n_rk on nation (n_regionkey asc) ; 26 | create unique index r_rk on region (r_regionkey asc) ; 27 | -------------------------------------------------------------------------------- /benchmark/db_schemas/tpch-schema-encrypted.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS nation CASCADE; 2 | DROP TABLE IF EXISTS region CASCADE; 3 | DROP TABLE IF EXISTS part CASCADE; 4 | DROP TABLE IF EXISTS supplier CASCADE; 5 | DROP TABLE IF EXISTS partsupp CASCADE; 6 | DROP TABLE IF EXISTS orders CASCADE; 7 | DROP TABLE IF EXISTS customer CASCADE; 8 | DROP TABLE IF EXISTS lineitem CASCADE; 9 | 10 | CREATE TABLE nation ( n_nationkey INTEGER NOT NULL, 11 | n_name enc_text NOT NULL, 12 | n_regionkey INTEGER NOT NULL, 13 | n_comment enc_text); 14 | 15 | CREATE TABLE region ( r_regionkey INTEGER NOT NULL, 16 | r_name enc_text NOT NULL, 17 | r_comment enc_text); 18 | 19 | CREATE TABLE part ( p_partkey INTEGER NOT NULL, 20 | p_name enc_text NOT NULL, 21 | p_mfgr enc_text NOT NULL, 22 | p_brand enc_text NOT NULL, 23 | p_type enc_text NOT NULL, 24 | p_size enc_int4 NOT NULL, 25 | p_container enc_text NOT NULL, 26 | p_retailprice enc_float4 NOT NULL, 27 | p_comment enc_text NOT NULL ); 28 | 29 | CREATE TABLE supplier ( s_suppkey INTEGER NOT NULL, 30 | s_name enc_text NOT NULL, 31 | s_address enc_text NOT NULL, 32 | s_nationkey INTEGER NOT NULL, 33 | s_phone enc_text NOT NULL, 34 | s_acctbal enc_float4 NOT NULL, 35 | s_comment enc_text NOT NULL); 36 | 37 | CREATE TABLE partsupp ( ps_partkey INTEGER NOT NULL, 38 | ps_suppkey INTEGER NOT NULL, 39 | ps_availqty enc_float4 NOT NULL, 40 | ps_supplycost enc_float4 NOT NULL, 41 | ps_comment enc_text NOT NULL ); 42 | 43 | CREATE TABLE customer ( c_custkey INTEGER NOT NULL, 44 | c_name enc_text NOT NULL, 45 | c_address enc_text NOT NULL, 46 | c_nationkey INTEGER NOT NULL, 47 | c_phone enc_text NOT NULL, 48 | c_acctbal enc_float4 NOT NULL, 49 | c_mktsegment enc_text NOT NULL, 50 | c_comment enc_text NOT NULL); 51 | 52 | CREATE TABLE orders ( o_orderkey INTEGER NOT NULL, 53 | o_custkey INTEGER NOT NULL, 54 | o_orderstatus enc_text NOT NULL, 55 | o_totalprice enc_float4 NOT NULL, 56 | o_orderdate DATE NOT NULL, 57 | o_orderpriority enc_text NOT NULL, 58 | o_clerk enc_text NOT NULL, 59 | o_shippriority enc_int4 NOT NULL, 60 | o_comment enc_text NOT NULL); 61 | 62 | CREATE TABLE lineitem ( l_orderkey INTEGER NOT NULL, 63 | l_partkey INTEGER NOT NULL, 64 | l_suppkey INTEGER NOT NULL, 65 | l_linenumber INTEGER NOT NULL, 66 | l_quantity enc_float4 NOT NULL, 67 | l_extendedprice enc_float4 NOT NULL, 68 | l_discount enc_float4 NOT NULL, 69 | l_tax enc_float4 NOT NULL, 70 | l_returnflag enc_text NOT NULL, 71 | l_linestatus enc_text NOT NULL, 72 | l_shipdate DATE NOT NULL, 73 | l_commitdate DATE NOT NULL, 74 | l_receiptdate DATE NOT NULL, 75 | l_shipinstruct enc_text NOT NULL, 76 | l_shipmode enc_text NOT NULL, 77 | l_comment enc_text NOT NULL); 78 | -------------------------------------------------------------------------------- /benchmark/db_schemas/tpch-schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS nation CASCADE; 2 | DROP TABLE IF EXISTS region CASCADE; 3 | DROP TABLE IF EXISTS part CASCADE; 4 | DROP TABLE IF EXISTS supplier CASCADE; 5 | DROP TABLE IF EXISTS partsupp CASCADE; 6 | DROP TABLE IF EXISTS orders CASCADE; 7 | DROP TABLE IF EXISTS customer CASCADE; 8 | DROP TABLE IF EXISTS lineitem CASCADE; 9 | 10 | CREATE TABLE nation ( n_nationkey INTEGER NOT NULL, 11 | n_name CHAR(25) NOT NULL, 12 | n_regionkey INTEGER NOT NULL, 13 | n_comment VARCHAR(152)); 14 | 15 | CREATE TABLE region ( r_regionkey INTEGER NOT NULL, 16 | r_name CHAR(25) NOT NULL, 17 | r_comment VARCHAR(152)); 18 | 19 | CREATE TABLE part ( p_partkey INTEGER NOT NULL, 20 | p_name VARCHAR(55) NOT NULL, 21 | p_mfgr CHAR(25) NOT NULL, 22 | p_brand CHAR(10) NOT NULL, 23 | p_type VARCHAR(25) NOT NULL, 24 | p_size INTEGER NOT NULL, 25 | p_container CHAR(10) NOT NULL, 26 | p_retailprice DECIMAL(15,2) NOT NULL, 27 | p_comment VARCHAR(23) NOT NULL ); 28 | 29 | CREATE TABLE supplier ( s_suppkey INTEGER NOT NULL, 30 | s_name CHAR(25) NOT NULL, 31 | s_address VARCHAR(40) NOT NULL, 32 | s_nationkey INTEGER NOT NULL, 33 | s_phone CHAR(15) NOT NULL, 34 | s_acctbal DECIMAL(15,2) NOT NULL, 35 | s_comment VARCHAR(101) NOT NULL); 36 | 37 | CREATE TABLE partsupp ( ps_partkey INTEGER NOT NULL, 38 | ps_suppkey INTEGER NOT NULL, 39 | ps_availqty INTEGER NOT NULL, 40 | ps_supplycost DECIMAL(15,2) NOT NULL, 41 | ps_comment VARCHAR(199) NOT NULL ); 42 | 43 | CREATE TABLE customer ( c_custkey INTEGER NOT NULL, 44 | c_name VARCHAR(25) NOT NULL, 45 | c_address VARCHAR(40) NOT NULL, 46 | c_nationkey INTEGER NOT NULL, 47 | c_phone CHAR(15) NOT NULL, 48 | c_acctbal DECIMAL(15,2) NOT NULL, 49 | c_mktsegment CHAR(10) NOT NULL, 50 | c_comment VARCHAR(117) NOT NULL); 51 | 52 | CREATE TABLE orders ( o_orderkey INTEGER NOT NULL, 53 | o_custkey INTEGER NOT NULL, 54 | o_orderstatus CHAR(1) NOT NULL, 55 | o_totalprice DECIMAL(15,2) NOT NULL, 56 | o_orderdate DATE NOT NULL, 57 | o_orderpriority CHAR(15) NOT NULL, 58 | o_clerk CHAR(15) NOT NULL, 59 | o_shippriority INTEGER NOT NULL, 60 | o_comment VARCHAR(79) NOT NULL); 61 | 62 | CREATE TABLE lineitem ( l_orderkey INTEGER NOT NULL, 63 | l_partkey INTEGER NOT NULL, 64 | l_suppkey INTEGER NOT NULL, 65 | l_linenumber INTEGER NOT NULL, 66 | l_quantity DECIMAL(15,2) NOT NULL, 67 | l_extendedprice DECIMAL(15,2) NOT NULL, 68 | l_discount DECIMAL(15,2) NOT NULL, 69 | l_tax DECIMAL(15,2) NOT NULL, 70 | l_returnflag CHAR(1) NOT NULL, 71 | l_linestatus CHAR(1) NOT NULL, 72 | l_shipdate DATE NOT NULL, 73 | l_commitdate DATE NOT NULL, 74 | l_receiptdate DATE NOT NULL, 75 | l_shipinstruct CHAR(25) NOT NULL, 76 | l_shipmode CHAR(10) NOT NULL, 77 | l_comment VARCHAR(44) NOT NULL); 78 | -------------------------------------------------------------------------------- /benchmark/log4j.properties: -------------------------------------------------------------------------------- 1 | # Set root logger level to DEBUG and its only appender to A1. 2 | log4j.rootLogger=INFO, A1 3 | log4j.rootLogger.layout=org.apache.log4j.PatternLayout 4 | 5 | # A1 is set to be a ConsoleAppender. 6 | log4j.appender.A1=org.apache.log4j.ConsoleAppender 7 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout 8 | log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} (%F:%L) %-5p - %m%n 9 | 10 | # API 11 | log4j.logger.com.oltpbenchmark=DEBUG 12 | log4j.logger.com.oltpbenchmark.api=DEBUG 13 | 14 | # Benchmarks 15 | log4j.logger.com.oltpbenchmark.benchmarks.tatp=INFO 16 | log4j.logger.com.oltpbenchmark.benchmarks.twitter=INFO 17 | log4j.logger.com.oltpbenchmark.benchmarks.wikipedia=INFO 18 | log4j.logger.com.oltpbenchmark.benchmarks.epinions=INFO 19 | log4j.logger.com.oltpbenchmark.benchmarks.ycsb=INFO 20 | log4j.logger.com.oltpbenchmark.benchmarks.seats=INFO 21 | log4j.logger.com.oltpbenchmark.benchmarks.linkbench=INFO 22 | log4j.logger.com.oltpbenchmark.benchmarks.sibench=INFO 23 | log4j.logger.com.oltpbenchmark.benchmarks.seats=INFO 24 | log4j.logger.com.oltpbenchmark.benchmarks.auctionmark=INFO 25 | log4j.logger.com.oltpbenchmark.benchmarks.chbenchmark=INFO 26 | 27 | # Loaders 28 | log4j.logger.com.oltpbenchmark.benchmarks.wikipedia.WikipediaLoader=INFO 29 | 30 | 31 | !============================================================================== 32 | ! log4j.properties - An example configuration properties file for log4j. 33 | ! 34 | ! Logging levels are: 35 | ! DEBUG < INFO < WARN < ERROR < FATAL 36 | !============================================================================== 37 | 38 | ! turn on the internal log4j debugging flag so we can see what it is doing 39 | #log4j.debug=true 40 | 41 | !============================================================================== 42 | ! JDBC API layer call logging : 43 | ! INFO shows logging, DEBUG also shows where in code the jdbc calls were made, 44 | ! setting DEBUG to true might cause minor slow-down in some environments. 45 | ! If you experience too much slowness, use INFO instead. 46 | 47 | ! Log only the SQL that is executed. 48 | log4j.logger.jdbc.sqlonly=DEBUG,A1 49 | log4j.additivity.jdbc.sqlonly=false 50 | -------------------------------------------------------------------------------- /benchmark/tools/dbgen: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptograph/stealthdb/1ca645ae1613c146d59900ce50abc873dc8a6d01/benchmark/tools/dbgen -------------------------------------------------------------------------------- /benchmark/tools/dists.dss: -------------------------------------------------------------------------------- 1 | # 2 | # $Id: dists.dss,v 1.2 2005/01/03 20:08:58 jms Exp $ 3 | # 4 | # Revision History 5 | # =================== 6 | # $Log: dists.dss,v $ 7 | # Revision 1.2 2005/01/03 20:08:58 jms 8 | # change line terminations 9 | # 10 | # Revision 1.1.1.1 2004/11/24 23:31:46 jms 11 | # re-establish external server 12 | # 13 | # Revision 1.1.1.1 2003/04/03 18:54:21 jms 14 | # recreation after CVS crash 15 | # 16 | # Revision 1.1.1.1 2003/04/03 18:54:21 jms 17 | # initial checkin 18 | # 19 | # 20 | # 21 | # 22 | # distributions have the following format: 23 | # 24 | # | # comment 25 | # 26 | # Distributions are used to bias the selection of a token 27 | # based on its associated weight. The list of tokens and values 28 | # between the keywords BEGIN and END define the distribution named after 29 | # the BEGIN. A uniformly random value from [0, sum(weights)] 30 | # will be chosen and the first token whose cumulative weight is greater than 31 | # or equal to the result will be returned. In essence, the weights for each 32 | # token represent its relative weight within a distribution. 33 | # 34 | # one special token is defined: count (number of data points in the 35 | # distribution). It MUST be defined for each named distribution. 36 | #----------------------------------------------------------------------- 37 | # currently defined distributions and their use: 38 | # NAME FIELD/NOTES 39 | # ======== ============== 40 | # category parts.category 41 | # container parts.container 42 | # instruct shipping instructions 43 | # msegmnt market segment 44 | # names parts.name 45 | # nations must be ordered along with regions 46 | # nations2 stand alone nations set for use with qgen 47 | # o_prio order priority 48 | # regions must be ordered along with nations 49 | # rflag lineitems.returnflag 50 | # types parts.type 51 | # colors embedded string creation; CANNOT BE USED FOR pick_str(), agg_str() perturbs order 52 | # articles comment generation 53 | # nouns 54 | # verbs 55 | # adverbs 56 | # auxillaries 57 | # prepositions 58 | # terminators 59 | # grammar sentence formation 60 | # np 61 | # vp 62 | ### 63 | # category 64 | ### 65 | BEGIN category 66 | COUNT|5 67 | FURNITURE|1 68 | STORAGE EQUIP|1 69 | TOOLS|1 70 | MACHINE TOOLS|1 71 | OTHER|1 72 | END category 73 | ### 74 | # container 75 | ### 76 | begin p_cntr 77 | count|40 78 | SM CASE|1 79 | SM BOX|1 80 | SM BAG|1 81 | SM JAR|1 82 | SM PACK|1 83 | SM PKG|1 84 | SM CAN|1 85 | SM DRUM|1 86 | LG CASE|1 87 | LG BOX|1 88 | LG BAG|1 89 | LG JAR|1 90 | LG PACK|1 91 | LG PKG|1 92 | LG CAN|1 93 | LG DRUM|1 94 | MED CASE|1 95 | MED BOX|1 96 | MED BAG|1 97 | MED JAR|1 98 | MED PACK|1 99 | MED PKG|1 100 | MED CAN|1 101 | MED DRUM|1 102 | JUMBO CASE|1 103 | JUMBO BOX|1 104 | JUMBO BAG|1 105 | JUMBO JAR|1 106 | JUMBO PACK|1 107 | JUMBO PKG|1 108 | JUMBO CAN|1 109 | JUMBO DRUM|1 110 | WRAP CASE|1 111 | WRAP BOX|1 112 | WRAP BAG|1 113 | WRAP JAR|1 114 | WRAP PACK|1 115 | WRAP PKG|1 116 | WRAP CAN|1 117 | WRAP DRUM|1 118 | end p_cntr 119 | ### 120 | # instruct 121 | ### 122 | begin instruct 123 | count|4 124 | DELIVER IN PERSON|1 125 | COLLECT COD|1 126 | TAKE BACK RETURN|1 127 | NONE|1 128 | end instruct 129 | ### 130 | # msegmnt 131 | ### 132 | begin msegmnt 133 | count|5 134 | AUTOMOBILE|1 135 | BUILDING|1 136 | FURNITURE|1 137 | HOUSEHOLD|1 138 | MACHINERY|1 139 | end msegmnt 140 | ### 141 | # names 142 | ### 143 | begin p_names 144 | COUNT|4 145 | CLEANER|1 146 | SOAP|1 147 | DETERGENT|1 148 | EXTRA|1 149 | end p_names 150 | ### 151 | # nations 152 | # NOTE: this is a special case; the weights here are adjustments to 153 | # map correctly into the regions table, and are *NOT* cummulative 154 | # values to mimic a distribution 155 | ### 156 | begin nations 157 | count|25 158 | ALGERIA|0 159 | ARGENTINA|1 160 | BRAZIL|0 161 | CANADA|0 162 | EGYPT|3 163 | ETHIOPIA|-4 164 | FRANCE|3 165 | GERMANY|0 166 | INDIA|-1 167 | INDONESIA|0 168 | IRAN|2 169 | IRAQ|0 170 | JAPAN|-2 171 | JORDAN|2 172 | KENYA|-4 173 | MOROCCO|0 174 | MOZAMBIQUE|0 175 | PERU|1 176 | CHINA|1 177 | ROMANIA|1 178 | SAUDI ARABIA|1 179 | VIETNAM|-2 180 | RUSSIA|1 181 | UNITED KINGDOM|0 182 | UNITED STATES|-2 183 | end nations 184 | ### 185 | # nations2 186 | ### 187 | begin nations2 188 | count|25 189 | ALGERIA|1 190 | ARGENTINA|1 191 | BRAZIL|1 192 | CANADA|1 193 | EGYPT|1 194 | ETHIOPIA|1 195 | FRANCE|1 196 | GERMANY|1 197 | INDIA|1 198 | INDONESIA|1 199 | IRAN|1 200 | IRAQ|1 201 | JAPAN|1 202 | JORDAN|1 203 | KENYA|1 204 | MOROCCO|1 205 | MOZAMBIQUE|1 206 | PERU|1 207 | CHINA|1 208 | ROMANIA|1 209 | SAUDI ARABIA|1 210 | VIETNAM|1 211 | RUSSIA|1 212 | UNITED KINGDOM|1 213 | UNITED STATES|1 214 | end nations2 215 | ### 216 | # regions 217 | ### 218 | begin regions 219 | count|5 220 | AFRICA|1 221 | AMERICA|1 222 | ASIA|1 223 | EUROPE|1 224 | MIDDLE EAST|1 225 | end regions 226 | ### 227 | # o_prio 228 | ### 229 | begin o_oprio 230 | count|5 231 | 1-URGENT|1 232 | 2-HIGH|1 233 | 3-MEDIUM|1 234 | 4-NOT SPECIFIED|1 235 | 5-LOW|1 236 | end o_oprio 237 | ### 238 | # rflag 239 | ### 240 | begin rflag 241 | count|2 242 | R|1 243 | A|1 244 | end rflag 245 | ### 246 | # smode 247 | ### 248 | begin smode 249 | count|7 250 | REG AIR|1 251 | AIR|1 252 | RAIL|1 253 | TRUCK|1 254 | MAIL|1 255 | FOB|1 256 | SHIP|1 257 | end smode 258 | ### 259 | # types 260 | ### 261 | begin p_types 262 | COUNT|150 263 | STANDARD ANODIZED TIN|1 264 | STANDARD ANODIZED NICKEL|1 265 | STANDARD ANODIZED BRASS|1 266 | STANDARD ANODIZED STEEL|1 267 | STANDARD ANODIZED COPPER|1 268 | STANDARD BURNISHED TIN|1 269 | STANDARD BURNISHED NICKEL|1 270 | STANDARD BURNISHED BRASS|1 271 | STANDARD BURNISHED STEEL|1 272 | STANDARD BURNISHED COPPER|1 273 | STANDARD PLATED TIN|1 274 | STANDARD PLATED NICKEL|1 275 | STANDARD PLATED BRASS|1 276 | STANDARD PLATED STEEL|1 277 | STANDARD PLATED COPPER|1 278 | STANDARD POLISHED TIN|1 279 | STANDARD POLISHED NICKEL|1 280 | STANDARD POLISHED BRASS|1 281 | STANDARD POLISHED STEEL|1 282 | STANDARD POLISHED COPPER|1 283 | STANDARD BRUSHED TIN|1 284 | STANDARD BRUSHED NICKEL|1 285 | STANDARD BRUSHED BRASS|1 286 | STANDARD BRUSHED STEEL|1 287 | STANDARD BRUSHED COPPER|1 288 | SMALL ANODIZED TIN|1 289 | SMALL ANODIZED NICKEL|1 290 | SMALL ANODIZED BRASS|1 291 | SMALL ANODIZED STEEL|1 292 | SMALL ANODIZED COPPER|1 293 | SMALL BURNISHED TIN|1 294 | SMALL BURNISHED NICKEL|1 295 | SMALL BURNISHED BRASS|1 296 | SMALL BURNISHED STEEL|1 297 | SMALL BURNISHED COPPER|1 298 | SMALL PLATED TIN|1 299 | SMALL PLATED NICKEL|1 300 | SMALL PLATED BRASS|1 301 | SMALL PLATED STEEL|1 302 | SMALL PLATED COPPER|1 303 | SMALL POLISHED TIN|1 304 | SMALL POLISHED NICKEL|1 305 | SMALL POLISHED BRASS|1 306 | SMALL POLISHED STEEL|1 307 | SMALL POLISHED COPPER|1 308 | SMALL BRUSHED TIN|1 309 | SMALL BRUSHED NICKEL|1 310 | SMALL BRUSHED BRASS|1 311 | SMALL BRUSHED STEEL|1 312 | SMALL BRUSHED COPPER|1 313 | MEDIUM ANODIZED TIN|1 314 | MEDIUM ANODIZED NICKEL|1 315 | MEDIUM ANODIZED BRASS|1 316 | MEDIUM ANODIZED STEEL|1 317 | MEDIUM ANODIZED COPPER|1 318 | MEDIUM BURNISHED TIN|1 319 | MEDIUM BURNISHED NICKEL|1 320 | MEDIUM BURNISHED BRASS|1 321 | MEDIUM BURNISHED STEEL|1 322 | MEDIUM BURNISHED COPPER|1 323 | MEDIUM PLATED TIN|1 324 | MEDIUM PLATED NICKEL|1 325 | MEDIUM PLATED BRASS|1 326 | MEDIUM PLATED STEEL|1 327 | MEDIUM PLATED COPPER|1 328 | MEDIUM POLISHED TIN|1 329 | MEDIUM POLISHED NICKEL|1 330 | MEDIUM POLISHED BRASS|1 331 | MEDIUM POLISHED STEEL|1 332 | MEDIUM POLISHED COPPER|1 333 | MEDIUM BRUSHED TIN|1 334 | MEDIUM BRUSHED NICKEL|1 335 | MEDIUM BRUSHED BRASS|1 336 | MEDIUM BRUSHED STEEL|1 337 | MEDIUM BRUSHED COPPER|1 338 | LARGE ANODIZED TIN|1 339 | LARGE ANODIZED NICKEL|1 340 | LARGE ANODIZED BRASS|1 341 | LARGE ANODIZED STEEL|1 342 | LARGE ANODIZED COPPER|1 343 | LARGE BURNISHED TIN|1 344 | LARGE BURNISHED NICKEL|1 345 | LARGE BURNISHED BRASS|1 346 | LARGE BURNISHED STEEL|1 347 | LARGE BURNISHED COPPER|1 348 | LARGE PLATED TIN|1 349 | LARGE PLATED NICKEL|1 350 | LARGE PLATED BRASS|1 351 | LARGE PLATED STEEL|1 352 | LARGE PLATED COPPER|1 353 | LARGE POLISHED TIN|1 354 | LARGE POLISHED NICKEL|1 355 | LARGE POLISHED BRASS|1 356 | LARGE POLISHED STEEL|1 357 | LARGE POLISHED COPPER|1 358 | LARGE BRUSHED TIN|1 359 | LARGE BRUSHED NICKEL|1 360 | LARGE BRUSHED BRASS|1 361 | LARGE BRUSHED STEEL|1 362 | LARGE BRUSHED COPPER|1 363 | ECONOMY ANODIZED TIN|1 364 | ECONOMY ANODIZED NICKEL|1 365 | ECONOMY ANODIZED BRASS|1 366 | ECONOMY ANODIZED STEEL|1 367 | ECONOMY ANODIZED COPPER|1 368 | ECONOMY BURNISHED TIN|1 369 | ECONOMY BURNISHED NICKEL|1 370 | ECONOMY BURNISHED BRASS|1 371 | ECONOMY BURNISHED STEEL|1 372 | ECONOMY BURNISHED COPPER|1 373 | ECONOMY PLATED TIN|1 374 | ECONOMY PLATED NICKEL|1 375 | ECONOMY PLATED BRASS|1 376 | ECONOMY PLATED STEEL|1 377 | ECONOMY PLATED COPPER|1 378 | ECONOMY POLISHED TIN|1 379 | ECONOMY POLISHED NICKEL|1 380 | ECONOMY POLISHED BRASS|1 381 | ECONOMY POLISHED STEEL|1 382 | ECONOMY POLISHED COPPER|1 383 | ECONOMY BRUSHED TIN|1 384 | ECONOMY BRUSHED NICKEL|1 385 | ECONOMY BRUSHED BRASS|1 386 | ECONOMY BRUSHED STEEL|1 387 | ECONOMY BRUSHED COPPER|1 388 | PROMO ANODIZED TIN|1 389 | PROMO ANODIZED NICKEL|1 390 | PROMO ANODIZED BRASS|1 391 | PROMO ANODIZED STEEL|1 392 | PROMO ANODIZED COPPER|1 393 | PROMO BURNISHED TIN|1 394 | PROMO BURNISHED NICKEL|1 395 | PROMO BURNISHED BRASS|1 396 | PROMO BURNISHED STEEL|1 397 | PROMO BURNISHED COPPER|1 398 | PROMO PLATED TIN|1 399 | PROMO PLATED NICKEL|1 400 | PROMO PLATED BRASS|1 401 | PROMO PLATED STEEL|1 402 | PROMO PLATED COPPER|1 403 | PROMO POLISHED TIN|1 404 | PROMO POLISHED NICKEL|1 405 | PROMO POLISHED BRASS|1 406 | PROMO POLISHED STEEL|1 407 | PROMO POLISHED COPPER|1 408 | PROMO BRUSHED TIN|1 409 | PROMO BRUSHED NICKEL|1 410 | PROMO BRUSHED BRASS|1 411 | PROMO BRUSHED STEEL|1 412 | PROMO BRUSHED COPPER|1 413 | end p_types 414 | ### 415 | # colors 416 | # NOTE: This distribution CANNOT be used by pick_str(), since agg_str() perturbs its order 417 | ### 418 | begin colors 419 | COUNT|92 420 | almond|1 421 | antique|1 422 | aquamarine|1 423 | azure|1 424 | beige|1 425 | bisque|1 426 | black|1 427 | blanched|1 428 | blue|1 429 | blush|1 430 | brown|1 431 | burlywood|1 432 | burnished|1 433 | chartreuse|1 434 | chiffon|1 435 | chocolate|1 436 | coral|1 437 | cornflower|1 438 | cornsilk|1 439 | cream|1 440 | cyan|1 441 | dark|1 442 | deep|1 443 | dim|1 444 | dodger|1 445 | drab|1 446 | firebrick|1 447 | floral|1 448 | forest|1 449 | frosted|1 450 | gainsboro|1 451 | ghost|1 452 | goldenrod|1 453 | green|1 454 | grey|1 455 | honeydew|1 456 | hot|1 457 | indian|1 458 | ivory|1 459 | khaki|1 460 | lace|1 461 | lavender|1 462 | lawn|1 463 | lemon|1 464 | light|1 465 | lime|1 466 | linen|1 467 | magenta|1 468 | maroon|1 469 | medium|1 470 | metallic|1 471 | midnight|1 472 | mint|1 473 | misty|1 474 | moccasin|1 475 | navajo|1 476 | navy|1 477 | olive|1 478 | orange|1 479 | orchid|1 480 | pale|1 481 | papaya|1 482 | peach|1 483 | peru|1 484 | pink|1 485 | plum|1 486 | powder|1 487 | puff|1 488 | purple|1 489 | red|1 490 | rose|1 491 | rosy|1 492 | royal|1 493 | saddle|1 494 | salmon|1 495 | sandy|1 496 | seashell|1 497 | sienna|1 498 | sky|1 499 | slate|1 500 | smoke|1 501 | snow|1 502 | spring|1 503 | steel|1 504 | tan|1 505 | thistle|1 506 | tomato|1 507 | turquoise|1 508 | violet|1 509 | wheat|1 510 | white|1 511 | yellow|1 512 | end colors 513 | ################ 514 | ################ 515 | ## psuedo text distributions 516 | ################ 517 | ################ 518 | ### 519 | # nouns 520 | ### 521 | BEGIN nouns 522 | COUNT|45 523 | packages|40 524 | requests|40 525 | accounts|40 526 | deposits|40 527 | foxes|20 528 | ideas|20 529 | theodolites|20 530 | pinto beans|20 531 | instructions|20 532 | dependencies|10 533 | excuses|10 534 | platelets|10 535 | asymptotes|10 536 | courts|5 537 | dolphins|5 538 | multipliers|1 539 | sauternes|1 540 | warthogs|1 541 | frets|1 542 | dinos|1 543 | attainments|1 544 | somas|1 545 | Tiresias|1 546 | patterns|1 547 | forges|1 548 | braids|1 549 | frays|1 550 | warhorses|1 551 | dugouts|1 552 | notornis|1 553 | epitaphs|1 554 | pearls|1 555 | tithes|1 556 | waters|1 557 | orbits|1 558 | gifts|1 559 | sheaves|1 560 | depths|1 561 | sentiments|1 562 | decoys|1 563 | realms|1 564 | pains|1 565 | grouches|1 566 | escapades|1 567 | hockey players|1 568 | END nouns 569 | ### 570 | # verbs 571 | ### 572 | BEGIN verbs 573 | COUNT|40 574 | sleep|20 575 | wake|20 576 | are|20 577 | cajole|20 578 | haggle|20 579 | nag|10 580 | use|10 581 | boost|10 582 | affix|5 583 | detect|5 584 | integrate|5 585 | maintain|1 586 | nod|1 587 | was|1 588 | lose|1 589 | sublate|1 590 | solve|1 591 | thrash|1 592 | promise|1 593 | engage|1 594 | hinder|1 595 | print|1 596 | x-ray|1 597 | breach|1 598 | eat|1 599 | grow|1 600 | impress|1 601 | mold|1 602 | poach|1 603 | serve|1 604 | run|1 605 | dazzle|1 606 | snooze|1 607 | doze|1 608 | unwind|1 609 | kindle|1 610 | play|1 611 | hang|1 612 | believe|1 613 | doubt|1 614 | END verbs 615 | ### 616 | # adverbs 617 | ## 618 | BEGIN adverbs 619 | COUNT|28 620 | sometimes|1 621 | always|1 622 | never|1 623 | furiously|50 624 | slyly|50 625 | carefully|50 626 | blithely|40 627 | quickly|30 628 | fluffily|20 629 | slowly|1 630 | quietly|1 631 | ruthlessly|1 632 | thinly|1 633 | closely|1 634 | doggedly|1 635 | daringly|1 636 | bravely|1 637 | stealthily|1 638 | permanently|1 639 | enticingly|1 640 | idly|1 641 | busily|1 642 | regularly|1 643 | finally|1 644 | ironically|1 645 | evenly|1 646 | boldly|1 647 | silently|1 648 | END adverbs 649 | ### 650 | # articles 651 | ## 652 | BEGIN articles 653 | COUNT|3 654 | the|50 655 | a|20 656 | an|5 657 | END articles 658 | ### 659 | # prepositions 660 | ## 661 | BEGIN prepositions 662 | COUNT|47 663 | about|50 664 | above|50 665 | according to|50 666 | across|50 667 | after|50 668 | against|40 669 | along|40 670 | alongside of|30 671 | among|30 672 | around|20 673 | at|10 674 | atop|1 675 | before|1 676 | behind|1 677 | beneath|1 678 | beside|1 679 | besides|1 680 | between|1 681 | beyond|1 682 | by|1 683 | despite|1 684 | during|1 685 | except|1 686 | for|1 687 | from|1 688 | in place of|1 689 | inside|1 690 | instead of|1 691 | into|1 692 | near|1 693 | of|1 694 | on|1 695 | outside|1 696 | over|1 697 | past|1 698 | since|1 699 | through|1 700 | throughout|1 701 | to|1 702 | toward|1 703 | under|1 704 | until|1 705 | up|1 706 | upon|1 707 | whithout|1 708 | with|1 709 | within|1 710 | END prepositions 711 | ### 712 | # auxillaries 713 | ## 714 | BEGIN auxillaries 715 | COUNT|18 716 | do|1 717 | may|1 718 | might|1 719 | shall|1 720 | will|1 721 | would|1 722 | can|1 723 | could|1 724 | should|1 725 | ought to|1 726 | must|1 727 | will have to|1 728 | shall have to|1 729 | could have to|1 730 | should have to|1 731 | must have to|1 732 | need to|1 733 | try to|1 734 | END auxiallaries 735 | ### 736 | # terminators 737 | ## 738 | BEGIN terminators 739 | COUNT|6 740 | .|50 741 | ;|1 742 | :|1 743 | ?|1 744 | !|1 745 | --|1 746 | END terminators 747 | ### 748 | # adjectives 749 | ## 750 | BEGIN adjectives 751 | COUNT|29 752 | special|20 753 | pending|20 754 | unusual|20 755 | express|20 756 | furious|1 757 | sly|1 758 | careful|1 759 | blithe|1 760 | quick|1 761 | fluffy|1 762 | slow|1 763 | quiet|1 764 | ruthless|1 765 | thin|1 766 | close|1 767 | dogged|1 768 | daring|1 769 | brave|1 770 | stealthy|1 771 | permanent|1 772 | enticing|1 773 | idle|1 774 | busy|1 775 | regular|50 776 | final|40 777 | ironic|40 778 | even|30 779 | bold|20 780 | silent|10 781 | END adjectives 782 | ### 783 | # grammar 784 | # first level grammar. N=noun phrase, V=verb phrase, 785 | # P=prepositional phrase, T=setence termination 786 | ## 787 | BEGIN grammar 788 | COUNT|5 789 | N V T|3 790 | N V P T|3 791 | N V N T|3 792 | N P V N T|1 793 | N P V P T|1 794 | END grammar 795 | ### 796 | # NP 797 | # second level grammar. Noun phrases. N=noun, A=article, 798 | # J=adjective, D=adverb 799 | ## 800 | BEGIN np 801 | COUNT|4 802 | N|10 803 | J N|20 804 | J, J N|10 805 | D J N|50 806 | END np 807 | ### 808 | # VP 809 | # second level grammar. Verb phrases. V=verb, X=auxiallary, 810 | # D=adverb 811 | ## 812 | BEGIN vp 813 | COUNT|4 814 | V|30 815 | X V|1 816 | V D|40 817 | X V D|1 818 | END vp 819 | ### 820 | # Q13 821 | # Substitution parameters for Q13 822 | ## 823 | BEGIN Q13a 824 | COUNT|4 825 | special|20 826 | pending|20 827 | unusual|20 828 | express|20 829 | END Q13a 830 | BEGIN Q13b 831 | COUNT|4 832 | packages|40 833 | requests|40 834 | accounts|40 835 | deposits|40 836 | END Q13b 837 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:latest 2 | 3 | RUN apt-get update \ 4 | && apt-get install --yes \ 5 | nasm \ 6 | build-essential \ 7 | ocaml \ 8 | automake \ 9 | autoconf \ 10 | git \ 11 | libtool \ 12 | wget \ 13 | python \ 14 | #Have to use downgraded openSSL headers due to compilation errors. 15 | libssl1.0-dev \ 16 | libcurl4-openssl-dev \ 17 | protobuf-compiler \ 18 | libprotobuf-dev \ 19 | postgresql-server-dev-all \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | COPY sgx-deps.mk /opt/Makefile 23 | WORKDIR /opt 24 | RUN make 25 | 26 | RUN git clone https://github.com/cryptograph/stealthdb /home/stealthDB 27 | 28 | WORKDIR /home/stealthDB 29 | RUN make && make install 30 | -------------------------------------------------------------------------------- /docker/sgx-deps.mk: -------------------------------------------------------------------------------- 1 | #Builds Intel SGX libraries and binaries required by StealthDB. 2 | #Does not include those corresponding to the AESMD service and SGX driver. 3 | 4 | SGX_MODE ?= HW 5 | export SGX_MODE 6 | 7 | USE_OPT_LIBS = 1 8 | export USE_OPT_LIBS 9 | 10 | SDK_REV := sgx_2.0 11 | SDK_SRC := $(SDK_REV) 12 | SDK_BUILD_DIR := $(SDK_SRC)/build/linux 13 | SDK_INSTALL_PATH := /opt/intel/sgxsdk 14 | 15 | SGX_BUILD_LIBS := libsgx_trts.a libsgx_tservice.a libsgx_tstdc.a libsgx_tcrypto.a libsgx_tstdcxx.a libsgx_tcxx.a 16 | SGX_RUNTIME_LIBS := libsgx_urts.so libsgx_uae_service.so 17 | SGX_LIBS_INSTALL_DIR := $(SDK_INSTALL_PATH)/lib64 18 | 19 | SGX_BINS := sgx_sign sgx_edger8r 20 | SGX_BINS_INSTALL_DIR := $(SDK_INSTALL_PATH)/bin/x64 21 | 22 | SGX_HEADERS_INSTALL_DIR := $(SDK_INSTALL_PATH)/include 23 | 24 | .PHONY: all 25 | all: $(addprefix $(SGX_LIBS_INSTALL_DIR)/, $(SGX_BUILD_LIBS) $(SGX_RUNTIME_LIBS)) $(addprefix $(SGX_BINS_INSTALL_DIR)/, $(SGX_BINS)) sgx_headers 26 | 27 | $(SGX_LIBS_INSTALL_DIR)/libsgx_%: $(SDK_BUILD_DIR)/libsgx_% | $(SGX_LIBS_INSTALL_DIR) 28 | cp $(SDK_BUILD_DIR)/libsgx_$* $@ 29 | 30 | $(SDK_BUILD_DIR)/libsgx_%.a: | $(SDK_SRC) 31 | $(MAKE) -C $(SDK_SRC)/sdk $* 32 | 33 | $(SDK_BUILD_DIR)/libsgx_%.so: | $(SDK_SRC) 34 | $(MAKE) -C $(SDK_SRC)/psw CXXFLAGS="-Wno-unused-parameter -fPIC" $* 35 | 36 | $(SGX_BINS_INSTALL_DIR)/sgx_%: $(SDK_BUILD_DIR)/sgx_% | $(SGX_BINS_INSTALL_DIR) 37 | cp $(SDK_BUILD_DIR)/sgx_$* $@ 38 | 39 | $(SDK_BUILD_DIR)/sgx_sign: | $(SDK_SRC) 40 | $(MAKE) -C $(SDK_SRC)/sdk signtool 41 | 42 | $(SDK_BUILD_DIR)/sgx_edger8r: | $(SDK_SRC) 43 | $(MAKE) -C $(SDK_SRC)/sdk edger8r 44 | 45 | .PHONY: sgx_headers 46 | sgx_headers: | $(SGX_HEADERS_INSTALL_DIR) 47 | cp -R $(SDK_SRC)/common/inc/* $| 48 | 49 | $(SGX_HEADERS_INSTALL_DIR) $(SGX_BINS_INSTALL_DIR) $(SGX_LIBS_INSTALL_DIR): 50 | mkdir -p $@ 51 | 52 | $(SDK_SRC): $(SDK_REV).git 53 | git --git-dir=$< fetch origin master 54 | git --git-dir=$< archive --prefix=$@/ HEAD | tar -x 55 | ifeq ($(USE_OPT_LIBS),1) 56 | cd $@ && ./download_prebuilt.sh 57 | endif 58 | 59 | $(SDK_REV).git: 60 | git clone --depth 1 --branch $(SDK_REV) --bare https://github.com/01org/linux-sgx.git $@ 61 | 62 | .PHONY: uninstall 63 | uninstall: 64 | $(RM) $(addprefix $(SGX_LIBS_INSTALL_DIR), $(SGX_LIBS))\ 65 | $(addprefix $(SGX_BINS_INSTALL_DIR), $(SGX_BINS))\ 66 | -r $(SGX_HEADERS_INSTALL_DIR) 67 | 68 | .PHONY: clean 69 | clean: 70 | $(RM) -r $(SDK_SRC) $(SDK_REV) 71 | -------------------------------------------------------------------------------- /docs/developer/dirlayout.md: -------------------------------------------------------------------------------- 1 | # Source Directory Layout 2 | 3 | * `src` contains the source code for the enclave as well as the PostgreSQL interface. 4 | * `docker` contains all that is necessary to build and run a docker container. 5 | * `benchmark` and `test` contain tools to respectively benchmark and test the extension. 6 | -------------------------------------------------------------------------------- /docs/user/README.md: -------------------------------------------------------------------------------- 1 | The installation process is described in detail [here](install.md). 2 | 3 | #Supported Data Types and Operations 4 | 5 | * [Numeric Types](numeric.md) 6 | * [Character Types](character.md) 7 | * [Date/Time Types](datetime.md) 8 | * [StealthDB defined functions](utils.md) 9 | 10 | For each supported type `x`, we provide a corresponding encrypted type `enc_x`. All operations valid for type `x` are valid for `enc_x`. 11 | 12 | -------------------------------------------------------------------------------- /docs/user/character.md: -------------------------------------------------------------------------------- 1 | # Supported Character Types 2 | 3 | ## Text 4 | 5 | ### Types 6 | 7 | * text 8 | 9 | ### Functions 10 | 11 | * Relational operators: `!=`, `<>`, `=`, `<=`, `<`, `>`, `>=` 12 | * BETWEEN x AND y 13 | * NOT BETWEEN x AND y 14 | * BETWEEN SYMMETRIC x AND y 15 | * NOT BETWEEN SYMMETRIC x AND y 16 | * IS DISTINCT FROM b 17 | * IS NOT DISTINCT FROM b 18 | * expression IS NULL 19 | * expression IS NOT NULL 20 | * expression ISNULL 21 | * expression NOTNULL 22 | 23 | * Mathematical Operators: +, -, \*, /, % 24 | 25 | * String functions: `||`, `LIKE`, `SUBSTRING` 26 | -------------------------------------------------------------------------------- /docs/user/datetime.md: -------------------------------------------------------------------------------- 1 | # Supported Date/Time Types 2 | 3 | ## Timestamp 4 | 5 | ### Types 6 | 7 | * timestamp 8 | 9 | ### Functions 10 | 11 | * Relational operators: `!=`, `<>`, `=`, `<=`, `<`, `>`, `>=` 12 | * BETWEEN x AND y 13 | * NOT BETWEEN x AND y 14 | * BETWEEN SYMMETRIC x AND y 15 | * NOT BETWEEN SYMMETRIC x AND y 16 | * IS DISTINCT FROM b 17 | * IS NOT DISTINCT FROM b 18 | * expression IS NULL 19 | * expression IS NOT NULL 20 | * expression ISNULL 21 | * expression NOTNULL 22 | 23 | * date_part with the 'field' argument being 'year' 24 | -------------------------------------------------------------------------------- /docs/user/install.md: -------------------------------------------------------------------------------- 1 | # The StealthDB Installation Process 2 | 3 | ## 1. a) Building and Installing StealthDB on Ubuntu 4 | 5 | The build process, which is kicked off by running `make`, consists of the building the enclave used by StealthDB as well as the interface it presents to PostgreSQL. The enclave is built as a shared library (`enclave.so`) and is signed using a signing key generated during the build process. The extension itself is also a shared library (`encdb.so`). All the build artifacts can be found in the `build/` folder. 6 | 7 | `sudo make install` starts the installation process, which involes copying the artifacts in the `build` directory into various system and PostgreSQL directories. 8 | 9 | ## 1. b) Building and Installing StealthDB in a Debian-based Docker container 10 | 11 | To build the docker image, we bypass the `install_dependencies.sh` script and specify that the Dockerfile install dependencies and clone the StealthDB GitHub repository. This built image is then run, and we specify that the running container use the Intel SGX driver (installed on the host kernel) and Intel AESMD service (running on the host) using the `--device=/dev/isgx` and `--volume=/var/run/aesmd/aesm.socket` flags. 12 | 13 | As a result, we need only build in the docker container a subset of all the Intel SGX artifacts. The Dockerfile invokes the `sgx-deps.mk` Makefile to do exactly this, and proceeds to build StealthDB inside the running container through a process analogous to the one described in Section 1. a). 14 | 15 | ## Note 16 | 17 | The enclave created by the above build process is created with SGX_DEBUG=1 flag and is signed with an automatically generated signing key. It is thus a debug enclave. To use an enclave in production, the signing key must be whitelisted by Intel. 18 | 19 | -------------------------------------------------------------------------------- /docs/user/numeric.md: -------------------------------------------------------------------------------- 1 | # Supported Numeric Types 2 | 3 | ## Integers 4 | 5 | ### Types 6 | 7 | * int4 8 | 9 | ### Functions 10 | 11 | * Relational operators: `!=`, `<>`, `=`, `<=`, `<`, `>`, `>=` 12 | * BETWEEN x AND y 13 | * NOT BETWEEN x AND y 14 | * BETWEEN SYMMETRIC x AND y 15 | * NOT BETWEEN SYMMETRIC x AND y 16 | * IS DISTINCT FROM b 17 | * IS NOT DISTINCT FROM b 18 | * expression IS NULL 19 | * expression IS NOT NULL 20 | * expression ISNULL 21 | * expression NOTNULL 22 | 23 | * Mathematical Operators: +, -, \*, /, % 24 | * Aggregate: AVG, MIN, MAX, SUM 25 | 26 | ## Floating Point 27 | 28 | ### Types 29 | 30 | * float4 31 | 32 | ### Functions 33 | 34 | * Relational operators: `!=`, `<>`, `=`, `<=`, `<`, `>`, `>=` 35 | * BETWEEN x AND y 36 | * NOT BETWEEN x AND y 37 | * BETWEEN SYMMETRIC x AND y 38 | * NOT BETWEEN SYMMETRIC x AND y 39 | * IS DISTINCT FROM b 40 | * IS NOT DISTINCT FROM b 41 | * expression IS NULL 42 | * expression IS NOT NULL 43 | * expression ISNULL 44 | * expression NOTNULL 45 | 46 | * Mathematical Operators: +, -, \*, /, % 47 | * Aggregate: AVG, SUM 48 | -------------------------------------------------------------------------------- /docs/user/oblvs.md: -------------------------------------------------------------------------------- 1 | ## Oblivious Operators 2 | 3 | Operations such as addition, comparison, mutliplication that form the building blocks for queries are carried out inside an SGX enclave. While this is done to ensure confidentiality of the operands, the enclave is still vulnerable to side channel timing attacks. 4 | 5 | We presently have oblivious implementations of operations involving the enc_int4 type. To enable these, run `make` with the `OBLVS=1` option. By default, `OBLVS` is 0. 6 | -------------------------------------------------------------------------------- /docs/user/utils.md: -------------------------------------------------------------------------------- 1 | # StealthDB special functions 2 | * ``` 3 | generate_key() 4 | ``` 5 | Generates a new key, seals it with SGX hardware key and appends to the local file DATA_FILENAME. All computations with the secret data are performed inside an enclave. The function returns the serial number of the key (note: temporarily, serial number is always 0). 6 | 7 | * ``` 8 | load_key(int4) 9 | ``` 10 | Reads sealed key from the local file DATA_FILENAME, unseals it and uploads into an enclave as the master key. The argument is a serial number of a previously generated key (note: temporarily, serial number is always 0). 11 | 12 | * ``` 13 | enable_debug_mode(int4) 14 | ``` 15 | Enables/disables encryption of PostgreSQL datatypes and their conversion into encrypted ones, it also allows automatically decrypt the query result. The argument is 0 (disable) or 1 (enable). This function makes the system insecure, because a malicious DBMS can potentially extract and decrypt all encrypted values. Eventually, the function will be moved to an independent enclave according to the paper. 16 | * ``` 17 | pg_enc_int4_encrypt(int4) 18 | ``` 19 | Encrypts an int4 with the master key, returns enc_int4 element. 20 | * ``` 21 | pg_enc_int4_decrypt(enc_int4) 22 | ``` 23 | Decrypts an enc_int4 element with the master key and returns int4. 24 | * ``` 25 | pg_enc_float4_encrypt(float4) 26 | ``` 27 | Encrypts a float4 with the master key, returns enc_float4 element. 28 | * ``` 29 | pg_enc_float4_decrypt(enc_float4) 30 | ``` 31 | Decrypts an enc_float4 element with the master key and returns float4. 32 | * ``` 33 | pg_enc_text_encrypt(varchar) 34 | ``` 35 | Encrypts a string with the master key, returns enc_text element as a string (note: temporarily, the length of the input string is limited by 1024 characters) 36 | * ``` 37 | pg_enc_text_decrypt(enc_text) 38 | ``` 39 | Decrypts an enc_text element with the master key and returns a string. 40 | * ``` 41 | pg_enc_timestamp_enrypt(timestamp) 42 | ``` 43 | Encrypts the timestamp with the master key, returns enc_timestamp element. 44 | * ``` 45 | pg_enc_timestamp_decrypt(enc_timestamp) 46 | ``` 47 | Decrypts an enc_timestamp element with the master key and returns timestamp. 48 | 49 | -------------------------------------------------------------------------------- /src/enclave.mk: -------------------------------------------------------------------------------- 1 | include vars.mk 2 | -include status.mk 3 | 4 | SIGNDATA := $(ENCLAVE_DIR)/$(ENCLAVE_NAME).signdata 5 | MRENCLAVE := $(ENCLAVE_DIR)/$(ENCLAVE_NAME).mrenclave 6 | SIGNED_TARGET := $(ENCLAVE_DIR)/$(ENCLAVE_NAME).signed.so 7 | ENCLAVE_CONFIG := $(ENCLAVE_DIR)/$(ENCLAVE_NAME).config.xml 8 | SGX_ENCLAVE_SIGNER := $(SDK_INSTALL_PATH)/bin/x64/sgx_sign 9 | 10 | DEBUG_ENCLAVE_NAME := $(ENCLAVE_NAME).debug 11 | DEBUG_SIGNDATA := $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).signdata 12 | DEBUG_SIGNED_TARGET := $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).signed.so 13 | DEBUG_ENCLAVE_CONFIG := $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).config.xml 14 | 15 | CXX_SRCS := $(wildcard tools/*.cpp) $(filter-out $(wildcard $(ENCLAVE_DIR)/*int32*.cpp),$(wildcard $(ENCLAVE_DIR)/*.cpp)) 16 | ifeq ($(OBLVS), 1) 17 | BUILD_TARGET = oblvs 18 | CXX_SRCS += $(ENCLAVE_DIR)/enc_oblvs_int32_ops.cpp 19 | else 20 | BUILD_TARGET = non_oblvs 21 | CXX_SRCS += $(ENCLAVE_DIR)/enc_int32_ops.cpp 22 | endif 23 | CXX_OBJS := $(CXX_SRCS:.cpp=.o) 24 | 25 | TARGET := $(ENCLAVE_DIR)/$(ENCLAVE_NAME).so 26 | 27 | ifndef BUILT_TARGET 28 | BUILT_TARGET = $(BUILD_TARGET) 29 | endif 30 | 31 | ASM_SRCS := $(wildcard tools/*.S) 32 | ASM_OBJS := $(ASM_SRCS:.S=.o) 33 | 34 | C_SRCS := $(wildcard tools/*.c) 35 | C_OBJS := $(C_SRCS:.c=.o) 36 | 37 | CPPFLAGS := $(addprefix -I, include $(SGX_INCLUDE_PATH) $(SGX_INCLUDE_PATH)/tlibc) 38 | 39 | FLAGS:= -m64 -O0 -g -fvisibility=hidden -fpie -fstack-protector -fno-builtin-printf -Wall -Wextra -Wpedantic 40 | CFLAGS := $(FLAGS) $(CPPFLAGS) -nostdinc -std=c11 41 | CXXFLAGS := $(FLAGS) $(CPPFLAGS) -nostdinc++ -std=c++11 42 | 43 | LDFLAGS := \ 44 | -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SDK_INSTALL_PATH)/lib64\ 45 | -Wl,--whole-archive -lsgx_trts -Wl,--no-whole-archive \ 46 | -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_tcrypto -lsgx_tservice -Wl,--end-group \ 47 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 48 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 49 | -Wl,--defsym,__ImageBase=0 \ 50 | -Wl,--version-script=$(ENCLAVE_DIR)/enclave.lds 51 | 52 | .PHONY: check_target 53 | check_target: 54 | ifneq ($(BUILT_TARGET),$(BUILD_TARGET)) 55 | $(error "A different target was built earlier. Run 'make clean' first.") 56 | endif 57 | @echo "BUILT_TARGET=$(BUILD_TARGET)" > status.mk 58 | 59 | .PHONY: all 60 | all: check_target $(DEBUG_SIGNED_TARGET) $(TARGET) 61 | 62 | $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).key: 63 | @openssl genrsa -out $@ -3 3072 64 | 65 | $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).pub: %.pub: %.key 66 | @openssl rsa -out $@ -in $< -pubout 67 | 68 | $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).sig: %.sig: %.signdata %.key 69 | @openssl dgst -sha256 -out $@ -sign $*.key $*.signdata 70 | 71 | $(ENCLAVE_DIR)/enclave_t.c: $(SGX_EDGER8R) $(ENCLAVE_DIR)/enclave.edl 72 | @cd $(ENCLAVE_DIR) && $(SGX_EDGER8R) --trusted enclave.edl 73 | @mv $(ENCLAVE_DIR)/enclave_t.h include/enclave 74 | @echo "GEN => $@" 75 | 76 | $(ENCLAVE_DIR)/enclave_t.o: $(ENCLAVE_DIR)/enclave_t.c 77 | @$(CC) -Iinclude/enclave $(CFLAGS) -c $< -o $@ 78 | @echo "CC <= $<" 79 | 80 | $(C_OBJS): %.o: %.c 81 | @$(CC) $(CFLAGS) -c $< -o $@ 82 | @echo "CC <= $<" 83 | 84 | $(CXX_OBJS): %.o: %.cpp 85 | @$(CXX) $(CXXFLAGS) -c $< -o $@ 86 | @echo "CXX <= $<" 87 | 88 | $(ASM_OBJS): %.o: %.S 89 | @nasm -f elf64 $< -o $@ 90 | @echo "NASM <= $<" 91 | 92 | $(TARGET): $(ENCLAVE_DIR)/enclave_t.o $(CXX_OBJS) $(ASM_OBJS) $(C_OBJS) 93 | @$(CXX) $^ -o $@ $(LDFLAGS) 94 | @echo "LINK => $@" 95 | 96 | $(DEBUG_ENCLAVE_CONFIG): $(ENCLAVE_CONFIG) 97 | @sed -e 's@1@0@' $< > $@ 98 | 99 | $(SIGNDATA) $(DEBUG_SIGNDATA): %.signdata: $(TARGET) %.config.xml | $(SGX_SIGN) 100 | $(SGX_ENCLAVE_SIGNER) gendata -out $@ -enclave $(TARGET) -config $*.config.xml 101 | @echo "GENDATA => $@" 102 | 103 | $(DEBUG_SIGNED_TARGET): %.signed.so: $(TARGET) %.pub %.sig %.signdata 104 | @$(SGX_ENCLAVE_SIGNER) catsig -enclave $(TARGET) -unsigned $*.signdata -out $@ -config $*.config.xml -key $*.pub -sig $*.sig 105 | cp $(DEBUG_SIGNED_TARGET) $(BUILD_DIR) 106 | @echo "SIGN => $@" 107 | 108 | .PHONY: install 109 | install: 110 | @if [ -e $(SIGNED_TARGET) ]; then cp $(SIGNED_TARGET) $(STEALTHDIR)/$(ENCLAVE_NAME).signed.so; fi 111 | @if [ -e $(DEBUG_SIGNED_TARGET) ]; then cp $(DEBUG_SIGNED_TARGET) $(STEALTHDIR)/$(ENCLAVE_NAME).signed.so; fi 112 | @echo cp $(BUILD_DIR)/$(DEBUG_ENCLAVE_NAME).signed.so $(STEALTHDIR)/$(ENCLAVE_NAME).signed.so; 113 | 114 | .PHONY: clean 115 | clean: 116 | @$(RM) status.mk *.so \ 117 | $(ASM_OBJS) $(CXX_OBJS) $(TARGET) \ 118 | $(SIGNDATA) $(MRENCLAVE) $(SIGNED_TARGET) \ 119 | $(ENCLAVE_DIR)/enclave_t.* \ 120 | $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).key \ 121 | $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).pub \ 122 | $(ENCLAVE_DIR)/$(DEBUG_ENCLAVE_NAME).sig \ 123 | $(DEBUG_SIGNDATA) $(DEBUG_SIGNED_TARGET) 124 | -------------------------------------------------------------------------------- /src/enclave/enc_float32_ops.cpp: -------------------------------------------------------------------------------- 1 | #include "enclave/enc_float32_ops.hpp" 2 | 3 | /* Compare two aes_gcm-encrypted floats 4 | @input: uint8_t array - encrypted lhs 5 | size_t - length of encrypted lhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + 6 | SGX_AESGCM_MAC_SIZE = 32) 7 | uint8_t array - encrypted rhs 8 | size_t - length of 9 | encrypted rhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 10 | uint8_t array - which contains the output 1 (if lhs > rhs). -1 (if lhs 11 | < rhs), 0 (if lhs == rhs) size_t - length of out (INT64_LENGTH = 4) 12 | 13 | @return: 14 | * SGX_error, if there was an error during decryption 15 | */ 16 | int enc_float32_cmp(uint8_t* in1, 17 | size_t in1_size, 18 | uint8_t* in2, 19 | size_t in2_size, 20 | uint8_t* out, 21 | size_t out_size) 22 | { 23 | int result, resp; 24 | union_float4 lhs, rhs; 25 | 26 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 27 | if (resp != SGX_SUCCESS) 28 | return resp; 29 | 30 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 31 | if (resp != SGX_SUCCESS) 32 | return resp; 33 | 34 | result = (lhs.val == rhs.val) ? 0 : (lhs.val < rhs.val) ? -1 : 1; 35 | 36 | memcpy(out, &result, out_size); 37 | 38 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 39 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 40 | 41 | return resp; 42 | } 43 | 44 | /* Add two aes_gcm-encrypted floats 45 | @input: uint8_t array - encrypted lhs 46 | size_t - length of encrypted lhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + 47 | SGX_AESGCM_MAC_SIZE = 32) 48 | uint8_t array - encrypted rhs 49 | size_t - length of 50 | encrypted rhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 51 | uint8_t array - encrypted out 52 | size_t - length of encrypted out (SGX_AESGCM_IV_SIZE + INT_LENGTH + 53 | SGX_AESGCM_MAC_SIZE = 32) 54 | @return: 55 | * SGX_error, if there was an error during encryption/decryption 56 | 0, otherwise 57 | */ 58 | /* comment from PSQL code 59 | * There isn't any way to check for underflow of addition/subtraction 60 | * because numbers near the underflow value have already been rounded to 61 | * the point where we can't detect that the two values were originally 62 | * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 == 63 | * 1.4013e-45. 64 | * we have only 4 bytes for float4 datatype 65 | * we can check if the out size is less 8^4 66 | * 67 | */ 68 | int enc_float32_add(uint8_t* in1, 69 | size_t in1_size, 70 | uint8_t* in2, 71 | size_t in2_size, 72 | uint8_t* out, 73 | size_t out_size) 74 | { 75 | union_float4 lhs, rhs, result; 76 | int resp; 77 | 78 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 79 | if (resp != SGX_SUCCESS) 80 | return resp; 81 | 82 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 83 | if (resp != SGX_SUCCESS) 84 | return resp; 85 | 86 | result.val = lhs.val + rhs.val; 87 | 88 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_size); 89 | 90 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 91 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 92 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 93 | 94 | return resp; 95 | } 96 | 97 | /* Subtract one aes_gcm-encrypted float from another 98 | @input: uint8_t array - encrypted lhs 99 | size_t - length of encrypted lhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + 100 | SGX_AESGCM_MAC_SIZE = 32) 101 | uint8_t array - encrypted rhs size_t - length of 102 | encrypted rhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 103 | uint8_t array - encrypted out 104 | size_t - length of encrypted out (SGX_AESGCM_IV_SIZE + INT_LENGTH + 105 | SGX_AESGCM_MAC_SIZE = 32) 106 | @return: 107 | * SGX_error, if there was an error during encryption/decryption 108 | 0, otherwise 109 | */ 110 | int enc_float32_sub(uint8_t* in1, 111 | size_t in1_size, 112 | uint8_t* in2, 113 | size_t in2_size, 114 | uint8_t* out, 115 | size_t out_size) 116 | { 117 | union_float4 lhs, rhs, result; 118 | int resp; 119 | 120 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 121 | if (resp != SGX_SUCCESS) 122 | return resp; 123 | 124 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 125 | if (resp != SGX_SUCCESS) 126 | return resp; 127 | 128 | result.val = lhs.val - rhs.val; 129 | 130 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_size); 131 | 132 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 133 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 134 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 135 | 136 | return resp; 137 | } 138 | 139 | /* Multiply two aes_gcm-encrypted floats 140 | @input: uint8_t array - encrypted lhs 141 | size_t - length of encrypted lhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + 142 | SGX_AESGCM_MAC_SIZE = 32) 143 | uint8_t array - encrypted rhs size_t - length of 144 | encrypted rhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 145 | uint8_t array - encrypted out 146 | size_t - length of encrypted out (SGX_AESGCM_IV_SIZE + INT_LENGTH + 147 | SGX_AESGCM_MAC_SIZE = 32) 148 | @return: 149 | * SGX_error, if there was an error during encryption/decryption 150 | 0, otherwise 151 | */ 152 | int enc_float32_mult(uint8_t* in1, 153 | size_t in1_size, 154 | uint8_t* in2, 155 | size_t in2_size, 156 | uint8_t* out, 157 | size_t out_size) 158 | { 159 | union_float4 lhs, rhs, result; 160 | int resp; 161 | 162 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 163 | if (resp != SGX_SUCCESS) 164 | return resp; 165 | 166 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 167 | if (resp != SGX_SUCCESS) 168 | return resp; 169 | 170 | /*TODO: Check for overflow*/ 171 | result.val = lhs.val * rhs.val; 172 | 173 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_size); 174 | 175 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 176 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 177 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 178 | 179 | return resp; 180 | } 181 | 182 | /* Take the power of one aes_gcm-encrypted float by another 183 | @input: uint8_t array - encrypted float base 184 | size_t - length of encrypted base (SGX_AESGCM_IV_SIZE + INT_LENGTH + 185 | SGX_AESGCM_MAC_SIZE = 32) 186 | uint8_t array - encrypted float exponent 187 | size_t - length of encrypted exponent (SGX_AESGCM_IV_SIZE + INT_LENGTH + 188 | SGX_AESGCM_MAC_SIZE = 32) 189 | uint8_t array - encrypted out size_t - length of 190 | encrypted out (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 191 | @return: 192 | * SGX_error, if there was an error during encryption/decryption 193 | 0, otherwise 194 | */ 195 | int enc_float32_pow(uint8_t* in1, 196 | size_t in1_size, 197 | uint8_t* in2, 198 | size_t in2_size, 199 | uint8_t* out, 200 | size_t out_size) 201 | { 202 | union_float4 lhs, rhs, result; 203 | int resp; 204 | 205 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 206 | if (resp != SGX_SUCCESS) 207 | return resp; 208 | 209 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 210 | if (resp != SGX_SUCCESS) 211 | return resp; 212 | 213 | /*TODO: Check for overflow*/ 214 | result.val = pow(lhs.val, rhs.val); 215 | 216 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_size); 217 | 218 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 219 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 220 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 221 | 222 | return resp; 223 | } 224 | 225 | /* Divide two aes_gcm-encrypted floats 226 | @input: uint8_t array - encrypted lhs 227 | size_t - length of encrypted lhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + 228 | SGX_AESGCM_MAC_SIZE = 32) 229 | uint8_t array - encrypted rhs size_t - length of 230 | encrypted src3 (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 231 | uint8_t array - encrypted out 232 | size_t - length of encrypted out (SGX_AESGCM_IV_SIZE + INT_LENGTH + 233 | SGX_AESGCM_MAC_SIZE = 32) 234 | @return: 235 | * SGX_error, if there was an error during encryption/decryption 236 | 0, otherwise 237 | */ 238 | int enc_float32_div(uint8_t* in1, 239 | size_t in1_size, 240 | uint8_t* in2, 241 | size_t in2_size, 242 | uint8_t* out, 243 | size_t out_size) 244 | { 245 | union_float4 lhs, rhs, result; 246 | int resp; 247 | 248 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 249 | if (resp != SGX_SUCCESS) 250 | return resp; 251 | 252 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 253 | if (resp != SGX_SUCCESS) 254 | return resp; 255 | 256 | /*TODO: Check for overflow*/ 257 | if (rhs.val == 0) 258 | return ARITHMETIC_ERROR; 259 | result.val = lhs.val / rhs.val; 260 | 261 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_size); 262 | 263 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 264 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 265 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 266 | 267 | return resp; 268 | } 269 | 270 | /* Take the modulus of one aes_gcm-encrypted float with respect to another 271 | @input: uint8_t array - encrypted lhs 272 | size_t - length of encrypted lhs (SGX_AESGCM_IV_SIZE + INT_LENGTH + 273 | SGX_AESGCM_MAC_SIZE = 32) 274 | uint8_t array - encrypted module size_t - length of 275 | encrypted module (SGX_AESGCM_IV_SIZE + INT_LENGTH + SGX_AESGCM_MAC_SIZE = 32) 276 | uint8_t array - encrypted out 277 | size_t - length of encrypted out (SGX_AESGCM_IV_SIZE + INT_LENGTH + 278 | SGX_AESGCM_MAC_SIZE = 32) 279 | @return: 280 | * SGX_error, if there was an error during encryption/decryption 281 | 0, otherwise 282 | */ 283 | int enc_float32_mod(uint8_t* in1, 284 | size_t in1_size, 285 | uint8_t* in2, 286 | size_t in2_size, 287 | uint8_t* out, 288 | size_t out_size) 289 | { 290 | union_float4 lhs, rhs, result; 291 | int resp; 292 | 293 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, FLOAT4_LENGTH); 294 | if (resp != SGX_SUCCESS) 295 | return resp; 296 | 297 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, FLOAT4_LENGTH); 298 | if (resp != SGX_SUCCESS) 299 | return resp; 300 | 301 | /*TODO: Check for correctness*/ 302 | result.val = (int)lhs.val % (int)rhs.val; 303 | 304 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_size); 305 | 306 | memset_s(lhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 307 | memset_s(rhs.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 308 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 309 | 310 | return resp; 311 | } 312 | 313 | int enc_float32_sum_bulk(uint8_t* in1, 314 | size_t in1_len, 315 | uint8_t* in2, 316 | size_t in2_len, 317 | uint8_t* out, 318 | size_t out_len) 319 | { 320 | union_float4 temp, result; 321 | int32_t bulk_size = 0, current_position = 0; 322 | int resp, counter = 0; 323 | 324 | if (bytearray2int(in1, bulk_size, INT32_LENGTH)) 325 | return MEMORY_COPY_ERROR; 326 | 327 | result.val = 0; 328 | while (counter < bulk_size) 329 | { 330 | resp = decrypt_bytes( 331 | in2 + current_position, ENC_FLOAT4_LENGTH, temp.bytes, FLOAT4_LENGTH); 332 | if (resp != SGX_SUCCESS) 333 | return resp; 334 | current_position += ENC_FLOAT4_LENGTH; 335 | 336 | result.val += temp.val; 337 | counter++; 338 | } 339 | 340 | resp = encrypt_bytes(result.bytes, FLOAT4_LENGTH, out, out_len); 341 | 342 | memset_s(temp.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 343 | memset_s(result.bytes, FLOAT4_LENGTH, 0, FLOAT4_LENGTH); 344 | 345 | return resp; 346 | } 347 | -------------------------------------------------------------------------------- /src/enclave/enc_text_ops.cpp: -------------------------------------------------------------------------------- 1 | #include "enclave/enc_text_ops.hpp" 2 | 3 | /* Compare two encrypted by aes_gcm strings 4 | @input: uint8_t array - encrypted string1 5 | size_t - length of encrypted string1 (max lenght = SGX_AESGCM_IV_SIZE + 6 | ??? + SGX_AESGCM_MAC_SIZE = 32) 7 | uint8_t array - encrypted string2 size_t - 8 | length of encrypted string2 (SGX_AESGCM_IV_SIZE + ??? + SGX_AESGCM_MAC_SIZE = 9 | 32) 10 | uint8_t array - which contains the result 1 (if a > b). -1 (if b > a), 11 | 0 (if a == b) 12 | size_t - length of result (INT32_LENGTH = 4) 13 | @return: 14 | * SGX_error, if there was an error during decryption 15 | */ 16 | int enc_text_like(uint8_t* in1, 17 | size_t in1_size, 18 | uint8_t* in2, 19 | size_t in2_size, 20 | uint8_t* out, 21 | size_t out_size) 22 | { 23 | int str_raw_size = in1_size - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 24 | int pattern_raw_size = in2_size - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 25 | int resp, result; 26 | char* str = (char*)malloc(str_raw_size + 1); 27 | char* pattern = (char*)malloc(pattern_raw_size + 1); 28 | 29 | resp = decrypt_bytes((uint8_t*)in1, in1_size, (uint8_t*)str, str_raw_size); 30 | if (resp != SGX_SUCCESS) 31 | return resp; 32 | 33 | resp = decrypt_bytes((uint8_t*)in2, in2_size, (uint8_t*)pattern, pattern_raw_size); 34 | if (resp != SGX_SUCCESS) 35 | return resp; 36 | 37 | result = (MatchText(str, str_raw_size, pattern, pattern_raw_size) == LIKE_TRUE); 38 | 39 | memcpy(out, &result, out_size); 40 | 41 | memset_s(str, str_raw_size + 1, 0, str_raw_size + 1); 42 | memset_s(pattern, pattern_raw_size + 1, 0, pattern_raw_size + 1); 43 | memset_s(&result, sizeof(result), 0, sizeof(result)); 44 | 45 | free(str); 46 | free(pattern); 47 | 48 | return resp; 49 | } 50 | /* Compare two encrypted by aes_gcm strings 51 | @input: uint8_t array - encrypted string1 52 | size_t - length of encrypted string1 (max lenght = SGX_AESGCM_IV_SIZE + 53 | ??? + SGX_AESGCM_MAC_SIZE = 32) 54 | uint8_t array - encrypted string2 size_t - 55 | length of encrypted string2 (SGX_AESGCM_IV_SIZE + ??? + SGX_AESGCM_MAC_SIZE = 56 | 32) 57 | uint8_t array - which contains the result 1 (if a > b). -1 (if b > a), 58 | 0 (if a == b) 59 | size_t - length of result (INT32_LENGTH = 4) 60 | 61 | @return: 62 | * SGX_error, if there was an error during decryption 63 | */ 64 | int enc_text_cmp(uint8_t* string1, 65 | size_t string1_len, 66 | uint8_t* string2, 67 | size_t string2_len, 68 | uint8_t* result, 69 | size_t res_len) 70 | { 71 | if ((string1_len < SGX_AESGCM_IV_SIZE + SGX_AESGCM_MAC_SIZE) || (string2_len < SGX_AESGCM_IV_SIZE + SGX_AESGCM_MAC_SIZE)) 72 | return MEMORY_COPY_ERROR; 73 | 74 | int raw_str1_len = string1_len - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 75 | int raw_str2_len = string2_len - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 76 | int resp, cmp; 77 | uint8_t* dec_string1 = (uint8_t*)malloc(raw_str1_len + 1); 78 | uint8_t* dec_string2 = (uint8_t*)malloc(raw_str2_len + 1); 79 | 80 | resp = decrypt_bytes(string1, string1_len, dec_string1, raw_str1_len); 81 | if (resp != SGX_SUCCESS) 82 | return resp; 83 | 84 | resp = decrypt_bytes(string2, string2_len, dec_string2, raw_str2_len); 85 | if (resp != SGX_SUCCESS) 86 | return resp; 87 | 88 | dec_string1[raw_str1_len] = dec_string2[raw_str2_len] = '\0'; 89 | 90 | cmp = strcmp((const char*)dec_string1, (const char*)dec_string2); 91 | 92 | memcpy(result, &cmp, res_len); 93 | 94 | memset_s(dec_string1, raw_str1_len + 1, 0, raw_str1_len + 1); 95 | memset_s(dec_string2, raw_str2_len + 1, 0, raw_str2_len + 1); 96 | 97 | free(dec_string1); 98 | free(dec_string2); 99 | 100 | return resp; 101 | } 102 | 103 | /* Concatenation of two encrypted by aes_gcm strings 104 | @input: uint8_t array - encrypted integer1 105 | size_t - length of encrypted integer1 (SGX_AESGCM_IV_SIZE + ?? + 106 | SGX_AESGCM_MAC_SIZE = 32) 107 | uint8_t array - encrypted integer2 size_t - length of 108 | encrypted integer2 (SGX_AESGCM_IV_SIZE + ?? + SGX_AESGCM_MAC_SIZE = 32) 109 | uint8_t array - encrypted result size_t - length of encrypted result 110 | (SGX_AESGCM_IV_SIZE + ?? + SGX_AESGCM_MAC_SIZE = 32) 111 | @return: 112 | * SGX_error, if there was an error during encryption/decryption 113 | 0, otherwise 114 | */ 115 | int enc_text_concatenate(uint8_t* string1, 116 | size_t string1_len, 117 | uint8_t* string2, 118 | size_t string2_len, 119 | uint8_t* string3, 120 | size_t string3_len) 121 | { 122 | int raw_str1_len = string1_len - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 123 | int raw_str2_len = string2_len - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 124 | int raw_str3_len = string3_len - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 125 | int resp; 126 | 127 | uint8_t* dec_string1 = (uint8_t*)malloc(raw_str1_len + 1); 128 | uint8_t* dec_string2 = (uint8_t*)malloc(raw_str2_len + 1); 129 | uint8_t* dec_string3 = (uint8_t*)malloc(raw_str3_len + 1); 130 | 131 | resp = decrypt_bytes(string1, string1_len, dec_string1, raw_str1_len); 132 | if (resp != SGX_SUCCESS) 133 | return resp; 134 | 135 | resp = decrypt_bytes(string2, string2_len, dec_string2, raw_str2_len); 136 | if (resp != SGX_SUCCESS) 137 | return resp; 138 | 139 | memcpy(dec_string3, dec_string1, raw_str1_len); 140 | memcpy(dec_string3 + raw_str1_len, dec_string2, raw_str2_len); 141 | 142 | resp = encrypt_bytes(dec_string3, raw_str3_len, string3, string3_len); 143 | 144 | memset_s(dec_string1, raw_str1_len + 1, 0, raw_str1_len + 1); 145 | memset_s(dec_string2, raw_str2_len + 1, 0, raw_str2_len + 1); 146 | memset_s(dec_string3, raw_str3_len + 1, 0, raw_str3_len + 1); 147 | 148 | free_allocated_memory(dec_string1); 149 | free_allocated_memory(dec_string2); 150 | free_allocated_memory(dec_string3); 151 | 152 | return resp; 153 | } 154 | 155 | /* Search for substring in the string (both are encrypted by aes_gcm) 156 | @input: uint8_t array - encrypted string 157 | size_t - length of encrypted string (SGX_AESGCM_IV_SIZE + ?? + 158 | SGX_AESGCM_MAC_SIZE = 32) 159 | uint8_t array - encrypted substring size_t - length 160 | of encrypted substring (SGX_AESGCM_IV_SIZE + ?? + SGX_AESGCM_MAC_SIZE = 32) 161 | @return: 162 | * SGX_error, if there was an error during encryption/decryption 163 | 0, if the strings contains the substring 164 | 1, it not 165 | */ 166 | int enc_text_substring(uint8_t* in1, 167 | size_t in1_size, 168 | uint8_t* in2, 169 | size_t in2_size, 170 | uint8_t* in3, 171 | size_t in3_size, 172 | uint8_t* out, 173 | size_t* out_size) 174 | { 175 | size_t str_size = in1_size - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 176 | 177 | union { 178 | int val; 179 | unsigned char bytes[sizeof(val)]; 180 | } from, n_chars; 181 | 182 | char* str = (char*)malloc(str_size + 1); 183 | uint8_t* result = (uint8_t*)malloc(*out_size + 1); 184 | int resp = decrypt_bytes(in1, in1_size, (uint8_t*)str, str_size); 185 | if (resp != SGX_SUCCESS) 186 | return resp; 187 | 188 | if ((in2_size == INT32_LENGTH) && (in3_size == INT32_LENGTH)) 189 | { 190 | memcpy(from.bytes, in2, INT32_LENGTH); 191 | memcpy(n_chars.bytes, in3, INT32_LENGTH); 192 | } 193 | else 194 | { 195 | resp = decrypt_bytes(in2, in2_size, from.bytes, INT32_LENGTH); 196 | if (resp != SGX_SUCCESS) 197 | return resp; 198 | 199 | resp = decrypt_bytes(in3, in3_size, n_chars.bytes, INT32_LENGTH); 200 | if (resp != SGX_SUCCESS) 201 | return resp; 202 | } 203 | 204 | if ((from.val < 0 || n_chars.val < 0) || (from.val + n_chars.val > str_size)) 205 | { 206 | return OUT_OF_THE_RANGE_ERROR; 207 | } 208 | 209 | for (size_t i = 0; i < n_chars.val; i++) 210 | { 211 | result[i] = str[from.val + i - 1]; 212 | } 213 | 214 | resp = encrypt_bytes(result, n_chars.val, out, *out_size); 215 | 216 | memset_s(result, *out_size + 1, 0, *out_size + 1); 217 | 218 | *out_size = n_chars.val + SGX_AESGCM_IV_SIZE + SGX_AESGCM_MAC_SIZE; 219 | 220 | memset_s(str, str_size + 1, 0, str_size + 1); 221 | memset_s(from.bytes, INT32_LENGTH, 0, INT32_LENGTH); 222 | memset_s(n_chars.bytes, INT32_LENGTH, 0, INT32_LENGTH); 223 | 224 | free(str); 225 | free(result); 226 | 227 | return resp; 228 | } 229 | -------------------------------------------------------------------------------- /src/enclave/enc_timestamp_ops.cpp: -------------------------------------------------------------------------------- 1 | #include "enclave/enc_timestamp_ops.hpp" 2 | 3 | /* Compare two encrypted timestamps(int64 - 8 bytes) by aes_gcm algorithm 4 | @input: uint8_t array - encrypted source1 5 | size_t - sizegth of encrypted source1 (SGX_AESGCM_IV_SIZE + 6 | INT64_LENGTH + SGX_AESGCM_MAC_SIZE = 36) 7 | uint8_t array - encrypted source2 8 | size_t - sizegth of encrypted source2 (SGX_AESGCM_IV_SIZE + 9 | INT64_LENGTH + SGX_AESGCM_MAC_SIZE = 36) 10 | uint8_t array - which contains the result 1 (if a > b). -1 (if b > a), 11 | 0 (if a == b) 12 | size_t - size of result (TIMESTAMP_LENGTH = 4) 13 | 14 | @return: 15 | * SGX_error, if there was an error during decryption 16 | */ 17 | int enc_timestamp_cmp(uint8_t* in1, 18 | size_t in1_size, 19 | uint8_t* in2, 20 | size_t in2_size, 21 | uint8_t* out, 22 | size_t out_size) 23 | { 24 | int resp, cmp; 25 | 26 | union { 27 | TIMESTAMP ts; 28 | unsigned char bytes[TIMESTAMP_LENGTH]; 29 | } lhs, rhs; 30 | 31 | resp = decrypt_bytes(in1, in1_size, lhs.bytes, TIMESTAMP_LENGTH); 32 | if (resp != SGX_SUCCESS) 33 | return resp; 34 | 35 | resp = decrypt_bytes(in2, in2_size, rhs.bytes, TIMESTAMP_LENGTH); 36 | if (resp != SGX_SUCCESS) 37 | return resp; 38 | 39 | cmp = (lhs.ts == rhs.ts) ? 0 : ((lhs.ts < rhs.ts) ? -1 : 1); 40 | 41 | memcpy(out, &cmp, out_size); 42 | 43 | memset_s(lhs.bytes, TIMESTAMP_LENGTH, 0, TIMESTAMP_LENGTH); 44 | memset_s(rhs.bytes, TIMESTAMP_LENGTH, 0, TIMESTAMP_LENGTH); 45 | 46 | return resp; 47 | } 48 | 49 | int enc_timestamp_extract_year(uint8_t* in, 50 | size_t in_size, 51 | uint8_t* out, 52 | size_t out_size) 53 | { 54 | union { 55 | int val; 56 | unsigned char bytes[INT32_LENGTH]; 57 | } year; 58 | 59 | union { 60 | TIMESTAMP val; 61 | unsigned char bytes[TIMESTAMP_LENGTH]; 62 | } timestamp; 63 | 64 | int resp = decrypt_bytes(in, in_size, timestamp.bytes, TIMESTAMP_LENGTH); 65 | if (resp != SGX_SUCCESS) 66 | return resp; 67 | 68 | year.val = year_from_timestamp(timestamp.val); 69 | 70 | resp = encrypt_bytes(year.bytes, INT32_LENGTH, out, out_size); 71 | memset_s(timestamp.bytes, TIMESTAMP_LENGTH, 0, TIMESTAMP_LENGTH); 72 | memset_s(year.bytes, INT32_LENGTH, 0, INT32_LENGTH); 73 | 74 | return resp; 75 | } 76 | -------------------------------------------------------------------------------- /src/enclave/enclave.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 0 3 | 0 4 | 0x40000 5 | 0x100000 6 | 10 7 | 1 8 | 0 9 | 10 | -------------------------------------------------------------------------------- /src/enclave/enclave.edl: -------------------------------------------------------------------------------- 1 | /* enclave.edl - Top EDL file. */ 2 | 3 | enclave { 4 | /* 5 | * ocall_enclave_sample - invokes OCALL to display string buffer inside the enclave. 6 | * [in]: copy the string buffer to App outside. 7 | * [string]: specifies 'str' is a NULL terminated buffer. 8 | */ 9 | untrusted { 10 | 11 | }; 12 | 13 | trusted { 14 | public int generateKeyEnclave([out, size = sealedkey_len] uint8_t *sealed_key, size_t sealedkey_len); 15 | public int loadKeyEnclave ([in, size = len] uint8_t *key, size_t len); 16 | public int enclaveProcess ([user_check]void* inQueue); 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /src/enclave/enclave.lds: -------------------------------------------------------------------------------- 1 | enclave.so 2 | { 3 | global: 4 | g_global_data_sim; 5 | g_global_data; 6 | enclave_entry; 7 | local: 8 | *; 9 | }; 10 | -------------------------------------------------------------------------------- /src/include/defs.h: -------------------------------------------------------------------------------- 1 | // not sure what is better to use 2 | // #define(appropriate in c) or const int (c++ standard) 3 | // my vote for 'const int' 4 | 5 | typedef unsigned char BYTE; // 1byte 6 | typedef unsigned short WORD; // 2bytes 7 | typedef unsigned long DWORD; //4bytes 8 | 9 | #define SEALED_KEY_LENGTH 576 10 | 11 | #define ENC_INT32_LENGTH_B64 45 //((4 * n / 3) + 3) & ~3 12 | #define ENC_INT32_LENGTH 32 13 | #define INT32_LENGTH sizeof(int) 14 | 15 | #define ENC_FLOAT4_LENGTH_B64 45 //((4 * n / 3) + 3) & ~3 16 | #define ENC_FLOAT4_LENGTH 32 17 | #define FLOAT4_LENGTH sizeof(float) 18 | 19 | #define ENC_TIMESTAMP_LENGTH_B64 49 //((4 * n / 3) + 3) & ~3 20 | #define ENC_TIMESTAMP_LENGTH 36 21 | #define TIMESTAMP int64_t 22 | #define TIMESTAMP_LENGTH sizeof(int64_t) 23 | 24 | #define ENC_STRING_LENGTH_B64 1405 //((4 * n / 3) + 3) & ~3 25 | #define ENC_STRING_LENGTH 1052 26 | #define STRING_LENGTH 1024 27 | #define INPUT_BUFFER_SIZE ENC_STRING_LENGTH_B64 + ENC_STRING_LENGTH_B64 + 1 28 | 29 | #define BULK_SIZE 256 30 | 31 | // errors 32 | #define ENCLAVE_IS_NOT_RUNNING -2 33 | #define MEMORY_COPY_ERROR -3 34 | #define ARITHMETIC_ERROR -4 35 | #define MEMORY_ALLOCATION_ERROR -5 36 | #define OUT_OF_THE_RANGE_ERROR -6 37 | #define BASE64DECODER_ERROR -7 38 | #define IS_NOT_INITIALIZE -8 39 | #define NO_KEYS_STORAGE -9 40 | #define NO_KEY_ID -10 41 | #define NOT_IMPLEMENTED_OPERATOR -11 42 | #define TOO_MANY_ELEMENTS_IN_BULK -12 43 | 44 | // COMMANDS 45 | #define CMD_INT64_PLUS 1 46 | #define CMD_INT64_MINUS 2 47 | #define CMD_INT64_MULT 3 48 | #define CMD_INT64_DIV 4 49 | #define CMD_INT64_CMP 5 50 | #define CMD_INT64_ENC 6 51 | #define CMD_INT64_DEC 7 52 | #define CMD_INT64_EXP 8 53 | #define CMD_INT64_MOD 9 54 | #define CMD_INT32_SUM_BULK 10 55 | 56 | #define CMD_FLOAT4_PLUS 101 57 | #define CMD_FLOAT4_MINUS 102 58 | #define CMD_FLOAT4_MULT 103 59 | #define CMD_FLOAT4_DIV 104 60 | #define CMD_FLOAT4_CMP 105 61 | #define CMD_FLOAT4_ENC 106 62 | #define CMD_FLOAT4_DEC 107 63 | #define CMD_FLOAT4_EXP 108 64 | #define CMD_FLOAT4_MOD 109 65 | #define CMD_FLOAT4_SUM_BULK 110 66 | 67 | #define CMD_STRING_CMP 201 68 | #define CMD_STRING_ENC 202 69 | #define CMD_STRING_DEC 203 70 | #define CMD_STRING_SUBSTRING 204 71 | #define CMD_STRING_CONCAT 205 72 | #define CMD_STRING_LIKE 206 73 | 74 | #define CMD_TIMESTAMP_CMP 150 75 | #define CMD_TIMESTAMP_ENC 151 76 | #define CMD_TIMESTAMP_DEC 152 77 | #define CMD_TIMESTAMP_EXTRACT_YEAR 153 78 | -------------------------------------------------------------------------------- /src/include/enclave/Queue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tools/sync_utils.hpp" 3 | #include 4 | 5 | struct request 6 | { 7 | static const int max_buffer_size = 65536; 8 | int ocall_index; 9 | unsigned char buffer[max_buffer_size]; 10 | volatile int is_done; 11 | int resp; 12 | }; 13 | 14 | class Queue 15 | { 16 | public: 17 | Queue(); 18 | virtual ~Queue(); 19 | int enqueue(request* elem); 20 | request* dequeue(); 21 | int front, rear; 22 | 23 | private: 24 | static const int queue_size = 1024000; 25 | request* q[queue_size]; 26 | int volatile _lock; 27 | }; 28 | -------------------------------------------------------------------------------- /src/include/enclave/enc_float32_ops.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "enclave/enclave.hpp" 4 | #include "enclave/enclave_t.h" 5 | 6 | typedef union { 7 | float val; 8 | unsigned char bytes[FLOAT4_LENGTH]; 9 | } union_float4; 10 | 11 | int enc_float32_add(uint8_t* in1, 12 | size_t in1_size, 13 | uint8_t* in2, 14 | size_t in2_size, 15 | uint8_t* out, 16 | size_t out_size); 17 | int enc_float32_cmp(uint8_t* in1, 18 | size_t in1_size, 19 | uint8_t* in2, 20 | size_t in2_size, 21 | uint8_t* out, 22 | size_t out_size); 23 | int enc_float32_sub(uint8_t* in1, 24 | size_t in1_size, 25 | uint8_t* in2, 26 | size_t in2_size, 27 | uint8_t* out, 28 | size_t out_size); 29 | int enc_float32_mult(uint8_t* in1, 30 | size_t in1_size, 31 | uint8_t* in2, 32 | size_t in2_size, 33 | uint8_t* out, 34 | size_t out_size); 35 | int enc_float32_div(uint8_t* in1, 36 | size_t in1_size, 37 | uint8_t* in2, 38 | size_t in2_size, 39 | uint8_t* out, 40 | size_t out_size); 41 | int enc_float32_mod(uint8_t* in1, 42 | size_t in1_size, 43 | uint8_t* in2, 44 | size_t in2_size, 45 | uint8_t* out, 46 | size_t out_size); 47 | int enc_float32_pow(uint8_t* in1, 48 | size_t in1_size, 49 | uint8_t* in2, 50 | size_t in2_size, 51 | uint8_t* out, 52 | size_t out_size); 53 | int enc_float32_sum_bulk(uint8_t* in1, 54 | size_t in1_size, 55 | uint8_t* in2, 56 | size_t in2_size, 57 | uint8_t* out, 58 | size_t out_size); 59 | -------------------------------------------------------------------------------- /src/include/enclave/enc_int32_ops.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "enclave/enclave.hpp" 4 | #include "enclave/enclave_t.h" /* print_string */ 5 | #include "tools/bytes.hpp" 6 | int enc_int32_add(uint8_t* int1, 7 | size_t int1_len, 8 | uint8_t* int2, 9 | size_t int2_len, 10 | uint8_t* int3, 11 | size_t int3_len); 12 | int enc_int32_cmp(uint8_t* int1, 13 | size_t int1_len, 14 | uint8_t* int2, 15 | size_t int2_len, 16 | uint8_t* result, 17 | size_t res_len); 18 | int enc_int32_sub(uint8_t* int1, 19 | size_t int1_len, 20 | uint8_t* int2, 21 | size_t int2_len, 22 | uint8_t* result, 23 | size_t res_len); 24 | int enc_int32_mult(uint8_t* int1, 25 | size_t int1_len, 26 | uint8_t* int2, 27 | size_t int2_len, 28 | uint8_t* result, 29 | size_t res_len); 30 | int enc_int32_div(uint8_t* int1, 31 | size_t int1_len, 32 | uint8_t* int2, 33 | size_t int2_len, 34 | uint8_t* result, 35 | size_t res_len); 36 | int enc_int32_mod(uint8_t* int1, 37 | size_t int1_len, 38 | uint8_t* int2, 39 | size_t int2_len, 40 | uint8_t* result, 41 | size_t res_len); 42 | int enc_int32_pow(uint8_t* int1, 43 | size_t int1_len, 44 | uint8_t* int2, 45 | size_t int2_len, 46 | uint8_t* result, 47 | size_t res_len); 48 | int enc_int32_sum_bulk(uint8_t* arg1, 49 | size_t arg1_len, 50 | uint8_t* arg2, 51 | size_t arg2_len, 52 | uint8_t* result, 53 | size_t res_len); 54 | -------------------------------------------------------------------------------- /src/include/enclave/enc_text_ops.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "defs.h" 4 | #include "enclave/enclave.hpp" 5 | #include "tools/like_match.h" 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" 10 | { 11 | #endif 12 | 13 | int enc_text_cmp(uint8_t* in1, 14 | size_t in1_size, 15 | uint8_t* in2, 16 | size_t in2_size, 17 | uint8_t* out, 18 | size_t out_size); 19 | int enc_text_like(uint8_t* in1, 20 | size_t in1_size, 21 | uint8_t* in2, 22 | size_t in2_size, 23 | uint8_t* out, 24 | size_t out_size); 25 | int enc_text_concatenate(uint8_t* in1, 26 | size_t in1_size, 27 | uint8_t* in2, 28 | size_t in2_size, 29 | uint8_t* out, 30 | size_t out_size); 31 | int enc_text_substring(uint8_t* in1, 32 | size_t in1_size, 33 | uint8_t* in2, 34 | size_t in2_size, 35 | uint8_t* in3, 36 | size_t in3_size, 37 | uint8_t* out, 38 | size_t* out_size); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /src/include/enclave/enc_timestamp_ops.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "enclave/enclave.hpp" 3 | #include "enclave/enclave_t.h" 4 | #include "tools/timestamp.h" 5 | 6 | int enc_timestamp_cmp(uint8_t* src1, 7 | size_t src1_len, 8 | uint8_t* src2, 9 | size_t src2_len, 10 | uint8_t* result, 11 | size_t res_len); 12 | int enc_timestamp_extract_year(uint8_t* in1, 13 | size_t in1_len, 14 | uint8_t* out, 15 | size_t out_size); 16 | -------------------------------------------------------------------------------- /src/include/enclave/enclave.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sgx_eid.h" 4 | #include "sgx_tcrypto.h" 5 | #include "sgx_trts.h" 6 | #include "sgx_tseal.h" 7 | #include 8 | #include 9 | 10 | #include "math.h" 11 | #include 12 | #include 13 | 14 | #include "defs.h" 15 | #include "enclave/Queue.hpp" 16 | #include "enclave/enc_float32_ops.hpp" 17 | #include "enclave/enc_int32_ops.hpp" 18 | #include "enclave/enc_text_ops.hpp" 19 | #include "enclave/enc_timestamp_ops.hpp" 20 | #include "tools/sync_utils.hpp" 21 | 22 | #if defined(__cplusplus) 23 | extern "C" 24 | { 25 | #endif 26 | 27 | void free_allocated_memory(void* pointer); 28 | 29 | // FUNCTIONS 30 | int decrypt_bytes(uint8_t* pSrc, size_t srcLen, uint8_t* pDst, size_t dstLen); 31 | int encrypt_bytes(uint8_t* pSrc, size_t srcLen, uint8_t* pDst, size_t dstLen); 32 | #if defined(__cplusplus) 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /src/include/tools/base64.hpp: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | 3 | int ToBase64Fast(const unsigned char* pSrc, int nLenSrc, char* pDst, int nLenDst); 4 | int FromBase64Fast(const BYTE* pSrc, int nLenSrc, char* pDst, int nLenDst); 5 | int FromBase64Fast(const BYTE* pSrc, int nLenSrc, BYTE* pDst, int nLenDst); 6 | -------------------------------------------------------------------------------- /src/include/tools/bytes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "defs.h" 3 | #include 4 | #include 5 | #include 6 | 7 | int int2bytearray(int, uint8_t*, size_t); 8 | int bytearray2int(uint8_t*, int&, size_t); 9 | -------------------------------------------------------------------------------- /src/include/tools/like_match.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define GETCHAR(t) (t) 3 | #define LIKE_TRUE 1 4 | #define LIKE_FALSE 0 5 | #define LIKE_ABORT (-1) 6 | 7 | #define CHAREQ(p1, p2) (*(p1) == *(p2)) 8 | #define NextByte(p, plen) ((p)++, (plen)--) 9 | #define NextChar(p, plen) NextByte((p), (plen)) 10 | #define CopyAdvChar(dst, src, srclen) (*(dst)++ = *(src)++, (srclen)--) 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | int MatchText(char*, int, char*, int); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /src/include/tools/oblvs_int32_ops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | /*Return 1 if lhs == rhs and 0 otherwise*/ 7 | int32_t obs_int32_eq(int32_t lhs, int32_t rhs); 8 | 9 | /* Return 1 if lhs < rhs and 0 otherwise*/ 10 | int32_t obs_int32_lt(int32_t lhs, int32_t rhs); 11 | 12 | /*Return rhs if sel = 0 and lhs otherwise*/ 13 | int32_t obs_int32_select(int32_t lhs, int32_t rhs, int32_t sel); 14 | 15 | /* Return base^exp*/ 16 | int32_t obs_int32_pow(int32_t base, int32_t exp); 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | int32_t obs_int32_neq(int32_t lhs, int32_t rhs) 22 | { 23 | return 1 ^ obs_int32_eq(lhs, rhs); 24 | } 25 | 26 | /*Return 1 if lhs > rhs and 0 otherwise*/ 27 | int32_t obs_int32_gt(int32_t lhs, int32_t rhs) { 28 | return obs_int32_lt(rhs, lhs); 29 | } 30 | 31 | /*Return 1 if lhs >= rhs and 0 otherwise*/ 32 | int32_t obs_int32_ge(int32_t lhs, int32_t rhs) { 33 | return 1 ^ obs_int32_lt(lhs, rhs); 34 | } 35 | 36 | /*Return 1 if lhs <= rhs and 0 otherwise*/ 37 | int32_t obs_int32_le(int32_t lhs, int32_t rhs) { 38 | return 1 ^ obs_int32_gt(rhs, lhs); 39 | } 40 | 41 | /*Return 1 if lhs > rhs, -1 if lhs < rhs and 0 otherwise*/ 42 | int32_t obs_int32_cmp(int32_t lhs, int32_t rhs) { 43 | return obs_int32_gt(lhs, rhs) | -obs_int32_lt(lhs, rhs); 44 | } 45 | -------------------------------------------------------------------------------- /src/include/tools/sync_utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void spin_lock(int volatile* p); 4 | void spin_unlock(int volatile* p); 5 | void spin_lock(unsigned char volatile* p); 6 | void spin_unlock(unsigned char volatile* p); 7 | -------------------------------------------------------------------------------- /src/include/tools/timestamp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | /* TMODULO() 6 | * Implements modf() in for the timestamp (aka int64) datatype. 7 | * We assume that int64 follows the C99 semantics for division (negative 8 | * quotients truncate towards zero). 9 | */ 10 | #define TMODULO(t,q,u) \ 11 | do { \ 12 | (q) = ((t) / (u)); \ 13 | if ((q) != 0) (t) -= ((q) * (u)); \ 14 | } while(0) 15 | 16 | #define INT64CONST(x) (x##L) 17 | #define USECS_PER_DAY INT64CONST(86400000000) 18 | #define POSTGRES_EPOCH_JDATE 2451545 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | int year_from_timestamp(int64_t timestamp); 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /src/include/untrusted/extensions/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | #include 8 | #include 9 | #include 10 | 11 | #include "enclave_u.h" 12 | #include "sgx_eid.h" /* sgx_enclave_id_t */ 13 | #include "sgx_tcrypto.h" 14 | 15 | #include "postgres.h" 16 | #include "fmgr.h" 17 | #include 18 | 19 | #include 20 | #include 21 | #include "utils/builtins.h" 22 | 23 | #include "defs.h" 24 | #include "untrusted/interface/interface.h" 25 | 26 | typedef struct _sgx_errlist_t { 27 | sgx_status_t err; 28 | const char* msg; 29 | const char* sug; /* Suggestion */ 30 | } sgx_errlist_t; 31 | 32 | void sgxErrorHandler(int code); 33 | 34 | /* Error code returned by sgx_create_enclave */ 35 | static sgx_errlist_t sgx_errlist[] = { 36 | { 37 | SGX_ERROR_INVALID_KEYNAME, 38 | "The key name is an unsupported value", 39 | NULL 40 | }, 41 | { 42 | SGX_ERROR_INVALID_ISVSVN, 43 | "The isv svn is greater than the enclave's isv svn", 44 | NULL 45 | }, 46 | { 47 | SGX_ERROR_MAC_MISMATCH, 48 | "Indicates verification error for reports, sealed datas, MAC checks and etc", 49 | NULL 50 | }, 51 | { 52 | SGX_ERROR_INVALID_ATTRIBUTE, 53 | "The cpu svn is beyond platform's cpu svn value", 54 | NULL 55 | }, 56 | 57 | { 58 | SGX_ERROR_INVALID_PARAMETER, 59 | "Invalid parameter.", 60 | NULL 61 | }, 62 | { 63 | SGX_ERROR_OUT_OF_MEMORY, 64 | "Out of memory.", 65 | NULL 66 | }, 67 | { 68 | SGX_ERROR_ENCLAVE_LOST, 69 | "Power transition occurred.", 70 | "Please refer to the sample \"PowerTransition\" for details." 71 | }, 72 | { 73 | SGX_ERROR_INVALID_ENCLAVE, 74 | "Invalid enclave image.", 75 | NULL 76 | }, 77 | { 78 | SGX_ERROR_INVALID_ENCLAVE_ID, 79 | "Invalid enclave identification.", 80 | NULL 81 | }, 82 | { 83 | SGX_ERROR_INVALID_SIGNATURE, 84 | "Invalid enclave signature.", 85 | NULL 86 | }, 87 | { 88 | SGX_ERROR_OUT_OF_EPC, 89 | "Out of EPC memory.", 90 | NULL 91 | }, 92 | { 93 | SGX_ERROR_NO_DEVICE, 94 | "Invalid SGX device.", 95 | "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." 96 | }, 97 | { 98 | SGX_ERROR_MEMORY_MAP_CONFLICT, 99 | "Memory map conflicted.", 100 | NULL 101 | }, 102 | { 103 | SGX_ERROR_INVALID_METADATA, 104 | "Invalid enclave metadata.", 105 | NULL 106 | }, 107 | { 108 | SGX_ERROR_DEVICE_BUSY, 109 | "SGX device was busy.", 110 | NULL 111 | }, 112 | { 113 | SGX_ERROR_INVALID_VERSION, 114 | "Enclave version was invalid.", 115 | NULL 116 | }, 117 | { 118 | SGX_ERROR_INVALID_ATTRIBUTE, 119 | "Enclave was not authorized.", 120 | NULL 121 | }, 122 | { 123 | SGX_ERROR_ENCLAVE_FILE_ACCESS, 124 | "Can't open enclave file.", 125 | NULL 126 | }, 127 | { 128 | SGX_ERROR_SERVICE_UNAVAILABLE, 129 | "Indicates aesm didn't respond or the requested service is not supported", 130 | NULL 131 | }, 132 | }; 133 | -------------------------------------------------------------------------------- /src/include/untrusted/interface/interface.h: -------------------------------------------------------------------------------- 1 | #ifndef _APP_H_ 2 | #define _APP_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "sgx_eid.h" /* sgx_enclave_id_t */ 9 | #include "enclave_u.h" 10 | 11 | #ifndef TRUE 12 | # define TRUE 1 13 | #endif 14 | 15 | #ifndef FALSE 16 | # define FALSE 0 17 | #endif 18 | 19 | #if defined(__cplusplus) 20 | extern "C" { 21 | #endif 22 | extern sgx_enclave_id_t global_eid; /* global enclave id */ 23 | 24 | int generateKey(); 25 | int loadKey(int item); 26 | 27 | int initMultithreading(); 28 | int enc_int32_add(char *int1, char *int2, char *res); 29 | int enc_int32_sub(char *int1, char *int2, char *res); 30 | int enc_int32_mult(char *int1, char *int2, char *res); 31 | int enc_int32_div(char *int1, char *int2, char *res); 32 | int enc_int32_pow(char *int1, char *int2, char *res); 33 | int enc_int32_mod(char *int1, char *int2, char *res); 34 | int enc_int32_cmp(char *int1, char *int2, char *res); 35 | int enc_int32_encrypt(int pSrc, char *pDst); 36 | int enc_int32_decrypt(char *pSrc, char *pDst); 37 | int enc_int32_sum_bulk(size_t bulk_size, char *arg1, char *res); 38 | 39 | int enc_text_cmp(char *arg1, size_t arg1_len, char *arg2, size_t arg2_len, char *res); 40 | int enc_text_concatenate(char *arg1, size_t arg1_len, char *arg2, size_t arg2_len, char *dst, size_t* dst_len); 41 | int enc_text_substring(char* in1, size_t in1_size, char* in2, size_t in2_size, char* in3, size_t in3_size, char* out, size_t* out_size); 42 | 43 | int enc_text_like(char* in1, size_t in1_size, char* in2, size_t in2_size, int* out); 44 | 45 | int enc_text_encrypt(char* arg1, size_t arg1_len, char* res, size_t dst_len); 46 | int enc_text_decrypt(char* arg1, size_t arg1_len, char* res, size_t dst_len); 47 | 48 | int enc_float32_cmp(char *arg1, char *arg2, char *res); 49 | int enc_float32_encrypt(float pSrc, char *pDst); 50 | int enc_float32_decrypt(char *pSrc, char *pDst); 51 | int enc_float32_add(char *arg1, char *arg2, char *res); 52 | int enc_float32_sub(char *arg1, char *arg2, char *res); 53 | int enc_float32_mult(char *arg1, char *arg2, char *res); 54 | int enc_float32_div(char *arg1, char *arg2, char *res); 55 | int enc_float32_pow(char *arg1, char *arg2, char *res); 56 | int enc_float32_mod(char *arg1, char *arg2, char *res); 57 | int enc_float32_sum_bulk(size_t bulk_size, char *arg1, char *res); 58 | 59 | int enc_timestamp_decrypt(char* src, char *dst); 60 | int enc_timestamp_encrypt(char* src, char *dst); 61 | int enc_timestamp_cmp(char* src1, char *src2, char *dst); 62 | int enc_timestamp_extract_year(char* in, char* out); 63 | 64 | #if defined(__cplusplus) 65 | } 66 | #endif 67 | 68 | #endif /* !_APP_H_ */ 69 | -------------------------------------------------------------------------------- /src/include/untrusted/interface/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | #include 8 | #include "sgx_urts.h" 9 | #include "sgx_tcrypto.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "enclave/Queue.hpp" 19 | #include "tools/sync_utils.hpp" 20 | #include "tools/base64.hpp" 21 | #include "defs.h" 22 | -------------------------------------------------------------------------------- /src/tools/Queue.cpp: -------------------------------------------------------------------------------- 1 | #include "enclave/Queue.hpp" 2 | 3 | Queue::Queue() 4 | { 5 | front = rear = 0; 6 | for (int i = 0; i < queue_size; i++) 7 | { 8 | q[i] = NULL; 9 | } 10 | } 11 | 12 | Queue::~Queue() {} 13 | 14 | int Queue::enqueue(request* elem) 15 | { 16 | spin_lock(&_lock); 17 | 18 | if (rear - front == queue_size) 19 | { 20 | spin_unlock(&_lock); 21 | abort(); 22 | return -1; 23 | } 24 | 25 | q[rear % queue_size] = elem; 26 | ++rear; 27 | 28 | spin_unlock(&_lock); 29 | return 0; 30 | } 31 | 32 | request* 33 | Queue::dequeue() 34 | { 35 | spin_lock(&_lock); 36 | 37 | if (front == rear) 38 | { 39 | spin_unlock(&_lock); 40 | return NULL; 41 | } 42 | 43 | request* result = q[front % queue_size]; 44 | ++front; 45 | spin_unlock(&_lock); 46 | 47 | return result; 48 | } 49 | -------------------------------------------------------------------------------- /src/tools/bytes.cpp: -------------------------------------------------------------------------------- 1 | #include "tools/bytes.hpp" 2 | 3 | /* Convert an integer to a byte array. 4 | Should pay attention to the endian. 5 | @input: src - integer 6 | pDst - pointer to the result array with size INT32_LENGTH 7 | dstLen - length of the array 8 | @return: 9 | 1, if the size of array is less than INT32_LENGTH 10 | 0 otherwise 11 | */ 12 | int int2bytearray(int src, uint8_t* pDst, size_t dstLen) 13 | { 14 | if (dstLen < INT32_LENGTH) 15 | return 1; 16 | 17 | memcpy(pDst, &src, INT32_LENGTH); 18 | 19 | return 0; 20 | } 21 | 22 | /* Convert an array to an integer. 23 | Should pay attention to the endian. 24 | @input: 25 | pDst - pointer to the result array with size INT32_LENGTH 26 | src - output integer 27 | dstLen - length of the array 28 | @return: 29 | 1, if the size of array is less than INT32_LENGTH 30 | 0 otherwise 31 | 32 | */ 33 | int bytearray2int(uint8_t* pSrc, int& dst, size_t srcLen) 34 | { 35 | if (srcLen < INT32_LENGTH) 36 | return 1; 37 | 38 | memcpy(&dst, pSrc, INT32_LENGTH); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/tools/like_match.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * like_match.c 4 | * LIKE pattern matching internal code. 5 | * 6 | * This file is included by like.c four times, to provide matching code for 7 | * (1) single-byte encodings, (2) UTF8, (3) other multi-byte encodings, 8 | * and (4) case insensitive matches in single-byte encodings. 9 | * (UTF8 is a special case because we can use a much more efficient version 10 | * of NextChar than can be used for general multi-byte encodings.) 11 | * 12 | * Before the inclusion, we need to define the following macros: 13 | * 14 | * NextChar 15 | * MatchText - to name of function wanted 16 | * do_like_escape - name of function if wanted - needs CHAREQ and CopyAdvChar 17 | * MATCH_LOWER - define for case (4) to specify case folding for 1-byte chars 18 | * 19 | * Copyright (c) 1996-2018, PostgreSQL Global Development Group 20 | * 21 | * IDENTIFICATION 22 | * src/backend/utils/adt/like_match.c 23 | * 24 | *------------------------------------------------------------------------- 25 | */ 26 | 27 | /* 28 | * Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. 29 | * Rich $alz is now . 30 | * Special thanks to Lars Mathiesen for the LABORT code. 31 | * 32 | * This code was shamelessly stolen from the "pql" code by myself and 33 | * slightly modified :) 34 | * 35 | * All references to the word "star" were replaced by "percent" 36 | * All references to the word "wild" were replaced by "like" 37 | * 38 | * All the nice shell RE matching stuff was replaced by just "_" and "%" 39 | * 40 | * As I don't have a copy of the SQL standard handy I wasn't sure whether 41 | * to leave in the '\' escape character handling. 42 | * 43 | * Keith Parks. 44 | * 45 | * SQL lets you specify the escape character by saying 46 | * LIKE ESCAPE . We are a small operation 47 | * so we force you to use '\'. - ay 7/95 48 | * 49 | * Now we have the like_escape() function that converts patterns with 50 | * any specified escape character (or none at all) to the internal 51 | * default escape character, which is still '\'. - tgl 9/2000 52 | * 53 | * The code is rewritten to avoid requiring null-terminated strings, 54 | * which in turn allows us to leave out some memcpy() operations. 55 | * This code should be faster and take less memory, but no promises... 56 | * - thomas 2000-08-06 57 | */ 58 | 59 | 60 | /*-------------------- 61 | * Match text and pattern, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT. 62 | * 63 | * LIKE_TRUE: they match 64 | * LIKE_FALSE: they don't match 65 | * LIKE_ABORT: not only don't they match, but the text is too short. 66 | * 67 | * If LIKE_ABORT is returned, then no suffix of the text can match the 68 | * pattern either, so an upper-level % scan can stop scanning now. 69 | *-------------------- 70 | */ 71 | 72 | #include "tools/like_match.h" 73 | 74 | int 75 | MatchText(char *t, int tlen, char *p, int plen) 76 | { 77 | /* Fast path for match-everything pattern */ 78 | if (plen == 1 && *p == '%') 79 | return LIKE_TRUE; 80 | 81 | /* Since this function recurses, it could be driven to stack overflow */ 82 | /*check_stack_depth();*/ 83 | 84 | /* 85 | * In this loop, we advance by char when matching wildcards (and thus on 86 | * recursive entry to this function we are properly char-synced). On other 87 | * occasions it is safe to advance by byte, as the text and pattern will 88 | * be in lockstep. This allows us to perform all comparisons between the 89 | * text and pattern on a byte by byte basis, even for multi-byte 90 | * encodings. 91 | */ 92 | while (tlen > 0 && plen > 0) 93 | { 94 | if (*p == '\\') 95 | { 96 | /* Next pattern byte must match literally, whatever it is */ 97 | NextByte(p, plen); 98 | /* ... and there had better be one, per SQL standard */ 99 | if (plen <= 0) 100 | return LIKE_ABORT; 101 | if (GETCHAR(*p) != GETCHAR(*t)) 102 | return LIKE_FALSE; 103 | } 104 | else if (*p == '%') 105 | { 106 | char firstpat; 107 | 108 | /* 109 | * % processing is essentially a search for a text position at 110 | * which the remainder of the text matches the remainder of the 111 | * pattern, using a recursive call to check each potential match. 112 | * 113 | * If there are wildcards immediately following the %, we can skip 114 | * over them first, using the idea that any sequence of N _'s and 115 | * one or more %'s is equivalent to N _'s and one % (ie, it will 116 | * match any sequence of at least N text characters). In this way 117 | * we will always run the recursive search loop using a pattern 118 | * fragment that begins with a literal character-to-match, thereby 119 | * not recursing more than we have to. 120 | */ 121 | NextByte(p, plen); 122 | 123 | while (plen > 0) 124 | { 125 | if (*p == '%') 126 | NextByte(p, plen); 127 | else if (*p == '_') 128 | { 129 | /* If not enough text left to match the pattern, ABORT */ 130 | if (tlen <= 0) 131 | return LIKE_ABORT; 132 | NextChar(t, tlen); 133 | NextByte(p, plen); 134 | } 135 | else 136 | break; /* Reached a non-wildcard pattern char */ 137 | } 138 | 139 | /* 140 | * If we're at end of pattern, match: we have a trailing % which 141 | * matches any remaining text string. 142 | */ 143 | if (plen <= 0) 144 | return LIKE_TRUE; 145 | 146 | /* 147 | * Otherwise, scan for a text position at which we can match the 148 | * rest of the pattern. The first remaining pattern char is known 149 | * to be a regular or escaped literal character, so we can compare 150 | * the first pattern byte to each text byte to avoid recursing 151 | * more than we have to. This fact also guarantees that we don't 152 | * have to consider a match to the zero-length substring at the 153 | * end of the text. 154 | */ 155 | if (*p == '\\') 156 | { 157 | if (plen < 2) 158 | return LIKE_ABORT; 159 | firstpat = GETCHAR(p[1]); 160 | } 161 | else 162 | firstpat = GETCHAR(*p); 163 | 164 | while (tlen > 0) 165 | { 166 | if (GETCHAR(*t) == firstpat) 167 | { 168 | int matched = MatchText(t, tlen, p, plen); 169 | 170 | if (matched != LIKE_FALSE) 171 | return matched; /* TRUE or ABORT */ 172 | } 173 | 174 | NextChar(t, tlen); 175 | } 176 | 177 | /* 178 | * End of text with no match, so no point in trying later places 179 | * to start matching this pattern. 180 | */ 181 | return LIKE_ABORT; 182 | } 183 | else if (*p == '_') 184 | { 185 | /* _ matches any single character, and we know there is one */ 186 | NextChar(t, tlen); 187 | NextByte(p, plen); 188 | continue; 189 | } 190 | else if (GETCHAR(*p) != GETCHAR(*t)) 191 | { 192 | /* non-wildcard pattern char fails to match text char */ 193 | return LIKE_FALSE; 194 | } 195 | 196 | /* 197 | * Pattern and text match, so advance. 198 | * 199 | * It is safe to use NextByte instead of NextChar here, even for 200 | * multi-byte character sets, because we are not following immediately 201 | * after a wildcard character. If we are in the middle of a multibyte 202 | * character, we must already have matched at least one byte of the 203 | * character from both text and pattern; so we cannot get out-of-sync 204 | * on character boundaries. And we know that no backend-legal 205 | * encoding allows ASCII characters such as '%' to appear as non-first 206 | * bytes of characters, so we won't mistakenly detect a new wildcard. 207 | */ 208 | NextByte(t, tlen); 209 | NextByte(p, plen); 210 | } 211 | 212 | if (tlen > 0) 213 | return LIKE_FALSE; /* end of pattern, but not of text */ 214 | 215 | /* 216 | * End of text, but perhaps not of pattern. Match iff the remaining 217 | * pattern can match a zero-length string, ie, it's zero or more %'s. 218 | */ 219 | while (plen > 0 && *p == '%') 220 | NextByte(p, plen); 221 | if (plen <= 0) 222 | return LIKE_TRUE; 223 | 224 | /* 225 | * End of text with no match, so no point in trying later places to start 226 | * matching this pattern. 227 | */ 228 | return LIKE_ABORT; 229 | } /* MatchText() */ 230 | -------------------------------------------------------------------------------- /src/tools/oblvs_int32_ops.S: -------------------------------------------------------------------------------- 1 | %macro DEF 1 2 | global %1:function 3 | %1: 4 | %endmacro 5 | 6 | section .text 7 | 8 | DEF obs_int32_eq 9 | xor eax, eax 10 | cmp edi, esi 11 | sete al 12 | ret 13 | 14 | DEF obs_int32_lt 15 | xor eax, eax 16 | cmp edi, esi 17 | setl al 18 | ret 19 | 20 | DEF obs_int32_select 21 | test edx, edx 22 | cmovne edi, esi 23 | mov eax, edi 24 | ret 25 | 26 | obs_int32_bits: 27 | xor eax, eax 28 | cmp edi, 65535 29 | seta al 30 | shl eax, 4 31 | mov ecx, eax 32 | shr edi, cl 33 | xor edx, edx 34 | cmp edi, 255 35 | seta dl 36 | lea ecx, [8*rdx] 37 | shr edi, cl 38 | lea eax, [rax + 8*rdx] 39 | xor edx, edx 40 | cmp edi, 15 41 | seta dl 42 | lea ecx, [4*rdx] 43 | shr edi, cl 44 | lea eax, [rax + 4*rdx] 45 | xor edx, edx 46 | cmp edi, 3 47 | seta dl 48 | lea ecx, [rdx + rdx] 49 | shr edi, cl 50 | lea eax, [rax + 2*rdx] 51 | shr edi, 1 52 | or eax, edi 53 | ret 54 | 55 | DEF obs_int32_pow 56 | push r14 57 | push rbx 58 | 59 | mov r14d, edi 60 | mov edi, esi 61 | call obs_int32_bits 62 | mov edi, r14d 63 | mov r14d, eax 64 | 65 | mov eax, 1 66 | 67 | .loop: 68 | mov ebx, 1 69 | mov ecx, r14d 70 | shl ebx, cl 71 | and ebx, esi 72 | 73 | mov r8d, eax 74 | 75 | imul eax, eax 76 | imul r8d, edi 77 | imul edi, edi 78 | 79 | xor edx, edx 80 | test ebx, ebx 81 | setne dl 82 | neg edx 83 | mov ebx, edx 84 | 85 | and ebx, r8d 86 | mov ecx, edx 87 | not ecx 88 | and eax, ecx 89 | or eax, ebx 90 | 91 | and edx, edi 92 | and ecx, r8d 93 | or ecx, edx 94 | 95 | test r14d, r14d 96 | 97 | lea edx, [r14 - 1] 98 | mov r14d, edx 99 | mov edi, ecx 100 | jg .loop 101 | 102 | pop rbx 103 | pop r14 104 | ret 105 | -------------------------------------------------------------------------------- /src/tools/sync_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "tools/sync_utils.hpp" 2 | 3 | void spin_lock(int volatile* p) 4 | { 5 | while (!__sync_bool_compare_and_swap(p, 0, 1)) 6 | { 7 | while (*p) 8 | __asm__("pause"); 9 | } 10 | } 11 | 12 | void spin_unlock(int volatile* p) 13 | { 14 | asm volatile(""); // acts as a memory barrier. 15 | *p = 0; 16 | } 17 | 18 | void spin_lock(unsigned char volatile* p) 19 | { 20 | while (!__sync_bool_compare_and_swap(p, 0, 1)) 21 | { 22 | while (*p) 23 | __asm__("pause"); 24 | } 25 | } 26 | 27 | void spin_unlock(unsigned char volatile* p) 28 | { 29 | asm volatile(""); // acts as a memory barrier. 30 | *p = 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/tools/timestamp.c: -------------------------------------------------------------------------------- 1 | #include "tools/timestamp.h" 2 | 3 | /*------------------------------------------------------------------------- 4 | * 5 | * This function has been adapted from the timestamp2tm function found in 6 | * src/backend/utils/adt/timestamp.c of the PostgreSQL source, a file 7 | * for which: 8 | * 9 | * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group 10 | * Portions Copyright (c) 1994, Regents of the University of California 11 | */ 12 | 13 | int year_from_timestamp(int64_t timestamp) 14 | { 15 | 16 | int64_t date; 17 | unsigned int quad; 18 | unsigned int extra; 19 | int year; 20 | 21 | TMODULO(timestamp, date, USECS_PER_DAY); 22 | if (timestamp < INT64CONST(0)) 23 | { 24 | timestamp += USECS_PER_DAY; 25 | date -= 1; 26 | } 27 | 28 | /* add offset to go from J2000 back to standard Julian date */ 29 | date += POSTGRES_EPOCH_JDATE; 30 | 31 | /* Julian day routine does not work for negative Julian days */ 32 | if (date < 0 || date > (int64_t)INT_MAX) 33 | return -1; 34 | 35 | date += 32044; 36 | quad = date / 146097; 37 | extra = (date - quad * 146097) * 4 + 3; 38 | 39 | date += 60 + quad * 3 + extra / 146097; 40 | quad = date / 1461; 41 | date -= quad * 1461; 42 | 43 | year = date * 4 / 1461; 44 | year += quad * 4; 45 | return year - 4800; 46 | } 47 | -------------------------------------------------------------------------------- /src/untrusted.mk: -------------------------------------------------------------------------------- 1 | include vars.mk 2 | 3 | UNTRUSTED_DIR=untrusted 4 | INTERFACE_DIR=untrusted/interface 5 | EXTENSION_DIR=untrusted/extensions 6 | PSQL_PKG_LIBDIR = $(shell pg_config --pkglibdir) 7 | PSQL_SHAREDIR = $(shell pg_config --sharedir)/extension 8 | PSQL_LIBDIR = $(shell pg_config --libdir) 9 | 10 | EXTENSION = $(EXTENSION_DIR)/encdb # the extension's name 11 | DATA = $(EXTENSION_DIR)/encdb--0.0.1.sql # scripts to install 12 | 13 | C_SRCS := $(wildcard $(EXTENSION_DIR)/*.c) 14 | C_OBJS := $(C_SRCS:.c=.o) 15 | 16 | CXX_SRCS := $(wildcard tools/*.cpp) $(wildcard $(INTERFACE_DIR)/*.cpp) 17 | CXX_OBJS := $(CXX_SRCS:.cpp=.o) 18 | 19 | PSQL_CPPFLAGS := $(addprefix -I, $(CURDIR) $(shell pg_config --includedir-server) $(shell pg_config --includedir)) 20 | 21 | CPPFLAGS := -DTOKEN_FILENAME=\"$(STEALTHDIR)/$(ENCLAVE_NAME).token\" \ 22 | -DENCLAVE_FILENAME=\"$(STEALTHDIR)/$(ENCLAVE_NAME).signed.so\" \ 23 | -DDATA_FILENAME=\"$(STEALTHDIR)/stealthDB.data\" \ 24 | $(addprefix -I, include $(SGX_INCLUDE_PATH) $(UNTRUSTED_DIR)) 25 | 26 | FLAGS := -m64 -O0 -g -fPIC -Wall -Wextra -Wpedantic 27 | CFLAGS := $(FLAGS) $(CPPFLAGS) 28 | CXXFLAGS := $(FLAGS) $(CPPFLAGS) -std=c++11 29 | LDFLAGS := -lsgx_urts -lpthread 30 | 31 | .PHONY: all 32 | all: $(UNTRUSTED_DIR)/encdb.so 33 | 34 | tools/%.o: tools/%.cpp 35 | @$(CXX) $(CXXFLAGS) -c $< -o $@ 36 | @echo "CXX <= $<" 37 | 38 | $(UNTRUSTED_DIR)/enclave_u.c: $(SGX_EDGER8R) $(ENCLAVE_DIR)/enclave.edl 39 | @cd $(UNTRUSTED_DIR) && $(SGX_EDGER8R) --untrusted ../$(ENCLAVE_DIR)/enclave.edl 40 | @echo "GEN => $@" 41 | 42 | $(UNTRUSTED_DIR)/enclave_u.o: $(UNTRUSTED_DIR)/enclave_u.c 43 | @$(CC) $(CFLAGS) -c $< -o $@ 44 | @echo "CC <= $<" 45 | 46 | $(INTERFACE_DIR)/%.o: $(INTERFACE_DIR)/%.cpp 47 | @$(CXX) $(CXXFLAGS) -o $@ -c $^ 48 | @echo "CXX interface <= $<" 49 | 50 | 51 | $(EXTENSION_DIR)/%.o: $(EXTENSION_DIR)/%.c 52 | @$(CC) $(CFLAGS) $(PSQL_CPPFLAGS) -o $@ -c $^ 53 | @echo "CC extension <= $<" 54 | 55 | $(UNTRUSTED_DIR)/encdb.so: $(UNTRUSTED_DIR)/enclave_u.o $(CXX_OBJS) $(C_OBJS) 56 | @$(CC) -shared -L$(PSQL_LIBDIR) $^ -o $@ $(LDFLAGS) 57 | @echo "CC extension <= $<" 58 | @mkdir -p $(BUILD_DIR) 59 | @mv $(UNTRUSTED_DIR)/encdb.so $(BUILD_DIR) 60 | @cp $(EXTENSION_DIR)/*.control $(BUILD_DIR) 61 | @cp $(EXTENSION_DIR)/*.sql $(BUILD_DIR) 62 | 63 | 64 | .PHONY: install 65 | install: | $(STEALTHDIR) 66 | cp $(BUILD_DIR)/encdb.so $(PSQL_PKG_LIBDIR) 67 | cp $(BUILD_DIR)/*.control $(PSQL_SHAREDIR) 68 | cp $(BUILD_DIR)/*.sql $(PSQL_SHAREDIR) 69 | @test -e $(STEALTHDIR)/stealthDB.data || touch $(STEALTHDIR)/stealthDB.data 70 | @chown postgres:postgres $(STEALTHDIR)/stealthDB.data 71 | 72 | $(STEALTHDIR): 73 | mkdir -p $@ 74 | 75 | .PHONY: uninstall 76 | uninstall: 77 | $(RM) $(PSQL_PKG_LIBDIR).encdb.so \ 78 | $(PSQL_SHAREDIR)/*.control \ 79 | $(PSQL_SHAREDIR)/*.sql \ 80 | -r $(STEALTHDIR) $(BUILD_DIR) 81 | 82 | .PHONY: clean 83 | clean: 84 | @$(RM) $(CXX_OBJS) $(C_OBJS) $(UNTRUSTED_DIR)/enclave_u.* 85 | -------------------------------------------------------------------------------- /src/untrusted/Makefile: -------------------------------------------------------------------------------- 1 | MODULES = encdb 2 | EXTENSION = encdb 3 | DATA = encdb--0.0.1.sql 4 | PG_CONFIG = pg_config 5 | PGXS := $(shell $(PG_CONFIG) --pgxs) 6 | include $(PGXS) 7 | -------------------------------------------------------------------------------- /src/untrusted/extensions/encdb.c: -------------------------------------------------------------------------------- 1 | #include "untrusted/extensions/stdafx.h" 2 | 3 | PG_MODULE_MAGIC; 4 | bool debugMode = false; 5 | 6 | void sgxErrorHandler(int code) 7 | { 8 | size_t i; 9 | size_t ttl = sizeof sgx_errlist / sizeof sgx_errlist[0]; 10 | 11 | if ((code > 1) || (code < -6)) 12 | { 13 | for (i = 0; i < ttl; i++) 14 | { 15 | if (sgx_errlist[i].err == code) 16 | ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE %d: %s \n", code, sgx_errlist[i].msg))); 17 | } 18 | //ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE: %d \n", code))); 19 | } 20 | 21 | if (code == -2) 22 | ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE %d: ENCLAVE IS NOT RUNNING", code))); 23 | if (code == -3) 24 | ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE %d: MEMORY_COPY_ERROR", code))); 25 | if (code == -4) 26 | ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE %d: ARITHMETIC_ERROR", code))); 27 | if (code == -5) 28 | ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE %d: MEMORY_ALLOCATION_ERROR", code))); 29 | if (code == -6) 30 | ereport(ERROR, (-1, errmsg("SGX_ERROR_CODE %d: OUT_OF_THE_RANGE_ERROR", code))); 31 | if (code == -7) 32 | ereport(ERROR, (-1, errmsg("INTERFACE_ERROR_CODE %d: BASE64DECODER_ERROR", code))); 33 | if (code == -8) 34 | ereport(ERROR, (-1, errmsg("INTERFACE_ERROR_CODE %d: \n The extension was not initialized. Run 'select launch();'", code))); 35 | if (code == -9) 36 | ereport(ERROR, (-1, errmsg("INTERFACE_ERROR_CODE %d: \n Cannot open key storage file.'", code))); 37 | if (code == -10) 38 | ereport(ERROR, (-1, errmsg("INTERFACE_ERROR_CODE %d: \n The default master key was not set up. Run 'select generate_key();'.", code))); 39 | if (code == TOO_MANY_ELEMENTS_IN_BULK) 40 | ereport(ERROR, (-1, errmsg("INTERFACE_ERROR_CODE %d: Too many elements in a bulk for an aggregation function.", code))); 41 | } 42 | 43 | PG_FUNCTION_INFO_V1(launch); 44 | Datum 45 | launch(PG_FUNCTION_ARGS) 46 | { 47 | int resp = initMultithreading(); 48 | sgxErrorHandler(resp); 49 | resp = loadKey(0); 50 | sgxErrorHandler(resp); 51 | ereport(INFO, (errmsg("StealthDB is initialized: the default key has been loaded."))); 52 | 53 | PG_RETURN_INT32(resp); 54 | } 55 | 56 | PG_FUNCTION_INFO_V1(generate_key); 57 | Datum 58 | generate_key(PG_FUNCTION_ARGS) 59 | { 60 | int resp = generateKey(); 61 | sgxErrorHandler(resp); 62 | 63 | PG_RETURN_INT32(resp); 64 | } 65 | 66 | PG_FUNCTION_INFO_V1(load_key); 67 | Datum 68 | load_key(PG_FUNCTION_ARGS) 69 | { 70 | int item = PG_GETARG_INT64(0); 71 | 72 | int resp = loadKey(item); 73 | sgxErrorHandler(resp); 74 | 75 | PG_RETURN_INT32(resp); 76 | } 77 | 78 | PG_FUNCTION_INFO_V1(enable_debug_mode); 79 | Datum 80 | enable_debug_mode(PG_FUNCTION_ARGS) 81 | { 82 | int item = PG_GETARG_INT64(0); 83 | debugMode = item; 84 | 85 | PG_RETURN_INT32(0); 86 | } 87 | -------------------------------------------------------------------------------- /src/untrusted/extensions/encdb.control: -------------------------------------------------------------------------------- 1 | # encrypted database extension 2 | default_version = '0.0.1' 3 | module_pathname = '$libdir/encdb' 4 | relocatable = true 5 | -------------------------------------------------------------------------------- /src/untrusted/interface/enc_float32.cpp: -------------------------------------------------------------------------------- 1 | #include "untrusted/interface/interface.h" 2 | #include "untrusted/interface/stdafx.h" 3 | #include // for copy 4 | #include 5 | 6 | extern sgx_enclave_id_t global_eid; 7 | extern Queue* inQueue; 8 | extern bool status; 9 | 10 | int enc_float32_sum_bulk(size_t bulk_size, char* arg1, char* res) 11 | { 12 | if (!status) 13 | { 14 | int resp = initMultithreading(); 15 | resp = loadKey(0); 16 | // return resp;//IS_NOT_INITIALIZE; 17 | } 18 | int current_position = 0, arg_position = 0; 19 | int resp = ENCLAVE_IS_NOT_RUNNING; 20 | request* req = new request; 21 | 22 | uint8_t* int2_v = (uint8_t*)malloc(bulk_size * ENC_FLOAT4_LENGTH); 23 | uint8_t* int3_v = (uint8_t*)malloc(ENC_FLOAT4_LENGTH); 24 | 25 | memcpy(req->buffer, &bulk_size, FLOAT4_LENGTH); 26 | current_position += FLOAT4_LENGTH; 27 | 28 | size_t counter = 0; 29 | 30 | if (req->max_buffer_size < bulk_size * ENC_FLOAT4_LENGTH) 31 | return TOO_MANY_ELEMENTS_IN_BULK; 32 | 33 | while (counter < bulk_size) 34 | { 35 | if (!FromBase64Fast((const BYTE*)arg1 + arg_position, 36 | ENC_FLOAT4_LENGTH_B64 - 1, 37 | int2_v, 38 | ENC_FLOAT4_LENGTH)) 39 | return BASE64DECODER_ERROR; 40 | 41 | memcpy(req->buffer + current_position, int2_v, ENC_FLOAT4_LENGTH); 42 | current_position += ENC_FLOAT4_LENGTH; 43 | arg_position += ENC_FLOAT4_LENGTH_B64; 44 | counter++; 45 | } 46 | 47 | req->ocall_index = CMD_FLOAT4_SUM_BULK; 48 | req->is_done = -1; 49 | 50 | inQueue->enqueue(req); 51 | while (true) 52 | { 53 | if (req->is_done == -1) 54 | { 55 | __asm__("pause"); 56 | } 57 | else 58 | { 59 | memcpy(int3_v, req->buffer + current_position, ENC_FLOAT4_LENGTH); 60 | resp = req->resp; 61 | if (!ToBase64Fast( 62 | (const BYTE*)int3_v, ENC_FLOAT4_LENGTH, res, ENC_FLOAT4_LENGTH_B64)) 63 | resp = BASE64DECODER_ERROR; 64 | spin_unlock(&req->is_done); 65 | break; 66 | } 67 | } 68 | 69 | delete req; 70 | return resp; 71 | } 72 | 73 | int enc_float32_ops(int cmd, char* src1, char* src2, char* res) 74 | { 75 | if (!status) 76 | { 77 | int resp = initMultithreading(); 78 | resp = loadKey(0); 79 | // return resp;//IS_NOT_INITIALIZE; 80 | } 81 | 82 | int resp = ENCLAVE_IS_NOT_RUNNING; 83 | request* req = new request; 84 | 85 | std::array src1_decoded; 86 | std::array src2_decoded; 87 | std::array dst_decoded; 88 | 89 | if (!FromBase64Fast((const BYTE*)src1, 90 | ENC_FLOAT4_LENGTH_B64 - 1, 91 | src1_decoded.begin(), 92 | ENC_FLOAT4_LENGTH)) 93 | return BASE64DECODER_ERROR; 94 | 95 | if (!FromBase64Fast((const BYTE*)src2, 96 | ENC_FLOAT4_LENGTH_B64 - 1, 97 | src2_decoded.begin(), 98 | ENC_FLOAT4_LENGTH)) 99 | return BASE64DECODER_ERROR; 100 | 101 | std::copy(src1_decoded.begin(), src1_decoded.end(), &req->buffer[0]); 102 | std::copy( 103 | src2_decoded.begin(), src2_decoded.end(), &req->buffer[ENC_FLOAT4_LENGTH]); 104 | 105 | req->ocall_index = cmd; 106 | req->is_done = -1; 107 | 108 | inQueue->enqueue(req); 109 | 110 | while (true) 111 | { 112 | if (req->is_done == -1) 113 | { 114 | __asm__("pause"); 115 | } 116 | else 117 | { 118 | std::copy(&req->buffer[2 * ENC_FLOAT4_LENGTH], 119 | &req->buffer[3 * ENC_FLOAT4_LENGTH], 120 | dst_decoded.begin()); 121 | resp = req->resp; 122 | if (!ToBase64Fast((const BYTE*)dst_decoded.begin(), 123 | ENC_FLOAT4_LENGTH, 124 | res, 125 | ENC_FLOAT4_LENGTH_B64)) 126 | resp = BASE64DECODER_ERROR; 127 | spin_unlock(&req->is_done); 128 | break; 129 | } 130 | } 131 | 132 | delete req; 133 | return resp; 134 | } 135 | 136 | int enc_float32_add(char* src1, char* src2, char* res) 137 | { 138 | int resp = enc_float32_ops(CMD_FLOAT4_PLUS, src1, src2, res); 139 | return resp; 140 | } 141 | 142 | int enc_float32_sub(char* src1, char* src2, char* res) 143 | { 144 | int resp = enc_float32_ops(CMD_FLOAT4_MINUS, src1, src2, res); 145 | return resp; 146 | } 147 | 148 | int enc_float32_mult(char* src1, char* src2, char* res) 149 | { 150 | int resp = enc_float32_ops(CMD_FLOAT4_MULT, src1, src2, res); 151 | return resp; 152 | } 153 | 154 | int enc_float32_div(char* src1, char* src2, char* res) 155 | { 156 | int resp = enc_float32_ops(CMD_FLOAT4_DIV, src1, src2, res); 157 | return resp; 158 | } 159 | 160 | int enc_float32_pow(char* src1, char* src2, char* res) 161 | { 162 | int resp = enc_float32_ops(CMD_FLOAT4_EXP, src1, src2, res); 163 | return resp; 164 | } 165 | 166 | int enc_float32_mod(char* src1, char* src2, char* res) 167 | { 168 | int resp = enc_float32_ops(CMD_FLOAT4_MOD, src1, src2, res); 169 | return resp; 170 | } 171 | 172 | int enc_float32_cmp(char* src1, char* src2, char* res) 173 | { 174 | if (!status) 175 | { 176 | int resp = initMultithreading(); 177 | resp = loadKey(0); 178 | // return resp;//IS_NOT_INITIALIZE; 179 | } 180 | 181 | int resp = ENCLAVE_IS_NOT_RUNNING; 182 | request* req = new request; 183 | 184 | std::array src1_decoded; 185 | std::array src2_decoded; 186 | 187 | if (!FromBase64Fast((const BYTE*)src1, 188 | ENC_FLOAT4_LENGTH_B64 - 1, 189 | src1_decoded.begin(), 190 | ENC_FLOAT4_LENGTH)) 191 | return BASE64DECODER_ERROR; 192 | 193 | if (!FromBase64Fast((const BYTE*)src2, 194 | ENC_FLOAT4_LENGTH_B64 - 1, 195 | src2_decoded.begin(), 196 | ENC_FLOAT4_LENGTH)) 197 | return BASE64DECODER_ERROR; 198 | 199 | std::copy(src1_decoded.begin(), src1_decoded.end(), &req->buffer[0]); 200 | std::copy( 201 | src2_decoded.begin(), src2_decoded.end(), &req->buffer[ENC_FLOAT4_LENGTH]); 202 | req->ocall_index = CMD_FLOAT4_CMP; 203 | req->is_done = -1; 204 | 205 | inQueue->enqueue(req); 206 | 207 | while (true) 208 | { 209 | if (req->is_done == -1) 210 | { 211 | __asm__("pause"); 212 | } 213 | else 214 | { 215 | resp = req->resp; 216 | std::copy(&req->buffer[2 * ENC_FLOAT4_LENGTH], 217 | &req->buffer[2 * ENC_FLOAT4_LENGTH + FLOAT4_LENGTH], 218 | &res[0]); 219 | spin_unlock(&req->is_done); 220 | 221 | // res[0] = req->ocall_index; 222 | break; 223 | } 224 | } 225 | delete req; 226 | 227 | return resp; 228 | } 229 | 230 | int enc_float32_encrypt(float pSrc, char* pDst) 231 | { 232 | if (!status) 233 | { 234 | int resp = initMultithreading(); 235 | resp = loadKey(0); 236 | // return resp;//IS_NOT_INITIALIZE; 237 | } 238 | 239 | int resp = ENCLAVE_IS_NOT_RUNNING; 240 | request* req = new request(); 241 | std::array encrypted_src; 242 | 243 | memcpy(req->buffer, &pSrc, FLOAT4_LENGTH); 244 | req->ocall_index = CMD_FLOAT4_ENC; 245 | req->is_done = -1; 246 | 247 | inQueue->enqueue(req); 248 | 249 | while (true) 250 | { 251 | if (req->is_done == -1) 252 | { 253 | __asm__("pause"); 254 | } 255 | else 256 | { 257 | std::copy(&req->buffer[FLOAT4_LENGTH], 258 | &req->buffer[FLOAT4_LENGTH + ENC_FLOAT4_LENGTH], 259 | encrypted_src.begin()); 260 | resp = req->resp; 261 | spin_unlock(&req->is_done); 262 | break; 263 | } 264 | } 265 | 266 | if (!ToBase64Fast((const BYTE*)encrypted_src.begin(), 267 | ENC_FLOAT4_LENGTH, 268 | pDst, 269 | ENC_FLOAT4_LENGTH_B64)) 270 | resp = BASE64DECODER_ERROR; 271 | 272 | pDst[ENC_FLOAT4_LENGTH_B64 - 1] = '\0'; 273 | delete req; 274 | 275 | return resp; 276 | } 277 | 278 | int enc_float32_decrypt(char* pSrc, char* pDst) 279 | { 280 | if (!status) 281 | { 282 | int resp = initMultithreading(); 283 | resp = loadKey(0); 284 | // return resp;//IS_NOT_INITIALIZE; 285 | } 286 | 287 | int resp = ENCLAVE_IS_NOT_RUNNING; 288 | request* req = new request; 289 | 290 | std::array src_decoded; 291 | if (!FromBase64Fast((const BYTE*)pSrc, 292 | ENC_FLOAT4_LENGTH_B64 - 1, 293 | src_decoded.begin(), 294 | ENC_FLOAT4_LENGTH)) 295 | return BASE64DECODER_ERROR; 296 | 297 | std::copy(src_decoded.begin(), src_decoded.end(), &req->buffer[0]); 298 | req->ocall_index = CMD_FLOAT4_DEC; 299 | req->is_done = -1; 300 | 301 | inQueue->enqueue(req); 302 | 303 | while (true) 304 | { 305 | if (req->is_done == -1) 306 | { 307 | __asm__("pause"); 308 | } 309 | else 310 | { 311 | std::copy(&req->buffer[ENC_FLOAT4_LENGTH], 312 | &req->buffer[ENC_FLOAT4_LENGTH + FLOAT4_LENGTH], 313 | &pDst[0]); 314 | resp = req->resp; 315 | spin_unlock(&req->is_done); 316 | break; 317 | } 318 | } 319 | 320 | delete req; 321 | 322 | return resp; 323 | } 324 | -------------------------------------------------------------------------------- /src/untrusted/interface/enc_int32.cpp: -------------------------------------------------------------------------------- 1 | #include "untrusted/interface/interface.h" 2 | #include "untrusted/interface/stdafx.h" 3 | 4 | extern sgx_enclave_id_t global_eid; 5 | extern Queue* inQueue; 6 | extern bool status; 7 | 8 | int enc_int32_sum_bulk(size_t bulk_size, char* arg1, char* res) 9 | { 10 | if (!status) 11 | { 12 | int resp = initMultithreading(); 13 | resp = loadKey(0); 14 | // return resp;//IS_NOT_INITIALIZE; 15 | } 16 | int current_position = 0, arg_position = 0; 17 | int resp = ENCLAVE_IS_NOT_RUNNING; 18 | request* req = new request; 19 | 20 | uint8_t* int2_v = (uint8_t*)malloc(bulk_size * ENC_INT32_LENGTH); 21 | uint8_t* int3_v = (uint8_t*)malloc(ENC_INT32_LENGTH); 22 | 23 | memcpy(req->buffer, &bulk_size, INT32_LENGTH); 24 | current_position += INT32_LENGTH; 25 | 26 | size_t counter = 0; 27 | 28 | if (req->max_buffer_size < bulk_size * ENC_INT32_LENGTH) 29 | return TOO_MANY_ELEMENTS_IN_BULK; 30 | 31 | while (counter < bulk_size) 32 | { 33 | if (!FromBase64Fast((const BYTE*)arg1 + arg_position, 34 | ENC_INT32_LENGTH_B64 - 1, 35 | int2_v, 36 | ENC_INT32_LENGTH)) 37 | return BASE64DECODER_ERROR; 38 | 39 | memcpy(req->buffer + current_position, int2_v, ENC_INT32_LENGTH); 40 | current_position += ENC_INT32_LENGTH; 41 | arg_position += ENC_INT32_LENGTH_B64; 42 | counter++; 43 | } 44 | 45 | req->ocall_index = CMD_INT32_SUM_BULK; 46 | req->is_done = -1; 47 | 48 | inQueue->enqueue(req); 49 | while (true) 50 | { 51 | if (req->is_done == -1) 52 | { 53 | __asm__("pause"); 54 | } 55 | else 56 | { 57 | memcpy(int3_v, req->buffer + current_position, ENC_INT32_LENGTH); 58 | resp = req->resp; 59 | if (!ToBase64Fast( 60 | (const BYTE*)int3_v, ENC_INT32_LENGTH, res, ENC_INT32_LENGTH_B64)) 61 | resp = BASE64DECODER_ERROR; 62 | spin_unlock(&req->is_done); 63 | break; 64 | } 65 | } 66 | 67 | delete req; 68 | 69 | return resp; 70 | } 71 | 72 | int enc_int32_ops(int cmd, char* int1, char* int2, char* res) 73 | { 74 | if (!status) 75 | { 76 | int resp = initMultithreading(); 77 | resp = loadKey(0); 78 | // return resp;//IS_NOT_INITIALIZE; 79 | } 80 | 81 | int resp = ENCLAVE_IS_NOT_RUNNING; 82 | request* req = new request; 83 | 84 | std::array int1_v; 85 | std::array int2_v; 86 | std::array int3_v; 87 | 88 | if (!FromBase64Fast((const BYTE*)int1, 89 | ENC_INT32_LENGTH_B64 - 1, 90 | int1_v.begin(), 91 | ENC_INT32_LENGTH)) 92 | return BASE64DECODER_ERROR; 93 | 94 | if (!FromBase64Fast((const BYTE*)int2, 95 | ENC_INT32_LENGTH_B64 - 1, 96 | int2_v.begin(), 97 | ENC_INT32_LENGTH)) 98 | return BASE64DECODER_ERROR; 99 | 100 | std::copy(int1_v.begin(), int1_v.end(), &req->buffer[0]); 101 | std::copy(int2_v.begin(), int2_v.end(), &req->buffer[ENC_INT32_LENGTH]); 102 | 103 | req->ocall_index = cmd; 104 | req->is_done = -1; 105 | 106 | inQueue->enqueue(req); 107 | 108 | while (true) 109 | { 110 | if (req->is_done == -1) 111 | { 112 | __asm__("pause"); 113 | } 114 | else 115 | { 116 | std::copy(&req->buffer[2 * ENC_INT32_LENGTH], 117 | &req->buffer[3 * ENC_INT32_LENGTH], 118 | int3_v.begin()); 119 | resp = req->resp; 120 | if (!ToBase64Fast((const BYTE*)int3_v.begin(), 121 | ENC_INT32_LENGTH, 122 | res, 123 | ENC_INT32_LENGTH_B64)) 124 | resp = BASE64DECODER_ERROR; 125 | spin_unlock(&req->is_done); 126 | break; 127 | } 128 | } 129 | 130 | delete req; 131 | 132 | return resp; 133 | } 134 | 135 | int enc_int32_add(char* int1, char* int2, char* res) 136 | { 137 | return enc_int32_ops(CMD_INT64_PLUS, int1, int2, res); 138 | } 139 | 140 | int enc_int32_sub(char* int1, char* int2, char* res) 141 | { 142 | int resp = enc_int32_ops(CMD_INT64_MINUS, int1, int2, res); 143 | return resp; 144 | } 145 | 146 | int enc_int32_mult(char* int1, char* int2, char* res) 147 | { 148 | int resp = enc_int32_ops(CMD_INT64_MULT, int1, int2, res); 149 | return resp; 150 | } 151 | 152 | int enc_int32_div(char* int1, char* int2, char* res) 153 | { 154 | int resp = enc_int32_ops(CMD_INT64_DIV, int1, int2, res); 155 | return resp; 156 | } 157 | 158 | int enc_int32_pow(char* int1, char* int2, char* res) 159 | { 160 | int resp = enc_int32_ops(CMD_INT64_EXP, int1, int2, res); 161 | return resp; 162 | } 163 | 164 | int enc_int32_mod(char* int1, char* int2, char* res) 165 | { 166 | int resp = enc_int32_ops(CMD_INT64_MOD, int1, int2, res); 167 | return resp; 168 | } 169 | 170 | int enc_int32_cmp(char* int1, char* int2, char* res) 171 | { 172 | if (!status) 173 | { 174 | int resp = initMultithreading(); 175 | resp = loadKey(0); 176 | // return resp;//IS_NOT_INITIALIZE; 177 | } 178 | int resp = ENCLAVE_IS_NOT_RUNNING; 179 | request* req = new request; 180 | 181 | std::array int1_v; 182 | std::array int2_v; 183 | 184 | if (!FromBase64Fast((const BYTE*)int1, 185 | ENC_INT32_LENGTH_B64 - 1, 186 | int1_v.begin(), 187 | ENC_INT32_LENGTH)) 188 | return BASE64DECODER_ERROR; 189 | 190 | if (!FromBase64Fast((const BYTE*)int2, 191 | ENC_INT32_LENGTH_B64 - 1, 192 | int2_v.begin(), 193 | ENC_INT32_LENGTH)) 194 | return BASE64DECODER_ERROR; 195 | 196 | std::copy(int1_v.begin(), int1_v.end(), &req->buffer[0]); 197 | std::copy(int2_v.begin(), int2_v.end(), &req->buffer[ENC_INT32_LENGTH]); 198 | 199 | req->ocall_index = CMD_INT64_CMP; 200 | req->is_done = -1; 201 | inQueue->enqueue(req); 202 | 203 | while (true) 204 | { 205 | if (req->is_done == -1) 206 | { 207 | __asm__("pause"); 208 | } 209 | else 210 | { 211 | resp = req->resp; 212 | std::copy(&req->buffer[2 * ENC_INT32_LENGTH], 213 | &req->buffer[2 * ENC_INT32_LENGTH + INT32_LENGTH], 214 | &res[0]); 215 | spin_unlock(&req->is_done); 216 | break; 217 | } 218 | } 219 | delete req; 220 | return resp; 221 | } 222 | 223 | int enc_int32_encrypt(int pSrc, char* pDst) 224 | { 225 | if (!status) 226 | { 227 | int resp = initMultithreading(); 228 | resp = loadKey(0); 229 | // return resp;//IS_NOT_INITIALIZE; 230 | } 231 | 232 | int resp = ENCLAVE_IS_NOT_RUNNING; 233 | request* req = new request; 234 | std::array int1_v; 235 | 236 | memcpy(req->buffer, &pSrc, INT32_LENGTH); 237 | req->ocall_index = CMD_INT64_ENC; 238 | req->is_done = -1; 239 | 240 | inQueue->enqueue(req); 241 | while (true) 242 | { 243 | if (req->is_done == -1) 244 | { 245 | __asm__("pause"); 246 | } 247 | else 248 | { 249 | std::copy(&req->buffer[INT32_LENGTH], 250 | &req->buffer[INT32_LENGTH + ENC_INT32_LENGTH], 251 | int1_v.begin()); 252 | resp = req->resp; 253 | // spin_unlock(&req->is_done); 254 | break; 255 | } 256 | } 257 | 258 | if (!ToBase64Fast((const BYTE*)int1_v.begin(), 259 | ENC_INT32_LENGTH, 260 | pDst, 261 | ENC_INT32_LENGTH_B64)) 262 | resp = BASE64DECODER_ERROR; 263 | pDst[ENC_INT32_LENGTH_B64 - 1] = '\0'; 264 | 265 | delete req; 266 | return resp; 267 | } 268 | 269 | int enc_int32_decrypt(char* pSrc, char* pDst) 270 | { 271 | if (!status) 272 | { 273 | int resp = initMultithreading(); 274 | resp = loadKey(0); 275 | // return resp;//IS_NOT_INITIALIZE; 276 | } 277 | 278 | int resp = ENCLAVE_IS_NOT_RUNNING; 279 | request* req = new request; 280 | 281 | std::array int1_v; 282 | if (!FromBase64Fast((const BYTE*)pSrc, 283 | ENC_INT32_LENGTH_B64 - 1, 284 | int1_v.begin(), 285 | ENC_INT32_LENGTH)) 286 | return BASE64DECODER_ERROR; 287 | 288 | std::copy(int1_v.begin(), int1_v.end(), &req->buffer[0]); 289 | req->ocall_index = CMD_INT64_DEC; 290 | req->is_done = -1; 291 | inQueue->enqueue(req); 292 | 293 | while (true) 294 | { 295 | if (req->is_done == -1) 296 | { 297 | __asm__("pause"); 298 | } 299 | else 300 | { 301 | std::copy(&req->buffer[ENC_INT32_LENGTH], 302 | &req->buffer[ENC_INT32_LENGTH + INT32_LENGTH], 303 | &pDst[0]); 304 | resp = req->resp; 305 | spin_unlock(&req->is_done); 306 | break; 307 | } 308 | } 309 | 310 | delete req; 311 | return resp; 312 | } 313 | -------------------------------------------------------------------------------- /src/untrusted/interface/enc_text.cpp: -------------------------------------------------------------------------------- 1 | #include "untrusted/interface/interface.h" 2 | #include "untrusted/interface/stdafx.h" 3 | #include 4 | 5 | extern sgx_enclave_id_t global_eid; 6 | extern Queue* inQueue; 7 | extern bool status; 8 | 9 | int enc_text_concatenate(char* src1, 10 | size_t src1_len, 11 | char* src2, 12 | size_t src2_len, 13 | char* dst, 14 | size_t* dst_len) 15 | { 16 | int resp = ENCLAVE_IS_NOT_RUNNING; 17 | if (!status) 18 | { 19 | resp = initMultithreading(); 20 | resp = loadKey(0); 21 | } 22 | 23 | int str3_len; 24 | int len_raw_str1, len_raw_str2, len_raw_str3; 25 | 26 | memcpy(&str3_len, dst_len, sizeof(uint8_t)); 27 | 28 | uint8_t* str1 = new uint8_t[src1_len]; 29 | uint8_t* str2 = new uint8_t[src2_len]; 30 | uint8_t* str3 = new uint8_t[str3_len]; 31 | 32 | request* req = new request; 33 | 34 | len_raw_str1 = FromBase64Fast((const BYTE*)src1, src1_len, str1, src1_len); 35 | len_raw_str2 = FromBase64Fast((const BYTE*)src2, src2_len, str2, src2_len); 36 | 37 | if (!len_raw_str1 || !len_raw_str2) 38 | return BASE64DECODER_ERROR; 39 | 40 | memcpy(req->buffer, &len_raw_str1, INT32_LENGTH); 41 | memcpy(req->buffer + INT32_LENGTH, str1, len_raw_str1); 42 | 43 | memcpy( 44 | req->buffer + len_raw_str1 + INT32_LENGTH, &len_raw_str2, INT32_LENGTH); 45 | memcpy(req->buffer + len_raw_str1 + INT32_LENGTH + INT32_LENGTH, 46 | str2, 47 | len_raw_str2); 48 | 49 | req->ocall_index = CMD_STRING_CONCAT; 50 | req->is_done = -1; 51 | 52 | inQueue->enqueue(req); 53 | 54 | while (true) 55 | { 56 | if (req->is_done == -1) 57 | { 58 | __asm__("pause"); 59 | } 60 | else 61 | { 62 | memcpy(&len_raw_str3, 63 | req->buffer + len_raw_str1 + 2 * INT32_LENGTH + len_raw_str2, 64 | INT32_LENGTH); 65 | if (str3_len < len_raw_str3) 66 | return MEMORY_ALLOCATION_ERROR; 67 | 68 | memcpy(str3, 69 | req->buffer + len_raw_str1 + 3 * INT32_LENGTH + len_raw_str2, 70 | len_raw_str3); 71 | resp = req->resp; 72 | spin_unlock(&req->is_done); 73 | break; 74 | } 75 | } 76 | 77 | int dst_b64_len = ToBase64Fast((const unsigned char*)str3, len_raw_str3, dst, str3_len); 78 | if (!dst_b64_len) 79 | return BASE64DECODER_ERROR; 80 | dst[dst_b64_len] = '\0'; 81 | memcpy(dst_len, &dst_b64_len, sizeof(uint8_t)); 82 | 83 | delete[] str1; 84 | delete[] str2; 85 | delete[] str3; 86 | delete req; 87 | 88 | return resp; 89 | } 90 | 91 | int enc_text_substring(char* in1, 92 | size_t in1_size, 93 | char* in2, 94 | size_t in2_size, 95 | char* in3, 96 | size_t in3_size, 97 | char* out, 98 | size_t* out_size) 99 | { 100 | int resp = ENCLAVE_IS_NOT_RUNNING; 101 | if (!status) 102 | { 103 | resp = initMultithreading(); 104 | resp = loadKey(0); 105 | } 106 | 107 | request* req = new request; 108 | 109 | uint8_t* str = new uint8_t[in1_size]; 110 | size_t str_size, in_size; 111 | 112 | uint8_t* from = new uint8_t[in2_size]; 113 | uint8_t* n_chars = new uint8_t[in3_size]; 114 | 115 | uint8_t* result = new uint8_t[*out_size]; 116 | int result_raw_size = 0; 117 | 118 | int buf_pos = 0; 119 | 120 | str_size = FromBase64Fast((const unsigned char*)in1, in1_size, str, in1_size); 121 | if (!str_size) 122 | return BASE64DECODER_ERROR; 123 | 124 | if ((in2_size == INT32_LENGTH) && (in3_size == INT32_LENGTH)) 125 | { 126 | memcpy(from, in2, in2_size); 127 | memcpy(n_chars, in3, in3_size); 128 | in_size = INT32_LENGTH; 129 | } 130 | else 131 | { 132 | if (!FromBase64Fast((const unsigned char*)in2, 133 | ENC_INT32_LENGTH_B64 - 1, 134 | from, 135 | ENC_INT32_LENGTH)) 136 | return BASE64DECODER_ERROR; 137 | 138 | if (!FromBase64Fast((const unsigned char*)in3, 139 | ENC_INT32_LENGTH_B64 - 1, 140 | n_chars, 141 | ENC_INT32_LENGTH)) 142 | return BASE64DECODER_ERROR; 143 | in_size = ENC_INT32_LENGTH; 144 | } 145 | 146 | memcpy(req->buffer + buf_pos, &str_size, INT32_LENGTH); 147 | buf_pos += INT32_LENGTH; 148 | 149 | memcpy(req->buffer + buf_pos, str, str_size); 150 | buf_pos += str_size; 151 | 152 | memcpy(req->buffer + buf_pos, &in_size, INT32_LENGTH); 153 | buf_pos += INT32_LENGTH; 154 | 155 | memcpy(req->buffer + buf_pos, from, in_size); 156 | buf_pos += in_size; 157 | 158 | memcpy(req->buffer + buf_pos, &in_size, INT32_LENGTH); 159 | buf_pos += INT32_LENGTH; 160 | 161 | memcpy(req->buffer + buf_pos, n_chars, in_size); 162 | buf_pos += in_size; 163 | 164 | memcpy(req->buffer + buf_pos, out_size, INT32_LENGTH); 165 | buf_pos += INT32_LENGTH; 166 | 167 | memcpy(req->buffer + buf_pos, out, *out_size); 168 | buf_pos += *out_size; 169 | 170 | req->ocall_index = CMD_STRING_SUBSTRING; 171 | req->is_done = -1; 172 | 173 | inQueue->enqueue(req); 174 | 175 | while (true) 176 | { 177 | if (req->is_done == -1) 178 | { 179 | __asm__("pause"); 180 | } 181 | else 182 | { 183 | memcpy(&result_raw_size, req->buffer + buf_pos, INT32_LENGTH); 184 | buf_pos += INT32_LENGTH; 185 | memcpy(result, req->buffer + buf_pos, result_raw_size + 1); 186 | resp = req->resp; 187 | spin_unlock(&req->is_done); 188 | break; 189 | } 190 | } 191 | 192 | size_t result_b64_size = ToBase64Fast((const unsigned char*)result, result_raw_size, out, *out_size); 193 | if (!result_b64_size) 194 | return BASE64DECODER_ERROR; 195 | out[result_b64_size] = '\0'; 196 | *out_size = result_b64_size; 197 | delete[] str; 198 | delete[] result; 199 | delete[] from; 200 | delete[] n_chars; 201 | delete req; 202 | 203 | return resp; 204 | } 205 | 206 | int enc_text_like(char* in1, size_t in1_size, char* in2, size_t in2_size, int* out) 207 | { 208 | int resp = ENCLAVE_IS_NOT_RUNNING; 209 | if (!status) 210 | { 211 | resp = initMultithreading(); 212 | resp = loadKey(0); 213 | } 214 | 215 | request* req = new request; 216 | 217 | uint8_t* str = new uint8_t[in1_size]; 218 | uint8_t* pattern = new uint8_t[in2_size]; 219 | 220 | int str_raw_size = FromBase64Fast((const unsigned char*)in1, in1_size, str, in1_size); 221 | int pattern_raw_size = FromBase64Fast((const unsigned char*)in2, in2_size, pattern, in2_size); 222 | if (!str_raw_size || !pattern_raw_size) 223 | return BASE64DECODER_ERROR; 224 | 225 | size_t buf_pos = 0; 226 | memcpy(req->buffer + buf_pos, &str_raw_size, INT32_LENGTH); 227 | buf_pos += INT32_LENGTH; 228 | 229 | memcpy(req->buffer + buf_pos, str, str_raw_size); 230 | buf_pos += str_raw_size; 231 | 232 | memcpy(req->buffer + buf_pos, &pattern_raw_size, INT32_LENGTH); 233 | buf_pos += INT32_LENGTH; 234 | 235 | memcpy(req->buffer + buf_pos, pattern, pattern_raw_size); 236 | buf_pos += pattern_raw_size; 237 | 238 | req->ocall_index = CMD_STRING_LIKE; 239 | req->is_done = -1; 240 | 241 | inQueue->enqueue(req); 242 | 243 | while (true) 244 | { 245 | if (req->is_done == -1) 246 | { 247 | __asm__("pause"); 248 | } 249 | else 250 | { 251 | resp = req->resp; 252 | std::copy( 253 | &req->buffer[buf_pos], &req->buffer[buf_pos + INT32_LENGTH], out); 254 | spin_unlock(&req->is_done); 255 | break; 256 | } 257 | } 258 | 259 | delete req; 260 | delete[] str; 261 | delete[] pattern; 262 | 263 | return resp; 264 | } 265 | 266 | int enc_text_encrypt(char* pSrc, size_t src_len, char* pDst, size_t dst_len) 267 | { 268 | int resp = ENCLAVE_IS_NOT_RUNNING; 269 | if (!status) 270 | { 271 | resp = initMultithreading(); 272 | resp = loadKey(0); 273 | } 274 | 275 | int len, raw_dst_len; 276 | 277 | request* req = new request; 278 | uint8_t* dst = new uint8_t[dst_len + 1]; 279 | 280 | memcpy(req->buffer, &src_len, INT32_LENGTH); 281 | memcpy(req->buffer + INT32_LENGTH, pSrc, src_len); 282 | 283 | req->ocall_index = CMD_STRING_ENC; 284 | req->is_done = -1; 285 | 286 | inQueue->enqueue(req); 287 | 288 | while (true) 289 | { 290 | if (req->is_done == -1) 291 | { 292 | __asm__("pause"); 293 | } 294 | else 295 | { 296 | memcpy(&raw_dst_len, req->buffer + src_len + INT32_LENGTH, INT32_LENGTH); 297 | memcpy(dst, req->buffer + src_len + 2 * INT32_LENGTH, raw_dst_len); 298 | resp = req->resp; 299 | spin_unlock(&req->is_done); 300 | break; 301 | } 302 | } 303 | 304 | len = ToBase64Fast((const unsigned char*)dst, raw_dst_len, pDst, dst_len + 1); 305 | if (!len) 306 | return BASE64DECODER_ERROR; 307 | pDst[dst_len] = '\0'; 308 | 309 | delete req; 310 | delete[] dst; 311 | 312 | return resp; 313 | } 314 | int enc_text_cmp(char* src1, 315 | size_t src1_len, 316 | char* src2, 317 | size_t src2_len, 318 | char* res) 319 | { 320 | int resp = ENCLAVE_IS_NOT_RUNNING; 321 | if (!status) 322 | { 323 | resp = initMultithreading(); 324 | resp = loadKey(0); 325 | } 326 | 327 | request* req = new request; 328 | 329 | uint8_t* arg1 = new uint8_t[src1_len]; 330 | uint8_t* arg2 = new uint8_t[src2_len]; 331 | 332 | int len_raw_str1 = FromBase64Fast((const BYTE*)src1, src1_len, arg1, src1_len); 333 | int len_raw_str2 = FromBase64Fast((const BYTE*)src2, src2_len, arg2, src2_len); 334 | 335 | if (!len_raw_str1 || !len_raw_str2) 336 | return BASE64DECODER_ERROR; 337 | 338 | memcpy(req->buffer, &len_raw_str1, INT32_LENGTH); 339 | memcpy(req->buffer + INT32_LENGTH, arg1, len_raw_str1); 340 | memcpy( 341 | req->buffer + len_raw_str1 + INT32_LENGTH, &len_raw_str2, INT32_LENGTH); 342 | memcpy(req->buffer + len_raw_str1 + INT32_LENGTH + INT32_LENGTH, 343 | arg2, 344 | len_raw_str2); 345 | 346 | req->ocall_index = CMD_STRING_CMP; 347 | req->is_done = -1; 348 | 349 | inQueue->enqueue(req); 350 | 351 | while (true) 352 | { 353 | if (req->is_done == -1) 354 | { 355 | __asm__("pause"); 356 | } 357 | else 358 | { 359 | resp = req->resp; 360 | std::copy(&req->buffer[len_raw_str1 + 2 * INT32_LENGTH + len_raw_str2], 361 | &req->buffer[len_raw_str1 + 2 * INT32_LENGTH + len_raw_str2 + INT32_LENGTH], 362 | &res[0]); 363 | spin_unlock(&req->is_done); 364 | break; 365 | } 366 | } 367 | 368 | delete req; 369 | delete[] arg1; 370 | delete[] arg2; 371 | 372 | return resp; 373 | } 374 | 375 | int enc_text_decrypt(char* pSrc, size_t src_len, char* pDst, size_t dst_len) 376 | { 377 | int resp = ENCLAVE_IS_NOT_RUNNING; 378 | if (!status) 379 | { 380 | resp = initMultithreading(); 381 | resp = loadKey(0); 382 | } 383 | 384 | int src_decrypted_len, src_bytearray_len; 385 | request* req = new request; 386 | uint8_t* dst = new uint8_t[src_len]; 387 | 388 | src_bytearray_len = FromBase64Fast((const BYTE*)pSrc, src_len, dst, src_len); 389 | src_decrypted_len = src_bytearray_len - SGX_AESGCM_IV_SIZE - SGX_AESGCM_MAC_SIZE; 390 | 391 | if (src_decrypted_len > dst_len) 392 | return MEMORY_ALLOCATION_ERROR; 393 | 394 | memcpy(req->buffer, &src_bytearray_len, INT32_LENGTH); 395 | memcpy(req->buffer + INT32_LENGTH, dst, src_bytearray_len); 396 | 397 | req->ocall_index = CMD_STRING_DEC; 398 | req->is_done = -1; 399 | 400 | inQueue->enqueue(req); 401 | 402 | while (true) 403 | { 404 | if (req->is_done == -1) 405 | { 406 | __asm__("pause"); 407 | } 408 | else 409 | { 410 | memcpy( 411 | &dst_len, req->buffer + src_bytearray_len + INT32_LENGTH, INT32_LENGTH); 412 | memcpy(pDst, 413 | req->buffer + src_bytearray_len + 2 * INT32_LENGTH, 414 | src_bytearray_len); 415 | resp = req->resp; 416 | spin_unlock(&req->is_done); 417 | break; 418 | } 419 | } 420 | 421 | pDst[dst_len] = '\0'; 422 | 423 | delete req; 424 | delete[] dst; 425 | 426 | return resp; 427 | } 428 | -------------------------------------------------------------------------------- /src/untrusted/interface/enc_timestamp.cpp: -------------------------------------------------------------------------------- 1 | #include "untrusted/interface/interface.h" 2 | #include "untrusted/interface/stdafx.h" 3 | 4 | extern sgx_enclave_id_t global_eid; 5 | extern Queue* inQueue; 6 | extern bool status; 7 | 8 | int enc_timestamp_extract_year(char* in, char* result) 9 | { 10 | if (!status) 11 | { 12 | int resp = initMultithreading(); 13 | resp = loadKey(0); 14 | } 15 | int resp = ENCLAVE_IS_NOT_RUNNING; 16 | request* req = new request; 17 | size_t buf_pos = 0; 18 | std::array timestamp; 19 | 20 | if (!FromBase64Fast((const BYTE*)in, 21 | ENC_TIMESTAMP_LENGTH_B64 - 1, 22 | timestamp.begin(), 23 | ENC_TIMESTAMP_LENGTH)) 24 | return BASE64DECODER_ERROR; 25 | 26 | std::copy(timestamp.begin(), timestamp.end(), &req->buffer[buf_pos]); 27 | buf_pos += ENC_TIMESTAMP_LENGTH; 28 | 29 | req->ocall_index = CMD_TIMESTAMP_EXTRACT_YEAR; 30 | req->is_done = -1; 31 | inQueue->enqueue(req); 32 | 33 | while (true) 34 | { 35 | if (req->is_done == -1) 36 | { 37 | __asm__("pause"); 38 | } 39 | else 40 | { 41 | resp = req->resp; 42 | if (!ToBase64Fast((const BYTE*)&req->buffer[buf_pos], 43 | ENC_INT32_LENGTH, 44 | result, 45 | ENC_INT32_LENGTH_B64)) 46 | resp = BASE64DECODER_ERROR; 47 | 48 | spin_unlock(&req->is_done); 49 | break; 50 | } 51 | } 52 | delete req; 53 | return resp; 54 | } 55 | 56 | int enc_timestamp_cmp(char* src1, char* src2, char* res) 57 | { 58 | if (!status) 59 | { 60 | int resp = initMultithreading(); 61 | resp = loadKey(0); 62 | // return resp;//IS_NOT_INITIALIZE; 63 | } 64 | int resp = ENCLAVE_IS_NOT_RUNNING; 65 | request* req = new request; 66 | 67 | std::array src1_decoded; 68 | std::array src2_decoded; 69 | 70 | if (!FromBase64Fast((const BYTE*)src1, 71 | ENC_TIMESTAMP_LENGTH_B64 - 1, 72 | src1_decoded.begin(), 73 | ENC_TIMESTAMP_LENGTH)) 74 | return BASE64DECODER_ERROR; 75 | 76 | if (!FromBase64Fast((const BYTE*)src2, 77 | ENC_TIMESTAMP_LENGTH_B64 - 1, 78 | src2_decoded.begin(), 79 | ENC_TIMESTAMP_LENGTH)) 80 | return BASE64DECODER_ERROR; 81 | 82 | std::copy(src1_decoded.begin(), src1_decoded.end(), &req->buffer[0]); 83 | std::copy(src2_decoded.begin(), 84 | src2_decoded.end(), 85 | &req->buffer[ENC_TIMESTAMP_LENGTH]); 86 | 87 | req->ocall_index = CMD_TIMESTAMP_CMP; 88 | req->is_done = -1; 89 | inQueue->enqueue(req); 90 | 91 | while (true) 92 | { 93 | if (req->is_done == -1) 94 | { 95 | __asm__("pause"); 96 | } 97 | else 98 | { 99 | resp = req->resp; 100 | std::copy(&req->buffer[2 * ENC_TIMESTAMP_LENGTH], 101 | &req->buffer[2 * ENC_TIMESTAMP_LENGTH + INT32_LENGTH], 102 | &res[0]); 103 | spin_unlock(&req->is_done); 104 | break; 105 | } 106 | } 107 | delete req; 108 | 109 | return resp; 110 | } 111 | 112 | int enc_timestamp_encrypt(char* src, char* dst) 113 | { 114 | if (!status) 115 | { 116 | int resp = initMultithreading(); 117 | resp = loadKey(0); 118 | // return resp;//IS_NOT_INITIALIZE; 119 | } 120 | 121 | int resp = ENCLAVE_IS_NOT_RUNNING; 122 | request* req = new request; 123 | std::array src_encrypted; 124 | 125 | memcpy(req->buffer, src, TIMESTAMP_LENGTH); 126 | req->ocall_index = CMD_TIMESTAMP_ENC; 127 | req->is_done = -1; 128 | 129 | inQueue->enqueue(req); 130 | 131 | while (true) 132 | { 133 | if (req->is_done == -1) 134 | { 135 | __asm__("pause"); 136 | } 137 | else 138 | { 139 | std::copy(&req->buffer[TIMESTAMP_LENGTH], 140 | &req->buffer[TIMESTAMP_LENGTH + ENC_TIMESTAMP_LENGTH], 141 | src_encrypted.begin()); 142 | resp = req->resp; 143 | spin_unlock(&req->is_done); 144 | break; 145 | } 146 | } 147 | 148 | if (!ToBase64Fast((const BYTE*)src_encrypted.begin(), 149 | ENC_TIMESTAMP_LENGTH, 150 | dst, 151 | ENC_TIMESTAMP_LENGTH_B64)) 152 | return BASE64DECODER_ERROR; 153 | 154 | dst[ENC_TIMESTAMP_LENGTH_B64 - 1] = '\0'; 155 | 156 | delete req; 157 | return resp; 158 | } 159 | 160 | int enc_timestamp_decrypt(char* src, char* dst) 161 | { 162 | if (!status) 163 | { 164 | int resp = initMultithreading(); 165 | resp = loadKey(0); 166 | // return resp;//IS_NOT_INITIALIZE; 167 | } 168 | 169 | int resp = ENCLAVE_IS_NOT_RUNNING; 170 | request* req = new request; 171 | 172 | std::array src_decoded; 173 | if (!FromBase64Fast((const BYTE*)src, 174 | ENC_TIMESTAMP_LENGTH_B64 - 1, 175 | src_decoded.begin(), 176 | ENC_TIMESTAMP_LENGTH)) 177 | return BASE64DECODER_ERROR; 178 | 179 | std::copy(src_decoded.begin(), src_decoded.end(), req->buffer); 180 | req->ocall_index = CMD_TIMESTAMP_DEC; 181 | req->is_done = -1; 182 | 183 | inQueue->enqueue(req); 184 | 185 | while (true) 186 | { 187 | if (req->is_done == -1) 188 | { 189 | __asm__("pause"); 190 | } 191 | else 192 | { 193 | std::copy(&req->buffer[ENC_TIMESTAMP_LENGTH], 194 | &req->buffer[ENC_TIMESTAMP_LENGTH + TIMESTAMP_LENGTH], 195 | dst); 196 | resp = req->resp; 197 | spin_unlock(&req->is_done); 198 | break; 199 | } 200 | } 201 | 202 | delete req; 203 | return resp; 204 | } 205 | -------------------------------------------------------------------------------- /src/untrusted/interface/interface.cpp: -------------------------------------------------------------------------------- 1 | #define MAX_PATH FILENAME_MAX 2 | 3 | #include "untrusted/interface/interface.h" 4 | #include "untrusted/interface/stdafx.h" 5 | #include 6 | #include 7 | 8 | /* Global EID shared by multiple threads */ 9 | sgx_enclave_id_t global_eid = 0; 10 | 11 | uint8_t INPUT_BUFFER[INPUT_BUFFER_SIZE]; 12 | uint8_t OUTPUT_BUFFER[INPUT_BUFFER_SIZE]; 13 | Queue* inQueue; 14 | bool status = false; 15 | 16 | int launch_enclave(sgx_launch_token_t* token, int* updated) 17 | { 18 | sgx_status_t ret = SGX_ERROR_UNEXPECTED; 19 | 20 | ret = sgx_create_enclave( 21 | ENCLAVE_FILENAME, TRUE, token, updated, &global_eid, NULL); 22 | if (ret != SGX_SUCCESS) 23 | return ret; 24 | else 25 | return 0; 26 | } 27 | 28 | int init() 29 | { 30 | sgx_launch_token_t token = { 0 }; 31 | int updated = 0; 32 | int resp = launch_enclave(&token, &updated); 33 | 34 | return resp; 35 | } 36 | 37 | // void *enclaveThread(void *) { 38 | void enclaveThread() 39 | { 40 | int resp = 0; 41 | enclaveProcess(global_eid, &resp, inQueue); 42 | } 43 | int initMultithreading() 44 | { 45 | sgx_launch_token_t token = { 0 }; 46 | int updated = 0; 47 | status = true; 48 | int ans = launch_enclave(&token, &updated); 49 | 50 | inQueue = new Queue(); 51 | 52 | for (int i = 0; i < INPUT_BUFFER_SIZE; i++) 53 | INPUT_BUFFER[i] = OUTPUT_BUFFER[i] = 0; 54 | 55 | std::thread th = std::thread(&enclaveThread); 56 | 57 | th.detach(); 58 | 59 | return ans; 60 | } 61 | 62 | int generateKey() 63 | { 64 | if (!status) 65 | { 66 | int resp = initMultithreading(); 67 | if (resp != SGX_SUCCESS) 68 | return resp; 69 | } 70 | 71 | int resp, resp_enclave, flength; 72 | uint8_t* sealed_key_b = new uint8_t[SEALED_KEY_LENGTH]; 73 | 74 | std::fstream data_file; 75 | data_file.open(DATA_FILENAME, 76 | std::fstream::in | std::fstream::out | std::fstream::binary); 77 | if (data_file) 78 | { 79 | data_file.seekg(0, data_file.end); 80 | flength = data_file.tellg(); 81 | 82 | if (flength == SEALED_KEY_LENGTH) 83 | return 0; 84 | 85 | else 86 | { 87 | resp = generateKeyEnclave( 88 | global_eid, &resp_enclave, sealed_key_b, SEALED_KEY_LENGTH); 89 | if (resp != SGX_SUCCESS) 90 | return resp; 91 | data_file.write((char*)sealed_key_b, SEALED_KEY_LENGTH); 92 | } 93 | } 94 | else 95 | return NO_KEYS_STORAGE; 96 | 97 | data_file.close(); 98 | delete[] sealed_key_b; 99 | 100 | return (int)flength / SEALED_KEY_LENGTH; 101 | } 102 | 103 | int loadKey(int item) 104 | { 105 | if (!status) 106 | { 107 | int resp = initMultithreading(); 108 | if (resp != SGX_SUCCESS) 109 | return resp; 110 | } 111 | int resp, resp_enclave; 112 | uint8_t sealed_key_b[SEALED_KEY_LENGTH]; 113 | 114 | std::fstream data_file; 115 | data_file.open(DATA_FILENAME, std::fstream::in | std::fstream::binary); 116 | if (data_file) 117 | { 118 | data_file.seekg(0, data_file.end); 119 | int flength = data_file.tellg(); 120 | if (flength < item * SEALED_KEY_LENGTH + SEALED_KEY_LENGTH) 121 | return NO_KEY_ID; 122 | 123 | data_file.seekg(item * SEALED_KEY_LENGTH); 124 | data_file.read((char*)sealed_key_b, SEALED_KEY_LENGTH); 125 | resp = loadKeyEnclave( 126 | global_eid, &resp_enclave, sealed_key_b, SEALED_KEY_LENGTH); 127 | if (resp != SGX_SUCCESS) 128 | return resp; 129 | } 130 | else 131 | return NO_KEYS_STORAGE; 132 | 133 | data_file.close(); 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /src/vars.mk: -------------------------------------------------------------------------------- 1 | BUILD_DIR := $(CURDIR)/../build 2 | ENCLAVE_DIR := enclave 3 | ENCLAVE_NAME := enclave 4 | STEALTHDIR := /usr/local/lib/stealthDB 5 | 6 | SDK_INSTALL_PATH := /opt/intel/sgxsdk 7 | SGX_INCLUDE_PATH := $(SDK_INSTALL_PATH)/include 8 | SGX_EDGER8R := $(SDK_INSTALL_PATH)/bin/x64/sgx_edger8r 9 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Test suite 2 | 3 | We use pgTAP tool to make testing cases based on SQL queries. 4 | 5 | ## Install 6 | 7 | ``` 8 | sudo apt-get install libtap-parser-sourcehandler-pgtap-perl 9 | 10 | ``` 11 | 12 | ## Run 13 | 14 | ``` 15 | pg_prove -U postgres -d postgres encdb/run_test.sql 16 | 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /test/encdb/run_test.sql: -------------------------------------------------------------------------------- 1 | \unset ECHO 2 | \i sql/setup.sql 3 | 4 | select plan(47); 5 | 6 | DROP TABLE IF EXISTS test_table; 7 | CREATE TABLE test_table (id int, num_i enc_int4, num_f enc_float4, str enc_text, time enc_timestamp); 8 | 9 | 10 | --CREATE FUNCTION TEST_INSERT () 11 | --DECLARE 12 | -- counter INTEGER := 0 ; 13 | ---BEGIN 14 | 15 | -- WHILE counter <= 20 LOOP 16 | --counter := counter + 1 ; 17 | -- END LOOP ; END ; 18 | 19 | --INSERT INTO test_table VALUES (1,'qPi1p4veVIVUTOauaOlrKcnY0aj5K+GS9q6QWYlmKkH=','+G3Bb/jHI78D3Hq3gbo+DEfOtLdWEPqYYs9baZrNobP=','dtf8fCOV4LuswydUmfzFsrHkjHupFElIjD5K26pANmk8'); 20 | --INSERT INTO test_table VALUES (2,'imddM6yDio+8m9YjdgHAd8W2Zr+PCE0Yfh3PCpoMyQX=','AJrPjKwICexdS5dsuQKiwQBQs7eZ/zUlDaNCTYHNjDD=','JclPi1jtjtI7nnxbZ/xZoRleWHHdXdtLKmZ5JW3pTv4ziAP9ZkAEMw=='); 21 | --INSERT INTO test_table VALUES (3,'cYJSlL5Z1LQwHSHa9iDAIG3xg/2x9RLhxAHBkVWGrqv=','5ptgfZb2N6s0jo+pnJM8nwQw3vQWWmELg8Le6zv/oBn=','VJ6kaUSHFcQU25XCKIGi8VHdFM5Di/kUCz67QQ=='); 22 | 23 | select ok(pg_enc_int4_decrypt(pg_enc_int4_encrypt(1)) = 1::int4, 'enc_int4: encryption/decryption test'); 24 | select ok(pg_enc_float4_decrypt(pg_enc_float4_encrypt(1.1)) = 1.1::float4, 'enc_float4: encryption/decryption test'); 25 | --select is(pg_enc_timestamp_decrypt(pg_enc_timestamp_encrypt('11/11/11 11:11:11')), '11/11/11 11:11:11'::timestamp, 'enc_timestamp: encryption/decryption test'); 26 | --select ok(pg_enc_text_decrypt(pg_enc_text_encrypt('test')) = 'test'::cstring, 'enc_test: encryption/decryption test'); 27 | 28 | select enable_debug_mode(1); 29 | 30 | INSERT INTO test_table VALUES (1, '1', '1.1', 'hello', '01/01/2020'); 31 | INSERT INTO test_table VALUES (2, '2', '2.1', 'world', '01/01/2019'); 32 | INSERT INTO test_table VALUES (3, '3', '3.1', 'from', '01/01/2018'); 33 | INSERT INTO test_table VALUES (3, '3', '3.1', 'stealth', '01/01/2017'); 34 | 35 | 36 | SELECT results_eq( 37 | 'select SUM(num_i) from test_table', 38 | $$VALUES (9::enc_int4)$$, 39 | 'enc_int4: SUM function ' 40 | ); 41 | 42 | SELECT results_eq( 43 | 'select MIN(num_i) from test_table', 44 | $$VALUES (1::enc_int4)$$, 45 | 'enc_int4: MIN function ' 46 | ); 47 | 48 | SELECT results_eq( 49 | 'select MAX(num_i) from test_table', 50 | $$VALUES (3::enc_int4)$$, 51 | 'enc_int4: MAX function ' 52 | ); 53 | 54 | SELECT results_eq( 55 | 'select AVG(num_i) from test_table', 56 | $$VALUES (2::enc_int4)$$, 57 | 'enc_int4: AVG function (with rounding)' 58 | ); 59 | 60 | SELECT results_eq( 61 | 'select SUM(num_f) from test_table', 62 | $$VALUES (9.4::enc_float4)$$, 63 | 'enc_float4: SUM function' 64 | ); 65 | 66 | SELECT results_eq( 67 | 'select AVG(num_f) from test_table', 68 | $$VALUES (2.35::enc_float4)$$, 69 | 'enc_float4: AVG function' 70 | ); 71 | 72 | DECLARE q1 CURSOR FOR select id from test_table where time < '01/01/2018'; 73 | SELECT results_eq( 74 | 'q1'::refcursor, 75 | $$VALUES (3::int4)$$, 76 | 'enc_float: < operator in a table' 77 | ); 78 | 79 | DECLARE q2 CURSOR FOR select id from test_table where str = 'stealth'; 80 | SELECT results_eq( 81 | 'q2'::refcursor, 82 | $$VALUES (3)$$, 83 | 'enc_text: = operator in a table' 84 | ); 85 | 86 | --select ok(0::enc_int4 = 0::int4, 'enc_int4: encryption/decryption test in a preprocessing form'); 87 | --select ok(0.5::enc_float4 = 0.5::float4, 'enc_float4: encryption/decryption test in a preprocessing form'); 88 | --select ok('11/11/11 11:11:11'::enc_timestamp = '11/11/11 11:11:11'::timestamp, 'enc_timestamp: encryption/decryption test in a preprocessing form'); 89 | --select ok('test2'::enc_text = 'test2'::cstring, 'enc_text: encryption/decryption test in a preprocessing form'); 90 | 91 | select ok(1::enc_int4 = 1::enc_int4, 'enc_int4: inequality test, operator ='); 92 | select ok(0::enc_int4 != 1::enc_int4, 'enc_int4: inequality test, operator !='); 93 | select ok(0::enc_int4 <> 1::enc_int4, 'enc_int4: inequality test, operator <>'); 94 | select ok(1::enc_int4 <= 2::enc_int4, 'enc_int4: inequality test, operator <='); 95 | select ok(1::enc_int4 <= 1::enc_int4, 'enc_int4: inequality test, operator <='); 96 | select ok(3::enc_int4 >= 2::enc_int4, 'enc_int4: inequality test, operator >='); 97 | select ok(1::enc_int4 >= 1::enc_int4, 'enc_int4: inequality test, operator >='); 98 | select ok(2::enc_int4 < 3::enc_int4, 'enc_int4: inequality test, operator <'); 99 | select ok(3::enc_int4 > 2::enc_int4, 'enc_int4: inequality test, operator >'); 100 | 101 | select ok(2::enc_int4 + 1::enc_int4 = 3::enc_int4, 'enc_int4: operator +'); 102 | select ok(2::enc_int4 - 1::enc_int4 = 1::enc_int4, 'enc_int4: operator -'); 103 | select ok(2::enc_int4 * 2::enc_int4 = 4::enc_int4, 'enc_int4: operator *'); 104 | select ok(6::enc_int4 / 2::enc_int4 = 3::enc_int4, 'enc_int4: operator /'); 105 | --SELECT throws_ok(6::enc_int4 / 0::enc_int4, '', 'SGX_ERROR_CODE -4: ARITHMETIC_ERROR', '' ); 106 | 107 | 108 | select ok(1.1::enc_float4 = 1.1::enc_float4, 'enc_float4: inequality test, operator ='); 109 | select ok(0.2::enc_float4 != 1.1::enc_float4, 'enc_float4: inequality test, operator !='); 110 | select ok(0.2::enc_float4 <> 1.1::enc_float4, 'enc_float4: inequality test, operator <>'); 111 | select ok(1.1::enc_float4 <= 2.3::enc_float4, 'enc_float4: inequality test, operator <='); 112 | select ok(1.1::enc_float4 <= 1.1::enc_float4, 'enc_float4: inequality test, operator <='); 113 | select ok(3.4::enc_float4 >= 2.3::enc_float4, 'enc_float4: inequality test, operator >='); 114 | select ok(1.1::enc_float4 >= 1.1::enc_float4, 'enc_float4: inequality test, operator >='); 115 | select ok(2.3::enc_float4 < 3.4::enc_float4, 'enc_float4: inequality test, operator <'); 116 | select ok(3.4::enc_float4 > 2.3::enc_float4, 'enc_float4: inequality test, operator >'); 117 | 118 | select ok(2.3::enc_float4 + 1.1::enc_float4 = 3.4::enc_float4, 'enc_float4: operator +'); 119 | --select ok(pg_enc_float4_encrypt(2.3) - pg_enc_float4_encrypt(1.1) = pg_enc_float4_encrypt(1.2), 'enc_float4: operator -'); 120 | --select ok(2.3::enc_float4 - 1.1::enc_float4 = 1.2::enc_float4, 'enc_float4: operator -'); 121 | --select ok(2.3::enc_float4 * 2.3::enc_float4 = 5.29::enc_float4, 'enc_float4: operator *'); 122 | select ok(9.9::enc_float4 / 3.3::enc_float4 = 3::enc_float4, 'enc_float4: operator /'); 123 | 124 | select ok('11/11/12'::enc_timestamp = '11/11/12'::enc_timestamp, 'enc_timestamp: inequality test, operator ='); 125 | select ok('11/11/12 00:00:01'::enc_timestamp != '11/11/12 00:00:02'::enc_timestamp, 'enc_timestamp: inequality test, operator !='); 126 | select ok('11/11/12 00:00:01'::enc_timestamp <> '11/11/12 00:00:02'::enc_timestamp, 'enc_timestamp: inequality test, operator <>'); 127 | select ok('11/11/12 00:00:01'::enc_timestamp <= '11/11/12 00:00:01'::enc_timestamp, 'enc_timestamp: inequality test, operator <='); 128 | select ok('11/11/12 00:00:01'::enc_timestamp <= '11/11/12 00:00:03'::enc_timestamp, 'enc_timestamp: inequality test, operator <='); 129 | select ok('11/11/12 00:00:01'::enc_timestamp >= '11/11/12 00:00:01'::enc_timestamp, 'enc_timestamp: inequality test, operator >='); 130 | select ok('11/11/12 00:00:02'::enc_timestamp >= '11/11/12 00:00:01'::enc_timestamp, 'enc_timestamp: inequality test, operator >='); 131 | select ok('11/11/12 00:00:01'::enc_timestamp < '11/11/12 00:00:03'::enc_timestamp, 'enc_timestamp: inequality test, operator <'); 132 | select ok('11/11/12 00:00:03'::enc_timestamp > '11/11/12 00:00:01'::enc_timestamp, 'enc_timestamp: inequality test, operator >'); 133 | 134 | select ok('test1'::enc_text = 'test1'::enc_text, 'enc_text: inequality test, operator ='); 135 | select ok('test1'::enc_text != 'test2'::enc_text, 'enc_text: inequality test, operator !='); 136 | select ok('test1'::enc_text <> 'test2'::enc_text, 'enc_text: inequality test, operator <>'); 137 | select ok('hello'::enc_text || 'world'::enc_text = 'helloworld'::enc_text, 'enc_text: operator ||'); 138 | 139 | 140 | select * from finish(); 141 | --DROP TABLE IF EXISTS test_table; 142 | ROLLBACK; 143 | -------------------------------------------------------------------------------- /test/sql/pgtap--0.90.0--0.91.0.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE FUNCTION pgtap_version() 2 | RETURNS NUMERIC AS 'SELECT 0.91;' 3 | LANGUAGE SQL IMMUTABLE; 4 | 5 | CREATE OR REPLACE FUNCTION has_tablespace( NAME, TEXT, TEXT ) 6 | RETURNS TEXT AS $$ 7 | BEGIN 8 | IF pg_version_num() >= 90200 THEN 9 | RETURN ok( 10 | EXISTS( 11 | SELECT true 12 | FROM pg_catalog.pg_tablespace 13 | WHERE spcname = $1 14 | AND pg_tablespace_location(oid) = $2 15 | ), $3 16 | ); 17 | ELSE 18 | RETURN ok( 19 | EXISTS( 20 | SELECT true 21 | FROM pg_catalog.pg_tablespace 22 | WHERE spcname = $1 23 | AND spclocation = $2 24 | ), $3 25 | ); 26 | END IF; 27 | END; 28 | $$ LANGUAGE plpgsql; 29 | 30 | -------------------------------------------------------------------------------- /test/sql/pgtap--0.93.0--0.94.0.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE FUNCTION pgtap_version() 2 | RETURNS NUMERIC AS 'SELECT 0.94;' 3 | LANGUAGE SQL IMMUTABLE; 4 | 5 | CREATE OR REPLACE FUNCTION _get_func_privs(TEXT, TEXT) 6 | RETURNS TEXT[] AS $$ 7 | BEGIN 8 | IF pg_catalog.has_function_privilege($1, $2, 'EXECUTE') THEN 9 | RETURN '{EXECUTE}'; 10 | ELSE 11 | RETURN '{}'; 12 | END IF; 13 | EXCEPTION 14 | -- Not a valid func name. 15 | WHEN undefined_function THEN RETURN '{undefined_function}'; 16 | -- Not a valid role. 17 | WHEN undefined_object THEN RETURN '{undefined_role}'; 18 | END; 19 | $$ LANGUAGE plpgsql; 20 | 21 | CREATE OR REPLACE FUNCTION _fprivs_are ( TEXT, NAME, NAME[], TEXT ) 22 | RETURNS TEXT AS $$ 23 | DECLARE 24 | grants TEXT[] := _get_func_privs($2, $1); 25 | BEGIN 26 | IF grants[1] = 'undefined_function' THEN 27 | RETURN ok(FALSE, $4) || E'\n' || diag( 28 | ' Function ' || $1 || ' does not exist' 29 | ); 30 | ELSIF grants[1] = 'undefined_role' THEN 31 | RETURN ok(FALSE, $4) || E'\n' || diag( 32 | ' Role ' || quote_ident($2) || ' does not exist' 33 | ); 34 | END IF; 35 | RETURN _assets_are('privileges', grants, $3, $4); 36 | END; 37 | $$ LANGUAGE plpgsql; 38 | 39 | -- has_table( schema, table ) 40 | CREATE OR REPLACE FUNCTION has_table ( NAME, NAME ) 41 | RETURNS TEXT AS $$ 42 | SELECT ok( 43 | _rexists( 'r', $1, $2 ), 44 | 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' 45 | ); 46 | $$ LANGUAGE SQL; 47 | 48 | -- hasnt_table( schema, table ) 49 | CREATE OR REPLACE FUNCTION hasnt_table ( NAME, NAME ) 50 | RETURNS TEXT AS $$ 51 | SELECT ok( 52 | NOT _rexists( 'r', $1, $2 ), 53 | 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' 54 | ); 55 | $$ LANGUAGE SQL; 56 | 57 | -- has_foreign_table( schema, table ) 58 | CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, NAME ) 59 | RETURNS TEXT AS $$ 60 | SELECT ok( 61 | _rexists( 'f', $1, $2 ), 62 | 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' 63 | ); 64 | $$ LANGUAGE SQL; 65 | 66 | -- hasnt_foreign_table( schema, table ) 67 | CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, NAME ) 68 | RETURNS TEXT AS $$ 69 | SELECT ok( 70 | NOT _rexists( 'f', $1, $2 ), 71 | 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' not should exist' 72 | ); 73 | $$ LANGUAGE SQL; 74 | 75 | CREATE OR REPLACE FUNCTION skip ( why text, how_many int ) 76 | RETURNS TEXT AS $$ 77 | DECLARE 78 | output TEXT[]; 79 | BEGIN 80 | output := '{}'; 81 | FOR i IN 1..how_many LOOP 82 | output = array_append( 83 | output, 84 | ok( TRUE ) || ' ' || diag( 'SKIP' || COALESCE( ' ' || why, '') ) 85 | ); 86 | END LOOP; 87 | RETURN array_to_string(output, E'\n'); 88 | END; 89 | $$ LANGUAGE plpgsql; 90 | 91 | CREATE OR REPLACE FUNCTION skip ( text ) 92 | RETURNS TEXT AS $$ 93 | SELECT ok( TRUE ) || ' ' || diag( 'SKIP' || COALESCE(' ' || $1, '') ); 94 | $$ LANGUAGE sql; 95 | 96 | -- check_test( test_output, pass, name, description, diag, match_diag ) 97 | CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT, BOOLEAN ) 98 | RETURNS SETOF TEXT AS $$ 99 | DECLARE 100 | tnumb INTEGER; 101 | aok BOOLEAN; 102 | adescr TEXT; 103 | res BOOLEAN; 104 | descr TEXT; 105 | adiag TEXT; 106 | have ALIAS FOR $1; 107 | eok ALIAS FOR $2; 108 | name ALIAS FOR $3; 109 | edescr ALIAS FOR $4; 110 | ediag ALIAS FOR $5; 111 | matchit ALIAS FOR $6; 112 | BEGIN 113 | -- What test was it that just ran? 114 | tnumb := currval('__tresults___numb_seq'); 115 | 116 | -- Fetch the results. 117 | EXECUTE 'SELECT aok, descr FROM __tresults__ WHERE numb = ' || tnumb 118 | INTO aok, adescr; 119 | 120 | -- Now delete those results. 121 | EXECUTE 'DELETE FROM __tresults__ WHERE numb = ' || tnumb; 122 | EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb; 123 | 124 | -- Set up the description. 125 | descr := coalesce( name || ' ', 'Test ' ) || 'should '; 126 | 127 | -- So, did the test pass? 128 | RETURN NEXT is( 129 | aok, 130 | eok, 131 | descr || CASE eok WHEN true then 'pass' ELSE 'fail' END 132 | ); 133 | 134 | -- Was the description as expected? 135 | IF edescr IS NOT NULL THEN 136 | RETURN NEXT is( 137 | adescr, 138 | edescr, 139 | descr || 'have the proper description' 140 | ); 141 | END IF; 142 | 143 | -- Were the diagnostics as expected? 144 | IF ediag IS NOT NULL THEN 145 | -- Remove ok and the test number. 146 | adiag := substring( 147 | have 148 | FROM CASE WHEN aok THEN 4 ELSE 9 END + char_length(tnumb::text) 149 | ); 150 | 151 | -- Remove the description, if there is one. 152 | IF adescr <> '' THEN 153 | adiag := substring( 154 | adiag FROM 1 + char_length( ' - ' || substr(diag( adescr ), 3) ) 155 | ); 156 | END IF; 157 | 158 | IF NOT aok THEN 159 | -- Remove failure message from ok(). 160 | adiag := substring(adiag FROM 1 + char_length(diag( 161 | 'Failed test ' || tnumb || 162 | CASE adescr WHEN '' THEN '' ELSE COALESCE(': "' || adescr || '"', '') END 163 | ))); 164 | END IF; 165 | 166 | IF ediag <> '' THEN 167 | -- Remove the space before the diagnostics. 168 | adiag := substring(adiag FROM 2); 169 | END IF; 170 | 171 | -- Remove the #s. 172 | adiag := replace( substring(adiag from 3), E'\n# ', E'\n' ); 173 | 174 | -- Now compare the diagnostics. 175 | IF matchit THEN 176 | RETURN NEXT matches( 177 | adiag, 178 | ediag, 179 | descr || 'have the proper diagnostics' 180 | ); 181 | ELSE 182 | RETURN NEXT is( 183 | adiag, 184 | ediag, 185 | descr || 'have the proper diagnostics' 186 | ); 187 | END IF; 188 | END IF; 189 | 190 | -- And we're done 191 | RETURN; 192 | END; 193 | $$ LANGUAGE plpgsql; 194 | -------------------------------------------------------------------------------- /test/sql/pgtap--0.95.0--0.96.0.sql: -------------------------------------------------------------------------------- 1 | CREATE OR REPLACE FUNCTION pgtap_version() 2 | RETURNS NUMERIC AS 'SELECT 0.96;' 3 | LANGUAGE SQL IMMUTABLE; 4 | 5 | CREATE OR REPLACE FUNCTION findfuncs( NAME, TEXT, TEXT ) 6 | RETURNS TEXT[] AS $$ 7 | SELECT ARRAY( 8 | SELECT DISTINCT quote_ident(n.nspname) || '.' || quote_ident(p.proname) AS pname 9 | FROM pg_catalog.pg_proc p 10 | JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid 11 | WHERE n.nspname = $1 12 | AND p.proname ~ $2 13 | AND ($3 IS NULL OR p.proname !~ $3) 14 | ORDER BY pname 15 | ); 16 | $$ LANGUAGE sql; 17 | CREATE OR REPLACE FUNCTION findfuncs( NAME, TEXT ) 18 | RETURNS TEXT[] AS $$ 19 | SELECT findfuncs( $1, $2, NULL ) 20 | $$ LANGUAGE sql; 21 | 22 | CREATE OR REPLACE FUNCTION findfuncs( TEXT, TEXT ) 23 | RETURNS TEXT[] AS $$ 24 | SELECT ARRAY( 25 | SELECT DISTINCT quote_ident(n.nspname) || '.' || quote_ident(p.proname) AS pname 26 | FROM pg_catalog.pg_proc p 27 | JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid 28 | WHERE pg_catalog.pg_function_is_visible(p.oid) 29 | AND p.proname ~ $1 30 | AND ($2 IS NULL OR p.proname !~ $2) 31 | ORDER BY pname 32 | ); 33 | $$ LANGUAGE sql; 34 | CREATE OR REPLACE FUNCTION findfuncs( TEXT ) 35 | RETURNS TEXT[] AS $$ 36 | SELECT findfuncs( $1, NULL ) 37 | $$ LANGUAGE sql; 38 | 39 | CREATE OR REPLACE FUNCTION runtests( NAME, TEXT ) 40 | RETURNS SETOF TEXT AS $$ 41 | SELECT * FROM _runner( 42 | findfuncs( $1, '^startup' ), 43 | findfuncs( $1, '^shutdown' ), 44 | findfuncs( $1, '^setup' ), 45 | findfuncs( $1, '^teardown' ), 46 | findfuncs( $1, $2, '^(startup|shutdown|setup|teardown)' ) 47 | ); 48 | $$ LANGUAGE sql; 49 | 50 | -- runtests( match ) 51 | CREATE OR REPLACE FUNCTION runtests( TEXT ) 52 | RETURNS SETOF TEXT AS $$ 53 | SELECT * FROM _runner( 54 | findfuncs( '^startup' ), 55 | findfuncs( '^shutdown' ), 56 | findfuncs( '^setup' ), 57 | findfuncs( '^teardown' ), 58 | findfuncs( $1, '^(startup|shutdown|setup|teardown)' ) 59 | ); 60 | $$ LANGUAGE sql; 61 | 62 | -- database_privs_are ( db, user, privileges[], description ) 63 | CREATE OR REPLACE FUNCTION database_privs_are ( NAME, NAME, NAME[], TEXT ) 64 | RETURNS TEXT AS $$ 65 | DECLARE 66 | grants TEXT[] := _get_db_privs( $2, $1::TEXT ); 67 | BEGIN 68 | IF grants[1] = 'invalid_catalog_name' THEN 69 | RETURN ok(FALSE, $4) || E'\n' || diag( 70 | ' Database ' || quote_ident($1) || ' does not exist' 71 | ); 72 | ELSIF grants[1] = 'undefined_role' THEN 73 | RETURN ok(FALSE, $4) || E'\n' || diag( 74 | ' Role ' || quote_ident($2) || ' does not exist' 75 | ); 76 | END IF; 77 | RETURN _assets_are('privileges', grants, $3, $4); 78 | END; 79 | $$ LANGUAGE plpgsql; 80 | 81 | -- schema_privs_are ( schema, user, privileges[], description ) 82 | CREATE OR REPLACE FUNCTION schema_privs_are ( NAME, NAME, NAME[], TEXT ) 83 | RETURNS TEXT AS $$ 84 | DECLARE 85 | grants TEXT[] := _get_schema_privs( $2, $1::TEXT ); 86 | BEGIN 87 | IF grants[1] = 'invalid_schema_name' THEN 88 | RETURN ok(FALSE, $4) || E'\n' || diag( 89 | ' Schema ' || quote_ident($1) || ' does not exist' 90 | ); 91 | ELSIF grants[1] = 'undefined_role' THEN 92 | RETURN ok(FALSE, $4) || E'\n' || diag( 93 | ' Role ' || quote_ident($2) || ' does not exist' 94 | ); 95 | END IF; 96 | RETURN _assets_are('privileges', grants, $3, $4); 97 | END; 98 | $$ LANGUAGE plpgsql; 99 | 100 | -- tablespace_privs_are ( tablespace, user, privileges[], description ) 101 | CREATE OR REPLACE FUNCTION tablespace_privs_are ( NAME, NAME, NAME[], TEXT ) 102 | RETURNS TEXT AS $$ 103 | DECLARE 104 | grants TEXT[] := _get_tablespaceprivs( $2, $1::TEXT ); 105 | BEGIN 106 | IF grants[1] = 'undefined_tablespace' THEN 107 | RETURN ok(FALSE, $4) || E'\n' || diag( 108 | ' Tablespace ' || quote_ident($1) || ' does not exist' 109 | ); 110 | ELSIF grants[1] = 'undefined_role' THEN 111 | RETURN ok(FALSE, $4) || E'\n' || diag( 112 | ' Role ' || quote_ident($2) || ' does not exist' 113 | ); 114 | END IF; 115 | RETURN _assets_are('privileges', grants, $3, $4); 116 | END; 117 | $$ LANGUAGE plpgsql; 118 | 119 | CREATE OR REPLACE FUNCTION fdw_privs_are ( NAME, NAME, NAME[], TEXT ) 120 | RETURNS TEXT AS $$ 121 | DECLARE 122 | grants TEXT[] := _get_fdw_privs( $2, $1::TEXT ); 123 | BEGIN 124 | IF grants[1] = 'undefined_fdw' THEN 125 | RETURN ok(FALSE, $4) || E'\n' || diag( 126 | ' FDW ' || quote_ident($1) || ' does not exist' 127 | ); 128 | ELSIF grants[1] = 'undefined_role' THEN 129 | RETURN ok(FALSE, $4) || E'\n' || diag( 130 | ' Role ' || quote_ident($2) || ' does not exist' 131 | ); 132 | END IF; 133 | RETURN _assets_are('privileges', grants, $3, $4); 134 | END; 135 | $$ LANGUAGE plpgsql; 136 | 137 | -- server_privs_are ( server, user, privileges[], description ) 138 | CREATE OR REPLACE FUNCTION server_privs_are ( NAME, NAME, NAME[], TEXT ) 139 | RETURNS TEXT AS $$ 140 | DECLARE 141 | grants TEXT[] := _get_server_privs( $2, $1::TEXT ); 142 | BEGIN 143 | IF grants[1] = 'undefined_server' THEN 144 | RETURN ok(FALSE, $4) || E'\n' || diag( 145 | ' Server ' || quote_ident($1) || ' does not exist' 146 | ); 147 | ELSIF grants[1] = 'undefined_role' THEN 148 | RETURN ok(FALSE, $4) || E'\n' || diag( 149 | ' Role ' || quote_ident($2) || ' does not exist' 150 | ); 151 | END IF; 152 | RETURN _assets_are('privileges', grants, $3, $4); 153 | END; 154 | $$ LANGUAGE plpgsql; 155 | 156 | -- Get extensions in a given schema 157 | CREATE OR REPLACE FUNCTION _extensions( NAME ) 158 | RETURNS SETOF NAME AS $$ 159 | SELECT e.extname 160 | FROM pg_catalog.pg_namespace n 161 | JOIN pg_catalog.pg_extension e ON n.oid = e.extnamespace 162 | WHERE n.nspname = $1 163 | $$ LANGUAGE SQL; 164 | 165 | CREATE OR REPLACE FUNCTION _extensions() 166 | RETURNS SETOF NAME AS $$ 167 | SELECT extname FROM pg_catalog.pg_extension 168 | $$ LANGUAGE SQL; 169 | 170 | -- extensions_are( schema, extensions, description ) 171 | CREATE OR REPLACE FUNCTION extensions_are( NAME, NAME[], TEXT ) 172 | RETURNS TEXT AS $$ 173 | SELECT _are( 174 | 'extensions', 175 | ARRAY(SELECT _extensions($1) EXCEPT SELECT unnest($2)), 176 | ARRAY(SELECT unnest($2) EXCEPT SELECT _extensions($1)), 177 | $3 178 | ); 179 | $$ LANGUAGE SQL; 180 | 181 | -- extensions_are( schema, extensions) 182 | CREATE OR REPLACE FUNCTION extensions_are( NAME, NAME[] ) 183 | RETURNS TEXT AS $$ 184 | SELECT extensions_are( 185 | $1, $2, 186 | 'Schema ' || quote_ident($1) || ' should have the correct extensions' 187 | ); 188 | $$ LANGUAGE SQL; 189 | 190 | -- extensions_are( extensions, description ) 191 | CREATE OR REPLACE FUNCTION extensions_are( NAME[], TEXT ) 192 | RETURNS TEXT AS $$ 193 | SELECT _are( 194 | 'extensions', 195 | ARRAY(SELECT _extensions() EXCEPT SELECT unnest($1)), 196 | ARRAY(SELECT unnest($1) EXCEPT SELECT _extensions()), 197 | $2 198 | ); 199 | $$ LANGUAGE SQL; 200 | 201 | -- extensions_are( schema, extensions) 202 | CREATE OR REPLACE FUNCTION extensions_are( NAME[] ) 203 | RETURNS TEXT AS $$ 204 | SELECT extensions_are($1, 'Should have the correct extensions'); 205 | $$ LANGUAGE SQL; 206 | 207 | CREATE OR REPLACE FUNCTION _error_diag( 208 | sqlstate TEXT DEFAULT NULL, 209 | errmsg TEXT DEFAULT NULL, 210 | detail TEXT DEFAULT NULL, 211 | hint TEXT DEFAULT NULL, 212 | context TEXT DEFAULT NULL, 213 | schname TEXT DEFAULT NULL, 214 | tabname TEXT DEFAULT NULL, 215 | colname TEXT DEFAULT NULL, 216 | chkname TEXT DEFAULT NULL, 217 | typname TEXT DEFAULT NULL 218 | ) RETURNS TEXT AS $$ 219 | SELECT COALESCE( 220 | COALESCE( NULLIF(sqlstate, '') || ': ', '' ) || COALESCE( NULLIF(errmsg, ''), '' ), 221 | 'NO ERROR FOUND' 222 | ) 223 | || COALESCE(E'\n DETAIL: ' || nullif(detail, ''), '') 224 | || COALESCE(E'\n HINT: ' || nullif(hint, ''), '') 225 | || COALESCE(E'\n SCHEMA: ' || nullif(schname, ''), '') 226 | || COALESCE(E'\n TABLE: ' || nullif(tabname, ''), '') 227 | || COALESCE(E'\n COLUMN: ' || nullif(colname, ''), '') 228 | || COALESCE(E'\n CONSTRAINT: ' || nullif(chkname, ''), '') 229 | || COALESCE(E'\n TYPE: ' || nullif(typname, ''), '') 230 | -- We need to manually indent all the context lines 231 | || COALESCE(E'\n CONTEXT:\n' 232 | || regexp_replace(NULLIF( context, ''), '^', ' ', 'gn' 233 | ), ''); 234 | $$ LANGUAGE sql IMMUTABLE; 235 | 236 | -- lives_ok( sql, description ) 237 | CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT ) 238 | RETURNS TEXT AS $$ 239 | DECLARE 240 | code TEXT := _query($1); 241 | descr ALIAS FOR $2; 242 | detail text; 243 | hint text; 244 | context text; 245 | schname text; 246 | tabname text; 247 | colname text; 248 | chkname text; 249 | typname text; 250 | BEGIN 251 | EXECUTE code; 252 | RETURN ok( TRUE, descr ); 253 | EXCEPTION WHEN OTHERS THEN 254 | -- There should have been no exception. 255 | GET STACKED DIAGNOSTICS 256 | detail = PG_EXCEPTION_DETAIL, 257 | hint = PG_EXCEPTION_HINT, 258 | context = PG_EXCEPTION_CONTEXT, 259 | schname = SCHEMA_NAME, 260 | tabname = TABLE_NAME, 261 | colname = COLUMN_NAME, 262 | chkname = CONSTRAINT_NAME, 263 | typname = PG_DATATYPE_NAME; 264 | RETURN ok( FALSE, descr ) || E'\n' || diag( 265 | ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) 266 | ); 267 | END; 268 | $$ LANGUAGE plpgsql; 269 | 270 | CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] ) 271 | RETURNS SETOF TEXT AS $$ 272 | DECLARE 273 | startup ALIAS FOR $1; 274 | shutdown ALIAS FOR $2; 275 | setup ALIAS FOR $3; 276 | teardown ALIAS FOR $4; 277 | tests ALIAS FOR $5; 278 | tap TEXT; 279 | tfaild INTEGER := 0; 280 | ffaild INTEGER := 0; 281 | tnumb INTEGER := 0; 282 | fnumb INTEGER := 0; 283 | tok BOOLEAN := TRUE; 284 | BEGIN 285 | BEGIN 286 | -- No plan support. 287 | PERFORM * FROM no_plan(); 288 | FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap; END LOOP; 289 | EXCEPTION 290 | -- Catch all exceptions and simply rethrow custom exceptions. This 291 | -- will roll back everything in the above block. 292 | WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM; 293 | END; 294 | 295 | -- Record how startup tests have failed. 296 | tfaild := num_failed(); 297 | 298 | FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP 299 | 300 | -- What subtest are we running? 301 | RETURN NEXT ' ' || diag_test_name('Subtest: ' || tests[i]); 302 | 303 | -- Reset the results. 304 | tok := TRUE; 305 | tnumb := COALESCE(_get('curr_test'), 0); 306 | 307 | IF tnumb > 0 THEN 308 | EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1'; 309 | PERFORM _set('curr_test', 0); 310 | PERFORM _set('failed', 0); 311 | END IF; 312 | 313 | DECLARE 314 | errstate text; 315 | errmsg text; 316 | detail text; 317 | hint text; 318 | context text; 319 | schname text; 320 | tabname text; 321 | colname text; 322 | chkname text; 323 | typname text; 324 | BEGIN 325 | BEGIN 326 | -- Run the setup functions. 327 | FOR tap IN SELECT * FROM _runem(setup, false) LOOP 328 | RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); 329 | END LOOP; 330 | 331 | -- Run the actual test function. 332 | FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP 333 | RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); 334 | END LOOP; 335 | 336 | -- Run the teardown functions. 337 | FOR tap IN SELECT * FROM _runem(teardown, false) LOOP 338 | RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); 339 | END LOOP; 340 | 341 | -- Emit the plan. 342 | fnumb := COALESCE(_get('curr_test'), 0); 343 | RETURN NEXT ' 1..' || fnumb; 344 | 345 | -- Emit any error messages. 346 | IF fnumb = 0 THEN 347 | RETURN NEXT ' # No tests run!'; 348 | tok = false; 349 | ELSE 350 | -- Report failures. 351 | ffaild := num_failed(); 352 | IF ffaild > 0 THEN 353 | tok := FALSE; 354 | RETURN NEXT ' ' || diag( 355 | 'Looks like you failed ' || ffaild || ' test' || 356 | CASE tfaild WHEN 1 THEN '' ELSE 's' END 357 | || ' of ' || fnumb 358 | ); 359 | END IF; 360 | END IF; 361 | 362 | EXCEPTION WHEN raise_exception THEN 363 | -- Something went wrong. Record that fact. 364 | errstate := SQLSTATE; 365 | errmsg := SQLERRM; 366 | GET STACKED DIAGNOSTICS 367 | detail = PG_EXCEPTION_DETAIL, 368 | hint = PG_EXCEPTION_HINT, 369 | context = PG_EXCEPTION_CONTEXT, 370 | schname = SCHEMA_NAME, 371 | tabname = TABLE_NAME, 372 | colname = COLUMN_NAME, 373 | chkname = CONSTRAINT_NAME, 374 | typname = PG_DATATYPE_NAME; 375 | END; 376 | 377 | -- Always raise an exception to rollback any changes. 378 | RAISE EXCEPTION '__TAP_ROLLBACK__'; 379 | 380 | EXCEPTION WHEN raise_exception THEN 381 | IF errmsg IS NOT NULL THEN 382 | -- Something went wrong. Emit the error message. 383 | tok := FALSE; 384 | RETURN NEXT regexp_replace( diag('Test died: ' || _error_diag( 385 | errstate, errmsg, detail, hint, context, schname, tabname, colname, chkname, typname 386 | )), '^', ' ', 'gn'); 387 | errmsg := NULL; 388 | END IF; 389 | END; 390 | 391 | -- Restore the sequence. 392 | EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1; 393 | PERFORM _set('curr_test', tnumb); 394 | PERFORM _set('failed', tfaild); 395 | 396 | -- Record this test. 397 | RETURN NEXT ok(tok, tests[i]); 398 | IF NOT tok THEN tfaild := tfaild + 1; END IF; 399 | 400 | END LOOP; 401 | 402 | -- Run the shutdown functions. 403 | FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap; END LOOP; 404 | 405 | -- Finish up. 406 | FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP 407 | RETURN NEXT tap; 408 | END LOOP; 409 | 410 | -- Clean up and return. 411 | PERFORM _cleanup(); 412 | RETURN; 413 | END; 414 | $$ LANGUAGE plpgsql; 415 | 416 | -------------------------------------------------------------------------------- /test/sql/setup.sql: -------------------------------------------------------------------------------- 1 | \set QUIET 1 2 | 3 | -- 4 | -- Tests for pgTAP. 5 | -- 6 | -- 7 | -- Format the output for nice TAP. 8 | \pset format unaligned 9 | \pset tuples_only true 10 | \pset pager 11 | 12 | -- Revert all changes on failure. 13 | \set ON_ERROR_ROLLBACK 1 14 | \set ON_ERROR_STOP true 15 | 16 | BEGIN; 17 | 18 | -- Uncomment when testing with PGOPTIONS=--search_path=tap 19 | -- CREATE SCHEMA tap; SET search_path TO tap,public; 20 | 21 | -- Load the TAP functions. 22 | \i sql/pgtap.sql 23 | --------------------------------------------------------------------------------