1 // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru> 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining 4 // a copy of this software and associated documentation files (the 5 // "Software"), to deal in the Software without restriction, including 6 // without limitation the rights to use, copy, modify, merge, publish, 7 // distribute, sublicense, and/or sell copies of the Software, and to 8 // permit persons to whom the Software is furnished to do so, subject to 9 // the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be 12 // included in all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 package uuid 23 24 import ( 25 "crypto/md5" 26 "crypto/rand" 27 "crypto/sha1" 28 "encoding/binary" 29 "fmt" 30 "hash" 31 "io" 32 "net" 33 "sync" 34 "time" 35 ) 36 37 // Difference in 100-nanosecond intervals between 38 // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). 39 const epochStart = 122192928000000000 40 41 type epochFunc func() time.Time 42 43 // HWAddrFunc is the function type used to provide hardware (MAC) addresses. 44 type HWAddrFunc func() (net.HardwareAddr, error) 45 46 // DefaultGenerator is the default UUID Generator used by this package. 47 var DefaultGenerator Generator = NewGen() 48 49 // NewV1 returns a UUID based on the current timestamp and MAC address. 50 func NewV1() (UUID, error) { 51 return DefaultGenerator.NewV1() 52 } 53 54 // NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name. 55 func NewV3(ns UUID, name string) UUID { 56 return DefaultGenerator.NewV3(ns, name) 57 } 58 59 // NewV4 returns a randomly generated UUID. 60 func NewV4() (UUID, error) { 61 return DefaultGenerator.NewV4() 62 } 63 64 // NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name. 65 func NewV5(ns UUID, name string) UUID { 66 return DefaultGenerator.NewV5(ns, name) 67 } 68 69 // NewV6 returns a k-sortable UUID based on a timestamp and 48 bits of 70 // pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit 71 // order being adjusted to allow the UUID to be k-sortable. 72 // 73 // This is implemented based on revision 03 of the Peabody UUID draft, and may 74 // be subject to change pending further revisions. Until the final specification 75 // revision is finished, changes required to implement updates to the spec will 76 // not be considered a breaking change. They will happen as a minor version 77 // releases until the spec is final. 78 func NewV6() (UUID, error) { 79 return DefaultGenerator.NewV6() 80 } 81 82 // NewV7 returns a k-sortable UUID based on the current millisecond precision 83 // UNIX epoch and 74 bits of pseudorandom data. 84 // 85 // This is implemented based on revision 03 of the Peabody UUID draft, and may 86 // be subject to change pending further revisions. Until the final specification 87 // revision is finished, changes required to implement updates to the spec will 88 // not be considered a breaking change. They will happen as a minor version 89 // releases until the spec is final. 90 func NewV7() (UUID, error) { 91 return DefaultGenerator.NewV7() 92 } 93 94 // Generator provides an interface for generating UUIDs. 95 type Generator interface { 96 NewV1() (UUID, error) 97 NewV3(ns UUID, name string) UUID 98 NewV4() (UUID, error) 99 NewV5(ns UUID, name string) UUID 100 NewV6() (UUID, error) 101 NewV7() (UUID, error) 102 } 103 104 // Gen is a reference UUID generator based on the specifications laid out in 105 // RFC-4122 and DCE 1.1: Authentication and Security Services. This type 106 // satisfies the Generator interface as defined in this package. 107 // 108 // For consumers who are generating V1 UUIDs, but don't want to expose the MAC 109 // address of the node generating the UUIDs, the NewGenWithHWAF() function has been 110 // provided as a convenience. See the function's documentation for more info. 111 // 112 // The authors of this package do not feel that the majority of users will need 113 // to obfuscate their MAC address, and so we recommend using NewGen() to create 114 // a new generator. 115 type Gen struct { 116 clockSequenceOnce sync.Once 117 hardwareAddrOnce sync.Once 118 storageMutex sync.Mutex 119 120 rand io.Reader 121 122 epochFunc epochFunc 123 hwAddrFunc HWAddrFunc 124 lastTime uint64 125 clockSequence uint16 126 hardwareAddr [6]byte 127 } 128 129 // interface check -- build will fail if *Gen doesn't satisfy Generator 130 var _ Generator = (*Gen)(nil) 131 132 // NewGen returns a new instance of Gen with some default values set. Most 133 // people should use this. 134 func NewGen() *Gen { 135 return NewGenWithHWAF(defaultHWAddrFunc) 136 } 137 138 // NewGenWithHWAF builds a new UUID generator with the HWAddrFunc provided. Most 139 // consumers should use NewGen() instead. 140 // 141 // This is used so that consumers can generate their own MAC addresses, for use 142 // in the generated UUIDs, if there is some concern about exposing the physical 143 // address of the machine generating the UUID. 144 // 145 // The Gen generator will only invoke the HWAddrFunc once, and cache that MAC 146 // address for all the future UUIDs generated by it. If you'd like to switch the 147 // MAC address being used, you'll need to create a new generator using this 148 // function. 149 func NewGenWithHWAF(hwaf HWAddrFunc) *Gen { 150 return &Gen{ 151 epochFunc: time.Now, 152 hwAddrFunc: hwaf, 153 rand: rand.Reader, 154 } 155 } 156 157 // NewV1 returns a UUID based on the current timestamp and MAC address. 158 func (g *Gen) NewV1() (UUID, error) { 159 u := UUID{} 160 161 timeNow, clockSeq, err := g.getClockSequence() 162 if err != nil { 163 return Nil, err 164 } 165 binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) 166 binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) 167 binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) 168 binary.BigEndian.PutUint16(u[8:], clockSeq) 169 170 hardwareAddr, err := g.getHardwareAddr() 171 if err != nil { 172 return Nil, err 173 } 174 copy(u[10:], hardwareAddr) 175 176 u.SetVersion(V1) 177 u.SetVariant(VariantRFC4122) 178 179 return u, nil 180 } 181 182 // NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name. 183 func (g *Gen) NewV3(ns UUID, name string) UUID { 184 u := newFromHash(md5.New(), ns, name) 185 u.SetVersion(V3) 186 u.SetVariant(VariantRFC4122) 187 188 return u 189 } 190 191 // NewV4 returns a randomly generated UUID. 192 func (g *Gen) NewV4() (UUID, error) { 193 u := UUID{} 194 if _, err := io.ReadFull(g.rand, u[:]); err != nil { 195 return Nil, err 196 } 197 u.SetVersion(V4) 198 u.SetVariant(VariantRFC4122) 199 200 return u, nil 201 } 202 203 // NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name. 204 func (g *Gen) NewV5(ns UUID, name string) UUID { 205 u := newFromHash(sha1.New(), ns, name) 206 u.SetVersion(V5) 207 u.SetVariant(VariantRFC4122) 208 209 return u 210 } 211 212 // NewV6 returns a k-sortable UUID based on a timestamp and 48 bits of 213 // pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit 214 // order being adjusted to allow the UUID to be k-sortable. 215 // 216 // This is implemented based on revision 03 of the Peabody UUID draft, and may 217 // be subject to change pending further revisions. Until the final specification 218 // revision is finished, changes required to implement updates to the spec will 219 // not be considered a breaking change. They will happen as a minor version 220 // releases until the spec is final. 221 func (g *Gen) NewV6() (UUID, error) { 222 var u UUID 223 224 if _, err := io.ReadFull(g.rand, u[10:]); err != nil { 225 return Nil, err 226 } 227 228 timeNow, clockSeq, err := g.getClockSequence() 229 if err != nil { 230 return Nil, err 231 } 232 233 binary.BigEndian.PutUint32(u[0:], uint32(timeNow>>28)) // set time_high 234 binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>12)) // set time_mid 235 binary.BigEndian.PutUint16(u[6:], uint16(timeNow&0xfff)) // set time_low (minus four version bits) 236 binary.BigEndian.PutUint16(u[8:], clockSeq&0x3fff) // set clk_seq_hi_res (minus two variant bits) 237 238 u.SetVersion(V6) 239 u.SetVariant(VariantRFC4122) 240 241 return u, nil 242 } 243 244 // getClockSequence returns the epoch and clock sequence for V1 and V6 UUIDs. 245 func (g *Gen) getClockSequence() (uint64, uint16, error) { 246 var err error 247 g.clockSequenceOnce.Do(func() { 248 buf := make([]byte, 2) 249 if _, err = io.ReadFull(g.rand, buf); err != nil { 250 return 251 } 252 g.clockSequence = binary.BigEndian.Uint16(buf) 253 }) 254 if err != nil { 255 return 0, 0, err 256 } 257 258 g.storageMutex.Lock() 259 defer g.storageMutex.Unlock() 260 261 timeNow := g.getEpoch() 262 // Clock didn't change since last UUID generation. 263 // Should increase clock sequence. 264 if timeNow <= g.lastTime { 265 g.clockSequence++ 266 } 267 g.lastTime = timeNow 268 269 return timeNow, g.clockSequence, nil 270 } 271 272 // NewV7 returns a k-sortable UUID based on the current millisecond precision 273 // UNIX epoch and 74 bits of pseudorandom data. 274 // 275 // This is implemented based on revision 03 of the Peabody UUID draft, and may 276 // be subject to change pending further revisions. Until the final specification 277 // revision is finished, changes required to implement updates to the spec will 278 // not be considered a breaking change. They will happen as a minor version 279 // releases until the spec is final. 280 func (g *Gen) NewV7() (UUID, error) { 281 var u UUID 282 283 if _, err := io.ReadFull(g.rand, u[6:]); err != nil { 284 return Nil, err 285 } 286 287 tn := g.epochFunc() 288 ms := uint64(tn.Unix())*1e3 + uint64(tn.Nanosecond())/1e6 289 u[0] = byte(ms >> 40) 290 u[1] = byte(ms >> 32) 291 u[2] = byte(ms >> 24) 292 u[3] = byte(ms >> 16) 293 u[4] = byte(ms >> 8) 294 u[5] = byte(ms) 295 296 u.SetVersion(V7) 297 u.SetVariant(VariantRFC4122) 298 299 return u, nil 300 } 301 302 // Returns the hardware address. 303 func (g *Gen) getHardwareAddr() ([]byte, error) { 304 var err error 305 g.hardwareAddrOnce.Do(func() { 306 var hwAddr net.HardwareAddr 307 if hwAddr, err = g.hwAddrFunc(); err == nil { 308 copy(g.hardwareAddr[:], hwAddr) 309 return 310 } 311 312 // Initialize hardwareAddr randomly in case 313 // of real network interfaces absence. 314 if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil { 315 return 316 } 317 // Set multicast bit as recommended by RFC-4122 318 g.hardwareAddr[0] |= 0x01 319 }) 320 if err != nil { 321 return []byte{}, err 322 } 323 return g.hardwareAddr[:], nil 324 } 325 326 // Returns the difference between UUID epoch (October 15, 1582) 327 // and current time in 100-nanosecond intervals. 328 func (g *Gen) getEpoch() uint64 { 329 return epochStart + uint64(g.epochFunc().UnixNano()/100) 330 } 331 332 // Returns the UUID based on the hashing of the namespace UUID and name. 333 func newFromHash(h hash.Hash, ns UUID, name string) UUID { 334 u := UUID{} 335 h.Write(ns[:]) 336 h.Write([]byte(name)) 337 copy(u[:], h.Sum(nil)) 338 339 return u 340 } 341 342 var netInterfaces = net.Interfaces 343 344 // Returns the hardware address. 345 func defaultHWAddrFunc() (net.HardwareAddr, error) { 346 ifaces, err := netInterfaces() 347 if err != nil { 348 return []byte{}, err 349 } 350 for _, iface := range ifaces { 351 if len(iface.HardwareAddr) >= 6 { 352 return iface.HardwareAddr, nil 353 } 354 } 355 return []byte{}, fmt.Errorf("uuid: no HW address found") 356 } 357