Skip to content

Encrypted Files

We show how to transparently encrypt files.

SCONE CAS Overview

SCONE CAS manages the keys of an application. The keys are under complete control of the application: only services given explicit control by the application get access to the keys.

Prerequisites

We assume that you already

Writing a file

Let us start a crosscompiler container. We first determine which SGX device to mount with function determine_sgx_device.

determine_sgx_device
docker run $MOUNT_SGXDEVICE  --network=host -it -v `pwd`:/work registry.scontain.com/sconecuratedimages/crosscompilers bash

We create a simple C program to store arguments passed via environment variables into a file:

cd /work
cat > fprint-arg-env.c <<EOF
#include <stdio.h>
#include <stdlib.h>

extern char **__environ;

int main (int argc, char **argv) {
    FILE *fp = fopen("/volume/output.txt", "w");
    fprintf(fp, "argv:");
    for (int i = 0; i < argc; i++) {
        fprintf(fp, " %s", argv[i]);
    }
    fprintf(fp, "\n");

    char** envp = __environ;
    fprintf(fp, "environ:\n");
    while (*envp != NULL) {
        fprintf(fp, "%s\n", *envp);
        envp++;
    }
    fclose(fp);
    return 0;
}
EOF

Let us now compile the program:

scone-gcc fprint-arg-env.c -g -O3 -o fprint-arg-env

We can execute the program as follows:

mkdir -p /volume
./fprint-arg-env

This creates file: /volume/output.txt. We can look into this file an see that this file is not encrpted:

cat /volume/output.txt 
argv: ./fprint-arg-env
environ:
SCONE_LAS_ADDR=172.30.0.1
...

While this program runs inside of an enclave, it does not encrypt files by default. We need to enable this via a policy.

Creating a policy

Our objective is to create a policy that encrypts the written file. We assign this policy the following name:

export SESSION=fprint-arg-env-$RANDOM-$RANDOM
echo $SESSION
export MRENCLAVE=`SCONE_HASH=1 ./fprint-arg-env`
echo $MRENCLAVE

We protect the execution of this program with a OTP (One Time Password). We store the secret in environment variable OTP:

export OTPSECRET=... # base32 encoded without trailing =
cat > session.yaml <<EOF
name: $SESSION
version: 0.3

security:
  attestation:
    tolerate: [debug-mode, hyperthreading, outdated-tcb]
    ignore_advisories: "*"
    one_time_password_shared_secret: $OTPSECRET

volumes:
  - name: my_encrypted_volume

images:
  - name: my_image
    volumes:
      - name: my_encrypted_volume
        path: /volume

services:
   - name: fprint-arg-env
     image_name: my_image
     mrenclaves: [$MRENCLAVE]
     command: ./fprint-arg-env need to pass your OTP
     environment:
        SCONE_MODE: hw
        env1: version
        env2: 3
        env3: otp-variant
     pwd: /
EOF

Set the CAS and LAS host names / IP addresses:

export SCONE_CAS_ADDR=scone-cas.cf
export SCONE_LAS_ADDR=172.30.0.1

We first need to attest CAS:

scone cas attest $SCONE_CAS_ADDR --only_for_testing-trust-any --only_for_testing-debug  --only_for_testing-ignore-signer -C -G -S

before we can create the session:

export PREDECESSOR=$(scone session create session.yaml)
echo $PREDECESSOR

We can now execute the program as follows - note this requires access to an authenticator to compute the OTP:

export OTP=...

before we can actually start the program. We need to set the policy name that guides this execution. This is specified with environment variable SCONE_CONFIG_ID:

SCONE_CONFIG_ID=$SESSION/fprint-arg-env@$OTP ./fprint-arg-env 

The output will contain some warnings

[SCONE|WARN] src/enclave/dispatch.c:197:print_version(): Application runs in SGX debug mode.
    Its memory can be read from outside the enclave with a debugger! This is not secure!
[SCONE|WARN] src/syscall/syscall.c:31:__scone_ni_syscall(): system call: membarrier, number 324 is not supported
[SCONE|WARN] src/process/init.c:722:__scone_apply_secure_config(): Ignoring `SCONE_PWD` environment variable and host provided process working directory.
    Applying process working directory from service's session configuration (/)

since we do not run in production mode.

We can now try to dump the file /volume/output.txt and see that the file is now encrypted:

cat /volume/output.txt 
?f˭??Y?B?ľ|?yڥxK?{??I?d????k??!>??3T"????D"S??V??.?:D??????}?!?+I...

Reading the encrypted file

We can now try to decrypt the file with a second program:

cd /work
cat > print_file.c <<EOF
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *fp = fopen("/volume/output.txt", "rb");
    fseek(fp, 0, SEEK_END);
    long fsize = ftell(fp);
    fseek(fp, 0, SEEK_SET);  /* same as rewind(f); */

    char *string = malloc(fsize + 1);
    fread(string, fsize, 1, fp);
    fclose(fp);

    string[fsize] = 0;
    printf("File content:\n%s", string);
}
EOF

We can compile the program

scone-gcc print_file.c -g -O3 -o print_file

and run it and we will only see encrypted content:

?f˭??Y?B?ľ|?yڥxK?{??I?d????k??!>??3T"????D"S??V??.?:D??????}?!?+I...

Extending the Policy

We need to grant the program access to the policy. Let us extend the policy accordingly:

export MRENCLAVE2=`SCONE_HASH=1 ./print_file`
echo $MRENCLAVE2

We can now define the extended policy:

cat > session2.yaml <<EOF
name: $SESSION
version: 0.3
predecessor: $PREDECESSOR

security:
  attestation:
    tolerate: [debug-mode, hyperthreading, outdated-tcb]
    ignore_advisories: "*"
    one_time_password_shared_secret: $OTPSECRET

volumes:
  - name: my_encrypted_volume

images:
  - name: my_image
    volumes:
      - name: my_encrypted_volume
        path: /volume

services:
   - name: fprint-arg-env
     image_name: my_image
     mrenclaves: [$MRENCLAVE]
     command: ./fprint-arg-env need to pass your OTP
     environment:
        SCONE_MODE: hw
        env1: version
        env2: 3
        env3: otp-variant
     pwd: /
   - name: print_file
     image_name: my_image
     mrenclaves: [$MRENCLAVE2]
     command: ./print_file
     pwd: /
EOF

We update the session:

export PREDECESSOR2=$(scone session update session2.yaml)
echo $PREDECESSOR2

and can now execute print_file with the correct OPT:

export OTP=...
SCONE_CONFIG_ID=$SESSION/print_file@$OTP ./print_file 

The output will look as follows:

File content:
argv: ./fprint-arg-env need to pass your OTP
environ:
env3=otp-variant
SCONE_MODE=hw
env1=version
env2=3

Running without attestation

In case you do not have access to a SGX-capable CPU, you can run this code also in simulation mode. For this to work, we need to change our policy to say that we do not want to perform the attestation of the CPU and the code:

cat > session3.yaml <<EOF
name: $SESSION
version: 0.3
predecessor: $PREDECESSOR2

security:
  attestation:
    mode: none
    one_time_password_shared_secret: $OTPSECRET

volumes:
  - name: my_encrypted_volume

images:
  - name: my_image
    volumes:
      - name: my_encrypted_volume
        path: /volume

services:
   - name: fprint-arg-env
     image_name: my_image
     command: ./fprint-arg-env need to pass your OTP
     environment:
        SCONE_MODE: hw
        env1: version
        env2: 3
        env3: otp-variant
     pwd: /
   - name: print_file
     image_name: my_image
     command: ./print_file
     pwd: /
EOF

We update the session:

export PREDECESSOR3=$(scone session update session2.yaml)
echo $PREDECESSOR3

And we can now run the code in simulation mode:

export OTP=...
SCONE_MODE=SIM SCONE_CONFIG_ID=$SESSION/print_file@$OTP ./print_file