uuid4.cpp 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. #pragma comment(lib, "Advapi32.lib")
  13. #endif
  14. #include "uuid4.h"
  15. static uint64_t seed[2];
  16. static uint64_t xorshift128plus(uint64_t* s) {
  17. /* http://xorshift.di.unimi.it/xorshift128plus.c */
  18. uint64_t s1 = s[0];
  19. const uint64_t s0 = s[1];
  20. s[0] = s0;
  21. s1 ^= s1 << 23;
  22. s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5);
  23. return s[1] + s0;
  24. }
  25. int uuid4_init(void) {
  26. #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
  27. int res;
  28. FILE* fp = fopen("/dev/urandom", "rb");
  29. if (!fp) {
  30. return UUID4_EFAILURE;
  31. }
  32. res = fread(seed, 1, sizeof(seed), fp);
  33. fclose(fp);
  34. if (res != sizeof(seed)) {
  35. return UUID4_EFAILURE;
  36. }
  37. #elif defined(_WIN32)
  38. int res;
  39. HCRYPTPROV hCryptProv;
  40. res = CryptAcquireContext(
  41. &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  42. if (!res) {
  43. return UUID4_EFAILURE;
  44. }
  45. res = CryptGenRandom(hCryptProv, (DWORD)sizeof(seed), (PBYTE)seed);
  46. CryptReleaseContext(hCryptProv, 0);
  47. if (!res) {
  48. return UUID4_EFAILURE;
  49. }
  50. #else
  51. #error "unsupported platform"
  52. #endif
  53. return UUID4_ESUCCESS;
  54. }
  55. void uuid4_generate(char* dst) {
  56. static const char* template1 = "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx";
  57. static const char* chars = "0123456789abcdef";
  58. union { unsigned char b[16]; uint64_t word[2]; } s;
  59. const char* p;
  60. int i, n;
  61. /* get random */
  62. s.word[0] = xorshift128plus(seed);
  63. s.word[1] = xorshift128plus(seed);
  64. /* build string */
  65. p = template1;
  66. i = 0;
  67. while (*p) {
  68. n = s.b[i >> 1];
  69. n = (i & 1) ? (n >> 4) : (n & 0xf);
  70. switch (*p) {
  71. case 'x': *dst = chars[n]; i++; break;
  72. case 'y': *dst = chars[(n & 0x3) + 8]; i++; break;
  73. default: *dst = *p;
  74. }
  75. dst++, p++;
  76. }
  77. *dst = '\0';
  78. }
  79. std::string uuid4_generate(int len)
  80. {
  81. char buf[UUID4_LEN];
  82. uuid4_init();
  83. uuid4_generate(buf);
  84. std::string result = buf;
  85. if (len > 0 && len <= 32)
  86. return result.substr(0, len);
  87. else
  88. return "";
  89. }