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
A collection of utility functions to prototype geometry processing research in python

gpytoolbox This repo is a work in progress and contains general utility functions I have needed to code while trying to work on geometry process resea

Silvia Sellán 73 Jan 06, 2023
Personal Toolbox Package

Jammy (Jam) A personal toolbox by Qsh.zh. Usage setup For core package, run pip install jammy To access functions in bin git clone https://gitlab.com/

5 Sep 16, 2022
Python module and its web equivalent, to hide text within text by manipulating bits

cacherdutexte.github.io This project contains : Python modules (binary and decimal system 6) with a dedicated tkinter program to use it. A web version

2 Sep 04, 2022
tade is a discussion/forum/link aggregator application. It provides three interfaces: a regular web page, a mailing list bridge and an NNTP server

tade is a discussion/forum/link aggregator application. It provides three interfaces: a regular web page, a mailing list bridge and an NNTP server

Manos Pitsidianakis 23 Nov 04, 2022
A collection of tools for biomedical research assay analysis in Python.

waltlabtools A collection of tools for biomedical research assay analysis in Python. Key Features Analysis for assays such as digital ELISA, including

Tyler Dougan 1 Apr 18, 2022
pydsinternals - A Python native library containing necessary classes, functions and structures to interact with Windows Active Directory.

pydsinternals - Directory Services Internals Library A Python native library containing necessary classes, functions and structures to interact with W

Podalirius 36 Dec 14, 2022
✨ Un pierre feuille ciseaux totalement fait en Python par moi, et en français.

Pierre Feuille Ciseaux ❗ Un pierre feuille ciseaux totalement fait en Python par moi. 🔮 Avec l'utilisation du module "random", j'ai pu faire un choix

MrGabin 3 Jun 06, 2021
It is a tool that looks for a specific username in social networks

It is a tool that looks for a specific username in social networks

MasterBurnt 6 Oct 07, 2022
Generate random german words

Generate random german words / Generiere zufällige deutsche Wörter Getting Started Pip install with pip install zufallsworte Install the library with

Maximilian Freitag 5 Mar 24, 2022
Brainfuck rollup scaling experiment for fun

Optimistic Brainfuck Ever wanted to run Brainfuck on ethereum? Don't ask, now you can! And at a fraction of the cost, thanks to optimistic rollup tech

Diederik Loerakker 48 Dec 28, 2022
Basic loader is a small tool that will help you generating Cloudflare cookies

Basic Loader Cloudflare cookies loader This tool may help some people getting valide cloudflare cookies Installation 🔌 : pip install -r requirements.

IHateTomLrge 8 Mar 30, 2022
a demo show how to dump lldb info to ida.

用一个demo来聊聊动态trace 这个仓库能做什么? 帮助理解动态trace的思想。仓库内的demo,可操作,可实践。 动态trace核心思想: 动态记录一个函数内每一条指令的执行中产生的信息,并导入IDA,用来弥补IDA等静态分析工具的不足。 反编译看一下 先clone仓库,把hellolldb

25 Nov 28, 2022
This repository contains some utilities for playing with PKINIT and certificates.

PKINIT tools This repository contains some utilities for playing with PKINIT and certificates. The tools are built on minikerberos and impacket. Accom

Dirk-jan 395 Dec 27, 2022
These scripts look for non-printable unicode characters in all text files in a source tree

find-unicode-control These scripts look for non-printable unicode characters in all text files in a source tree. find_unicode_control.py should work w

Siddhesh Poyarekar 25 Aug 30, 2022
Dependency Injector is a dependency injection framework for Python.

What is Dependency Injector? Dependency Injector is a dependency injection framework for Python. It helps implementing the dependency injection princi

ETS Labs 2.6k Jan 04, 2023
Bounding Boxes Python Utils

Bounding Boxes Python Utils

Vadim 4 May 01, 2022
Color box that provides various colors‘ rgb decimal code.

colorbox Color box that provides various colors‘ rgb decimal code

1 Dec 07, 2021
A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

PyBash 11 May 22, 2022
aws ec2.py companion script to generate sshconfigs with auto bastion host discovery

ec2-bastion-sshconfig This script will interate over instances found by ec2.py and if those instances are not publically accessible it will search the

Steve Melo 1 Sep 11, 2022
Simple integer-valued time series bit packing

Smahat allows to encode a sequence of integer values using a fixed (for all values) number of bits but minimal with regards to the data range. For example: for a series of boolean values only one bit

Ghiles Meddour 7 Aug 27, 2021