1 /* guuid.c - UUID functions
2 *
3 * Copyright (C) 2013-2015, 2017 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * licence, or (at your option) any later version.
9 *
10 * This is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 * License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18 * USA.
19 *
20 * Authors: Marc-André Lureau <marcandre.lureau@redhat.com>
21 */
22
23 #include "config.h"
24 #include <string.h>
25
26 #include "gi18n.h"
27 #include "gstrfuncs.h"
28 #include "grand.h"
29 #include "gmessages.h"
30 #include "gchecksum.h"
31
32 #include "guuid.h"
33
34 typedef struct {
35 guint8 bytes[16];
36 } GUuid;
37
38 /*
39 * g_uuid_to_string:
40 * @uuid: a #GUuid
41 *
42 * Creates a string representation of @uuid, of the form
43 * 06e023d5-86d8-420e-8103-383e4566087a (no braces nor urn:uuid:
44 * prefix).
45 *
46 * Returns: (transfer full): A string that should be freed with g_free().
47 * Since: STATIC
48 */
49 static gchar *
50 g_uuid_to_string (const GUuid *uuid)
51 {
52 const guint8 *bytes;
53
54 g_return_val_if_fail (uuid != NULL, NULL);
55
56 bytes = uuid->bytes;
57
58 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
59 "-%02x%02x%02x%02x%02x%02x",
60 bytes[0], bytes[1], bytes[2], bytes[3],
61 bytes[4], bytes[5], bytes[6], bytes[7],
62 bytes[8], bytes[9], bytes[10], bytes[11],
63 bytes[12], bytes[13], bytes[14], bytes[15]);
64 }
65
66 static gboolean
67 uuid_parse_string (const gchar *str,
68 GUuid *uuid)
69 {
70 GUuid tmp;
71 guint8 *bytes = tmp.bytes;
72 gint i, j, hi, lo;
73 guint expected_len = 36;
74
75 if (strlen (str) != expected_len)
76 return FALSE;
77
78 for (i = 0, j = 0; i < 16;)
79 {
80 if (j == 8 || j == 13 || j == 18 || j == 23)
81 {
82 if (str[j++] != '-')
83 return FALSE;
84
85 continue;
86 }
87
88 hi = g_ascii_xdigit_value (str[j++]);
89 lo = g_ascii_xdigit_value (str[j++]);
90
91 if (hi == -1 || lo == -1)
92 return FALSE;
93
94 bytes[i++] = hi << 4 | lo;
95 }
96
97 if (uuid != NULL)
98 *uuid = tmp;
99
100 return TRUE;
101 }
102
103 /**
104 * g_uuid_string_is_valid:
105 * @str: a string representing a UUID
106 *
107 * Parses the string @str and verify if it is a UUID.
108 *
109 * The function accepts the following syntax:
110 *
111 * - simple forms (e.g. `f81d4fae-7dec-11d0-a765-00a0c91e6bf6`)
112 *
113 * Note that hyphens are required within the UUID string itself,
114 * as per the aforementioned RFC.
115 *
116 * Returns: %TRUE if @str is a valid UUID, %FALSE otherwise.
117 * Since: 2.52
118 */
119 gboolean
120 g_uuid_string_is_valid (const gchar *str)
121 {
122 g_return_val_if_fail (str != NULL, FALSE);
123
124 return uuid_parse_string (str, NULL);
125 }
126
127 static void
128 uuid_set_version (GUuid *uuid, guint version)
129 {
130 guint8 *bytes = uuid->bytes;
131
132 /*
133 * Set the four most significant bits (bits 12 through 15) of the
134 * time_hi_and_version field to the 4-bit version number from
135 * Section 4.1.3.
136 */
137 bytes[6] &= 0x0f;
138 bytes[6] |= version << 4;
139 /*
140 * Set the two most significant bits (bits 6 and 7) of the
141 * clock_seq_hi_and_reserved to zero and one, respectively.
142 */
143 bytes[8] &= 0x3f;
144 bytes[8] |= 0x80;
145 }
146
147 /*
148 * g_uuid_generate_v4:
149 * @uuid: a #GUuid
150 *
151 * Generates a random UUID (RFC 4122 version 4).
152 * Since: STATIC
153 */
154 static void
155 g_uuid_generate_v4 (GUuid *uuid)
156 {
157 int i;
158 guint8 *bytes;
159 guint32 *ints;
160
161 g_return_if_fail (uuid != NULL);
162
163 bytes = uuid->bytes;
164 ints = (guint32 *) bytes;
165 for (i = 0; i < 4; i++)
166 ints[i] = g_random_int ();
167
168 uuid_set_version (uuid, 4);
169 }
170
171 /**
172 * g_uuid_string_random:
173 *
174 * Generates a random UUID (RFC 4122 version 4) as a string. It has the same
175 * randomness guarantees as #GRand, so must not be used for cryptographic
176 * purposes such as key generation, nonces, salts or one-time pads.
177 *
178 * Returns: (transfer full): A string that should be freed with g_free().
179 * Since: 2.52
180 */
181 gchar *
182 g_uuid_string_random (void)
183 {
184 GUuid uuid;
185
186 g_uuid_generate_v4 (&uuid);
187
188 return g_uuid_to_string (&uuid);
189 }