Runes - Simple Cookies You Can Extend (similar to Macaroons)

Overview

Runes - Simple Cookies You Can Extend (similar to Macaroons)

https://research.google/pubs/pub41892/ is a paper called "Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud". It has one good idea, some extended ideas nobody implements, and lots and lots of words.

The idea: a server issues a cookie to Alice. She can derive cookies with extra restrictions and hand them to Bob and Carol to send back to the server, and they can't remove the restrictions.

But they did it using a Message Authetication Code (MAC, get it?), which is actually counter-productive, since it's simpler and better to use Length Extension to achieve the same results. I call that a Rune; this version really only handles strings, but you can use hex or another encoding.

Rune Language

A rune is a series of restrictions; you have to pass all of them (so appending a new one always makes the rune less powerful). Each restriction is one or more alternatives ("cmd=foo OR cmd=bar"), any one of which can pass.

The form of each alternative is a simple string:

ALTERNATIVE := FIELDNAME CONDITION VALUE

FIELDNAME contains only UTF-8 characters, exclusive of ! " # $ % & ' ( ) * +, - . / : ; ? @ [ \ ] ^ _ ` { | } ~ (C's ispunct()). These can appear inside a VALUE, but &, | and \\ must be escaped with \ (escaping is legal for any character, but unnecessary).

CONDITION is one of the following values:

  • !: Pass if field is missing (value ignored)
  • =: Pass if exists and exactly equals
  • ^: Pass if exists and begins with
  • $: Pass if exists and ends with
  • ~: Pass if exists and contains
  • <: Pass if exists, is a valid decimal (may be signed), and numerically less than
  • >: Pass if exists, is a valid decimal (may be signed), and numerically greater than
  • }: Pass if exists and lexicograpically greater than (or longer)
  • {: Pass if exists and lexicograpically less than (or shorter)
  • #: Always pass: no condition, this is a comment.

Grouping using ( and ) may be added in future.

A restriction is a group of alternatives separated by |; restrictions are separated by &. e.g.

cmd=foo | cmd=bar
& subcmd! | subcmd{get

The first requires cmd be present, and to be foo or bar. The second requires that subcmd is not present, or is lexicographically less than get. Both must be true for authorization to succeed.

Rune Authorization

A run also comes with a SHA-256 authentication code. This is generated as SHA-256 of the following bytestream:

  1. The secret (less than 56 bytes, known only to the server which issued it).
  2. For every restriction:
    1. Pad the stream as per SHA-256 (i.e. append 0x80, then zeroes, then the big-endian 64-bit bitcount so far, such that it's a multiple of 64 bytes).
    2. Append the restriction.

By using the same padding scheme as SHA-256 usually uses to end the data, we have the property that we can initialize the SHA-256 function with the result from any prior restriction, and continue.

The server can validate the rune authorization by repeating this procedure and checking the result.

Rune Encoding

Runes are encoded as base64, starting with the 256-bit SHA256 authentication code, the followed by one or more restrictions separated by &.

Not because base64 is good, but because it's familiar to Web people; we use RFC3548 with + and / replaced by - and _ to make it URL safe.

API Example

Here's the server, making you a rune! (spoiler: it's "-YpZTBZ4Tb5SsUz3XIukxBxR619iEthm9oNJnC0LxZM=")

import runes
import secrets

# Secret determined by fair dice roll.
secret = bytes([5] * 16)

# Make an unrestricted rune.
rune = runes.MasterRune(secret)

# We could add our own restrictions here, if we wanted.
print("Your rune is {}".format(rune.to_base64()))

Here's the server, checking a rune. You will need to define what conditions you provide for the rune to test; one of the most useful ones is time, but other common things are the resource being accessed, (e.g. URL, or command and parameters), or who is accessing it (assuming you have authenticated them already in some way).

import runes
import time
import sys

secret = bytes([5] * 16)

# In real life, this would come from the web data.
runestring = sys.argv[1]

# This checks the format is correct, it's authorized, an that it meets
# our values.  I assume we have values time (UNIX, seconds since
# 1970), command and optional id.
# (You can also use rune.check() if you don't care *why* it failed)
ok, whyfail = rune.check_with_reason(secret, runestring,
                                     {'time': int(time.time()),
                                      'command': 'somecommand',
                                      'id': 'DEADBEEF'})
if not ok:
    print("Rune restrictions failed: {}".format(whyfail))
    sys.exit(1)

print("Yes, you passed!")

Here's the client Alice. She gets the rune and gives Bob a variant that can only be used for 1 minute:

import runes
import time

# In real life, this would come from the web data.
runestring = sys.argv[1]

# You'd catch exceptions here, usually.
rune = runes.from_base64(runestring)

# You can construct a Restriction class from a sequence of Alternative
# but it's easier to use decode() to translate a string
rune.add_restriction(rune.Restriction.decode("time < {}".format((int)time.time() + 60))

print("Your restricted rune is {}".format(rune.to_base64()))

You can find more examples in the examples/ subdirectory.

Author

Rusty Russell wrote it; but I blame @roasbeef for raving about them long enough at LnConf that I actually read the paper. It only took me 18 months to find a day to implement them.

Owner
Rusty Russell
GPG: 15EE 8D6C AB0E 7F0C F999 BFCB D920 0E6C D1AD B8F1 Rusty Russell
Rusty Russell
kawadi is a versatile tool that used as a form of weapon and is used to cut, shape and split wood.

kawadi kawadi (કવાડિ in Gujarati) (Axe in English) is a versatile tool that used as a form of weapon and is used to cut, shape and split wood. kawadi

Jay Vala 2 Jan 10, 2022
Cardano Stakepools: Check for scheduled blocks in current epoch.

ReLeaderLogs For Cardano Stakepool Operators: Lightweight Scheduled Blocks Checker for Current Epoch. No cardano-node Required, data is taken from blo

SNAKE (Cardano Stakepool) 2 Oct 19, 2021
This utility lets you draw using your laptop's touchpad on Linux.

FingerPaint This utility lets you draw using your laptop's touchpad on Linux. Pressing any key or clicking the touchpad will finish the drawing

Wazzaps 95 Dec 17, 2022
A Python package implementing various colour checker detection algorithms and related utilities.

A Python package implementing various colour checker detection algorithms and related utilities.

colour-science 147 Dec 29, 2022
Functional UUIDs for Python.

🏷️FUUID stands for Functional Universally Unique IDentifier. FUUIDs are compatible with regular UUIDs but are naturally ordered by generation time, collision-free and support succinct representations

Phil Demetriou 147 Oct 27, 2022
Collection of code auto-generation utility scripts for the Horizon `Boot` system module

boot-scripts This is a collection of code auto-generation utility scripts for the Horizon Boot system module, intended for use in Atmosphère. Usage Us

4 Oct 11, 2022
async parser for JET

This project is mainly aims to provide an async parsing option for NTDS.dit database file for obtaining user secrets.

15 Mar 08, 2022
A string to hashtags module

A string to hashtags module

Fayas Noushad 4 Dec 01, 2021
A simple tool to extract python code from a Jupyter notebook, and then run pylint on it for static analysis.

Jupyter Pylinter A simple tool to extract python code from a Jupyter notebook, and then run pylint on it for static analysis. If you find this tool us

Edmund Goodman 10 Oct 13, 2022
general-phylomoji: a phylogenetic tree of emoji

general-phylomoji: a phylogenetic tree of emoji

2 Dec 11, 2021
Display your calendar on the wallpaper.

wallCal Have your calendar appear as the wallpaper. disclaimer Use at your own risk. Don't blame me if you miss a meeting :-) Some parts of the script

7 Jun 14, 2022
Parse URLs for DOIs, PubMed identifiers, PMC identifiers, arXiv identifiers, etc.

citation-url Parse URLs for DOIs, PubMed identifiers, PMC identifiers, arXiv identifiers, etc. This module has a single parse() function that takes in

Charles Tapley Hoyt 2 Feb 12, 2022
A color library based on pokemons colors!

pokepalette A simple pokemon color chooser " This repo is based on CDWimmer/PokePalette and was originated from this tweet. If you don't remember your

Thomas Capelle 5 Aug 30, 2021
Tool to produce system call tables from Linux source code.

Syscalls Tool to generate system call tables from the linux source tree. Example The following will produce a markdown (.md) file containing the table

7 Jul 30, 2022
Auto-generate /etc/hosts for HackTheBox machines

Auto-generate /etc/hosts for HackTheBox machines Save yourself some tedium on getting started on a new machine by having your /etc/hosts ready to go.

3 Feb 16, 2022
Python program for Linux users to change any url to any domain name they want.

URLMask Python program for Linux users to change a URL to ANY domain. A program than can take any url and mask it to any domain name you like. E.g. ne

2 Jun 20, 2022
A python script to generate wallpaper

wallpaper eits Warning You need to set the path to Robot Mono font in the source code. (Settings are in the main function) Usage A script that given a

Henrique Tsuyoshi Yara 5 Dec 02, 2021
Here, I find the Fibonacci Series using python

Fibonacci-Series-using-python Here, I find the Fibonacci Series using python Requirements No Special Requirements Contribution I have strong belief on

Sachin Vinayak Dabhade 4 Sep 24, 2021
A monitor than send discord webhook when a specific monitored product has stock in your nearby pickup stores.

Welcome to Apple In-store Monitor This is a monitor that are not fully scaled, and might still have some bugs.

5 Jun 16, 2022
✨ Un générateur de mot de passe aléatoire totalement fait en Python par moi, et en français.

Password Generator ❗ Un générateur de mot de passe aléatoire totalement fait en Python par moi, et en français. 🔮 Grâce a une au module random et str

MrGabin 3 Jul 29, 2021