-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtokenizer_cryptopan.go
103 lines (87 loc) · 2.44 KB
/
tokenizer_cryptopan.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
package main
import (
"crypto/rand"
"crypto/sha256"
"errors"
"sync"
"github.com/Yawning/cryptopan"
uuid "github.com/google/uuid"
"github.com/prometheus/client_golang/prometheus"
)
const (
ipv4Len = 4
ipv6Len = 16
)
var (
errNoKey = errors.New("key has not been initialized yet")
errBadBlobLen = errors.New("blob length not supported")
)
// cryptoPAnTokenizer implements a tokenizer that uses Crypto-PAn to anonymize
// IP addresses.
type cryptoPAnTokenizer struct {
sync.RWMutex
cryptoPAn *cryptopan.Cryptopan
key []byte
}
func newCryptoPAnTokenizer() tokenizer {
return &cryptoPAnTokenizer{}
}
func (c *cryptoPAnTokenizer) isBlobSupported(b []byte) bool {
return len(b) == ipv4Len || len(b) == ipv6Len
}
func (c *cryptoPAnTokenizer) tokenize(s serializer) (token, error) {
c.RLock()
defer c.RUnlock()
if len(c.key) == 0 {
m.numTokenized.With(prometheus.Labels{outcome: failBecause(errNoKey)}).Inc()
return nil, errNoKey
}
blob := s.bytes()
if !c.isBlobSupported(blob) {
m.numTokenized.With(prometheus.Labels{outcome: failBecause(errBadBlobLen)}).Inc()
return nil, errBadBlobLen
}
m.numTokenized.With(prometheus.Labels{outcome: success}).Inc()
return token(c.cryptoPAn.Anonymize(blob)), nil
}
func (c *cryptoPAnTokenizer) tokenizeAndKeyID(s serializer) (token, *keyID, error) {
c.RLock()
defer c.RUnlock()
if len(c.key) == 0 {
m.numTokenized.With(prometheus.Labels{outcome: failBecause(errNoKey)}).Inc()
return nil, nil, errNoKey
}
blob := s.bytes()
if !c.isBlobSupported(blob) {
m.numTokenized.With(prometheus.Labels{outcome: failBecause(errBadBlobLen)}).Inc()
return nil, nil, errBadBlobLen
}
m.numTokenized.With(prometheus.Labels{outcome: success}).Inc()
return token(c.cryptoPAn.Anonymize(blob)), c.keyID(), nil
}
func (c *cryptoPAnTokenizer) keyID() *keyID {
c.RLock()
defer c.RUnlock()
// A v5 UUID is supposed to hash the given name (in our case: the key)
// using SHA-1 but let's be extra careful and hash the key using SHA-256
// before handing it over to the uuid package.
sum := sha256.Sum256(c.key)
return &keyID{UUID: uuid.NewSHA1(uuidNamespace, sum[:])}
}
func (c *cryptoPAnTokenizer) resetKey() error {
c.Lock()
defer c.Unlock()
var err error
c.key = make([]byte, cryptopan.Size)
if _, err = rand.Read(c.key); err != nil {
return err
}
c.cryptoPAn, err = cryptopan.New(c.key)
if err != nil {
return err
}
return nil
}
func (c *cryptoPAnTokenizer) preservesLen() bool {
return true
}