├── LICENSE ├── README.md ├── doc ├── 2019-05-29_095400.png ├── 2019-05-29_113640.png ├── Design_flowChart │ ├── exe_flow_step1_init.png │ ├── exe_flow_step2_keyChange.png │ ├── exe_flow_step3_swatt.png │ ├── exe_flow_step4_feedback.png │ ├── optee_client_server_2019_05_24.png │ ├── optee_client_server_2019_05_31.png │ ├── optee_client_server_2019_06_15.png │ ├── optee_client_server_2019_06_20.png │ └── optee_client_server_2019_07_10.png ├── Set_Raspberry_PI with Optee.docx ├── Set_Raspberry_PI with Optee.pdf ├── Trust client design.png ├── designDoc.pptx ├── design_31_05_2019.png ├── img │ ├── deviceVerify.png │ ├── filesStructure.png │ ├── generalWorkflow.png │ ├── getPATTparm.png │ ├── overview.png │ ├── resultUpload.png │ ├── toolchaindownload.png │ └── workflow.png ├── position.png ├── reuslt_0.png ├── testResult_2019-05-31-082728_1920x1080_scrot.png ├── test_result_2019-05-31-093949_1920x1080_scrot.png ├── trustclientResult.png └── worksitualtion.png └── src ├── Constants.py ├── IOT_Att.py ├── aesTest.c ├── aesTest.py ├── client.c ├── fileAccess.c ├── fileSwatt.c ├── firmwGlobal.py ├── firmwMsgMgr.py ├── firmwTAServer.py ├── firmwareSample ├── randomTest ├── server.py ├── taServer.py ├── trustClient.zip └── trustClient ├── run ├── configLocal.txt └── runTC.sh └── trustClient ├── Android.mk ├── Makefile ├── build_ta_helloworld_qemu.sh ├── doc ├── Makefile ├── close_session_and_finalize_context.msc ├── invoke_command.msc └── open_session.msc ├── host ├── Makefile └── main.c └── ta ├── Android.mk ├── Makefile ├── aes_ta.c ├── include └── aes_ta.h ├── sub.mk └── user_ta_header_defines.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Yuancheng Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Trust-Zone/Env (OPTEE) on Raspberry PI 2 | **Project Design**: The primary goal of this project is to utilize the Raspberry Pi as the foundation platform for constructing a secure "Trust IoT Device", employing ARM Trust-Zone technology to protect critical data/program such as encryption keys for communication channels and IoT firmware attestation program from potential information leaks and firmware attacks. To achieve this, we developed a "Trust Client" program and utilize the [OPTEE (Open Portable Trusted Execution Environment)](https://www.trustedfirmware.org/projects/op-tee/) library to establish a Trusted Execution Environment (TEE) on the Raspberry Pi 3B+. The Trust functions will run within this TEE to ensure security. The firmware attestation code will be integrated into a trust function running within the Trust-Zone, to verify the integrity of the executable firmware on the IoT device (Raspberry Pi Model 3). 3 | 4 | The system consists of two primary components: 5 | 6 | - **Trust IoT Firmware Attestation Server**: This server program operates on the IoT control hub (cloud) side. It is responsible for transmitting encrypted PATT (Physics-based Attestation) requests and parameters to the corresponding `Trust Client`. Subsequently, it verifies the response from the `Trust Client` to determine if the IoT device has been compromised. 7 | 8 | - **Trust IoT Firmware Attestation Client**: The Trust Client program is deployed on the IoT device (Raspberry Pi) and operates within both the Normal World and the Trust-Zone Secure World. The Trust Client's communication module in the Normal World forwards encrypted messages from the Trust Firmware Attestation Server to the secure world function. Subsequently, it performs the PATT check for the target Firmware/Application program based on the server's request. Upon completion, the Trust Client sends the encrypted result back to the server for verification. 9 | 10 | The system workflow overview is shown below: 11 | 12 | ![](doc/img/overview.png) 13 | 14 | ``` 15 | version: v0.1.2 16 | Copyright: Copyright (c) 2021 LiuYuancheng 17 | License: MIT License 18 | ``` 19 | 20 | 21 | 22 | **Table of Contents** 23 | 24 | [TOC] 25 | 26 | - [Trust-Zone/Env (OPTEE) on Raspberry PI](#trust-zone-env--optee--on-raspberry-pi) 27 | + [Introduction](#introduction) 28 | + [Background Knowledge](#background-knowledge) 29 | - [ARM Trust Zone](#arm-trust-zone) 30 | - [Trust Execution Environment and OP-TEE](#trust-execution-environment-and-op-tee) 31 | - [How Trust-Zone Ensures Security](#how-trust-zone-ensures-security) 32 | + [Project Design](#project-design) 33 | - [Device Verification and Server Connection](#device-verification-and-server-connection) 34 | - [Verification Result Upload and Firmware Attestation Parameters Fetch](#verification-result-upload-and-firmware-attestation-parameters-fetch) 35 | - [Running PATT Firmware Attestation and Uploading the Result](#running-patt-firmware-attestation-and-uploading-the-result) 36 | + [Program Setup](#program-setup) 37 | * [Hardware Need](#hardware-need) 38 | - [Detail Configuration Steps](#detail-configuration-steps) 39 | * [Step 1: Prepare Raspberry PI (mode 3) with Raspbian system installed](#step-1--prepare-raspberry-pi--mode-3--with-raspbian-system-installed) 40 | * [Step 2: Build the Raspbian with Trust Environment enabled](#step-2--build-the-raspbian-with-trust-environment-enabled) 41 | * [Step 3: Create a new OPTEE Trust Application and Test](#step-3--create-a-new-optee-trust-application-and-test) 42 | - [Program Execution](#program-execution) 43 | - [Build the Trust Client](#build-the-trust-client) 44 | * [Step 1: Setup the device verification constant](#step-1--setup-the-device-verification-constant) 45 | * [Step 2: Build the Project and copy the Trust Client in the Raspberry PI SD card](#step-2--build-the-project-and-copy-the-trust-client-in-the-raspberry-pi-sd-card) 46 | * [Step3: Run the Trust Client Normal World Module](#step3--run-the-trust-client-normal-world-module) 47 | - [Run Trust Server](#run-trust-server) 48 | + [Reference](#reference) 49 | 50 | - [Project Main Technical Feature and Reference](#project-main-technical-feature-and-reference) 51 | + [Problem and Solution](#problem-and-solution) 52 | 53 | 54 | 55 | `version v0.1.2` 56 | 57 | ------ 58 | 59 | ### Introduction 60 | 61 | With the advancement of reverse engineering techniques, hackers can easily extract part of source code from Linux-based IoT devices by dissecting the application type firmware files. For instance, consider a scenario where we utilize `pyInstaller` to compile our CV analysis program into a executable file on Raspbian OS, and deploy it on a Raspberry Pi to create a motion detection camera. If a hacker obtains such a camera, they can employ tools like `pyinstxtractor` to unpack the firmware and then use `uncompyle6` to decompile it, thereby gaining access to some part of the source code. Subsequently, armed with this knowledge, they can craft malicious firmware programs to launch attacks. Even if we incorporate a firmware attestation program in our IoT devices, hackers can also attempt to decompile it to identify the vulnerabilities and bypass security measures. 62 | 63 | To mitigate these risks, we propose relocating the critical functions (such as the firmware attestation logic) to the Raspberry Pi's ARM Trust-Zone. By doing so, we render the attestation program immune to de-compilation attempts by hackers. Additionally, we will securely store the Arm chip's unique `Device identification UDID` and our attestation message RSA encryption key within the Trust-Zone. The ARM chip verification program operating within the Trust-Zone will retrieve the ARM's `Device identification UDID` and compare it with stored records. If they do not match, the attestation process will fail. So, even if a hacker clones all components onto another Raspberry Pi, they will still be unable to implement a replay attack. 64 | 65 | Furthermore, the attestation result will be encrypted within the trust environment using the encryption key stored in the Trust-Zone. This ensures that even if hackers intercept communication between the IoT hub server and the device, they will be unable to decrypt the messages and launch a Man-in-the-Middle (MITM) attack. 66 | 67 | The general trust client workflow is shown below: 68 | 69 | ![](doc/img/generalWorkflow.png) 70 | 71 | The Trust Client program on the Raspberry Pi consists of three key sections: 72 | 73 | - **Normal World Program**: This segment operates within the application level Normal World, handling most program functions, facilitating the transmission of information to the IoT Control Hub, and passing data to the trust function in the Secure World. 74 | - **Trust Storage Constants**: All critical information and parameters, such as firmware attestation results, Device identification UDID, and RSA encryption keys, will be stored as constants or signature in the Secure World for the trust function's usage. 75 | - **Trust Execution Functions**: This component operates within the Secure World, containing essential secure function code, such as message RSA encryption, Arm chip UDID verification code, and the attestation algorithm function, to mitigate the risk of reverse engineering attacks. 76 | 77 | 78 | 79 | ------ 80 | 81 | ### Background Knowledge 82 | 83 | 84 | 85 | #### ARM Trust Zone 86 | 87 | Trust-Zone is a technology developed by ARM Holdings that provides hardware-based security features on ARM-based processors. It creates two separate execution environments: the "Normal World" and the "Secure World". These environments run concurrently on the same processor, but with different levels of access and privileges. Each world operates independently, with its own set of resources, privileges, and execution environments. Here's a basic overview of how ARM Trust-Zone works: 88 | 89 | 1. **Normal World**: This is where the regular operating system (such as Android, Linux, or other RTOS) runs along with user applications. It operates in a non-secure state and has access to regular resources and memory. 90 | 2. **Secure World**: This is a separate, isolated environment that runs a trusted operating system, often called a "Secure Monitor" or "Secure Kernel". The Secure World has higher privileges and access to secure resources such as cryptographic functions, secure storage, and secure boot mechanisms. It ensures that critical system functions and sensitive data are protected from unauthorized access or tampering. 91 | 92 | Trust-Zone technology enables secure boot, secure storage, secure communication channels, and secure execution environments for applications that require high levels of security, such as mobile payment systems, digital rights management (DRM), and enterprise security solutions. It provides a foundation for building trusted execution environments (TEEs) where sensitive operations can be performed with a high degree of assurance against attacks. 93 | 94 | > Reference: https://www.arm.com/technologies/trustzone-for-cortex-m#:~:text=Arm%20TrustZone%20technology%20is%20used,to%20as%20the%20secure%20monitor 95 | 96 | 97 | 98 | #### Trust Execution Environment and OP-TEE 99 | 100 | **Trusted Execution Environment (TEE)**: The Trusted Execution Environment (TEE) is a secure area within the Trust-Zone environment where trusted applications can run with higher levels of security and confidentiality. Trust-Zone divides the ARM processor into two separate worlds: Normal World and Secure World. The TEE is a secure execution environment for running critical security functions and trusted applications in the Secure World. It is a trusted operating environment that provides isolation and protection for sensitive operations and applications. TEE offers a secure runtime environment where trusted applications, such as secure payment solutions, digital rights management (DRM) systems, and secure authentication mechanisms, can run with confidentiality, integrity, and reliability. 101 | 102 | In essence, Trust-Zone provides the hardware support necessary to create a secure execution environment, while the TEE utilizes this environment to run trusted applications and execute critical security functions. The TEE leverages the security features provided by Trust-Zone, such as hardware isolation, secure boot, secure storage, and secure communication channels, to ensure the confidentiality and integrity of sensitive data and operations. 103 | 104 | OP-TEE is a Trusted Execution Environment (TEE) designed as companion to a non-secure Linux kernel running on Arm; Cortex-A cores using the Trust-Zone technology. OP-TEE implements TEE Internal Core API v1.1.x which is the API exposed to Trusted Applications and the TEE Client API v1.0, which is the API describing how to communicate with a TEE. Those APIs are defined in the Global Platform API specifications. 105 | 106 | > Reference: https://www.trustedfirmware.org/projects/op-tee/ 107 | 108 | 109 | 110 | #### How Trust-Zone Ensures Security 111 | 112 | Accessing data stored in the Trust-Zone storage is highly challenging for hackers due to the robust security mechanisms in place. Trust-Zone provides hardware-enforced isolation between the Normal World and the Secure World, ensuring that data stored in the Secure World is protected from unauthorized access. 113 | 114 | Here are some reasons why it's difficult for a hacker to access data saved in the Trust-Zone storage: 115 | 116 | 1. **Hardware Isolation**: Trust-Zone utilizes hardware-enforced isolation mechanisms to separate the Normal World and the Secure World. This prevents code running in the Normal World from directly accessing or tampering with data stored in the Secure World. 117 | 2. **Secure Boot**: Trust-Zone supports secure boot mechanisms, ensuring that only authenticated and trusted code can be loaded and executed in the Secure World. This prevents unauthorized code from accessing data stored in the Trust-Zone storage. 118 | 3. **Secure Storage**: Data stored in the Trust-Zone storage is encrypted and protected by cryptographic algorithms. Even if a hacker manages to gain access to the physical memory, they would still need to decrypt the data, which is typically challenging without the appropriate cryptographic keys. 119 | 4. **Secure Monitor**: The Secure Monitor, a trusted piece of firmware responsible for managing transitions between the Normal World and the Secure World, helps ensure the integrity and security of data stored in the Trust-Zone storage. 120 | 121 | While it's theoretically possible for sophisticated attackers to exploit vulnerabilities in Trust-Zone or the Secure Monitor firmware, doing so would require significant expertise, resources, and access to specialized equipment. Additionally, manufacturers continuously work to improve the security of Trust-Zone and address any discovered vulnerabilities through software updates and patches. Overall, Trust-Zone provides a high level of security for data stored in the Secure World, making it extremely difficult for hackers to access. 122 | 123 | 124 | 125 | ------ 126 | 127 | ### Project Design 128 | 129 | The trust IoT firmware attestation program follows the workflow diagram outlined below, which we'll break down into three distinct steps to illustrate a single round of firmware attestation: 130 | 131 | ![](doc/img/workflow.png) 132 | 133 | 1. **Device Verification and Server Connection**: In this initial step, the program verifies the device and establishes a connection with the server. It involves authenticating the server's integrity and ensuring mutual trust between the device and the server. 134 | 2. **Verification Result Upload and Firmware Attestation Parameters Fetch**: Following the device verification, the program uploads the verification result to the server and retrieves firmware attestation parameters. This step is crucial for obtaining necessary data and instructions to proceed with the firmware attestation process. 135 | 3. **Run PATT Firmware Attestation and Upload the Result**: Finally, the program executes the firmware attestation algorithm using the fetched parameters. It then uploads the attestation result to the server for verification. This step ensures the integrity of the firmware and enhances the overall security of the device. 136 | 137 | 138 | 139 | #### Device Verification and Server Connection 140 | 141 | During initialization of the Trust Client program, the trust IoT firmware attestation module loads the IoT configuration file and registers IoT information with the Trust Server. This allows the server to prepare the attestation key and parameters accordingly. Subsequently, the program reads the Raspberry Pi's ARM chip's `Device identification UDID` and initiates an OPTEE session to transmit the UDID to the trust environment. If the UDID matches the pre-saved data in the Trust Zone Storage, device verification succeeds, unlocking the PATT firmware attestation functions for next step. Conversely, if there is no match, indicating a potential cloning attempt (where a hacker replicates the contents from a legitimate IoT onto a new Raspberry Pi), the trust function considers the IoT as unauthorized. Consequently, it rejects any further OPTEE connection requests from the Normal World. The workflow of the device verification is shown blow: 142 | 143 | ![](doc/img/deviceVerify.png) 144 | 145 | In the event that the server does not receive the encrypted device validation message within the specified timeout period after IoT registration, it flags the IoT device as high risk or compromised. 146 | 147 | 148 | 149 | #### Verification Result Upload and Firmware Attestation Parameters Fetch 150 | 151 | The Trust Client will take 3 Steps to upload the chip verification result to server and fetch the firmware attestation parameters for running the PATT algorithm. The process will follow below work flow: 152 | 153 | ![](doc/img/getPATTparm.png) 154 | 155 | **Step1**: Upon completion of ARM chip UDID verification, the Trust-Zone function generates a 256-bit random number and constructs a verification string incorporating various elements: `message index`, `message element sequence type`, `verification result checksum`, `firmware information`, and the `random number#1` itself. Subsequently, the Trust function encrypts this string using the 2048-bit RSA key stored in the trust storage. The resulting encrypted data is then transmitted to the server-side by using the communication module operating within the Raspberry Pi's Normal World. 156 | 157 | **Step2**: Upon receiving the encrypted data, the server decrypts the message to extract IoT firmware information. It then extracts the `random number #1` from the IoT trust function, appends another 256-bit random number ( `random number #2` ), and includes all PATT execution parameters (such as the random memory address start seed) to generate the firmware attestation request string. This request string is also encrypted using RSA2048 before being dispatched to the Trust Client. 158 | 159 | **Step3**: Upon receiving the encrypted firmware attestation from the Trust Client's communication module, the Trust environment decrypts the message. The Trust function then verifies whether the message contains the random number(`random number #1`) it generated, thereby authenticating the server's identity and thwarting potential replay attacks by hackers attempting to exploit outdated server. 160 | 161 | 162 | 163 | #### Running PATT Firmware Attestation and Uploading the Result 164 | 165 | Once the server side has been verified as correct and trustworthy, the Trust function proceeds to execute the PATT firmware attestation algorithm using the provided parameters. It then sends the memory address to the Trust Client, which retrieves the data from the memory and forwards it to the Trust function. 166 | 167 | Upon completion of the PATT iteration, the final result is combined with `Random Number #2` (generated by the trust server in the Firmware Attestation Parameters Fetch section) to create the result string. The Trust function encrypts this message using RSA-2048 and the trust client's communication module will send it to the trust server. 168 | 169 | On the server side, the Firmware is executed within the IoT emulation environment using the same PATT parameters to obtain the PATT value. Upon receiving and decrypting the result message from the Trust Client, the server verifies that `Random Number #2` matches the one generated in the previous section. It then compares the obtained PATT value with the one calculated locally. If both values match, the IoT device is identified as a "Trust device"; otherwise, it is marked as unauthorized with high security risk. 170 | 171 | The work flow is shown below: 172 | 173 | ![](doc/img/resultUpload.png) 174 | 175 | Remark: The random numbers, labeled as `Random Number #1` and `Random Number #2` ,serve as one-time passwords (OTPs) to establish mutual trust between the IoT device and the server. These OTPs are utilized to authenticate both parties: ensuring that the IoT device can trust the server, and vice versa, that the server can trust the IoT device. The random number generation lib used in the project is : [Linear congruential random generator](https://rosettacode.org/wiki/Linear_congruential_generator) 176 | 177 | 178 | 179 | 180 | --- 181 | ### Program Setup 182 | 183 | ##### Hardware Need 184 | 185 | Raspberry PI 3B+ and the IoT sensor: 186 | 187 | ![](doc/img/Hardware.png) 188 | 189 | #### Detail Configuration Steps 190 | 191 | Follow the steps to build a Trust IoT device: 192 | 193 | ##### Step 1: Prepare Raspberry PI (mode 3) with Raspbian system installed 194 | **Dev Env**: Windows 10/7 195 | 196 | 1. Insert the 16GB SD card in the windows machine and use “SD Memory card formatter” to format the SD card. Download the SD memory card formatter from https://www.sdcard.org/downloads/formatter/ and follow all the default setting. 197 | 2. Download the Raspberry PI Raspbian OS(32-bit) from https://www.raspberrypi.org/downloads/raspbian/ . 198 | 3. Download the FlashFlawless from https://www.balena.io/etcher/ and flash the Raspbian image in to the SD card, put the SD card in Raspberry PI to double confirm the it works normally. 199 | 200 | 201 | 202 | ##### Step 2: Build the Raspbian with Trust Environment enabled 203 | 204 | **Dev Env**: Ubuntu 20.04 205 | 206 | 2.1 Install the packages that need to be installed to start with to make OPTEE: 207 | 208 | ```html 209 | $ sudo apt-get install android-tools-adb android-tools-fastboot autoconf \ 210 | automake bc bison build-essential cscope curl device-tree-compiler \ 211 | expect flex ftp-upload gdisk iasl libattr1-dev libc6:i386 libcap-dev \ 212 | libfdt-dev libftdi-dev libglib2.0-dev libhidapi-dev libncurses5-dev \ 213 | libpixman-1-dev libssl-dev libstdc++6:i386 libtool libz1:i386 make \ 214 | mtools netcat python-crypto python-serial python-wand unzip uuid-dev \ 215 | xdg-utils xterm xz-utils zlib1g-dev 216 | ``` 217 | 2.2 Download and install the Cross Build Toolchain: 218 | 219 | - Lib `AARCH64` & `AARCH32` are both needed, and `AARCH32` version must > 6.0 from `linaro` official web : 220 | https://releases.linaro.org/components/toolchain/binaries/ 221 | - Install the below cross build tool chain: `arm-linux-gnueabihf` and `aarch64-linux-gnu` and set the path in the `cmake` configuration `config.mk` file: 222 | ![](doc/img/toolchaindownload.png) 223 | 224 | 2.3 Download the Raspbian with OPTEE support project and follow the steps in link: https://github.com/benhaz1024/raspbian-tee and set up the config file(`Config.mk`) as: 225 | 226 | ```html 227 | export CROSS_COMPILE := /path/to/your/linaro/aarch32/bin/arm-linux-gnueabihf- 228 | export CROSS_COMPILE_AARCH64 := /path/to/your/linaro/aarch64/bin/aarch64-linux-gnu- 229 | ``` 230 | 231 | 2.4 Install the build tools package: 232 | 233 | ```html 234 | $ sudo apt-install u-boot-tools 235 | ``` 236 | 237 | 2.5 Build and check the result: 238 | 239 | ``` 240 | $ ./prepare-env.sh # if your had download all packages, skip this. 241 | $ make patch # this will patch linux kernel & ATF, if you have done before, skip this. 242 | $ make 243 | ``` 244 | 245 | 246 | 247 | ##### Step 3: Create a new OPTEE Trust Application and Test 248 | 249 | 3.1 Copy the configure OPTEE file to the Raspberry PI Raspbian OS boot folder 250 | 251 | ``` 252 | $ cp ./out/boot/* /media/user/boot 253 | $ sudo cp -r ./out/rootfs/* /media/user/rootfs 254 | ``` 255 | 256 | 3.2 Down load the OPTEE simple trust App example from https://github.com/linaro-swg/hello_world and put the folder in the raspbian-optee folder `dev/teepriv #`. Define the toolchains and environment variables with all 32-bit setting and make: 257 | 258 | ```html 259 | $ export TEEC_EXPORT=$PWD/../optee_client/out/export 260 | $ export HOST_CROSS_COMPILE=$[The arm-linux-gnueabihf position in <2.2>]/aarch32/bin/arm-linux-gnueabihf- 261 | $ export TA_CROSS_COMPILE=$[The arm-linux-gnueabihf position in <2.2>/aarch32/bin/arm-linux-gnueabihf- 262 | $ export TA_DEV_KIT_DIR=$PWD/../optee_os/out/arm/export-ta_arm32 263 | $ make 264 | ``` 265 | 266 | 3.3 Copy the file to the system and test: 1. Copy the normal world program `host\hello_world` to `\media\user\rootfs\bin` folder and copy the secure world file to `ta\7aaaf200-2450-11e4-abe2-0002a5d5c51b.ta` to `\media\user\rootfs\lib\optee_armtz\` folder. File system structure of the Raspbian OS boot up folder should be like below : 267 | 268 | ![](doc/img/filesStructure.png) 269 | 270 | 3.4 Put the SD card into the Raspberry PI and boot up. When you login, test whether the number increase function running in the trust environment work: 271 | 272 | ``` 273 | $ ls /dev/tee* 274 | /dev/tee0 /dev/teepriv0 # this prove tee driver & optee-os works. 275 | $ sudo tee-supplicant & 276 | $ sudo optee_example_hello_world 277 | ``` 278 | 279 | If in the normal word, the trust function send the data back as below which means the trust environment works normally, the OPTEE has been set successfully: 280 | 281 | ![](doc/img/result.png) 282 | 283 | Now we can setup our firmware attestation trust client on the Raspberry PI. 284 | 285 | 286 | 287 | ------ 288 | 289 | #### Program Execution 290 | 291 | #### Build the Trust Client 292 | 293 | ##### Step 1: Setup the device verification constant 294 | 295 | We can modify the OPTEE trust example from https://github.com/linaro-swg/hello_world to build our trust client. Before we compile our trust function, we need to get the Raspberry PI's Arm chip's UDIP, run the below simple python program to get the UDID value: 296 | 297 | ``` 298 | import subprocess 299 | import uuid 300 | 301 | def get_raspberry_pi_uuid(): 302 | # Execute command to get CPU serial number 303 | serial = subprocess.check_output(["cat", "/proc/cpuinfo"]).decode().split("\n")[1].split(":")[1].strip() 304 | 305 | # Generate UUID based on serial number 306 | mac = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) for elements in range(0,2*6,2)][::-1]) 307 | mac = mac.replace("ff", "00") 308 | return mac + "-" + serial 309 | 310 | if __name__ == "__main__": 311 | raspberry_pi_uuid = get_raspberry_pi_uuid() 312 | print("Raspberry Pi UDID:", raspberry_pi_uuid) 313 | ``` 314 | 315 | Ensure you have the necessary permissions to access `/proc/cpuinfo` when running this script. Additionally, note that the CPU serial number may vary depending on the Raspberry Pi model and hardware revisions. 316 | 317 | Then we hard code the Arm Chip UDID as a constant in the trust client's source code file `main.c` After change the host `main.c` and `ta\hello_world_ta.c` program We need to set the trust function's UUID in the file to make ta not conflict with the existed ta, set a UUID in the `ta\Android.mk` and `ta\Makefile` 318 | 319 | ``` 320 | LOCAL_PATH := $(call my-dir) 321 | 322 | local_module_UUID := 7aaaf200-2450-11e4-abe2-0002a5d5c51b.ta 323 | include $(BUILD_OPTEE_MK) 324 | ``` 325 | 326 | To generate the UUID, you can use this online tool: https://www.uuidgenerator.net/ 327 | 328 | 329 | 330 | ##### Step 2: Build the Project and copy the Trust Client in the Raspberry PI SD card 331 | 332 | Define the toolchains and environment variables with all 32bit setting and compile the trust application: 333 | 334 | ``` 335 | export TEEC_EXPORT=$PWD/../optee_client/out/export 336 | export HOST_CROSS_COMPILE=$[The arm-linux-gnueabihf position in <2.2> ]/aarch32/bin/arm-linux-gnueabihf- 337 | export TA_CROSS_COMPILE=$[The arm-linux-gnueabihf position in <2.2> /aarch32/bin/arm-linux-gnueabihf- 338 | export TA_DEV_KIT_DIR=$PWD/../optee_os/out/arm/export-ta_arm32 339 | make 340 | ``` 341 | 342 | Copy the normal world execution file to Raspbian OS bin folder, from `host\hello_world` to `\media\user\rootfs\bin` folder 343 | 344 | Copy the trust function binary file `ta\ 7aaaf200-2450-11e4-abe2-0002a5d5c51b.ta` to `\media\user\rootfs\lib\optee_armtz` 345 | 346 | Boot the Raspberry PI and check the result: 347 | 348 | ![](doc/img/trustclientResult.png) 349 | 350 | 351 | 352 | ##### Step3: Run the Trust Client Normal World Module 353 | 354 | Set the Config file and run the normal world trust client python wrapper: 355 | 356 | ``` 357 | python3 IOT_Att.py 358 | ``` 359 | 360 | #### Run Trust Server 361 | 362 | At server side, run the attestation trust server program 363 | 364 | ``` 365 | python3 firmwTAServer.py 366 | ``` 367 | 368 | 369 | 370 | ------ 371 | 372 | ### Reference 373 | 374 | #### Project Main Technical Feature and Reference 375 | 376 | As introduced in the previous section, the project encompasses several key technical features outlined below: 377 | 378 | **Main Technical Features** 379 | 380 | - Implementation of the Open Portable Trusted Execution Environment (OPTEE) on Raspberry Pi Model 3, establishing Trust Zone functionality within the Raspbian environment. 381 | - Establishment of secure client-server communication utilizing TCP with RSA-2048 encryption/decryption facilitated by Trust_Application. 382 | - Independent calculation of the IoT file's PATT (Platform Attestation Token) value within both the client's Trust Zone and the server component, followed by result comparison. 383 | - Retrieval of the running program's execution information under Raspbian, including relevant file descriptors and memory offsets. 384 | 385 | Related Reference Document or project we followed/used/learn to finished the project : 386 | 387 | - OPTEE Trust-Zone on Raspberry PI Mode 3: OP-TEE > link : https://github.com/OP-TEE/optee_os 388 | - Raspbian OS with OP-TEE Support Configuration: benhaz1024 > link : https://github.com/benhaz1024/raspbian-tee 389 | - Example of build a trust Application: linaro-swg > link : https://github.com/linaro-swg/hello_world 390 | - Physics-based Attestation of Control Systems paper link: https://www.usenix.org/system/files/raid2019-ghaeini.pdf 391 | 392 | ------ 393 | 394 | ### Problem and Solution 395 | 396 | Refer to `doc/ProblemAndSolution.md` 397 | 398 | ------ 399 | 400 | > Last edit by LiuYuancheng(liu_yuan_cheng@hotmail.com) at 30/01/2020, if you have any problem please free to message me. 401 | -------------------------------------------------------------------------------- /doc/2019-05-29_095400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/2019-05-29_095400.png -------------------------------------------------------------------------------- /doc/2019-05-29_113640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/2019-05-29_113640.png -------------------------------------------------------------------------------- /doc/Design_flowChart/exe_flow_step1_init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/exe_flow_step1_init.png -------------------------------------------------------------------------------- /doc/Design_flowChart/exe_flow_step2_keyChange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/exe_flow_step2_keyChange.png -------------------------------------------------------------------------------- /doc/Design_flowChart/exe_flow_step3_swatt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/exe_flow_step3_swatt.png -------------------------------------------------------------------------------- /doc/Design_flowChart/exe_flow_step4_feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/exe_flow_step4_feedback.png -------------------------------------------------------------------------------- /doc/Design_flowChart/optee_client_server_2019_05_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/optee_client_server_2019_05_24.png -------------------------------------------------------------------------------- /doc/Design_flowChart/optee_client_server_2019_05_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/optee_client_server_2019_05_31.png -------------------------------------------------------------------------------- /doc/Design_flowChart/optee_client_server_2019_06_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/optee_client_server_2019_06_15.png -------------------------------------------------------------------------------- /doc/Design_flowChart/optee_client_server_2019_06_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/optee_client_server_2019_06_20.png -------------------------------------------------------------------------------- /doc/Design_flowChart/optee_client_server_2019_07_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Design_flowChart/optee_client_server_2019_07_10.png -------------------------------------------------------------------------------- /doc/Set_Raspberry_PI with Optee.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Set_Raspberry_PI with Optee.docx -------------------------------------------------------------------------------- /doc/Set_Raspberry_PI with Optee.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Set_Raspberry_PI with Optee.pdf -------------------------------------------------------------------------------- /doc/Trust client design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/Trust client design.png -------------------------------------------------------------------------------- /doc/designDoc.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/designDoc.pptx -------------------------------------------------------------------------------- /doc/design_31_05_2019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/design_31_05_2019.png -------------------------------------------------------------------------------- /doc/img/deviceVerify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/deviceVerify.png -------------------------------------------------------------------------------- /doc/img/filesStructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/filesStructure.png -------------------------------------------------------------------------------- /doc/img/generalWorkflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/generalWorkflow.png -------------------------------------------------------------------------------- /doc/img/getPATTparm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/getPATTparm.png -------------------------------------------------------------------------------- /doc/img/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/overview.png -------------------------------------------------------------------------------- /doc/img/resultUpload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/resultUpload.png -------------------------------------------------------------------------------- /doc/img/toolchaindownload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/toolchaindownload.png -------------------------------------------------------------------------------- /doc/img/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/img/workflow.png -------------------------------------------------------------------------------- /doc/position.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/position.png -------------------------------------------------------------------------------- /doc/reuslt_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/reuslt_0.png -------------------------------------------------------------------------------- /doc/testResult_2019-05-31-082728_1920x1080_scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/testResult_2019-05-31-082728_1920x1080_scrot.png -------------------------------------------------------------------------------- /doc/test_result_2019-05-31-093949_1920x1080_scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/test_result_2019-05-31-093949_1920x1080_scrot.png -------------------------------------------------------------------------------- /doc/trustclientResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/trustclientResult.png -------------------------------------------------------------------------------- /doc/worksitualtion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/doc/worksitualtion.png -------------------------------------------------------------------------------- /src/Constants.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # Name: Constants.py 3 | # 4 | # Purpose: The constants which will be used in all the modules are set in 5 | # this module. 6 | # Author: Yuancheng Liu 7 | # 8 | # Created: 2019/07/05 9 | # Copyright: NUS – Singtel Cyber Security Research & Development Laboratory 10 | # License: YC @ NUS 11 | #------------------------------------------------------------------------------ 12 | 13 | LOCAL_IP = '127.0.0.1' 14 | 15 | # Defualt data received buffer size: 16 | BUFFER_SIZE = 1024 17 | 18 | # Data message dump and load tag 19 | CMD_TYPE = 'C'.encode('utf-8') # cmd type message used for contorl. 20 | FILE_TYPE = 'F'.encode('utf-8') # file(bytes) type. 21 | 22 | # Random bytes setting: 23 | RAN_LEN = 4 # The random number/bytes length. 24 | 25 | # SWA_TT setting: 26 | SWATT_ITER = 300 # Swatt calculation iteration count. -------------------------------------------------------------------------------- /src/IOT_Att.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # ----------------------------------------------------------------------------- 3 | # Name: IOT_ATT.py 4 | # 5 | # Purpose: This module is used to provide a SWATT calculator to get the 6 | # input file's swatt value. 7 | # Author: Mohamed Haroon Basheer, edit by LYC 8 | # 9 | # Created: 2019/05/06 10 | # Copyright: NUS – Singtel Cyber Security Research & Development Laboratory 11 | # License: YC @ NUS 12 | # ----------------------------------------------------------------------------- 13 | import os 14 | import random 15 | import string 16 | RAN_FLAG = True #Flag to decide wehter we ues Linear congruential generator(BSD) 17 | DE_PUFF = 154946511204680 18 | 19 | # ----------------------------------------------------------------------------- 20 | # Linear congruential generator(BSD) 21 | def bsd_rand(seed): 22 | """ Reference: https://rosettacode.org/wiki/Linear_congruential_generator """ 23 | def rand(): 24 | rand.seed = (1103515245*rand.seed + 12345) & 0x7fffffff 25 | return rand.seed 26 | rand.seed = seed 27 | return rand 28 | 29 | # ----------------------------------------------------------------------------- 30 | # ----------------------------------------------------------------------------- 31 | class swattCal(object): 32 | """ This module is used to provide a SWATT calculator to get the input file's 33 | swatt value. 34 | """ 35 | # --swattCal------------------------------------------------------------------- 36 | def __init__(self): 37 | self.state = None 38 | self.puffVal = DE_PUFF # DEFAULT PUFF VALUE FOR EACH DEVICE 39 | self.iterM = 0 # swatt iteration time. 40 | 41 | # --swattCal------------------------------------------------------------------- 42 | def bitExtracted(self, number, k, s): 43 | """ Extract specified length of bits.""" 44 | return (((1 << k) - 1) & (number >> (s-1) ) ) 45 | 46 | # --swattCal------------------------------------------------------------------- 47 | def extract_CRpair(self, challenegeStr): 48 | """ Extract challenege response pair for the given key and iteration.""" 49 | #final = self.bitExtracted( <= this caused SWATT val different on different divice. 50 | # get_mac(), 16, 1) # UNIQUE PUFF VALUE FOR EACH DEVICE 51 | final = self.bitExtracted(self.puffVal, 16, 1) 52 | test = [(ord(k) ^ final) for k in challenegeStr] 53 | for idx in range(len(test)-1): 54 | test[idx] ^= test[idx+1] 55 | final += test[idx] << 2 56 | return final 57 | 58 | # --swattCal------------------------------------------------------------------- 59 | def randomChallStr(self, stringLength=10): 60 | """ Generate a random chanllenge string of fixed length.""" 61 | letters = string.ascii_lowercase 62 | return ''.join(random.choice(letters) for i in range(stringLength)) 63 | 64 | # --swattCal------------------------------------------------------------------- 65 | def setKey(self, key, m): 66 | """ RC4 Key Scheduling Algorithm (KSA).""" 67 | j, self.state, = 0, list(range(m)) #[n for n in range(m)]#fill with numnber ranging from 0 to 255 68 | for i in range(m): 69 | j = (j + self.state[i] + key[i % len(key)]) % m 70 | self.state[i], self.state[j] = self.state[j], self.state[i] 71 | 72 | # --swattCal------------------------------------------------------------------- 73 | def setPuff(self, puff): 74 | """ Set the PUFF seed value. puff must be a int.""" 75 | if not isinstance(puff, int): 76 | print("The puff<%s> must be a int type" % puff) 77 | return 78 | self.puffVal = puff 79 | 80 | # --swattCal------------------------------------------------------------------- 81 | def setIterationNum(self, iterationNum): 82 | """ Set the SWATT iteration loop time.""" 83 | if iterationNum <= 0: return 84 | self.iterM = iterationNum 85 | 86 | # --swattCal------------------------------------------------------------------- 87 | def string_to_list(self, inputString): 88 | """Convert a string into a byte list.""" 89 | return [ord(c) for c in inputString] #returns the corresponding unicode integer for the char for ex; a==97 90 | 91 | # --swattCal------------------------------------------------------------------- 92 | def getSWATT(self, challengeStr, m, filePath): 93 | """ Calculate the file swatt value based on the input challenge string 94 | and the iterative count. 95 | """ 96 | if not os.path.exists(filePath): 97 | print("The file <%s> is not exist." % filePath) 98 | return None 99 | with open(filePath, "rb") as fh: 100 | self.setKey(self.string_to_list(challengeStr), m) 101 | cr_response = self.extract_CRpair(challengeStr) # P(C) 102 | #init_cs = cr_response ^ m # sigma(0)<--p(c) xor x0 103 | #pprev_cs = self.state[256] # c[(j-2)mod 8] 104 | #prev_cs = self.state[257] # c[(j-1)mod 8] 105 | #current_cs = self.state[258] # c[j] 106 | pprev_cs, prev_cs, current_cs = self.state[256:259] 107 | init_seed = m # set x(i-1) 108 | # print init_cs.bit_length(),bin(init_cs),init_cs 109 | iterNum = self.iterM if self.iterM > 0 else m 110 | for i in range(iterNum): 111 | swatt_seed = cr_response ^ init_seed # y(i-1)=p(c) xor x(i-1) 112 | # (RC4i<<8)+c[(j-1)mod 8] 113 | Address = (self.state[i] << 8)+prev_cs 114 | #use python PRG to generate address Range 115 | if RAN_FLAG: 116 | randGen = bsd_rand(Address) 117 | Address = randGen() % 128000+1 118 | else: 119 | random.seed(Address) 120 | # YC: why only check 128000 bytes? 121 | Address = random.randint(1, 128000) 122 | # read the EEPROM Memory content 123 | fh.seek(Address) 124 | strTemp = fh.read(1) 125 | # print(Address) 126 | #calculate checksum at the location 127 | # if not strTemp: continue # jump over the empty str "" 128 | num = ord(strTemp) if len(strTemp) != 0 else 0 129 | # current_cs=current_cs+(ord(strTemp[0])^pprev_cs+state[i-1]) 130 | current_cs = current_cs + (num ^ pprev_cs+self.state[i-1]) 131 | # extra seed for the SWATT 132 | init_seed = current_cs+swatt_seed 133 | # update current_cs 134 | current_cs = current_cs >> 1 135 | # update c[(j-2)mod 8] & c[(j-1)mod 8] 136 | pprev_cs = prev_cs 137 | prev_cs = current_cs 138 | #return current_cs 139 | return hex(hash(current_cs)) 140 | 141 | # ----------------------------------------------------------------------------- 142 | # Lib function test case(we will do this in the future.) 143 | def testCase(): 144 | firmwarePath = "".join([os.getcwd(), "\\firmwSign\\firmwareSample"]) 145 | calculator = swattCal() 146 | print("Start test.") 147 | puffVal = DE_PUFF 148 | calculator.setPuff(puffVal) 149 | result = calculator.getSWATT("Testing", 300, firmwarePath) 150 | print(result) 151 | if result == '0x397d' and not RAN_FLAG: 152 | print("SWATT calcualtion test pass.(use defualt random)") 153 | return 154 | elif result == '0x3b0d' and RAN_FLAG: 155 | print("SWATT calcualtion test pass.(use Linear congruential generator random)") 156 | return 157 | else: 158 | print("SWATT calculation test fail.") 159 | 160 | if __name__ == '__main__': 161 | testCase() 162 | 163 | 164 | -------------------------------------------------------------------------------- /src/aesTest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | * MCrypt API available online: 7 | * http://linux.die.net/man/3/mcrypt 8 | * Cmd to install mcrypt under ubuntu: 9 | * sudo apt-get install libmcrypt-dev 10 | * sudo apt-get install ruby-dev 11 | * gem install ruby-mcrypt -v '0.2.0' 12 | * Compile: 13 | * gcc aesTest.c -lmcrypt -lltdl 14 | */ 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | //-------------------------------------------------------------------- 22 | int encrypt( 23 | void* buffer, 24 | int buffer_len, /* Because the plaintext could include null bytes*/ 25 | char* IV, 26 | char* key, 27 | int key_len 28 | ){ 29 | MCRYPT td = mcrypt_module_open("rijndael-256", NULL, "cbc", NULL); 30 | int blocksize = mcrypt_enc_get_block_size(td); 31 | if( buffer_len % blocksize != 0 ){return 1;} 32 | 33 | mcrypt_generic_init(td, key, key_len, IV); 34 | mcrypt_generic(td, buffer, buffer_len); 35 | mcrypt_generic_deinit (td); 36 | mcrypt_module_close(td); 37 | 38 | return 0; 39 | } 40 | 41 | //-------------------------------------------------------------------- 42 | int decrypt( 43 | void* buffer, 44 | int buffer_len, 45 | char* IV, 46 | char* key, 47 | int key_len 48 | ){ 49 | MCRYPT td = mcrypt_module_open("rijndael-256", NULL, "cbc", NULL); 50 | int blocksize = mcrypt_enc_get_block_size(td); 51 | if( buffer_len % blocksize != 0 ){return 1;} 52 | 53 | mcrypt_generic_init(td, key, key_len, IV); 54 | mdecrypt_generic(td, buffer, buffer_len); 55 | mcrypt_generic_deinit (td); 56 | mcrypt_module_close(td); 57 | 58 | return 0; 59 | } 60 | 61 | //-------------------------------------------------------------------- 62 | void display(char* ciphertext, int len){ 63 | int v; 64 | for (v=0; v 3 | #include 4 | #include 5 | #include 6 | #include 7 | #define MAX 80 8 | #define PORT 5005 9 | #define SA struct sockaddr 10 | int func(int sockfd) 11 | { 12 | char buff[MAX]; 13 | int n; 14 | printf("wait for server response\n"); 15 | bzero(buff, sizeof(buff)); 16 | printf("Enter the string : \n"); 17 | n = 0; 18 | buff[0] = 'F'; 19 | buff[1] = 'D'; 20 | sleep(1); 21 | write(sockfd, buff, sizeof(buff)); 22 | bzero(buff, sizeof(buff)); 23 | read(sockfd, buff, sizeof(buff)); 24 | return atoi(buff); 25 | } 26 | 27 | int main() 28 | { 29 | int sockfd, connfd; 30 | int num; 31 | struct sockaddr_in servaddr, cli; 32 | 33 | // socket create and varification 34 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 35 | if (sockfd == -1) { 36 | printf("socket creation failed...\n"); 37 | exit(0); 38 | } 39 | else 40 | printf("Socket successfully created..\n"); 41 | bzero(&servaddr, sizeof(servaddr)); 42 | 43 | // assign IP, PORT 44 | servaddr.sin_family = AF_INET; 45 | servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 46 | servaddr.sin_port = htons(PORT); 47 | 48 | // connect the client socket to server socket 49 | if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) { 50 | printf("connection with the server failed...\n"); 51 | exit(0); 52 | } 53 | else 54 | printf("connected to the server..\n"); 55 | 56 | // function for chat 57 | num = func(sockfd); 58 | printf("The challenge numer is %d \n", num); 59 | char replay[10]; 60 | sprintf(replay, "%d", num); 61 | write(sockfd, replay, sizeof(replay)); 62 | 63 | // close the socket 64 | close(sockfd); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/fileAccess.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAXCHAR 1000 4 | int main() { 5 | 6 | char iv[32]; 7 | memset(iv, 0x5a, sizeof(iv)); 8 | printf("This is vi <%s> \n", iv); 9 | 10 | FILE *fp; 11 | char str[MAXCHAR]; 12 | char* filename = "input.txt"; 13 | fp = fopen(filename, "r"); 14 | if (fp == NULL){ 15 | printf("Could not open file %s",filename); 16 | return 1; 17 | } 18 | while (fgets(str, MAXCHAR, fp) != NULL) 19 | printf("%s \n", str); 20 | int num = atoi(str); 21 | fclose(fp); 22 | printf("K %d", num); 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/fileSwatt.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | /* Name: fileSwatt.c 6 | Purpose: This module is used to provide a SWATT calculator to get the 7 | input file's swatt value. 8 | Author: Yuancheng Liu 9 | Created: 2019/05/28 10 | Copyright: NUS – Singtel Cyber Security Research & Development Laboratory 11 | License: YC @ NUS 12 | */ 13 | 14 | 15 | int bsd_rand(); 16 | int rseed = 0; 17 | char gv_flph[80]; // file we are going to check. 18 | int debug = 0; // debug level. 19 | 20 | //------------------------------------------------------------------------------- 21 | /* Use Linear congruential generator(BSD) as the random number calculation result 22 | is different on different plantform or use differnt compiler. 23 | */ 24 | void bsd_srand(int x) 25 | { 26 | rseed = x; 27 | } 28 | 29 | #define BSD_RAND_MAX ((1U << 31) - 1) 30 | 31 | int bsd_rand() 32 | { 33 | return rseed = (rseed * 1103515245 + 12345) & BSD_RAND_MAX; 34 | } 35 | 36 | //------------------------------------------------------------------------------- 37 | 38 | /*read file block*/ 39 | char *readFileBytes(const char *name) 40 | { 41 | FILE *fl = fopen(name, "r"); 42 | fseek(fl, 0, SEEK_END); 43 | long len = ftell(fl); 44 | len = 128000; // Haroon use the fixed block size in his program 45 | char *ret = malloc(len); 46 | fseek(fl, 0, SEEK_SET); 47 | fread(ret, 1, len, fl); 48 | fclose(fl); 49 | return ret; 50 | } 51 | 52 | //------------------------------------------------------------------------------- 53 | int getSWATT(char challengeB[], int cSize, int m, int n, int puff) 54 | { 55 | // challengeB[] : a random challenge string 56 | // cSize : challenge string size 57 | // (m, n) : m-swap list size(must >=260), n-sample times in one block. 58 | 59 | strncpy(gv_flph, "firmwareSample", 16); 60 | char *ret = readFileBytes(gv_flph); 61 | char *challenge = challengeB; 62 | int keylen = cSize; 63 | // reference func: string_to_list 64 | int challengeInt[keylen]; 65 | for (int t = 0; t < keylen; t++) 66 | { 67 | challengeInt[t] = (int)challenge[t]; 68 | if (debug == 1) 69 | printf(":<%d>\n", challengeInt[t]); 70 | } 71 | // reference func: setKey 72 | int state[m]; 73 | for (int i = 0; i < m; i++) 74 | { 75 | state[i] = i; 76 | } 77 | int j = 0; 78 | for (int i = 0; i < m; i++) 79 | { 80 | j = (j + state[i] + challengeInt[i % keylen]) % m; 81 | int tmp = state[i]; 82 | state[i] = state[j]; 83 | state[j] = tmp; 84 | } 85 | // reference func: extract_CRpair 86 | int s = 1; 87 | int k = 16; 88 | int final = ((1 << k) - 1) & (puff >> (s - 1)); 89 | if (debug == 1) 90 | printf("Extract bytes final:<%d>\n", final); 91 | int test[keylen]; 92 | for (int t = 0; t < keylen; t++) 93 | test[t] = challengeInt[t] ^ final; 94 | for (int t = 0; t < keylen-1; t++) 95 | final += test[t] << 2; 96 | // main loop of the SWATT 97 | int cr_response = final; 98 | int pprev_cs = state[256]; 99 | int prev_cs = state[257]; 100 | int current_cs = state[258]; 101 | int init_seed = m; 102 | int swatt_seed = 0; 103 | for (int i = 0; i < n; i++) 104 | { 105 | swatt_seed = cr_response ^ init_seed; 106 | int Address = (state[i] << 8) + prev_cs; 107 | bsd_srand(Address); 108 | Address = bsd_rand() % 128000 + 1; 109 | char strTemp = ret[Address]; 110 | if (debug == 1) 111 | { 112 | printf("R2:<%c>\n", strTemp); 113 | printf("R3:<%d>\n", current_cs); 114 | printf("R4:<%d>\n", pprev_cs); 115 | } 116 | int num = i - 1; 117 | if (num < 0) 118 | num = m - 1; 119 | current_cs = current_cs +((int)strTemp ^ pprev_cs + state[num]); 120 | init_seed = current_cs+swatt_seed; 121 | current_cs = current_cs >> 1; 122 | pprev_cs = prev_cs; 123 | prev_cs = current_cs; 124 | } 125 | return current_cs; 126 | } 127 | 128 | //------------------------------------------------------------------------------- 129 | //------------------------------------------------------------------------------- 130 | int main(void) 131 | { 132 | int m = 300; 133 | int n = 100; 134 | int puff = 1549465112; // program unique id/computer MAC addr. 135 | char challenge[] = "Testing"; 136 | int number = getSWATT(challenge, 7, m, n, puff); 137 | printf("File swatt value :<%d>\n", number); 138 | if(number == 4519){ 139 | printf("Test case passed!\n"); 140 | } 141 | else{ 142 | printf("Test case Fail, please check the or the program!\n"); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/firmwGlobal.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Name: firmwGlobal.py 3 | # 4 | # Purpose: This module is used set the Local config file as global value 5 | # which will be used in the other modules. 6 | # Author: Yuancheng Liu 7 | # 8 | # Created: 2019/05/17 9 | # Copyright: NUS – Singtel Cyber Security Research & Development Laboratory 10 | # License: YC @ NUS 11 | #----------------------------------------------------------------------------- 12 | import os 13 | 14 | dirpath = os.getcwd() 15 | print("firmwGlobal: Current working directory is : %s" %dirpath) 16 | 17 | APP_NAME = 'XAKA firmware sign tool_v1.1' 18 | 19 | # Server ip and port for connection: 20 | LOCAL_IP = '127.0.0.1' 21 | SITCP_PORT = 5005 # port for firmware sign request. 22 | RGTCP_PORT = 5006 # port for sensor registration request. 23 | TCTCP_PORT = 5007 # port for trustClient executable file verification. 24 | 25 | # Firmware sign server choice: 26 | SI_SERVER_CHOICE = { 27 | "LocalDefault [127.0.0.1]" : ('127.0.0.1', SITCP_PORT), 28 | "Server_1 [192.168.0.100]" : ('192.168.0.100', SITCP_PORT), 29 | "Server_2 [192.168.0.101]" : ('192.168.0.101', SITCP_PORT) 30 | } 31 | 32 | #UI window ICON. 33 | ICON_PATH = "".join([dirpath, "\\firmwSign\\singtelIcon.ico"]) 34 | 35 | # Defualt firmware path 36 | DEFUALT_FW = "".join([dirpath, "\\firmwSign\\firmwareSample"]) 37 | 38 | # RSA encryp/decrypt setting: 39 | RSA_ENCODE_MODE = 'base64'# or 'hex' Sign encode mode. 40 | RSA_UNLOCK = "Anything for 30-day trial" # RSA unblock periodic 41 | RSA_CERT_PATH = "".join([dirpath, "\\firmwSign\\publickey.cer"]) 42 | RSA_PRI_PATH = "".join( [dirpath, "\\firmwSign\\privatekey.pem"]) # RSA pricate key 43 | 44 | # Recieved private key/sert from the server. 45 | RECV_CERT_PATH = "".join([dirpath, "\\firmwSign\\receivered.cer"]) 46 | RECV_PRIK_PATH = "".join([dirpath, "\\firmwSign\\receivered.pem"]) 47 | 48 | # sqlite database file. 49 | DB_PATH = "".join([dirpath, "\\firmwSign\\firmwDB.db"]) 50 | 51 | # TSL/SSL communication setting: 52 | CA_PATH = "".join([dirpath, "\\firmwSign\\testCert\\CA.cert"]) 53 | # Client SSL private key and certificate. 54 | CSSL_PRIK_PATH = "".join([dirpath, "\\firmwSign\\testCert\\client.pkey"]) 55 | CSSL_CERT_PATH = "".join([dirpath, "\\firmwSign\\testCert\\client.cert"]) 56 | # Server SSL pricate key and certificate 57 | SSSL_PRIK_PATH = "".join([dirpath, "\\firmwSign\\testCert\\server.pkey"]) 58 | SSSL_CERT_PATH = "".join([dirpath, "\\firmwSign\\testCert\\server.cert"]) 59 | 60 | # firmware sign pricate key and certificate 61 | SIGN_CERT_PATH = "".join([dirpath, "\\firmwSign\\testCert\\certificate.pem"]) 62 | SIGN_PRIV_PATH = "".join([dirpath, "\\firmwSign\\testCert\\private_key.pem"]) 63 | -------------------------------------------------------------------------------- /src/firmwMsgMgr.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Name: firmwMsgMgr.py 3 | # 4 | # Purpose: This module is used to create a message manager to 'dump' the 5 | # user message to a json string/bytes data and 'load' back to the 6 | # orignal data.(The detail usage you can follow the example in the 7 | # testCase, all the bytes type data in the json will be convert to 8 | # hex format.) 9 | # Author: Yuancheng Liu 10 | # 11 | # Created: 2019/05/09 12 | # Copyright: NUS – Singtel Cyber Security Research & Development Laboratory 13 | # License: YC @ NUS 14 | #----------------------------------------------------------------------------- 15 | 16 | import os 17 | import json 18 | import time 19 | from Constants import CMD_TYPE, FILE_TYPE, RAN_LEN 20 | 21 | # Message dump action type: 22 | # CR - Connection request 23 | # HB - Heart beat (feedback) 24 | # LI1 - Login request step 1 [Username + random1(client->sever)] 25 | # LR1 - Login response 1 [random1 + random2(client<-server)] 26 | # LI2 - Login request step2 [random2 + password] 27 | # LR2 - Login response 2 [Challenge for SWATT] 28 | # LO - Logout requst. 29 | # CF - Certificate file fetch. 30 | # SR - Signature response 31 | # RG - Sensor Gateway registration. 32 | 33 | #----------------------------------------------------------------------------- 34 | #----------------------------------------------------------------------------- 35 | class msgMgr(object): 36 | """ Create a message manager to dump the user message to a json string/bytes 37 | data and load back to orignal data. 38 | """ 39 | def __init__(self, parent): 40 | self.parent = parent 41 | 42 | #--msgMgr---------------------------------------------------------------------- 43 | def dumpMsg(self, action=None, dataArgs=None): 44 | """ Create the bytes message base on the action for sending to server. 45 | returned the created message or None if the action is invalid. 46 | Message sample: 'C'.encode('utf-8')+dict{'act': str, [data]} 47 | """ 48 | datab = None 49 | if action == 'CR': 50 | datab = self._createCRmsg() 51 | elif action == 'HB': 52 | lastAct, state = dataArgs 53 | datab = self._createHBmsg(lastAct, state) 54 | elif action == 'LI1': 55 | datab = self._createLI1msg(dataArgs) 56 | elif action == 'LI2': 57 | datab = self._createLI2msg(dataArgs) 58 | elif action == 'LR1': 59 | datab = self._createLR1msg(dataArgs) 60 | elif action == 'LR2': 61 | datab = self._createLR2msg(dataArgs) 62 | elif action == 'CF': 63 | datab = self._createCFmsg() 64 | elif action == 'FL': 65 | datab = self._createFLmsg(dataArgs) 66 | elif action == 'SR': 67 | datab = self._createSRmsg(dataArgs) 68 | elif action == 'LO': 69 | datab = self._createLOmsg() 70 | elif action == 'RG': 71 | datab = self._createRGmsg(dataArgs) 72 | else: 73 | print("The input action <%s> is invlid" %str(action)) 74 | return datab 75 | 76 | #--msgMgr---------------------------------------------------------------------- 77 | def loadMsg(self, msg): 78 | """ Convert the dumpped message back to orignal data.""" 79 | tag = msg[0:1] # Take out the tag data. 80 | data = json.loads(msg[1:]) if tag == CMD_TYPE else msg[1:] 81 | return data 82 | 83 | #--msgMgr---------------------------------------------------------------------- 84 | def _createCRmsg(self): 85 | """ Create the connection request message.""" 86 | msgDict = { 87 | "act" : 'CR', 88 | "time" : time.time() 89 | } 90 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 91 | 92 | #--msgMgr---------------------------------------------------------------------- 93 | def _createHBmsg(self, lastAct, state): 94 | """ Create a heartbeat function to handle the cmd execution response.""" 95 | if isinstance(state, bytes): state = state.hex() 96 | msgDict = { 97 | "act" : 'HB', 98 | "lAct" : lastAct, # last received action 99 | "state" : state # last action execution state/data 100 | } 101 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 102 | 103 | #--msgMgr---------------------------------------------------------------------- 104 | def _createLI1msg(self, userName): 105 | """ Create login step1 msg: send userName + randomNum1.""" 106 | if userName is None or not isinstance(userName, str): return None 107 | randomB = os.urandom(RAN_LEN) 108 | msgDict = { 109 | "act" : 'LI1', 110 | "user" : userName.strip(), 111 | "random1" : randomB.hex() 112 | } 113 | data = CMD_TYPE + json.dumps(msgDict).encode('utf-8') 114 | return (data, randomB) 115 | 116 | #--msgMgr---------------------------------------------------------------------- 117 | def _createLI2msg(self, args): 118 | """ Create login step2 msg: send randomNum2 + password.""" 119 | (random2, password) = args 120 | msgDict = { 121 | "act" : 'LI2', 122 | "random2" : random2, 123 | "password" : password 124 | } 125 | data = CMD_TYPE + json.dumps(msgDict).encode('utf-8') 126 | return data 127 | 128 | #--msgMgr---------------------------------------------------------------------- 129 | def _createLR1msg(self, args): 130 | """ Create login step1 response: randomNum1 + randomNum2.""" 131 | (randomB, state) = args 132 | randomB2 = os.urandom(RAN_LEN) 133 | msgDict = { 134 | "act" : 'LR1', 135 | "state" : state, 136 | "random1" : randomB, 137 | "random2" : randomB2.hex() 138 | } 139 | data = CMD_TYPE + json.dumps(msgDict).encode('utf-8') 140 | return (data, randomB2) 141 | 142 | #--msgMgr---------------------------------------------------------------------- 143 | def _createLR2msg(self, challengeStr): 144 | """ Create login step1 response: SWATT_challenge string. """ 145 | if challengeStr is None or not isinstance(challengeStr, str): return None 146 | msgDict = { 147 | "act" : 'LR2', 148 | "challenge" : challengeStr.strip(), 149 | } 150 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 151 | 152 | #--msgMgr---------------------------------------------------------------------- 153 | def _createLOmsg(self): 154 | """ Create a log out requst.""" 155 | msgDict = { 156 | "act" : 'LO', 157 | "time" : time.time() 158 | } 159 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 160 | 161 | #--msgMgr---------------------------------------------------------------------- 162 | def _createCFmsg(self): 163 | """ Create a certificate file fetch requset. """ 164 | msgDict = { 165 | "act" : 'CF', 166 | "time" : time.time() 167 | } 168 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 169 | 170 | #--msgMgr---------------------------------------------------------------------- 171 | def _createSRmsg(self, args): 172 | """ Create a sign response message.(Sign client->Sever) """ 173 | if len(args) != 7: 174 | print("Msgmgr: The required element missing in the RS msg<%s>" %str(args)) 175 | return None 176 | sensorId, signerId, swatt, date, typeS, versionS, signS = args 177 | msgDict = { 178 | "act" : 'SR', 179 | "id" : sensorId, # sensor ID 180 | "sid" : signerId, # Signer factory user ID. 181 | "swatt" : swatt, # File SWATT value. 182 | "date" : date, # time stamp. 183 | "tpye" : typeS, # Sensor type. 184 | "version" : versionS, # Sensor version. 185 | "signStr" : signS.hex() # Signature string. 186 | } 187 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 188 | 189 | #--msgMgr---------------------------------------------------------------------- 190 | def _createRGmsg(self, args): 191 | """ Create a sensor registration message.(Sensor client -> Server)""" 192 | if len(args) != 4: 193 | print("Msgmgr: The required element missing in RG msg <%s>" %str(args)) 194 | return None 195 | sensorId, sensorType, fwVersion, signS = args 196 | if isinstance(signS, bytes): signS = signS.hex() 197 | msgDict = { 198 | "act" : 'RG', 199 | "id" : sensorId, # sensor ID 200 | "type" : sensorType, # Signer factory user ID. 201 | "time" : time.time(), 202 | "version" : fwVersion, # Sensor version. 203 | "signStr" : signS # Signature string. 204 | } 205 | return CMD_TYPE + json.dumps(msgDict).encode('utf-8') 206 | 207 | #--msgMgr---------------------------------------------------------------------- 208 | def _createFLmsg(self, bytesData): 209 | """ Create the file message.""" 210 | return FILE_TYPE + bytesData 211 | 212 | #----------------------------------------------------------------------------- 213 | #----------------------------------------------------------------------------- 214 | def testCase(): 215 | testMsgr = msgMgr(None) 216 | print("Start the message process test:") 217 | pCount = 0 # test fail count. 218 | # 219 | tPass = True 220 | print("Connection request test:") 221 | msg = testMsgr.dumpMsg(action='CR') 222 | msgDict = testMsgr.loadMsg(msg) 223 | tPass = tPass and msgDict['act'] == 'CR' 224 | tPass = tPass and 'time' in msgDict.keys() 225 | if tPass: 226 | print("Connection request test pass.") 227 | else: 228 | pCount += 1 229 | print("Connection request test fail.") 230 | # 231 | tPass = True 232 | print("HearBeat message test:") 233 | msg = testMsgr.dumpMsg(action='HB', dataArgs=('HB', 1)) 234 | msgDict = testMsgr.loadMsg(msg) 235 | tPass = tPass and msgDict['act'] == 'HB' 236 | tPass = tPass and msgDict['lAct'] == 'HB' 237 | tPass = tPass and msgDict['state'] == 1 238 | if tPass: 239 | print("HeartBeat request test pass.") 240 | else: 241 | pCount += 1 242 | print("HeartBeat request test fail.") 243 | # 244 | tPass = True 245 | print("Login user request test:") 246 | msg, val = testMsgr.dumpMsg(action='LI1', dataArgs='user') 247 | msgDict = testMsgr.loadMsg(msg) 248 | tPass = tPass and msgDict['act'] == 'LI1' 249 | tPass = tPass and msgDict['user'] == 'user' 250 | tPass = tPass and val.hex() == msgDict['random1'] 251 | if tPass: 252 | print("Login user request test pass") 253 | else: 254 | pCount += 1 255 | print("Login user request test fail") 256 | # 257 | tPass = True 258 | print("Login password request test:") 259 | msg = testMsgr.dumpMsg(action='LI2', dataArgs=('1234', 'password')) 260 | msgDict = testMsgr.loadMsg(msg) 261 | tPass = tPass and msgDict['act'] == 'LI2' 262 | tPass = tPass and msgDict['random2'] == '1234' 263 | tPass = tPass and msgDict['password'] == 'password' 264 | if tPass: 265 | print("Login password request test pass") 266 | else: 267 | pCount += 1 268 | print("Login password request test fail") 269 | # 270 | tPass = True 271 | print("Login user response test:") 272 | msg, val = testMsgr.dumpMsg(action='LR1', dataArgs=('1234', 1)) 273 | msgDict = testMsgr.loadMsg(msg) 274 | tPass = tPass and msgDict['act'] == 'LR1' 275 | tPass = tPass and msgDict['state'] == 1 276 | tPass = tPass and msgDict['random1'] == '1234' 277 | tPass = tPass and msgDict['random2'] == val.hex() 278 | if tPass: 279 | print("Login user response test pass") 280 | else: 281 | pCount += 1 282 | print("Login suer response test fail") 283 | # 284 | tPass = True 285 | print("Login password response test:") 286 | msg = testMsgr.dumpMsg(action='LR2', dataArgs='challenge') 287 | msgDict = testMsgr.loadMsg(msg) 288 | tPass = tPass and msgDict['act'] == 'LR2' 289 | tPass = tPass and msgDict['challenge'] == 'challenge' 290 | if tPass: 291 | print("Login password response test pass") 292 | else: 293 | pCount += 1 294 | print("Login password response test fail") 295 | # 296 | tPass = True 297 | print("Certificate fetch request test:") 298 | msg = testMsgr.dumpMsg(action='CF') 299 | msgDict = testMsgr.loadMsg(msg) 300 | tPass = tPass and msgDict['act'] == 'CF' 301 | tPass = tPass and msgDict['time'] 302 | if tPass: 303 | print("Certificate fetch test pass") 304 | else: 305 | pCount += 1 306 | print("Certificate fetch test fail") 307 | # 308 | tPass = True 309 | print("Logout request test:") 310 | msg = testMsgr.dumpMsg(action='LO') 311 | msgDict = testMsgr.loadMsg(msg) 312 | tPass = tPass and msgDict['act'] == 'LO' 313 | tPass = tPass and msgDict['time'] 314 | if tPass: 315 | print("Logout requset test pass") 316 | else: 317 | pCount += 1 318 | print("Logout requset test fail") 319 | # 320 | tPass = True 321 | print("Sensor registoration request test:") 322 | msg = testMsgr.dumpMsg(action='RG', dataArgs =(100, 'XKAK_PPL_COUNT', '1.01', 'ThisIsTheSimapleSigatureString')) 323 | msgDict = testMsgr.loadMsg(msg) 324 | tPass = tPass and msgDict['act'] == 'RG' 325 | tPass = tPass and msgDict['id'] == 100 326 | tPass = tPass and msgDict['time'] 327 | tPass = tPass and msgDict['type'] == 'XKAK_PPL_COUNT' 328 | tPass = tPass and msgDict['signStr'] == 'ThisIsTheSimapleSigatureString' 329 | if tPass: 330 | print("Sensor resigtor requset test pass") 331 | else: 332 | pCount += 1 333 | print("Sensor resigtor requset test fail") 334 | 335 | print("Test done total <%s> fail" %str(pCount)) 336 | 337 | #----------------------------------------------------------------------------- 338 | if __name__ == '__main__': 339 | testCase() 340 | -------------------------------------------------------------------------------- /src/firmwTAServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #----------------------------------------------------------------------------- 3 | # Name: firmwTAServer.py 4 | # 5 | # Purpose: Trust application TCP server. Send the AES 256 session key and 6 | # swatt challenge string to the trust app and decode the response 7 | # swatt value.(AES256) 8 | # Author: Yuancheng Liu 9 | # 10 | # Created: 2019/05/08 11 | # Copyright: NUS – Singtel Cyber Security Research & Development Laboratory 12 | # License: YC @ NUS 13 | #----------------------------------------------------------------------------- 14 | import socket 15 | import IOT_Att as SWATT 16 | import firmwMsgMgr 17 | import firmwGlobal as gv 18 | 19 | # if got error install Crypto please usethis: 20 | # >> pip install pycryptodome 21 | # from Crypto.Cipher import AES #Works 22 | # or 23 | # >> pip install pycryptodomex 24 | # from Cryptodome.Cipher import AES 25 | # For python3 the package name is now pycryptodome or pycryptodomex 26 | # If you need compatibility with your project with Python2 use pycryptodome 27 | # or else use pycryptodomex which is a library independent of the old PyCrypto. 28 | # https://stackoverflow.com/questions/51824628/modulenotfounderror-no-module-named-crypto-error 29 | from Crypto.Cipher import AES 30 | 31 | LOCAL_BIND_IP = '0.0.0.0' 32 | DEFUALT_CH_LEN = 7 # default challenge we are going to use. 33 | 34 | # AES parameters: 35 | DE_BUFFER_SIZE = 32 # defialt AES cipher buffer size. 36 | DE_AES_KEY = bytes([0xa5]*32) # default AES Key 37 | DE_AES_IV = bytes([0xa5]*16) # default AES IV 38 | #----------------------------------------------------------------------------- 39 | #----------------------------------------------------------------------------- 40 | class AESCipher: 41 | """ AES256 bytes data cipher, edit from the github project: 42 | https://gist.github.com/swinton/8409454 43 | """ 44 | 45 | def __init__(self, key, iv, mode): 46 | self.iv = iv 47 | self.key = key 48 | self.cipherMode = mode 49 | 50 | def updateParam(self, key=None, iv=None, mode=None): 51 | if iv: self.iv = iv 52 | if key: self.key = key 53 | if mode:self.cipherMode = mode 54 | 55 | def encrypt(self, raw): 56 | #iv = bytes([0xa5]*16) 57 | #cipher = AES.new(self.key, AES.MODE_CBC, iv ) 58 | cipher = AES.new(self.key, self.cipherMode, self.iv) 59 | return cipher.encrypt(raw) 60 | 61 | def decrypt(self, enc): 62 | #iv = bytes([0xa5]*16) 63 | #cipher = AES.new(self.key, AES.MODE_CBC, iv ) 64 | cipher = AES.new(self.key, self.cipherMode, self.iv) 65 | return cipher.decrypt(enc) 66 | 67 | #----------------------------------------------------------------------------- 68 | #----------------------------------------------------------------------------- 69 | class firmwTAServer(object): 70 | """ Trust application TCP server. Send the AES 256 session key and 71 | swatt challenge string to the trust app and decode the response 72 | swatt value.(AES256) 73 | """ 74 | def __init__(self): 75 | """ init the TCP socket, SWATT calculator and AES cipher.""" 76 | try: 77 | # Init the TCP server. 78 | self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 79 | self.server.bind((LOCAL_BIND_IP, gv.TCTCP_PORT)) # port 5007 80 | self.server.listen(1) # max backlog of connections 81 | print('TA_Server: inited and listen on {}:{}'.format( 82 | LOCAL_BIND_IP, gv.TCTCP_PORT)) 83 | # Init the SWATT calculator. 84 | self.challengeStr = "" 85 | self.challengeLen = DEFUALT_CH_LEN 86 | self.challengeB = bytes([0x5a]*32) # defualt challenge bytes list. 87 | self.swattHd = SWATT.swattCal() 88 | self.swattHd.setPuff(SWATT.DE_PUFF) 89 | # Init the message manager. 90 | self.msgMgr= firmwMsgMgr.msgMgr(self) # create the message manager. 91 | # Fixed AES256 key which is same as the trust APP's TA 92 | self.key = DE_AES_KEY # Comm session key after connection authorization. 93 | # Init the AES cipher 94 | self.cipher = AESCipher(DE_AES_KEY, DE_AES_IV, AES.MODE_CBC) 95 | # Init checking file name/path 96 | self.filename = "ran" 97 | 98 | print("TA_Server: Init finished.") 99 | except Exception as e: 100 | print("TA_Server: Init failed, termiate the program. Exception: %s" %str(e)) 101 | exit() 102 | 103 | #--firmwTAServer--------------------------------------------------------------- 104 | def exchangeSessionKey(self, client_socket, key_v): 105 | """ Create the random 32bytes AES256 encryption/decryption session key, 106 | encrypted the session key with defualt key and send to the client. 107 | session key: 32bytes list will all lower case letters. 108 | """ 109 | print("TA_Server: user comm key version <%s>." % key_v) 110 | self.cipher.updateParam( 111 | key=DE_AES_KEY, iv=DE_AES_IV, mode=AES.MODE_CBC) 112 | sessionKey = self.swattHd.randomChallStr(stringLength=32) 113 | print("Send the session key used to encryption/decryptiuon: <%s>" % sessionKey) 114 | self.key = bytes([ord(n) for n in sessionKey]) 115 | self.encrypted = self.cipher.encrypt(self.key) 116 | client_socket.send(self.encrypted) 117 | request = client_socket.recv(DE_BUFFER_SIZE) 118 | data = self.msgMgr.loadMsg(request) 119 | print('TA_Server: Get client session key set message: {}'.format(data)) 120 | # Switch to use the new session key. 121 | self.cipher.updateParam(key=self.key, iv=DE_AES_IV, mode=AES.MODE_CBC) 122 | 123 | #--firmwTAServer--------------------------------------------------------------- 124 | def handleClientConnection(self, client_socket): 125 | """ Handle the connection request of the TCP client.""" 126 | request = client_socket.recv(DE_BUFFER_SIZE) 127 | print ('TA_Server: Get connection request message: {}'.format(request)) 128 | data = self.msgMgr.loadMsg(request) 129 | # Set the challenge string based on the request. 130 | key_v, gw_id, pro_v, c_len, m, n, _ = str(data)[2:].split(';') 131 | #print((key_v, gw_id, pro_v, c_len, m, n)) 132 | print(" - trusClient key version <%s>." % key_v) 133 | print(" - trusClient gateway id <%s>." % gw_id) 134 | print(" - trusClient program version <%s>." % pro_v) 135 | print(" - trusClient challenge len <%s>." % c_len) 136 | print(" - trusClient Swatt (m,n) len <%s>." % str((m, n))) 137 | 138 | # Set up and init AES connunication session key. 139 | self.exchangeSessionKey(client_socket, key_v) 140 | 141 | # Verify the file swatt value with the trustClient. 142 | resp = self.swattVerify(client_socket, c_len, m , n) 143 | 144 | # Send the verification result to the client and fetch the program running information. 145 | self.challengeB = bytes([ord(resp)]+[ord(n) for n in self.challengeStr] + [ 146 | ord('Z')]*(DE_BUFFER_SIZE-self.challengeLen-1)) 147 | self.encrypted = self.cipher.encrypt(self.challengeB) 148 | client_socket.send(self.encrypted) 149 | request = client_socket.recv(1024) 150 | msg = str(self.msgMgr.loadMsg(request))[2:].split(';') 151 | # Show the feedback result. 152 | fbMsg = "The program is not running." if msg[0] == '' else '\n'.join(msg[:-1]) 153 | print(fbMsg) 154 | print("Finished the verification ") 155 | 156 | #--firmwTAServer--------------------------------------------------------------- 157 | def setSwattChalStr(self, challengeStr, challengelen=None): 158 | """ Pad the input SWATT challengeStr""" 159 | if len(challengeStr) < self.challengeLen: 160 | print("TA_Server: The challenge string is not long enough.") 161 | return 162 | self.challengeLen = int(challengelen) if challengelen else DEFUALT_CH_LEN 163 | self.challengeStr = challengeStr[:self.challengeLen] 164 | # pad the input challenge string to bytes data with b'Z'. 165 | self.challengeB = bytes( 166 | [ord(n) for n in self.challengeStr] + [ord('Z')]*(DE_BUFFER_SIZE-self.challengeLen)) 167 | 168 | #--firmwTAServer--------------------------------------------------------------- 169 | def swattVerify(self, client_socket, c_len, m, n): 170 | """ Generate the random Swatt-challenge string based on the c_len, send 171 | AES encrypted challenge string and calcualte the local file's swatt 172 | value, then verfiy the feedback swatt data from the client. 173 | """ 174 | # Generate the new SWATT random challenge string and send to client. 175 | swattStr = self.swattHd.randomChallStr(stringLength=int(c_len)) 176 | self.setSwattChalStr(swattStr, challengelen=int(c_len)) 177 | print('TA_Server: Send the encrypted challenge string <%s> as bytes list.' % 178 | self.challengeStr) 179 | self.encrypted = self.cipher.encrypt(self.challengeB) 180 | client_socket.send(self.encrypted) 181 | self.swattHd.setIterationNum(int(n)) 182 | # Calcualte the SWATT value for verification. 183 | result = self.swattHd.getSWATT( 184 | self.challengeStr, int(m), self.filename) 185 | result = int(result, 0) # hex string to int. 186 | print('TA_Server: SWATT result<%s>' % str(result)) 187 | request = client_socket.recv(DE_BUFFER_SIZE) 188 | data = self.cipher.decrypt(request) 189 | data = str(data).split('x0')[0] 190 | print('TA_Server: Received the SWATT<%s>' % str(data)) 191 | resp = 'T' 192 | if int(data[2:-1]) == result: 193 | print("The file Swatt value has been verified.") 194 | else: 195 | print("The value are differet:"+str((data[2:-1], result))) 196 | resp = 'F' 197 | return resp 198 | 199 | #----------------------------------------------------------------------------- 200 | def startServer(self): 201 | """ Start the Server""" 202 | while True: 203 | print('Wait for trustClient make connection...') 204 | client_sock, address = self.server.accept() 205 | print ('Accepted connection from {}:{}'.format(address[0], address[1])) 206 | self.handleClientConnection(client_sock) 207 | client_sock.close() 208 | 209 | #----------------------------------------------------------------------------- 210 | def startServ(): 211 | server = firmwTAServer() 212 | print("Server inited.") 213 | server.startServer() 214 | 215 | if __name__ == '__main__': 216 | startServ() 217 | -------------------------------------------------------------------------------- /src/randomTest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/src/randomTest -------------------------------------------------------------------------------- /src/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import threading 3 | import time 4 | from Crypto import Random 5 | from Crypto.Cipher import AES 6 | 7 | bind_ip = '0.0.0.0' 8 | bind_port = 5005 9 | 10 | class AESCipher: 11 | 12 | def __init__( self, key ): 13 | self.key = key 14 | 15 | def encrypt( self, raw ): 16 | # iv = Random.new().read( AES.block_size ) 17 | iv = bytes([0xa5]*16) 18 | cipher = AES.new( self.key, AES.MODE_CBC, iv ) 19 | #return base64.b64encode( cipher.encrypt( raw ) ) 20 | return cipher.encrypt( raw ) 21 | 22 | def decrypt( self, enc ): 23 | #enc = base64.b64decode(enc) 24 | iv = bytes([0xa5]*16) 25 | cipher = AES.new(self.key, AES.MODE_CBC, iv ) 26 | return cipher.decrypt(enc) 27 | 28 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 29 | server.bind((bind_ip, bind_port)) 30 | server.listen(5) # max backlog of connections 31 | 32 | print ('Listening on {}:{}'.format(bind_ip, bind_port)) 33 | 34 | key = bytes([0xa5]*32) 35 | cipher = AESCipher(key) 36 | encrypted = cipher.encrypt(bytes([0x5a]*32)) 37 | 38 | decrypted = cipher.decrypt(encrypted) 39 | print (encrypted) 40 | print (decrypted) 41 | count = 0 42 | 43 | def handle_client_connection(client_socket): 44 | request = client_socket.recv(32) 45 | print ('Received {}'.format(request)) 46 | client_socket.send(encrypted) 47 | request = client_socket.recv(32) 48 | data = cipher.decrypt(encrypted) 49 | print(data) 50 | 51 | while True: 52 | client_sock, address = server.accept() 53 | print ('Accepted connection from {}:{}'.format(address[0], address[1])) 54 | target=handle_client_connection(client_sock) 55 | client_sock.close() 56 | -------------------------------------------------------------------------------- /src/taServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #----------------------------------------------------------------------------- 3 | # Name: taServer.py 4 | # 5 | # Purpose: Trust application TCP server. Send the challenge data to the 6 | # trust app and decode the response swatt value.(AES256) 7 | # Author: Yuancheng Liu 8 | # 9 | # Created: 2019/05/08 10 | # Copyright: YC 11 | # License: YC 12 | #----------------------------------------------------------------------------- 13 | import socket 14 | import threading 15 | import time 16 | import IOT_Att as SWATT 17 | 18 | # if got error install Crypto please usethis: 19 | # >> pip install pycryptodome 20 | # from Crypto.Cipher import AES #Works 21 | # or 22 | # >> pip install pycryptodomex 23 | # from Cryptodome.Cipher import AES 24 | # For python3 the package name is now pycryptodome or pycryptodomex 25 | # If you need compatibility with your project with Python2 use pycryptodome 26 | # or else use pycryptodomex which is a library independent of the old PyCrypto. 27 | # https://stackoverflow.com/questions/51824628/modulenotfounderror-no-module-named-crypto-error 28 | from Crypto.Cipher import AES 29 | 30 | 31 | LOCAL_BIND_IP = '0.0.0.0' 32 | LOCAL_PORT = 5007 33 | CHA_LEN = 7 # default challenge we are going to use. 34 | 35 | #----------------------------------------------------------------------------- 36 | #----------------------------------------------------------------------------- 37 | class AESCipher: 38 | """ Bytes AES256 cipher""" 39 | 40 | def __init__( self, key ): 41 | self.key = key 42 | 43 | def encrypt( self, raw ): 44 | iv = bytes([0xa5]*16) 45 | cipher = AES.new( self.key, AES.MODE_CBC, iv ) 46 | return cipher.encrypt( raw ) 47 | 48 | def decrypt( self, enc ): 49 | iv = bytes([0xa5]*16) 50 | cipher = AES.new(self.key, AES.MODE_CBC, iv ) 51 | return cipher.decrypt(enc) 52 | 53 | #----------------------------------------------------------------------------- 54 | #----------------------------------------------------------------------------- 55 | class taServer(object): 56 | 57 | def __init__(self): 58 | """ init the TCP socket.""" 59 | self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 60 | self.server.bind((LOCAL_BIND_IP, LOCAL_PORT)) 61 | self.server.listen(5) # max backlog of connections 62 | print ('Listening on {}:{}'.format(LOCAL_BIND_IP, LOCAL_PORT)) 63 | # Calculate the SWATT value 64 | self.challengeStr = "" 65 | self.swattHd = SWATT.swattCal() 66 | self.swattHd.setPuff(1549465112) 67 | 68 | # fixed AES key which is same as the trust APP's TA 69 | self.key = bytes([0xa5]*32) 70 | self.challengeB = bytes([0x5a]*32) 71 | # init the AES cipher 72 | self.cipher = AESCipher(self.key) 73 | self.encrypted = self.cipher.encrypt(self.challengeB) 74 | self.decrypted = self.cipher.decrypt(self.encrypted) 75 | print (self.encrypted) 76 | print (self.decrypted) 77 | print ("Init finished") 78 | 79 | def setSwattChalStr(self, challengeStr): 80 | 81 | if len(challengeStr) < CHA_LEN: 82 | print("The challenge string is not long enough.") 83 | return 84 | self.challengeStr = challengeStr[:CHA_LEN] 85 | self.challengeB = bytes([ord(n) for n in self.challengeStr] + [ord('Z')]*25) 86 | self.encrypted = self.cipher.encrypt(self.challengeB) 87 | print(self.challengeB) 88 | 89 | #----------------------------------------------------------------------------- 90 | def handle_client_connection(self, client_socket): 91 | request = client_socket.recv(32) 92 | print ('Received {}'.format(request)) 93 | print ('Send the encrypted challenge bytes') 94 | client_socket.send(self.encrypted) 95 | # Calcualte the SWATT value for verification. 96 | result = self.swattHd.getSWATT(self.challengeStr, 300, "firmwareSample") 97 | print ('Received the SWATT bytes and decode:') 98 | request = client_socket.recv(32) 99 | data = self.cipher.decrypt(request) 100 | print(result) 101 | print("-------------") 102 | data = str(data).split('x0')[0] 103 | print(data) 104 | # The back data example is b'4098\x00ZZZZZZZZZZ' 105 | if int(data[2:-1]) == result: 106 | print("The file Swatt value has been verified.") 107 | else: 108 | print("The value are differet:"+str((data[2:-1]), result)) 109 | 110 | #----------------------------------------------------------------------------- 111 | def startServer(self): 112 | while True: 113 | print('Wait for connection') 114 | client_sock, address = self.server.accept() 115 | print ('Accepted connection from {}:{}'.format(address[0], address[1])) 116 | self.handle_client_connection(client_sock) 117 | client_sock.close() 118 | 119 | #----------------------------------------------------------------------------- 120 | def startServ(): 121 | server = taServer() 122 | 123 | print("Server inited.") 124 | server.setSwattChalStr("abdcedfs") 125 | server.startServer() 126 | 127 | if __name__ == '__main__': 128 | startServ() -------------------------------------------------------------------------------- /src/trustClient.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuYuancheng/Raspberry_PI_OPTEE/0e75f7083436cb4ae739bfde5bd111e7e841f080/src/trustClient.zip -------------------------------------------------------------------------------- /src/trustClient/run/configLocal.txt: -------------------------------------------------------------------------------- 1 | # set fmt: Tag should be a 5letters str. 2 | 3 | # Set the program debug level. fmt: 4 | DEBUG:0 5 | 6 | # Set the TCP IP address fmt: 7 | TCPIP:127.0.0.1 8 | 9 | # Set the TCP listen fmt: 10 | PORTN:5007 11 | 12 | # Set the checked program path 13 | FILEP:firmwareSample 14 | 15 | # Set the checked program version fmt: 16 | P_VER:1 17 | 18 | # Set the gateway device ID fmt: 19 | GW_ID:1549465112 20 | 21 | # Set the AES256 encrypted key version fmt: 22 | K_VER:1 23 | 24 | # Set the challenge length fmt: 25 | C_LEN:7 26 | 27 | # Set the swatt init m(m>=280) fmt: 28 | SWA_M:300 29 | 30 | # Set the swatt interation time n fmt: 31 | SWA_N:100 32 | -------------------------------------------------------------------------------- /src/trustClient/run/runTC.sh: -------------------------------------------------------------------------------- 1 | #!/bin/hash 2 | echo "Start the trushClient..." 3 | 4 | # Check whether the OPTEE driver is running in background. 5 | pgrep -x tee-supplicant 6 | ret=$? 7 | 8 | if [ $ret -eq 0 ]; then 9 | echo "The OPTEE driver has started." 10 | sudo trustClient 11 | else 12 | echo "OPTEE dirver not start.Run [sudo tee-supplicant &] to start first!" 13 | fi -------------------------------------------------------------------------------- /src/trustClient/trustClient/Android.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Android optee-hello-world makefile # 3 | ################################################################################ 4 | LOCAL_PATH := $(call my-dir) 5 | 6 | CFG_TEEC_PUBLIC_INCLUDE = $(LOCAL_PATH)/../optee_client/public 7 | 8 | ################################################################################ 9 | # Build hello world # 10 | ################################################################################ 11 | include $(CLEAR_VARS) 12 | LOCAL_CFLAGS += -DANDROID_BUILD 13 | LOCAL_CFLAGS += -Wall 14 | 15 | LOCAL_SRC_FILES += host/main.c 16 | 17 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \ 18 | $(CFG_TEEC_PUBLIC_INCLUDE) \ 19 | 20 | LOCAL_SHARED_LIBRARIES := libteec 21 | LOCAL_MODULE := optee_example_aes 22 | LOCAL_MODULE_TAGS := optional 23 | include $(BUILD_EXECUTABLE) 24 | 25 | include $(LOCAL_PATH)/ta/Android.mk 26 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/Makefile: -------------------------------------------------------------------------------- 1 | 2 | export V?=0 3 | 4 | .PHONY: all 5 | all: 6 | $(MAKE) -C host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" 7 | $(MAKE) -C ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" 8 | 9 | .PHONY: clean 10 | clean: 11 | $(MAKE) -C host clean 12 | $(MAKE) -C ta clean 13 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/build_ta_helloworld_qemu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CURDIR=`pwd` 4 | 5 | # This expects that this is place as a first level folder relative to the other 6 | # OP-TEE folder in a setup using default repo configuration as described by the 7 | # documentation in optee_os (README.md) 8 | ROOT=${PWD} 9 | ROOT=`dirname $ROOT` 10 | 11 | # Path to the toolchain 12 | export PATH=${ROOT}/toolchains/aarch32/bin:$PATH 13 | 14 | # Path to the TA-DEV-KIT coming from optee_os 15 | export TA_DEV_KIT_DIR=${ROOT}/optee_os/out/arm/export-ta_arm32 16 | 17 | # Path to the client library (GP Client API) 18 | export TEEC_EXPORT=${ROOT}/optee_client/out/export 19 | 20 | export PLATFORM=vexpress 21 | export PLATFORM_FLAVOR=qemu_virt 22 | 23 | # Toolchain prefix for user space code (normal world) 24 | HOST_CROSS_COMPILE=arm-linux-gnueabihf- 25 | # Build the host application 26 | cd $CURDIR/host 27 | make CROSS_COMPILE=$HOST_CROSS_COMPILE $@ 28 | 29 | # Toolchain prefix for the Trusted Applications 30 | TA_CROSS_COMPILE=arm-linux-gnueabihf- 31 | # Build the Trusted Application 32 | cd $CURDIR/ta 33 | make CROSS_COMPILE=$TA_CROSS_COMPILE $@ 34 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/doc/Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: all 3 | all: 4 | 5 | MSC_SRCS = open_session.msc invoke_command.msc \ 6 | close_session_and_finalize_context.msc 7 | 8 | PNGS += $(MSC_SRCS:.msc=.png) 9 | 10 | # Disable all builtin rules 11 | .SUFFIXES: 12 | .SUFFIXES: .png .msc 13 | 14 | all: $(PNGS) 15 | 16 | %.png : %.msc 17 | mscgen -T png $< 18 | 19 | .PHONY: clean 20 | clean: 21 | rm -f $(PNGS) 22 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/doc/close_session_and_finalize_context.msc: -------------------------------------------------------------------------------- 1 | msc { 2 | hscale = "0.9", wordwraparcs = on; 3 | 4 | a [label="hello_world\nuser space"], 5 | b [label="hello world\nTEE Driver"], 6 | f [label="TEE Core"], 7 | g [label="TA"]; 8 | 9 | ||| ; 10 | a=>b [ label = "Close\nSession" ]; 11 | b=>f [ label = "Close\nSession" ]; 12 | f=>g [ label = "TA_CloseSessionEntryPoint" ]; 13 | g>>f ; 14 | f>>b ; 15 | b>>a ; 16 | a=>b [ label = "Finalize\nContext" ]; 17 | b>>a ; 18 | } 19 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/doc/invoke_command.msc: -------------------------------------------------------------------------------- 1 | msc { 2 | hscale = "0.9", wordwraparcs = on; 3 | 4 | a [label="hello_world\nuser space"], 5 | b [label="hello world\nTEE Driver"], 6 | f [label="TEE Core"], 7 | g [label="TA"]; 8 | 9 | ||| ; 10 | a=>b [ label = "Invoke\nCommand" ]; 11 | b=>f [ label = "Invoke\nCommand" ]; 12 | f=>g [ label = "TA_InvokeCommandEntryPoint" ]; 13 | g>>f [ label = "ret: result" ]; 14 | f>>b [ label = "ret: result" ]; 15 | b>>a [ label = "ret: result" ]; 16 | } 17 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/doc/open_session.msc: -------------------------------------------------------------------------------- 1 | msc { 2 | hscale = "0.9", wordwraparcs = on; 3 | 4 | a [label="hello_world\nuser space"], 5 | b [label="hello world\nTEE Driver"], 6 | c [label="tee-supplicant"], 7 | f [label="TEE Core"], 8 | g [label="TA"]; 9 | 10 | ||| ; 11 | a=>b [ label = "Open\nSession" ]; 12 | b=>f [ label = "Open\nSession" ]; 13 | f=>f [ label = "Looking for TA" ]; 14 | f=>c [ label = "Load TA" ]; 15 | c=>c [ label = "Loading TA" ]; 16 | c>>f [ label = "Load TA" ]; 17 | f=>f [ label = "Load TA" ]; 18 | f=>g [ label = "TA_OpenSessionEntryPoint" ]; 19 | g>>f ; 20 | f>>b [ label = "ret: session" ]; 21 | b>>a [ label = "ret: session" ]; 22 | } 23 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/host/Makefile: -------------------------------------------------------------------------------- 1 | CC = $(CROSS_COMPILE)gcc 2 | LD = $(CROSS_COMPILE)ld 3 | AR = $(CROSS_COMPILE)ar 4 | NM = $(CROSS_COMPILE)nm 5 | OBJCOPY = $(CROSS_COMPILE)objcopy 6 | OBJDUMP = $(CROSS_COMPILE)objdump 7 | READELF = $(CROSS_COMPILE)readelf 8 | 9 | OBJS = main.o 10 | 11 | CFLAGS += -Wall -I../ta/include -I$(TEEC_EXPORT)/include -I./include 12 | #Add/link other required libraries here 13 | LDADD += -lteec -L$(TEEC_EXPORT)/lib 14 | 15 | BINARY= trustClient 16 | 17 | .PHONY: all 18 | all: $(BINARY) 19 | 20 | $(BINARY): $(OBJS) 21 | $(CC) -o $@ $< $(LDADD) 22 | 23 | .PHONY: clean 24 | clean: 25 | rm -f $(OBJS) $(BINARY) 26 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/host/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* Name: trustClient 29 | Purpose: This module used optee to create a truct TCP client application 30 | to connection to the server to down load the AES256 encrypted challeage 31 | value to calculate the gate way program. This file is edited based on 32 | the optee aes example 33 | 34 | Author: Yuancheng Liu 35 | Created: 2019/05/28 36 | Copyright: (c) 2017, Linaro Limited, 2019, YC 37 | */ 38 | #define _GNU_SOURCE 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | /* OP-TEE TEE client API (built by optee_client) */ 48 | #include 49 | 50 | /* To the the UUID (found the the TA's h-file(s)) */ 51 | #include 52 | 53 | #define AES_TEST_BUFFER_SIZE 32 54 | #define AES_TEST_KEY_SIZE 32 55 | #define AES_TEST_IV_SIZE 16 56 | 57 | #define DECODE 0 58 | #define ENCODE 1 59 | #define SA struct sockaddr 60 | #define SWATT_PUFF 1549465112 61 | 62 | /*progress bar to show the swatt steps.*/ 63 | #define PBSTR "============================================================" 64 | #define PBWIDTH 60 65 | 66 | /* TEE resources */ 67 | struct test_ctx { 68 | TEEC_Context ctx; 69 | TEEC_Session sess; 70 | }; 71 | 72 | /* Global variables*/ 73 | int gv_dbug; // debug level of the program. 74 | 75 | char gv_ipAddr[20]; // Server IP addresss.(default 127.0.0.1) 76 | int gv_port; // Server connection port.(default 5007) 77 | 78 | char gv_flph[FILENAME_MAX]; // The path of the program. 79 | 80 | int gv_keyV; // AES key version. 81 | int gv_gwID; // Gateway unique ID(also used as the SWATT_PUFF) 82 | int gv_proV; // The checked program version. 83 | int gv_cLen; // challenge string length.(val<=16) 84 | int gv_sw_m; // SWATT init value m.(default 300) 85 | int gv_iter; // SWATT iteration time.(default 100) 86 | 87 | 88 | //------------------------------------------------------------------------------- 89 | 90 | /*TEE session setup.*/ 91 | void prepare_tee_session(struct test_ctx *ctx) 92 | { 93 | TEEC_UUID uuid = TA_AES_UUID; 94 | uint32_t origin; 95 | TEEC_Result res; 96 | 97 | /* Initialize a context connecting us to the TEE */ 98 | res = TEEC_InitializeContext(NULL, &ctx->ctx); 99 | if (res != TEEC_SUCCESS) 100 | errx(1, "TEEC_InitializeContext failed with code 0x%x", res); 101 | 102 | /* Open a session with the TA */ 103 | res = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid, 104 | TEEC_LOGIN_PUBLIC, NULL, NULL, &origin); 105 | if (res != TEEC_SUCCESS) 106 | errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x", 107 | res, origin); 108 | } 109 | 110 | void terminate_tee_session(struct test_ctx *ctx) 111 | { 112 | TEEC_CloseSession(&ctx->sess); 113 | TEEC_FinalizeContext(&ctx->ctx); 114 | } 115 | //------------------------------------------------------------------------------- 116 | 117 | /*AES encryptiong and decription*/ 118 | // Set AES encode/decode, algo mode, key size(AES128/256). 119 | void prepare_aes(struct test_ctx *ctx, int encode) 120 | { 121 | TEEC_Operation op; 122 | uint32_t origin; 123 | TEEC_Result res; 124 | 125 | memset(&op, 0, sizeof(op)); 126 | op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, 127 | TEEC_VALUE_INPUT, 128 | TEEC_VALUE_INPUT, 129 | TEEC_NONE); 130 | 131 | op.params[0].value.a = TA_AES_ALGO_CBC; // algo mode. 132 | op.params[1].value.a = TA_AES_SIZE_256BIT; // Keysize 133 | op.params[2].value.a = encode ? TA_AES_MODE_ENCODE : TA_AES_MODE_DECODE; 134 | 135 | res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_PREPARE, 136 | &op, &origin); 137 | if (res != TEEC_SUCCESS) 138 | errx(1, "TEEC_InvokeCommand(PREPARE) failed 0x%x origin 0x%x", 139 | res, origin); 140 | } 141 | 142 | // Set AES encryption/decryption key. 143 | void set_key(struct test_ctx *ctx, char *key, size_t key_sz) 144 | { 145 | TEEC_Operation op; 146 | uint32_t origin; 147 | TEEC_Result res; 148 | 149 | memset(&op, 0, sizeof(op)); 150 | op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, 151 | TEEC_NONE, TEEC_NONE, TEEC_NONE); 152 | 153 | op.params[0].tmpref.buffer = key; 154 | op.params[0].tmpref.size = key_sz; 155 | 156 | res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_KEY, 157 | &op, &origin); 158 | if (res != TEEC_SUCCESS) 159 | errx(1, "TEEC_InvokeCommand(SET_KEY) failed 0x%x origin 0x%x", 160 | res, origin); 161 | } 162 | 163 | // Set AES initialization vector. 164 | void set_iv(struct test_ctx *ctx, char *iv, size_t iv_sz) 165 | { 166 | TEEC_Operation op; 167 | uint32_t origin; 168 | TEEC_Result res; 169 | 170 | memset(&op, 0, sizeof(op)); 171 | op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, 172 | TEEC_NONE, TEEC_NONE, TEEC_NONE); 173 | op.params[0].tmpref.buffer = iv; 174 | op.params[0].tmpref.size = iv_sz; 175 | 176 | res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_IV, 177 | &op, &origin); 178 | if (res != TEEC_SUCCESS) 179 | errx(1, "TEEC_InvokeCommand(SET_IV) failed 0x%x origin 0x%x", 180 | res, origin); 181 | } 182 | 183 | // Data encryption/decryption. 184 | void cipher_buffer(struct test_ctx *ctx, char *in, char *out, size_t sz) 185 | { 186 | TEEC_Operation op; 187 | uint32_t origin; 188 | TEEC_Result res; 189 | 190 | memset(&op, 0, sizeof(op)); 191 | op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, 192 | TEEC_MEMREF_TEMP_OUTPUT, 193 | TEEC_NONE, TEEC_NONE); 194 | op.params[0].tmpref.buffer = in; 195 | op.params[0].tmpref.size = sz; 196 | op.params[1].tmpref.buffer = out; 197 | op.params[1].tmpref.size = sz; 198 | 199 | res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_CIPHER, 200 | &op, &origin); 201 | if (res != TEEC_SUCCESS) 202 | errx(1, "TEEC_InvokeCommand(CIPHER) failed 0x%x origin 0x%x", 203 | res, origin); 204 | } 205 | //------------------------------------------------------------------------------- 206 | 207 | /* File SWATT data calculation. */ 208 | 209 | // Read firmware file as bytes array. 210 | char *readFileBytes(const char *name) 211 | { 212 | if (gv_dbug > 1) 213 | printf("ReadFileBytes: read the file <%s> \n", name); 214 | FILE *fl = fopen(name, "r"); 215 | fseek(fl, 0, SEEK_END); 216 | long len = ftell(fl); 217 | //len = 128000; // Haroon's orignal python code use this value, why? 218 | char *ret = malloc(len); 219 | fseek(fl, 0, SEEK_SET); 220 | fread(ret, 1, len, fl); 221 | fclose(fl); 222 | return ret; 223 | } 224 | 225 | // Show a progress bar. 226 | void printProgress (double percentage) 227 | { 228 | int val = (int) (percentage * 100); 229 | int lpad = (int) (percentage * PBWIDTH); 230 | int rpad = PBWIDTH - lpad; 231 | printf ("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, ""); 232 | fflush (stdout); 233 | } 234 | 235 | // Calculate the firmware file SWATT int value. 236 | int get_swatt(struct test_ctx *ctx, char *key, size_t key_sz) 237 | { 238 | TEEC_Operation op; 239 | uint32_t origin; 240 | TEEC_Result res; 241 | 242 | // Set the parameters 243 | int m = gv_sw_m; 244 | int state[m]; 245 | int puff = gv_gwID; 246 | char challenge[key_sz]; 247 | strncpy(challenge, key, key_sz); 248 | int challengeInt[key_sz]; 249 | if (gv_dbug > 1) 250 | printf("SWATT: Challenge string is <%s>\n", challenge); 251 | // Read the firmware file. 252 | char *ret = readFileBytes(gv_flph); 253 | // reference func: string_to_list 254 | for (int t = 0; t < key_sz; t++) 255 | challengeInt[t] = (int)challenge[t]; 256 | // reference func: setKey 257 | for (int i = 0; i < m; i++) 258 | state[i] = i; 259 | int j = 0; 260 | for (int i = 0; i < m; i++) 261 | { 262 | j = (j + state[i] + challengeInt[i % key_sz]) % m; 263 | int tmp = state[i]; 264 | state[i] = state[j]; 265 | state[j] = tmp; 266 | } 267 | // reference func: extract_CRpair 268 | int s = 1; 269 | int k = 16; 270 | int final = ((1 << k) - 1) & (puff >> (s - 1)); 271 | if (gv_dbug > 1) 272 | printf("SWATT: final :<%d>\n", final); 273 | int test[key_sz]; 274 | for (int t = 0; t < key_sz; t++) 275 | test[t] = challengeInt[t] ^ final; 276 | for (int t = 0; t < key_sz; t++) 277 | { 278 | if (t != key_sz - 1) 279 | test[t] ^= test[t + 1]; 280 | final += test[t] << 2; 281 | } 282 | // Calculate file's address need to access in the trustApp. 283 | memset(&op, 0, sizeof(op)); 284 | op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_VALUE_INOUT, 285 | TEEC_VALUE_INOUT, TEEC_NONE); 286 | // reference func: getSWATT 287 | op.params[0].value.a = 0; //swatt_seed -> op.params[0].value.a 288 | op.params[0].value.b = m; //init_seed -> op.params[0].value.b 289 | op.params[1].value.a = 0; // Address -> op.params[1].value.a 290 | op.params[1].value.b = state[258]; // current_cs -> op.params[1].value.b 291 | op.params[2].value.a = state[257]; // prev_cs -> op.params[2].value.a 292 | op.params[2].value.b = state[256]; // pprev_cs -> op.params[3].value.b 293 | // Calculate the SWATT value. 294 | for (int i = 0; i < gv_iter; i++) 295 | { 296 | op.params[0].value.a = final ^ op.params[0].value.b; 297 | op.params[1].value.a = (state[i] << 8) + op.params[2].value.a; 298 | res = TEEC_InvokeCommand(&ctx->sess, TA_SWATT_CMD_RAND, &op, &origin); 299 | if (res != TEEC_SUCCESS) 300 | errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x", 301 | res, origin); 302 | int Address = op.params[1].value.a; 303 | char strTemp = ret[Address]; 304 | int num = i - 1; 305 | if (num < 0) 306 | num = m - 1; 307 | usleep(20000); // sleep a short while to avoid PI hang. 308 | op.params[1].value.b = op.params[1].value.b + ((int)strTemp ^ op.params[2].value.b + state[num]); 309 | res = TEEC_InvokeCommand(&ctx->sess, TA_SWATT_CMD_CAL, &op, &origin); 310 | if (res != TEEC_SUCCESS) 311 | errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x", 312 | res, origin); 313 | // Show the file checking progress bar. 314 | printProgress((double)i / gv_iter); 315 | } 316 | printf("Finished\n"); 317 | if (gv_dbug > 1) 318 | printf("SWATT: TA incremented value to %d\n", op.params[1].value.b); 319 | return op.params[1].value.b; 320 | } 321 | 322 | //------------------------------------------------------------------------------- 323 | /* Load the configuration file setting. */ 324 | void loadConfig() 325 | { 326 | FILE *fp; 327 | char *line = NULL; 328 | size_t len = 0; 329 | ssize_t read; 330 | printf("I/O: Load program setting from the configuration file."); 331 | fp = fopen("configLocal.txt", "r"); 332 | if (fp == NULL) 333 | { 334 | printf("Local config file open error."); 335 | exit(EXIT_FAILURE); 336 | } 337 | while ((read = getline(&line, &len, fp)) != -1) 338 | { 339 | if (line[0] == '#' || line[0] == '\n'|| line[0] == '\r' || line == NULL) 340 | continue; //remove the comment line 341 | char message[200]; 342 | strcpy(message, strtok(line, ":")); 343 | // load program' debug levle from line fmt: 344 | if (strstr(message, "DEBUG")) 345 | { 346 | gv_dbug = 0; 347 | gv_dbug = atoi(strtok(NULL, ":")); 348 | printf("Currently program debug print level is: <%d>\n", gv_dbug); 349 | } 350 | // load ip address from line 351 | else if (strstr(message, "TCPIP")) 352 | { 353 | strcpy(gv_ipAddr, strtok(NULL, ":")); 354 | // remove the \r or \n or \r\n 355 | for (int i = 0; i < strlen(gv_ipAddr); i++) 356 | { 357 | if (gv_ipAddr[i] == '\r' || gv_ipAddr[i] == '\n') 358 | gv_ipAddr[i] = '\0'; //remove the '\n' 359 | } 360 | if (gv_dbug > 1) 361 | printf("Server IP addresss is: <%s>\n", gv_ipAddr); 362 | } 363 | // load checked program' path from line 364 | else if (strstr(message, "FILEP")) 365 | { 366 | strcpy(gv_flph, strtok(NULL, ":")); 367 | for (int i = 0; i < strlen(gv_flph); i++) 368 | { 369 | if (gv_flph[i] == '\r' || gv_flph[i] == '\n') 370 | gv_flph[i] = '\0'; //remove the '\n' 371 | } 372 | if (gv_dbug > 1) 373 | printf("The file need to check is: <%s>\n", gv_flph); 374 | 375 | } 376 | // load the TCP port number from line 377 | else if (strstr(message, "PORTN")) 378 | { 379 | gv_port = 5007; 380 | gv_port = atoi(strtok(NULL, ":")); 381 | if (gv_dbug > 1) 382 | printf("port is: <%d>\n", gv_port); 383 | } 384 | // load checked program version from line 385 | else if (strstr(message, "P_VER")) 386 | { 387 | gv_proV = 0; 388 | gv_proV = atoi(strtok(NULL, ":")); 389 | if (gv_dbug > 1) 390 | printf("program version is: <%d>\n", gv_proV); 391 | } 392 | // load AES key version from line 393 | else if (strstr(message, "K_VER")) 394 | { 395 | gv_keyV = 0; 396 | gv_keyV = atoi(strtok(NULL, ":")); 397 | if (gv_dbug > 1) 398 | printf("key version is: <%d>\n", gv_keyV); 399 | } 400 | // load gate way id/SWATT PUFF from line 401 | else if (strstr(message, "GW_ID")) 402 | { 403 | gv_gwID = SWATT_PUFF; 404 | gv_gwID = atoi(strtok(NULL, ":")); 405 | if (gv_dbug > 1) 406 | printf("Gate way ID is: <%d>\n", gv_gwID); 407 | } 408 | // load swatt challenge string length from line 409 | else if (strstr(message, "C_LEN")) 410 | { 411 | gv_cLen = 0; 412 | gv_cLen = atoi(strtok(NULL, ":")); 413 | if (gv_cLen > 16) 414 | gv_cLen = 16; 415 | if (gv_dbug > 1) 416 | printf("challenge Len : <%d>\n", gv_cLen); 417 | } 418 | // load SWATT init m from line 419 | else if (strstr(message, "SWA_M")) 420 | { 421 | gv_sw_m = 300; // use 300 as default. 422 | gv_sw_m = atoi(strtok(NULL, ":")); 423 | if (gv_dbug > 1) 424 | printf("SWATT init m is: <%d>\n", gv_sw_m); 425 | } 426 | // load SWATT init m from line 427 | else if (strstr(message, "SWA_N")) 428 | { 429 | gv_iter = 100; // use 100 as defualt. 430 | gv_iter = atoi(strtok(NULL, ":")); 431 | if (gv_dbug > 1) 432 | printf("SWATT iteration n is: <%d>\n", gv_iter); 433 | } 434 | } 435 | fclose(fp); 436 | if (line) 437 | free(line); 438 | } 439 | 440 | //------------------------------------------------------------------------------- 441 | 442 | /* Display the hex number of the message/ciphText */ 443 | void display(char *ciphertext, int len, int debugLvl) 444 | { 445 | if(debugLvl == 0) 446 | return; // don't display anything if debug level == 0 447 | printf("len: %d \n", len); 448 | if(debugLvl <= 1) 449 | return; // only display data len if debug level == 1 450 | for (int v = 0; v < len; v++) 451 | printf("%d ", ciphertext[v]); 452 | printf("\n"); 453 | } 454 | //------------------------------------------------------------------------------- 455 | 456 | int main(void) 457 | { 458 | struct test_ctx ctx; 459 | char key[AES_TEST_KEY_SIZE]; 460 | char iv[AES_TEST_IV_SIZE]; 461 | char clear[AES_TEST_BUFFER_SIZE]; 462 | char ciph[AES_TEST_BUFFER_SIZE]; 463 | char temp[AES_TEST_BUFFER_SIZE]; 464 | char sessionKey[AES_TEST_BUFFER_SIZE]; 465 | 466 | printf("TEE: Prepare TrustZone session with the TA.\n"); 467 | prepare_tee_session(&ctx); 468 | // Step 1: make connection and fetch the AES session key from the server. 469 | printf("-------------------------------------------------------------------------------\n"); 470 | printf("TCP: Init the TCP client.\n"); 471 | // Init the TCP client 472 | int sockfd, connfd; 473 | struct sockaddr_in servaddr, cli; 474 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 475 | if (sockfd == -1) 476 | { 477 | printf("TCP: socket creation failed...\n"); 478 | exit(0); 479 | } 480 | else 481 | printf("TCP: Socket successfully created..\n"); 482 | bzero(&servaddr, sizeof(servaddr)); 483 | 484 | // Assign TCP IPaddr, PORT(load the setting from the config file.) 485 | loadConfig(); 486 | 487 | servaddr.sin_family = AF_INET; 488 | servaddr.sin_addr.s_addr = inet_addr(gv_ipAddr); 489 | servaddr.sin_port = htons(gv_port); 490 | // Connect the client socket to server socket 491 | if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) != 0) 492 | { 493 | printf("TCP: connection with the server failed...\n Client terminate.\n"); 494 | exit(0); 495 | } 496 | else 497 | printf("TCP: connected to the server..\n"); 498 | // Send program setting and session key fetch request. 499 | printf("TCP: send the session key fetch request.\n"); 500 | char rbuff[AES_TEST_BUFFER_SIZE]; 501 | bzero(rbuff, sizeof(rbuff)); 502 | sprintf(rbuff, "F%d;%d;%d;%d;%d;%d;", gv_keyV, gv_gwID, gv_proV, gv_cLen, gv_sw_m, gv_iter); 503 | write(sockfd, rbuff, sizeof(rbuff)); 504 | // get the cyphtext(session key) from the server. 505 | bzero(ciph, sizeof(ciph)); 506 | read(sockfd, ciph, sizeof(ciph)); 507 | printf("TCP: get <%d>Bytes session key ciphtext from server: \n", sizeof(ciph)); 508 | display(ciph, sizeof(ciph), gv_dbug); 509 | printf("-------------------------------------------------------------------------------\n"); 510 | 511 | // Step 2: Decode the session key by AES256 defualt key. 512 | printf("TrustZone: Prepare AES decode operation(AES_D)\n"); 513 | prepare_aes(&ctx, DECODE); 514 | 515 | printf("AES_D: Load default key inside TA.\n"); 516 | memset(key, 0xa5, sizeof(key)); // load some value as key(hard code) 517 | set_key(&ctx, key, AES_TEST_KEY_SIZE); 518 | display(key, sizeof(key), gv_dbug); 519 | 520 | printf("AES_D: Reset ciphering operation IV in TA.\n"); 521 | memset(iv, 0xa5, sizeof(iv)); /* Load 32bytes value as IV*/ 522 | set_iv(&ctx, iv, AES_TEST_IV_SIZE); 523 | display(iv, sizeof(iv), gv_dbug); 524 | 525 | printf("AES_D: Decrypt session key ciphtext from TA.\n"); 526 | cipher_buffer(&ctx, ciph, sessionKey, AES_TEST_BUFFER_SIZE); // challenge-> temp 527 | display(sessionKey, sizeof(sessionKey), gv_dbug); 528 | // Send the session key set confirmation info to the server. 529 | bzero(rbuff, sizeof(rbuff)); 530 | sprintf(rbuff, "FT"); 531 | write(sockfd, rbuff, sizeof(rbuff)); 532 | printf("-------------------------------------------------------------------------------\n"); 533 | 534 | // Step 3: Decode the message by AES256 session key and get challenge data. 535 | bzero(ciph, sizeof(ciph)); 536 | read(sockfd, ciph, sizeof(ciph)); 537 | printf("TCP: get <%d> Bytes SWATT-challenge ciphtext from server: \n", sizeof(ciph)); 538 | display(ciph, sizeof(ciph), gv_dbug); 539 | 540 | printf("Prepare AES decode operation(AES_D)\n"); 541 | prepare_aes(&ctx, DECODE); 542 | 543 | printf("AES_D:set session key inside TA\n"); 544 | set_key(&ctx, sessionKey, AES_TEST_KEY_SIZE); 545 | display(sessionKey, sizeof(sessionKey), gv_dbug); 546 | 547 | printf("AES_D: Reset ciphering operation IV in TA \n"); 548 | memset(iv, 0xa5, sizeof(iv)); /* Load 32bytes value as IV*/ 549 | set_iv(&ctx, iv, AES_TEST_IV_SIZE); 550 | display(iv, sizeof(iv), gv_dbug); 551 | 552 | printf("AES_D: Decrypt SWATT-challenge ciphtext buffer from TA.\n"); 553 | cipher_buffer(&ctx, ciph, temp, AES_TEST_BUFFER_SIZE); // challenge-> temp 554 | display(temp, sizeof(temp), gv_dbug); 555 | 556 | /* Check decoded is the clear content(only used for) */ 557 | //memset(clear, 0x5a, sizeof(clear)); /* Load some dummy value */ 558 | //printf("DC: This is the clear X: %X\n",clear ); 559 | //display(clear, sizeof(clear), gv_dbug)); 560 | //if (memcmp(clear, temp, AES_TEST_BUFFER_SIZE)) 561 | // printf("Clear text and decoded text differ => ERROR\n"); 562 | //else 563 | // printf("Clear text and decoded text match\n"); 564 | printf("-------------------------------------------------------------------------------\n"); 565 | 566 | // Step 4: Calcualte the SWATT data from the trust application. 567 | printf("SWATT: Pass in challenge data and calcualte: \n"); 568 | int swattVal = get_swatt(&ctx, temp, gv_cLen); 569 | printf("-------------------------------------------------------------------------------\n"); 570 | 571 | // Step 5: Encode the SWATT message by AES256 and send to server. 572 | printf("Prepare AES encode operation(AES_E) \n"); 573 | prepare_aes(&ctx, ENCODE); 574 | 575 | printf("AES_E: Load session key in TA.\n"); 576 | memset(key, 0xa5, sizeof(key)); // load some value as key(hard code) 577 | set_key(&ctx, sessionKey, AES_TEST_KEY_SIZE); 578 | display(sessionKey, sizeof(sessionKey), gv_dbug); 579 | 580 | printf("AES_E: Reset ciphering operation IV in TA.\n"); 581 | memset(iv, 0xa5, sizeof(iv)); /* Load some dummy value */ 582 | set_iv(&ctx, iv, AES_TEST_IV_SIZE); 583 | display(iv, sizeof(iv), gv_dbug); 584 | 585 | printf("AES_E: Encode challenge data buffer from TA.\n"); 586 | memset(clear, 0x5a, sizeof(clear)); /* Load some dummy value */ 587 | snprintf(clear, 10, "%d", swattVal); // copy int in to string 588 | if (gv_dbug > 0) 589 | printf("SWATT int val:<%s> \n", clear); 590 | cipher_buffer(&ctx, clear, ciph, AES_TEST_BUFFER_SIZE); 591 | display(ciph, sizeof(ciph), gv_dbug); 592 | printf("-------------------------------------------------------------------------------\n"); 593 | 594 | // Step 6: Send encrypted val to server and decrypt the response. 595 | printf("TCP: send the encrypted swatt data.\n"); 596 | write(sockfd, ciph, sizeof(ciph)); 597 | 598 | // wait for server verification reuslt. 599 | bzero(ciph, sizeof(ciph)); 600 | read(sockfd, ciph, sizeof(ciph)); 601 | printf("TCP: get <%d> Bytes server verification ciphtext from server.\n", sizeof(ciph)); 602 | printf("Prepare AES decode operation(AES_D).\n"); 603 | prepare_aes(&ctx, DECODE); 604 | 605 | printf("AES_D:Load session key inside TA.\n"); 606 | set_key(&ctx, sessionKey, AES_TEST_KEY_SIZE); 607 | display(sessionKey, sizeof(sessionKey), gv_dbug); 608 | 609 | printf("AES_D: Reset ciphering operation IV in TA.\n"); 610 | memset(iv, 0xa5, sizeof(iv)); /* Load 32bytes value as IV*/ 611 | set_iv(&ctx, iv, AES_TEST_IV_SIZE); 612 | display(iv, sizeof(iv), gv_dbug); 613 | 614 | printf("AES_D: Decrypte ciphtext buffer from TA.\n"); 615 | cipher_buffer(&ctx, ciph, temp, AES_TEST_BUFFER_SIZE); // challenge-> temp 616 | display(temp, sizeof(temp), gv_dbug); 617 | printf("-------------------------------------------------------------------------------\n"); 618 | 619 | // Step 7: Send the system lib/memory used by the checked program. 620 | if (temp[0] == 'T') 621 | { 622 | printf("The swatt value has been verified by the server.\n"); 623 | FILE *cmdfp; 624 | char data[FILENAME_MAX]; 625 | char cmd[100]; 626 | sprintf(cmd, "lsof -c %s;", gv_flph); 627 | cmdfp = popen(cmd, "r"); 628 | 629 | char var[40]; 630 | while (fgets(var, sizeof(var), cmdfp) != NULL) 631 | { 632 | if (gv_dbug > 1) 633 | printf("- %s", var); 634 | var[strlen(var) - 1] = ';'; // replace the '\n' with ';' 635 | strcat(data, var); 636 | } 637 | pclose(cmdfp); 638 | char data2[FILENAME_MAX]; 639 | sprintf(data2, "F%s;", data); 640 | // Send the response back to the server. 641 | write(sockfd, data2, sizeof(data2)); 642 | } 643 | else 644 | { 645 | printf("The swatt value was not verified by the server.\n Remove he un-verfied file.\n"); 646 | /*Do what need to do to if the file have been changed.*/ 647 | write(sockfd, "FF;", sizeof("FF;")); // 648 | } 649 | printf("-------------------------------------------------------------------------------\n"); 650 | 651 | // Step 7: Close the TCP socket and terminate the TA session. 652 | close(sockfd); 653 | terminate_tee_session(&ctx); 654 | return 0; 655 | } 656 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/ta/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | local_module := 7aaaf200-2450-11e4-abe2-0002a5d5c51b.ta 4 | include $(BUILD_OPTEE_MK) 5 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/ta/Makefile: -------------------------------------------------------------------------------- 1 | CFG_TEE_TA_LOG_LEVEL ?= 4 2 | CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL) 3 | 4 | # The UUID for the Trusted Application 5 | BINARY=7aaaf200-2450-11e4-abe2-0002a5d5c51b 6 | 7 | -include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk 8 | 9 | ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) 10 | clean: 11 | @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' 12 | @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' 13 | endif 14 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/ta/aes_ta.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #define AES128_KEY_BIT_SIZE 128 36 | #define AES128_KEY_BYTE_SIZE (AES128_KEY_BIT_SIZE / 8) 37 | #define AES256_KEY_BIT_SIZE 256 38 | #define AES256_KEY_BYTE_SIZE (AES256_KEY_BIT_SIZE / 8) 39 | 40 | /* 41 | * Ciphering context: each opened session relates to a cipehring operation. 42 | * - configure the AES flavour from a command. 43 | * - load key from a command (here the key is provided by the REE) 44 | * - reset init vector (here IV is provided by the REE) 45 | * - cipher a buffer frame (here input and output buffers are non-secure) 46 | */ 47 | struct aes_cipher { 48 | uint32_t algo; /* AES flavour */ 49 | uint32_t mode; /* Encode or decode */ 50 | uint32_t key_size; /* AES key size in byte */ 51 | TEE_OperationHandle op_handle; /* AES ciphering operation */ 52 | TEE_ObjectHandle key_handle; /* transient object to load the key */ 53 | }; 54 | 55 | //-------------------------------------------------- 56 | /*Linear congruential random generator*/ 57 | int bsd_rand(); 58 | int rseed = 0; 59 | 60 | void bsd_srand(int x) 61 | { 62 | rseed = x; 63 | } 64 | 65 | #define BSD_RAND_MAX ((1U << 31) - 1) 66 | 67 | int bsd_rand() 68 | { 69 | return rseed = (rseed * 1103515245 + 12345) & BSD_RAND_MAX; 70 | } 71 | //----------------------------------------------------- 72 | 73 | 74 | /* 75 | * Few routines to convert IDs from TA API into IDs from OP-TEE. 76 | */ 77 | static TEE_Result ta2tee_algo_id(uint32_t param, uint32_t *algo) 78 | { 79 | switch (param) { 80 | case TA_AES_ALGO_ECB: 81 | *algo = TEE_ALG_AES_ECB_NOPAD; 82 | return TEE_SUCCESS; 83 | case TA_AES_ALGO_CBC: 84 | *algo = TEE_ALG_AES_CBC_NOPAD; 85 | return TEE_SUCCESS; 86 | case TA_AES_ALGO_CTR: 87 | *algo = TEE_ALG_AES_CTR; 88 | return TEE_SUCCESS; 89 | default: 90 | EMSG("Invalid algo %u", param); 91 | return TEE_ERROR_BAD_PARAMETERS; 92 | } 93 | } 94 | static TEE_Result ta2tee_key_size(uint32_t param, uint32_t *key_size) 95 | { 96 | switch (param) { 97 | case AES128_KEY_BYTE_SIZE: 98 | case AES256_KEY_BYTE_SIZE: 99 | *key_size = param; 100 | return TEE_SUCCESS; 101 | default: 102 | EMSG("Invalid key size %u", param); 103 | return TEE_ERROR_BAD_PARAMETERS; 104 | } 105 | } 106 | static TEE_Result ta2tee_mode_id(uint32_t param, uint32_t *mode) 107 | { 108 | switch (param) { 109 | case TA_AES_MODE_ENCODE: 110 | *mode = TEE_MODE_ENCRYPT; 111 | return TEE_SUCCESS; 112 | case TA_AES_MODE_DECODE: 113 | *mode = TEE_MODE_DECRYPT; 114 | return TEE_SUCCESS; 115 | default: 116 | EMSG("Invalid mode %u", param); 117 | return TEE_ERROR_BAD_PARAMETERS; 118 | } 119 | } 120 | 121 | /* 122 | * Process command TA_AES_CMD_PREPARE. API in aes_ta.h 123 | * 124 | * Allocate resources required for the ciphering operation. 125 | * During ciphering operation, when expect client can: 126 | * - update the key materials (provided by client) 127 | * - reset the initial vector (provided by client) 128 | * - cipher an input buffer into an output buffer (provided by client) 129 | */ 130 | static TEE_Result alloc_resources(void *session, uint32_t param_types, 131 | TEE_Param params[4]) 132 | { 133 | const uint32_t exp_param_types = 134 | TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 135 | TEE_PARAM_TYPE_VALUE_INPUT, 136 | TEE_PARAM_TYPE_VALUE_INPUT, 137 | TEE_PARAM_TYPE_NONE); 138 | struct aes_cipher *sess; 139 | TEE_Attribute attr; 140 | TEE_Result res; 141 | char *key; 142 | 143 | /* Get ciphering context from session ID */ 144 | DMSG("Session %p: get ciphering resources", session); 145 | sess = (struct aes_cipher *)session; 146 | 147 | /* Safely get the invocation parameters */ 148 | if (param_types != exp_param_types) 149 | return TEE_ERROR_BAD_PARAMETERS; 150 | 151 | res = ta2tee_algo_id(params[0].value.a, &sess->algo); 152 | if (res != TEE_SUCCESS) 153 | return res; 154 | 155 | res = ta2tee_key_size(params[1].value.a, &sess->key_size); 156 | if (res != TEE_SUCCESS) 157 | return res; 158 | 159 | res = ta2tee_mode_id(params[2].value.a, &sess->mode); 160 | if (res != TEE_SUCCESS) 161 | return res; 162 | 163 | /* 164 | * Ready to allocate the resources which are: 165 | * - an operation handle, for an AES ciphering of given configuration 166 | * - a transient object that will be use to load the key materials 167 | * into the AES ciphering operation. 168 | */ 169 | 170 | /* Free potential previous operation */ 171 | if (sess->op_handle != TEE_HANDLE_NULL) 172 | TEE_FreeOperation(sess->op_handle); 173 | 174 | /* Allocate operation: AES/CTR, mode and size from params */ 175 | res = TEE_AllocateOperation(&sess->op_handle, 176 | sess->algo, 177 | sess->mode, 178 | sess->key_size * 8); 179 | if (res != TEE_SUCCESS) { 180 | EMSG("Failed to allocate operation"); 181 | sess->op_handle = TEE_HANDLE_NULL; 182 | goto err; 183 | } 184 | 185 | /* Free potential previous transient object */ 186 | if (sess->key_handle != TEE_HANDLE_NULL) 187 | TEE_FreeTransientObject(sess->key_handle); 188 | 189 | /* Allocate transient object according to target key size */ 190 | res = TEE_AllocateTransientObject(TEE_TYPE_AES, 191 | sess->key_size * 8, 192 | &sess->key_handle); 193 | if (res != TEE_SUCCESS) { 194 | EMSG("Failed to allocate transient object"); 195 | sess->key_handle = TEE_HANDLE_NULL; 196 | goto err; 197 | } 198 | 199 | /* 200 | * When loading a key in the cipher session, set_aes_key() 201 | * will reset the operation and load a key. But we cannot 202 | * reset and operation that has no key yet (GPD TEE Internal 203 | * Core API Specification – Public Release v1.1.1, section 204 | * 6.2.5 TEE_ResetOperation). In consequence, we will load a 205 | * dummy key in the operation so that operation can be reset 206 | * when updating the key. 207 | */ 208 | key = TEE_Malloc(sess->key_size, 0); 209 | if (!key) { 210 | res = TEE_ERROR_OUT_OF_MEMORY; 211 | goto err; 212 | } 213 | 214 | TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, sess->key_size); 215 | 216 | res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1); 217 | if (res != TEE_SUCCESS) { 218 | EMSG("TEE_PopulateTransientObject failed, %x", res); 219 | goto err; 220 | } 221 | 222 | res = TEE_SetOperationKey(sess->op_handle, sess->key_handle); 223 | if (res != TEE_SUCCESS) { 224 | EMSG("TEE_SetOperationKey failed %x", res); 225 | goto err; 226 | } 227 | 228 | return res; 229 | 230 | err: 231 | if (sess->op_handle != TEE_HANDLE_NULL) 232 | TEE_FreeOperation(sess->op_handle); 233 | sess->op_handle = TEE_HANDLE_NULL; 234 | 235 | if (sess->key_handle != TEE_HANDLE_NULL) 236 | TEE_FreeTransientObject(sess->key_handle); 237 | sess->key_handle = TEE_HANDLE_NULL; 238 | 239 | return res; 240 | } 241 | 242 | /* 243 | * Process command TA_AES_CMD_SET_KEY. API in aes_ta.h 244 | */ 245 | static TEE_Result set_aes_key(void *session, uint32_t param_types, 246 | TEE_Param params[4]) 247 | { 248 | const uint32_t exp_param_types = 249 | TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 250 | TEE_PARAM_TYPE_NONE, 251 | TEE_PARAM_TYPE_NONE, 252 | TEE_PARAM_TYPE_NONE); 253 | struct aes_cipher *sess; 254 | TEE_Attribute attr; 255 | TEE_Result res; 256 | uint32_t key_sz; 257 | char *key; 258 | 259 | /* Get ciphering context from session ID */ 260 | DMSG("Session %p: load key material", session); 261 | sess = (struct aes_cipher *)session; 262 | 263 | /* Safely get the invocation parameters */ 264 | if (param_types != exp_param_types) 265 | return TEE_ERROR_BAD_PARAMETERS; 266 | 267 | key = params[0].memref.buffer; 268 | key_sz = params[0].memref.size; 269 | 270 | if (key_sz != sess->key_size) { 271 | EMSG("Wrong key size %" PRIu32 ", expect %" PRIu32 " bytes", 272 | key_sz, sess->key_size); 273 | return TEE_ERROR_BAD_PARAMETERS; 274 | } 275 | 276 | /* 277 | * Load the key material into the configured operation 278 | * - create a secret key attribute with the key material 279 | * TEE_InitRefAttribute() 280 | * - reset transient object and load attribute data 281 | * TEE_ResetTransientObject() 282 | * TEE_PopulateTransientObject() 283 | * - load the key (transient object) into the cihering operation 284 | * TEE_SetOperationKey() 285 | * 286 | * TEE_SetOperationKey() requires operation to be in "initial state". 287 | * We can use TEE_ResetOperation() to reset the operation but this 288 | * api cannot be used on operation with key(s) not yet set. Hence, 289 | * when allocating the operation handle, we prevovision a dummy key. 290 | * Thus, set_key sequence always reset then set key on operation. 291 | */ 292 | 293 | TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, key_sz); 294 | 295 | TEE_ResetTransientObject(sess->key_handle); 296 | res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1); 297 | if (res != TEE_SUCCESS) { 298 | EMSG("TEE_PopulateTransientObject failed, %x", res); 299 | return res; 300 | } 301 | 302 | TEE_ResetOperation(sess->op_handle); 303 | res = TEE_SetOperationKey(sess->op_handle, sess->key_handle); 304 | if (res != TEE_SUCCESS) { 305 | EMSG("TEE_SetOperationKey failed %x", res); 306 | return res; 307 | } 308 | 309 | return res; 310 | } 311 | 312 | /* 313 | * Process command TA_AES_CMD_SET_IV. API in aes_ta.h 314 | */ 315 | static TEE_Result reset_aes_iv(void *session, uint32_t param_types, 316 | TEE_Param params[4]) 317 | { 318 | const uint32_t exp_param_types = 319 | TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 320 | TEE_PARAM_TYPE_NONE, 321 | TEE_PARAM_TYPE_NONE, 322 | TEE_PARAM_TYPE_NONE); 323 | struct aes_cipher *sess; 324 | size_t iv_sz; 325 | char *iv; 326 | 327 | /* Get ciphering context from session ID */ 328 | DMSG("Session %p: reset initial vector", session); 329 | sess = (struct aes_cipher *)session; 330 | 331 | /* Safely get the invocation parameters */ 332 | if (param_types != exp_param_types) 333 | return TEE_ERROR_BAD_PARAMETERS; 334 | 335 | iv = params[0].memref.buffer; 336 | iv_sz = params[0].memref.size; 337 | 338 | /* 339 | * Init cipher operation with the initialization vector. 340 | */ 341 | TEE_CipherInit(sess->op_handle, iv, iv_sz); 342 | 343 | return TEE_SUCCESS; 344 | } 345 | 346 | /* 347 | * Process command TA_AES_CMD_CIPHER. API in aes_ta.h 348 | */ 349 | static TEE_Result cipher_buffer(void *session, uint32_t param_types, 350 | TEE_Param params[4]) 351 | { 352 | const uint32_t exp_param_types = 353 | TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 354 | TEE_PARAM_TYPE_MEMREF_OUTPUT, 355 | TEE_PARAM_TYPE_NONE, 356 | TEE_PARAM_TYPE_NONE); 357 | struct aes_cipher *sess; 358 | 359 | /* Get ciphering context from session ID */ 360 | DMSG("Session %p: cipher buffer", session); 361 | sess = (struct aes_cipher *)session; 362 | 363 | /* Safely get the invocation parameters */ 364 | if (param_types != exp_param_types) 365 | return TEE_ERROR_BAD_PARAMETERS; 366 | 367 | if (params[1].memref.size < params[0].memref.size) { 368 | EMSG("Bad sizes: in %d, out %d", params[0].memref.size, 369 | params[1].memref.size); 370 | return TEE_ERROR_BAD_PARAMETERS; 371 | } 372 | 373 | if (sess->op_handle == TEE_HANDLE_NULL) 374 | return TEE_ERROR_BAD_STATE; 375 | 376 | /* 377 | * Process ciphering operation on provided buffers 378 | */ 379 | return TEE_CipherUpdate(sess->op_handle, 380 | params[0].memref.buffer, params[0].memref.size, 381 | params[1].memref.buffer, ¶ms[1].memref.size); 382 | } 383 | 384 | /* Get the BSD Linear congruential random value.*/ 385 | static TEE_Result rand_value(uint32_t param_types, TEE_Param params[4]) 386 | { 387 | const uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, 388 | TEE_PARAM_TYPE_VALUE_INOUT, 389 | TEE_PARAM_TYPE_VALUE_INOUT, 390 | TEE_PARAM_TYPE_NONE); 391 | 392 | DMSG("rand_value has been called"); 393 | if (param_types != exp_param_types) 394 | return TEE_ERROR_BAD_PARAMETERS; 395 | 396 | DMSG("Got rand seed: %u from NW", params[1].value.a); 397 | int Address = params[1].value.a; 398 | bsd_srand(Address); 399 | Address = bsd_rand() % 128000 + 1; 400 | params[1].value.a = Address; 401 | DMSG("Calculate random value: %u", params[1].value.a); 402 | return TEE_SUCCESS; 403 | } 404 | 405 | /* Get the SWATT next current byte, reference func: getSWATT */ 406 | static TEE_Result swatt_next(uint32_t param_types, TEE_Param params[4]) 407 | { 408 | const uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, 409 | TEE_PARAM_TYPE_VALUE_INOUT, 410 | TEE_PARAM_TYPE_VALUE_INOUT, 411 | TEE_PARAM_TYPE_NONE); 412 | 413 | DMSG("has been called"); 414 | if (param_types != exp_param_types) 415 | return TEE_ERROR_BAD_PARAMETERS; 416 | DMSG("Got value: %u from NW", params[0].value.a); 417 | params[0].value.b = params[1].value.b + params[0].value.a; 418 | params[1].value.b = params[1].value.b >> 1; 419 | params[2].value.b = params[2].value.a; 420 | params[2].value.a = params[1].value.b; 421 | DMSG("Increase value to: %u", params[0].value.a); 422 | return TEE_SUCCESS; 423 | } 424 | 425 | TEE_Result TA_CreateEntryPoint(void) 426 | { 427 | /* Nothing to do */ 428 | return TEE_SUCCESS; 429 | } 430 | 431 | void TA_DestroyEntryPoint(void) 432 | { 433 | /* Nothing to do */ 434 | } 435 | 436 | TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types, 437 | TEE_Param __unused params[4], 438 | void __unused **session) 439 | { 440 | struct aes_cipher *sess; 441 | 442 | /* 443 | * Allocate and init ciphering materials for the session. 444 | * The address of the structure is used as session ID for 445 | * the client. 446 | */ 447 | sess = TEE_Malloc(sizeof(*sess), 0); 448 | if (!sess) 449 | return TEE_ERROR_OUT_OF_MEMORY; 450 | 451 | sess->key_handle = TEE_HANDLE_NULL; 452 | sess->op_handle = TEE_HANDLE_NULL; 453 | 454 | *session = (void *)sess; 455 | DMSG("Session %p: newly allocated", *session); 456 | 457 | return TEE_SUCCESS; 458 | } 459 | 460 | void TA_CloseSessionEntryPoint(void *session) 461 | { 462 | struct aes_cipher *sess; 463 | 464 | /* Get ciphering context from session ID */ 465 | DMSG("Session %p: release session", session); 466 | sess = (struct aes_cipher *)session; 467 | 468 | /* Release the session resources */ 469 | if (sess->key_handle != TEE_HANDLE_NULL) 470 | TEE_FreeTransientObject(sess->key_handle); 471 | if (sess->op_handle != TEE_HANDLE_NULL) 472 | TEE_FreeOperation(sess->op_handle); 473 | TEE_Free(sess); 474 | } 475 | 476 | TEE_Result TA_InvokeCommandEntryPoint(void *session, 477 | uint32_t cmd, 478 | uint32_t param_types, 479 | TEE_Param params[4]) 480 | { 481 | switch (cmd) { 482 | case TA_AES_CMD_PREPARE: 483 | return alloc_resources(session, param_types, params); 484 | case TA_AES_CMD_SET_KEY: 485 | return set_aes_key(session, param_types, params); 486 | case TA_AES_CMD_SET_IV: 487 | return reset_aes_iv(session, param_types, params); 488 | case TA_AES_CMD_CIPHER: 489 | return cipher_buffer(session, param_types, params); 490 | case TA_SWATT_CMD_RAND: 491 | return rand_value(param_types, params); 492 | case TA_SWATT_CMD_CAL: 493 | return swatt_next(param_types, params); 494 | default: 495 | EMSG("Command ID 0x%x is not supported", cmd); 496 | return TEE_ERROR_NOT_SUPPORTED; 497 | } 498 | } 499 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/ta/include/aes_ta.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef __AES_TA_H__ 29 | #define __AES_TA_H__ 30 | 31 | /* UUID of the AES example trusted application */ 32 | #define TA_AES_UUID \ 33 | { 0x7aaaf200, 0x2450, 0x11e4, \ 34 | { 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} } 35 | 36 | /* 37 | * TA_AES_CMD_PREPARE - Allocate resources for the AES ciphering 38 | * param[0] (value) a: TA_AES_ALGO_xxx, b: unused 39 | * param[1] (value) a: key size in bytes, b: unused 40 | * param[2] (value) a: TA_AES_MODE_ENCODE/_DECODE, b: unused 41 | * param[3] unused 42 | */ 43 | #define TA_AES_CMD_PREPARE 0 44 | 45 | #define TA_AES_ALGO_ECB 0 46 | #define TA_AES_ALGO_CBC 1 47 | #define TA_AES_ALGO_CTR 2 48 | 49 | #define TA_AES_SIZE_128BIT (128 / 8) 50 | #define TA_AES_SIZE_256BIT (256 / 8) 51 | 52 | #define TA_AES_MODE_ENCODE 1 53 | #define TA_AES_MODE_DECODE 0 54 | 55 | /* 56 | * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering 57 | * param[0] (memref) key data, size shall equal key length 58 | * param[1] unused 59 | * param[2] unused 60 | * param[3] unused 61 | */ 62 | #define TA_AES_CMD_SET_KEY 1 63 | 64 | /* 65 | * TA_AES_CMD_SET_IV - reset IV 66 | * param[0] (memref) initial vector, size shall equal key length 67 | * param[1] unused 68 | * param[2] unused 69 | * param[3] unused 70 | */ 71 | #define TA_AES_CMD_SET_IV 2 72 | 73 | /* 74 | * TA_AES_CMD_CIPHER - Ciphere inut buffer into output buffer 75 | * param[0] (memref) input buffer 76 | * param[1] (memref) output buffer (shall be bigger than input buffer) 77 | * param[2] unused 78 | * param[3] unused 79 | */ 80 | #define TA_AES_CMD_CIPHER 3 81 | 82 | 83 | /* 84 | * TA_SWATT_CMD_RAND - random number seed input and random int output 85 | * param[0] (value) a: input random seed b: unused 86 | * param[1] unused 87 | * param[2] unused 88 | * param[3] unused 89 | */ 90 | #define TA_SWATT_CMD_RAND 4 91 | 92 | /* 93 | * TA_SWATT_CMD_CAL - SWATT byte swap and shift 94 | * param[0] (value) a: swatt_seed b: init_seed 95 | * param[1] (value) a: Address b: current_cs 96 | * param[2] (value) a: prev_cs b: pprev_cs 97 | * param[3] unused 98 | */ 99 | #define TA_SWATT_CMD_CAL 5 100 | 101 | #endif /* __AES_TA_H */ 102 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/ta/sub.mk: -------------------------------------------------------------------------------- 1 | global-incdirs-y += include 2 | #global-incdirs-y += ../host/include 3 | srcs-y += aes_ta.c 4 | 5 | # To remove a certain compiler flag, add a line like this 6 | #cflags-template_ta.c-y += -Wno-strict-prototypes 7 | -------------------------------------------------------------------------------- /src/trustClient/trustClient/ta/user_ta_header_defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* 29 | * The name of this file must not be modified 30 | */ 31 | 32 | #ifndef USER_TA_HEADER_DEFINES_H 33 | #define USER_TA_HEADER_DEFINES_H 34 | 35 | #include 36 | 37 | #define TA_UUID TA_AES_UUID 38 | 39 | #define TA_FLAGS TA_FLAG_EXEC_DDR 40 | #define TA_STACK_SIZE (2 * 1024) 41 | #define TA_DATA_SIZE (32 * 1024) 42 | 43 | #define TA_CURRENT_TA_EXT_PROPERTIES \ 44 | { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \ 45 | "Example of TA using an AES sequence" }, \ 46 | { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } } 47 | 48 | #endif /*USER_TA_HEADER_DEFINES_H*/ 49 | --------------------------------------------------------------------------------