uuid4.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /**
  2. * Copyright (c) 2018 rxi
  3. *
  4. * This library is free software; you can redistribute it and/or modify it
  5. * under the terms of the MIT license. See LICENSE for details.
  6. */
  7. #include <stdio.h>
  8. #include <stdint.h>
  9. #if defined(_WIN32)
  10. #include <windows.h>
  11. #include <wincrypt.h>
  12. #endif
  13. #include "uuid4.h"
  14. static uint64_t seed[2];
  15. static uint64_t xorshift128plus(uint64_t *s) {
  16. /* http://xorshift.di.unimi.it/xorshift128plus.c */
  17. uint64_t s1 = s[0];
  18. const uint64_t s0 = s[1];
  19. s[0] = s0;
  20. s1 ^= s1 << 23;
  21. s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5);
  22. return s[1] + s0;
  23. }
  24. int uuid4_init(void) {
  25. #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
  26. int res;
  27. FILE *fp = fopen("/dev/urandom", "rb");
  28. if (!fp) {
  29. return UUID4_EFAILURE;
  30. }
  31. res = fread(seed, 1, sizeof(seed), fp);
  32. fclose(fp);
  33. if ( res != sizeof(seed) ) {
  34. return UUID4_EFAILURE;
  35. }
  36. #elif defined(_WIN32)
  37. int res;
  38. HCRYPTPROV hCryptProv;
  39. res = CryptAcquireContext(
  40. &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  41. if (!res) {
  42. return UUID4_EFAILURE;
  43. }
  44. res = CryptGenRandom(hCryptProv, (DWORD) sizeof(seed), (PBYTE) seed);
  45. CryptReleaseContext(hCryptProv, 0);
  46. if (!res) {
  47. return UUID4_EFAILURE;
  48. }
  49. #else
  50. #error "unsupported platform"
  51. #endif
  52. return UUID4_ESUCCESS;
  53. }
  54. void uuid4_generate(char *dst) {
  55. static const char *template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
  56. static const char *chars = "0123456789abcdef";
  57. union { unsigned char b[16]; uint64_t word[2]; } s;
  58. const char *p;
  59. int i, n;
  60. /* get random */
  61. s.word[0] = xorshift128plus(seed);
  62. s.word[1] = xorshift128plus(seed);
  63. /* build string */
  64. p = template;
  65. i = 0;
  66. while (*p) {
  67. n = s.b[i >> 1];
  68. n = (i & 1) ? (n >> 4) : (n & 0xf);
  69. switch (*p) {
  70. case 'x' : *dst = chars[n]; i++; break;
  71. case 'y' : *dst = chars[(n & 0x3) + 8]; i++; break;
  72. default : *dst = *p;
  73. }
  74. dst++, p++;
  75. }
  76. *dst = '\0';
  77. }