-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathencoder.go
114 lines (94 loc) · 3.01 KB
/
encoder.go
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2022 Teal.Finance/incorruptible contributors
// This file is part of Teal.Finance/incorruptible
// a tiny+secured cookie token licensed under the MIT License.
// SPDX-License-Identifier: MIT
// Package incorruptible provides a safer, shorter, faster
// secret token for session cookie and Authorization HTTP header.
package incorruptible
import (
"errors"
"fmt"
"time"
)
const (
// Base91MinSize and ciphertextMinSize need to be adapted according
// on any change about expiry encoding size, padding size...
Base91MinSize = 42
ciphertextMinSize = 6
encryptedMinSize = aesNonceSize + ciphertextMinSize + gcmTagSize
// noSpaceDoubleQuoteSemicolon exclude character not welcome in cookie token:
// space, double-quote ", semi-colon ; and back-slash \
// This Base91 encoding alphabet is shuffled at startup time
// using the (secret) encryption key.
noSpaceDoubleQuoteSemicolon = "" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789!#$%&()*+,-./:<=>?@[]^_`{|}~'"
doPrint = false
)
func (incorr *Incorruptible) Encode(tv TValues) (string, error) {
printV("Encode Marshal", tv, nil)
plaintext, err := Marshal(tv, incorr.magic)
if err != nil {
return "", err
}
printB("Encode Encrypt plaintext", plaintext)
nonceCiphertextAndTag := Encrypt(incorr.cipher, plaintext)
printB("Encode EncodeToString ciphertext", nonceCiphertextAndTag)
str := incorr.baseN.EncodeToString(nonceCiphertextAndTag)
printS("Encode result = BasE91", str)
return str, nil
}
func (incorr *Incorruptible) Decode(base91 string) (TValues, error) {
var tv TValues
printS("Decode DecodeString BasE91", base91)
if len(base91) < Base91MinSize {
return tv, fmt.Errorf("BasE91 text too short: %d < min=%d", len(base91), Base91MinSize)
}
encrypted, err := incorr.baseN.DecodeString(base91)
if err != nil {
return tv, err
}
printB("Decode Decrypt", encrypted)
if len(encrypted) < encryptedMinSize {
return tv, fmt.Errorf("encrypted data too short: %d < min=%d", len(encrypted), encryptedMinSize)
}
plaintext, err := Decrypt(incorr.cipher, encrypted)
if err != nil {
return tv, err
}
printB("Decode Unmarshal plaintext", plaintext)
if MagicCode(plaintext) != incorr.magic {
return tv, errors.New("bad magic code")
}
tv, err = Unmarshal(plaintext)
printV("Decode result", tv, err)
return tv, err
}
// printS prints a string in debug mode (when doPrint is true).
func printS(name, s string) {
if doPrint {
n := len(s)
if n > 30 {
n = 30
}
log.Debugf("Incorr.%s len=%d %q", name, len(s), s[:n])
}
}
// printB prints a byte-buffer in debug mode (when doPrint is true).
func printB(name string, buf []byte) {
if doPrint {
n := len(buf)
if n > 30 {
n = 30
}
log.Debugf("Incorr.%s len=%d cap=%d %x", name, len(buf), cap(buf), buf[:n])
}
}
// printV prints TValues in debug mode (when doPrint is true).
func printV(name string, tv TValues, err error) {
if doPrint {
log.Debugf("Incorr.%s tv %v %v n=%d err=%s", name,
time.Unix(tv.Expires, 0), tv.IP, len(tv.Values), err)
}
}