Skip to content

Instantly share code, notes, and snippets.

@redwrasse
Last active February 19, 2022 06:01
Show Gist options
  • Save redwrasse/dd0c7823026cde99b1b4aac8b8b3dac8 to your computer and use it in GitHub Desktop.
Save redwrasse/dd0c7823026cde99b1b4aac8b8b3dac8 to your computer and use it in GitHub Desktop.
A mock reference monitor for accessing a top secret recipe
// A mock reference monitor design for a mock security system, enforcing the following access control policy:
// Only the user 'Alice' who identifies herself on requested inputs
// with her name and her birthday of '01.01.1980' is granted access to
// the top secret recipe file, stored on disk.
// This reference monitor design provides (some) security towards the given access policy
// by a) storing a hash rather than the values of the user inputs of (name, birthday) to compare against,
// and b) using a salt of the valid inputs as a symmetric key for AES encrypting the top secret recipe file beforehand and
// for decrypting before returning to Alice.
//
// Of course these comments would not be kept in the source code.
//
// Existing threat vectors:
// i) A simple brute-force attack.
// ...
//
///
// To run: save contents 'mvPVCvfYkKW51Vd9vcU7YVdiQol6TDlpL1vQT0WtNQi2qzI41yBcHexQgOx5d7_qoflLEg=='
// to a file called 'top_secret_encrypted', and start main().
package main
import (
"bufio"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
)
const CORRECT_INPUT = "VpRFAorxBrk6n_VmCZXLLL4CWHi95G7KpBRmcBc3Ltk="
const SALT = "foo1234567890123"
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter name: ")
name, _ := reader.ReadString('\n')
name = strings.TrimSuffix(name, "\n");
fmt.Println("Enter birthday: ")
birthday, _ := reader.ReadString('\n')
birthday = strings.TrimSuffix(birthday, "\n")
if checkInputs(name, birthday) {
dat := decryptFile(name, birthday)
fmt.Printf("Top secret recipe file contents:\n%s\n", string(dat))
}
}
func decryptFile(name string, birthday string) string {
dat, err := ioutil.ReadFile("./top_secret_encrypted")
check(err)
bdat, err2 := base64.URLEncoding.DecodeString(string(dat))
check(err2)
key := []byte(name + "|" + birthday + SALT)
dec, err3 := decrypt(key, bdat);
check(err3)
return string(dec)
}
func inputsHash(name string, birthday string) string {
return hash256(name + "|" + birthday)
}
func hash256(s string) string {
h := sha256.New()
h.Write([]byte(s))
sha := base64.URLEncoding.EncodeToString(h.Sum(nil))
return sha
}
func checkInputs(name string, birthday string) bool {
sha := inputsHash(name, birthday)
if sha == CORRECT_INPUT {
fmt.Println("Correct inputs. Proceeding ...")
return true
} else {
fmt.Println("Incorrect. Exiting.")
return false
}
}
func check(e error) {
if e != nil { panic(e) }
}
func encrypt(key []byte, text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
b := base64.StdEncoding.EncodeToString(text)
ciphertext := make([]byte, aes.BlockSize+len(b))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
return ciphertext, nil
}
func decrypt(key []byte, text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(text) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
data, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return nil, err
}
return data, nil
}
@redwrasse
Copy link
Author

Alice has a recipe file on disk to read when she wishes, and keep safe from Bob.

Alice could simply use OS-level controls to give her read permissions to the file, and Bob none. This threat model is fairly simple: Bob wants to read Alice’s file on disk, Bob needs file read permissions to do so.

However Alice wants to use a program for further flexibility and possible control: she has in mind auditing, sharing permissions, possible updating of the file, encryption. So she instead makes her recipe file read & write-accessible for her and no access for anyone else, and launches her program with her as the process owner, so the program has read-write access to her file. The program also accepts user inputs for certain functionalities. Alice will herself use this program for operations so she will present a special piece of information (a ‘key’) for requested operations. Things are a lot more interesting now for Bob.

Some things Bob may have in mind
i) Steal Alice’s key.
ii) If he can trick the program to delete the file on disk, he can replace it with his own. Alice may of course detect these changes in the OS log history.
iii) If Bob has otherwise general filesystem access, he may try to swap out the program itself on disk with his own. If/when Alice relaunches the program, it will be Bob’s malicious version. In particular, Bob’s malicious program may perform ii). Alice may of course see all this in the OS file change logs.

Some things Alice may have in mind
i) Separate out program read and write operations in different keys- if Bob steals Alice’s ‘read authorization key’ but not ‘write authorization key’ confidentiality of the recipe is compromised, but not integrity. An example of privilege separation.
ii) Digitally sign/verify encrypt/decrypt contents of the file, via the program (the cryptographic protocols used are of course standard). This gives additional authenticity, integrity, confidentiality tied to the key (either shared-key or private-public key setting) used. This is particularly useful if Bob bypasses OS controls.

Problem
Alice is a highly esteemed chef, with a top secret recipe she desires to be kept for her eyes only in a computer file. Bob is looking for some new tricks to maneuver a promotion to Director of Condiments. Alice is going to write a program to protect her recipe file, and Bob is likely going to try to break into it.

Alice of course wants this program to allow only her access, identifying her by name and birthdate.

Some ways, abstractly that Bob could break in: i) access the file directly if he has permissions, ii) get Alice’s name and birthdate from the program source code if has permissions (a confused deputy attack) iii) guess/brute force Alice’s name and birthdate. iv) Kidnap Alice and demand her name and birthdate, or access to any of the conduits i), ii).

The ‘parts’ of this system are Alice, Bob, Alice’s program, and the recipe file. The starting point of all security is isolation of parts, in this case limiting the interaction between Bob and the recipe file. Bob is a principal, the recipe file is a resource, and Alice’s program is a reference monitor for Bob’s access to the recipe file. Preferably the reference monitor should have a policy separate from the mechanism, so as to enable changes/evolution to policy.

Alice’s First Program
The program stores Alice’s name and birthdate as variables. It reads the user’s given name and birthdate from standard input, and if there’s a match, reads Alice’s Top Secret Recipe from disk and returns it to standard out. If there isn’t a match, the program goes back to being prompted for user input.

i), ii), iii), iv) are all valid ways for Bob to get into this program.

Alice’s Second Program
Perhaps in this step policy is formally separated from mechanism, in accordance with the reference monitor model.

Example possible mechanisms
i) A sleep before re-looping on incorrect inputs - guards against brute force attacks

ii) A time-dependent computation on Alice’s part before sending inputs: Say birthdate % current time. Helps against brute force attack on both program and encrypted file directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment