github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/twinj/uuid/rfc4122.go (about) 1 package uuid 2 3 /*************** 4 * Date: 14/02/14 5 * Time: 7:44 PM 6 ***************/ 7 8 import ( 9 "crypto/md5" 10 "crypto/rand" 11 "crypto/sha1" 12 "encoding/binary" 13 "log" 14 seed "math/rand" 15 "net" 16 ) 17 18 const ( 19 length = 16 20 21 // 3F used by RFC4122 although 1F works for all 22 variantSet = 0x3F 23 24 // rather than using 0xC0 we use 0xE0 to retrieve the variant 25 // The result is the same for all other variants 26 // 0x80 and 0xA0 are used to identify RFC4122 compliance 27 variantGet = 0xE0 28 ) 29 30 var ( 31 // nodeID is the default Namespace node 32 nodeId = []byte{ 33 // 00.192.79.212.48.200 34 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, 35 } 36 // The following standard UUIDs are for use with V3 or V5 UUIDs. 37 NamespaceDNS = &Struct{0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length} 38 NamespaceURL = &Struct{0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length} 39 NamespaceOID = &Struct{0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length} 40 NamespaceX500 = &Struct{0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length} 41 42 state State 43 ) 44 45 func init() { 46 seed.Seed((int64(timestamp())^int64(gregorianToUNIXOffset))*0x6ba7b814<<0x6ba7b812 | 1391463463) 47 state = State{ 48 randomNode: true, 49 randomSequence: true, 50 past: Timestamp((1391463463 * 10000000) + (100 * 10) + gregorianToUNIXOffset), 51 node: nodeId, 52 sequence: uint16(seed.Int()) & 0x3FFF, 53 saver: nil, 54 } 55 } 56 57 // NewV1 will generate a new RFC4122 version 1 UUID 58 func NewV1() UUID { 59 state.Lock() 60 defer state.Unlock() 61 now := currentUUIDTimestamp() 62 state.read(now, currentUUIDNodeId()) 63 state.persist() 64 return formatV1(now, uint16(1), ReservedRFC4122, state.node) 65 } 66 67 // NewV3 will generate a new RFC4122 version 3 UUID 68 // V3 is based on the MD5 hash of a namespace identifier UUID and 69 // any type which implements the UniqueName interface for the name. 70 // For strings and slices cast to a Name type 71 func NewV3(pNs UUID, pName UniqueName) UUID { 72 o := new(Array) 73 // Set all bits to MD5 hash generated from namespace and name. 74 Digest(o, pNs, pName, md5.New()) 75 o.setRFC4122Variant() 76 o.setVersion(3) 77 return o 78 } 79 80 // NewV4 will generate a new RFC4122 version 4 UUID 81 // A cryptographically secure random UUID. 82 func NewV4() UUID { 83 o := new(Array) 84 // Read random values (or pseudo-randomly) into Array type. 85 _, err := rand.Read(o[:length]) 86 if err != nil { 87 panic(err) 88 } 89 o.setRFC4122Variant() 90 o.setVersion(4) 91 return o 92 } 93 94 // NewV5 will generate a new RFC4122 version 5 UUID 95 // Generate a UUID based on the SHA-1 hash of a namespace 96 // identifier and a name. 97 func NewV5(pNs UUID, pName UniqueName) UUID { 98 o := new(Array) 99 Digest(o, pNs, pName, sha1.New()) 100 o.setRFC4122Variant() 101 o.setVersion(5) 102 return o 103 } 104 105 // either generates a random node when there is an error or gets 106 // the pre initialised one 107 func currentUUIDNodeId() (node net.HardwareAddr) { 108 if state.randomNode { 109 b := make([]byte, 16+6) 110 _, err := rand.Read(b) 111 if err != nil { 112 log.Println("UUID.currentUUIDNodeId error:", err) 113 node = nodeId 114 return 115 } 116 h := sha1.New() 117 h.Write(b) 118 binary.Write(h, binary.LittleEndian, state.sequence) 119 node = h.Sum(nil)[:6] 120 if err != nil { 121 log.Println("UUID.currentUUIDNodeId error:", err) 122 node = nodeId 123 return 124 } 125 // Mark as randomly generated 126 node[0] |= 0x01 127 } else { 128 node = state.node 129 } 130 return 131 } 132 133 // Unmarshal data into struct for V1 UUIDs 134 func formatV1(pNow Timestamp, pVersion uint16, pVariant byte, pNode []byte) UUID { 135 o := new(Struct) 136 o.timeLow = uint32(pNow & 0xFFFFFFFF) 137 o.timeMid = uint16((pNow >> 32) & 0xFFFF) 138 o.timeHiAndVersion = uint16((pNow >> 48) & 0x0FFF) 139 o.timeHiAndVersion |= uint16(pVersion << 12) 140 o.sequenceLow = byte(state.sequence & 0xFF) 141 o.sequenceHiAndVariant = byte((state.sequence & 0x3F00) >> 8) 142 o.sequenceHiAndVariant |= pVariant 143 o.node = pNode 144 o.size = length 145 return o 146 }