forked from dchest/reop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
devnotes.txt
95 lines (72 loc) · 4.28 KB
/
devnotes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
reop - reasonable expectation of privacy
developer notes
Some notes about the code that aren't necessarily relevant from a user
perspective.
current status
The code base is currently in the midst of a refactor to support a libreop
shared object. I didn't really have this in mind when writing 1.0, so it
involves quite some changes.
The two main issues are
1) keys/sigs/etc and idents are passed around separately. This is a historical
artifact inherited from its signify roots.
2) most functions operate on filenames, not file descriptors or buffers. This
makes sense for a standalone command line tool, it's less fun when you're
trying to save a signature in anything, such as a database.
I’m not enamored with the parsing code. Too much pointer banging.
layers
reop provides not one, not two, but three! layers of abstraction over nacl.
1) The wrapping of the raw crypt_box APIs and their uint8_t[] keys with some
basic structs.
2) Turning those binary structs into base64 text that can be shuffled around.
3) The key management layer, which basically consists of a few default files
in your home directory.
crypto notes
All the crypto comes from nacl (indirectly via libsodium). Specifically,
reop uses crypto_sign (Ed25519), crypto_box (Curve25519, Salsa20, and Poly1305)
and crypto_secretbox (Salsa20 and Poly1305). I have not personally vetted these
functions. Internet told me they were safe.
One thing to note is that the crypto_box construction may not behave
like other public key encryption schemes you are familiar with. It takes two
key pairs; the receiver’s public key as expected and the sender’s secret key,
which offers a measure of authentication.
What the nacl documentation doesn’t really make clear is that same set of keys
used for encrypting work for decrypting (i.e., it’s not asymmetric). For
instance, if Alice, sending a message to Bob, encrypts with secAlice and
pubBob, that would normally be decrypted by Bob with pubAlice and secBob. But
secAlice and pubBob work just as well to decrypt. If you were expecting to
encrypt some secret with a public key and then have that computer “forget” how
to access the secret, that won’t work.
reop used to work around this half-assedly. Now the workaround is at least
3/4-assed. An ephemeral key is generated. The meat of the message is encrypted
with secEph and pubBob. Then secEph is discarded. Now only pubEph and secBob
can decrypt. To authenticate the message, we encrypt pubEph with secAlice
and pubBob. Bob can authenticate the message with secBob and pubAlice, but he
could also have forged the message, giving Alice deniability.
This is something like what Noise Boxes would do, but which pub keys get
encrypted are swapped. (reop doesn’t hide sender identity.)
https://github.com/trevp/noise/wiki/Boxes
While it's possible to do things the other way around and try to provide
sender confidentiality, I'm not sure it's a good fit for reop. It doesn't
align with how the tool is likely to be used, and sender identity will most
likely leak some other way. Better IMO to simply not make that promise.
Nonces, where necessary, are generated randomly.
[The next two paragraphs are a little dated;
reop is using libsodium wrappers now.]
The nacl functions are all accessed via wrappers, very similar to the C++
wrappers. The C nacl API requires the caller to provide padded buffers
(i.e., ciphertext, auth tag, and zeroed scratch space all contiguous in memory),
which is somewhat inconvenient for a program like reop. As a result, more
memory is allocated and data copied than strictly mathematically necessary.
Additionally, nacl has a “packet” interface, not a “stream” interface, which
imposes some other limits on message size, but for most practical purposes it
should be fine.
It’s unfortunate, but I think nacl is the closest I’ve ever seen to a software
interface that is perpendicular to the rest of the program. For a program that
is essentially a CLI for nacl, reop spends considerable effort making sure that
things are just so. The ZEROBYTES vs BOXZEROBYTES nonsense is just this side of
ridiculous.
portability
The primary development platform is OpenBSD, but only a few necessary features
come from there and they're readily included in the other directory.
There's a fake configure script which should cook up an almost decent
Makefile.