carlos / contra Public

Clone
git clone https://amadan.net/carlos/contra

Plain git — no account needed to clone.

Download

Download this file

1package crypto
2
3import "errors"
4
5// PadBucket is the size item plaintexts are quantised into before sealing.
6//
7// A1 tolerates size residue; that is no reason to hand over item-length
8// fingerprints for free. An unpadded vault publishes the length of every
9// password and every note to anyone holding the bucket, and lengths are
10// enough to pick the interesting rows out of a pile of ciphertext.
11const PadBucket = 256
12
13var (
14 ErrPadLength = errors.New("crypto: padded length is not a whole number of buckets")
15 ErrPadBytes = errors.New("crypto: malformed padding bytes")
16)
17
18// Pad grows b to the next whole bucket using ISO/IEC 7816-4 padding: one
19// 0x80 byte, then zeros. Always adds at least one byte, so the boundary case
20// (input already bucket-aligned) is unambiguous rather than a special case
21// somebody's second implementation gets wrong.
22func Pad(b []byte) []byte {
23 n := len(b) + 1
24 if r := n % PadBucket; r != 0 {
25 n += PadBucket - r
26 }
27 out := make([]byte, n)
28 copy(out, b)
29 out[len(b)] = 0x80
30 return out
31}
32
33// Unpad reverses Pad, rejecting anything that is not exactly what Pad
34// produces — a wrong length, a missing marker, or a non-zero byte after it.
35func Unpad(b []byte) ([]byte, error) {
36 if len(b) == 0 || len(b)%PadBucket != 0 {
37 return nil, ErrPadLength
38 }
39 for i := len(b) - 1; i >= 0; i-- {
40 switch b[i] {
41 case 0x00:
42 continue
43 case 0x80:
44 return b[:i], nil
45 default:
46 return nil, ErrPadBytes
47 }
48 }
49 return nil, ErrPadBytes
50}
51
52// IsBucketAligned reports whether a sealed blob could have come from Pad.
53// Sealed length is the padded plaintext plus AES-GCM's 128-bit tag, so the
54// storage layer can check the invariant without holding a key.
55//
56// Scheme-independent on purpose: it says the plaintext was quantised, not
57// how. The exact padding bytes are pinned by the golden vectors when the
58// item format lands.
59func IsBucketAligned(sealed []byte) bool {
60 const tagLen = 16
61 return len(sealed) > tagLen && (len(sealed)-tagLen)%PadBucket == 0
62}
63