-
Notifications
You must be signed in to change notification settings - Fork 5.9k
/
rfc4122.go
146 lines (132 loc) · 3.73 KB
/
rfc4122.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package uuid
/***************
* Date: 14/02/14
* Time: 7:44 PM
***************/
import (
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"encoding/binary"
"log"
seed "math/rand"
"net"
)
const (
length = 16
// 3F used by RFC4122 although 1F works for all
variantSet = 0x3F
// rather than using 0xC0 we use 0xE0 to retrieve the variant
// The result is the same for all other variants
// 0x80 and 0xA0 are used to identify RFC4122 compliance
variantGet = 0xE0
)
var (
// nodeID is the default Namespace node
nodeId = []byte{
// 00.192.79.212.48.200
0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
}
// The following standard UUIDs are for use with V3 or V5 UUIDs.
NamespaceDNS = &Struct{0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
NamespaceURL = &Struct{0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
NamespaceOID = &Struct{0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
NamespaceX500 = &Struct{0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
state State
)
func init() {
seed.Seed((int64(timestamp())^int64(gregorianToUNIXOffset))*0x6ba7b814<<0x6ba7b812 | 1391463463)
state = State{
randomNode: true,
randomSequence: true,
past: Timestamp((1391463463 * 10000000) + (100 * 10) + gregorianToUNIXOffset),
node: nodeId,
sequence: uint16(seed.Int()) & 0x3FFF,
saver: nil,
}
}
// NewV1 will generate a new RFC4122 version 1 UUID
func NewV1() UUID {
state.Lock()
now := currentUUIDTimestamp()
state.read(now, currentUUIDNodeId())
state.persist()
state.Unlock()
return formatV1(now, uint16(1), ReservedRFC4122, state.node)
}
// NewV3 will generate a new RFC4122 version 3 UUID
// V3 is based on the MD5 hash of a namespace identifier UUID and
// any type which implements the UniqueName interface for the name.
// For strings and slices cast to a Name type
func NewV3(pNs UUID, pName UniqueName) UUID {
o := new(Array)
// Set all bits to MD5 hash generated from namespace and name.
Digest(o, pNs, pName, md5.New())
o.setRFC4122Variant()
o.setVersion(3)
return o
}
// NewV4 will generate a new RFC4122 version 4 UUID
// A cryptographically secure random UUID.
func NewV4() UUID {
o := new(Array)
// Read random values (or pseudo-randomly) into Array type.
_, err := rand.Read(o[:length])
if err != nil {
panic(err)
}
o.setRFC4122Variant()
o.setVersion(4)
return o
}
// NewV5 will generate a new RFC4122 version 5 UUID
// Generate a UUID based on the SHA-1 hash of a namespace
// identifier and a name.
func NewV5(pNs UUID, pName UniqueName) UUID {
o := new(Array)
Digest(o, pNs, pName, sha1.New())
o.setRFC4122Variant()
o.setVersion(5)
return o
}
// either generates a random node when there is an error or gets
// the pre initialised one
func currentUUIDNodeId() (node net.HardwareAddr) {
if state.randomNode {
b := make([]byte, 16+6)
_, err := rand.Read(b)
if err != nil {
log.Println("UUID.currentUUIDNodeId error:", err)
node = nodeId
return
}
h := sha1.New()
h.Write(b)
binary.Write(h, binary.LittleEndian, state.sequence)
node = h.Sum(nil)[:6]
if err != nil {
log.Println("UUID.currentUUIDNodeId error:", err)
node = nodeId
return
}
// Mark as randomly generated
node[0] |= 0x01
} else {
node = state.node
}
return
}
// Unmarshal data into struct for V1 UUIDs
func formatV1(pNow Timestamp, pVersion uint16, pVariant byte, pNode []byte) UUID {
o := new(Struct)
o.timeLow = uint32(pNow & 0xFFFFFFFF)
o.timeMid = uint16((pNow >> 32) & 0xFFFF)
o.timeHiAndVersion = uint16((pNow >> 48) & 0x0FFF)
o.timeHiAndVersion |= uint16(pVersion << 12)
o.sequenceLow = byte(state.sequence & 0xFF)
o.sequenceHiAndVariant = byte((state.sequence & 0x3F00) >> 8)
o.sequenceHiAndVariant |= pVariant
o.node = pNode
o.size = length
return o
}