Skip to content

Commit 93903bf

Browse files
committed
Use a simpler ASCII-based PAE (#27)
The previous PAE required binary encoding, which can be tricky in some langauges. The new PAE is pure ASCII so it can be implemented very easily in almost any language.
1 parent 1fecce3 commit 93903bf

File tree

2 files changed

+15
-28
lines changed

2 files changed

+15
-28
lines changed

implementation/signing_spec.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
The following example requires `pip3 install pycryptodome` and uses ecdsa.py in
77
the same directory as this file.
88
9-
>>> import binascii, os, sys, textwrap
9+
>>> import os, sys
1010
>>> from pprint import pprint
1111
>>> sys.path.insert(0, os.path.dirname(__file__))
1212
>>> import ecdsa
@@ -26,7 +26,7 @@
2626
>>> pprint(json.loads(signature_json))
2727
{'payload': 'aGVsbG8gd29ybGQ=',
2828
'payloadType': 'http://example.com/HelloWorld',
29-
'signatures': [{'sig': 'Cc3RkvYsLhlaFVd+d6FPx4ZClhqW4ZT0rnCYAfv6/ckoGdwT7g/blWNpOBuL/tZhRiVFaglOGTU8GEjm4aEaNA=='}]}
29+
'signatures': [{'sig': 'A3JqsQGtVsJ2O2xqrI5IcnXip5GToJ3F+FnZ+O88SjtR6rDAajabZKciJTfUiHqJPcIAriEGAHTVeCUjW2JIZA=='}]}
3030
3131
Verification example:
3232
@@ -36,14 +36,8 @@
3636
3737
PAE:
3838
39-
>>> def print_hex(b: bytes):
40-
... octets = ' '.join(textwrap.wrap(binascii.hexlify(b).decode('utf-8'), 2))
41-
... print(*textwrap.wrap(octets, 48), sep='\n')
42-
>>> print_hex(PAE(payloadType, payload))
43-
02 00 00 00 00 00 00 00 1d 00 00 00 00 00 00 00
44-
68 74 74 70 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63
45-
6f 6d 2f 48 65 6c 6c 6f 57 6f 72 6c 64 0b 00 00
46-
00 00 00 00 00 68 65 6c 6c 6f 20 77 6f 72 6c 64
39+
>>> PAE(payloadType, payload)
40+
b'DSSEv1 29 http://example.com/HelloWorld 11 hello world'
4741
"""
4842

4943
import base64, binascii, dataclasses, json, struct
@@ -88,12 +82,9 @@ def b64dec(m: str) -> bytes:
8882

8983

9084
def PAE(payloadType: str, payload: bytes) -> bytes:
91-
return b''.join([
92-
struct.pack('<Q', 2),
93-
struct.pack('<Q', len(payloadType)),
94-
payloadType.encode('utf-8'),
95-
struct.pack('<Q', len(payload)), payload
96-
])
85+
return b'DSSEv1 %d %b %d %b' % (
86+
len(payloadType), payloadType.encode('utf-8'),
87+
len(payload), payload)
9788

9889

9990
def Sign(payloadType: str, payload: bytes, signer: Signer) -> str:

protocol.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,12 @@ KEYID | string | No | No
5353

5454
Functions:
5555

56-
* PAE() is the
57-
[PASETO Pre-Authentication Encoding](https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Common.md#authentication-padding),
58-
where parameters `type` and `body` are byte sequences:
56+
* PAE() is the "Pre-Authentication Encoding", where parameters `type` and
57+
`body` are byte sequences:
5958

60-
```none
61-
PAE(type, body) := le64(2) || le64(len(type)) || type || le64(len(body)) || body
62-
le64(n) := 64-bit little-endian encoding of `n`, where 0 <= n < 2^63
59+
```python
60+
PAE(type, body) := "DSSEv1 <len(type)> <type> <len(body)> <body>"
61+
len(s) := ASCII decimal encoding of the byte length of s, with no leading zeros
6362
```
6463

6564
* Sign() is an arbitrary digital signature format. Details are agreed upon
@@ -102,7 +101,7 @@ either, and verifiers **MUST** accept either.
102101

103102
## Test Vectors
104103

105-
See [reference implementation](reference_implementation.ipynb). Here is an
104+
See [reference implementation](implementation/signing_spec.py). Here is an
106105
example.
107106

108107
SERIALIZED_BODY:
@@ -120,10 +119,7 @@ http://example.com/HelloWorld
120119
PAE:
121120

122121
```none
123-
02 00 00 00 00 00 00 00 1d 00 00 00 00 00 00 00
124-
68 74 74 70 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63
125-
6f 6d 2f 48 65 6c 6c 6f 57 6f 72 6c 64 0b 00 00
126-
00 00 00 00 00 68 65 6c 6c 6f 20 77 6f 72 6c 64
122+
DSSEv1 29 http://example.com/HelloWorld 11 hello world
127123
```
128124

129125
Cryptographic keys:
@@ -141,7 +137,7 @@ Result (using the recommended [JSON envelope](envelope.md)):
141137
```json
142138
{"payload": "aGVsbG8gd29ybGQ=",
143139
"payloadType": "http://example.com/HelloWorld",
144-
"signatures": [{"sig": "y7BK8Mm8Mr4gxk4+G9X3BD1iBc/vVVuJuV4ubmsEK4m/8MhQOOS26ejx+weIjyAx8VjYoZRPpoXSNjHEzdE7nQ=="}]}
140+
"signatures": [{"sig": "A3JqsQGtVsJ2O2xqrI5IcnXip5GToJ3F+FnZ+O88SjtR6rDAajabZKciJTfUiHqJPcIAriEGAHTVeCUjW2JIZA=="}]}
145141
```
146142

147143
[Canonical JSON]: http://wiki.laptop.org/go/Canonical_JSON

0 commit comments

Comments
 (0)