security.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package utils
  2. import (
  3. "crypto/rand"
  4. "encoding/hex"
  5. "errors"
  6. "log"
  7. "golang.org/x/crypto/scrypt"
  8. )
  9. const (
  10. SymbolSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~"
  11. LetterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  12. NumberSet = "0123456789"
  13. )
  14. // ErrInvalidCharsetLength 表示字符集长度错误
  15. var ErrInvalidCharsetLength = errors.New("字符集长度错误")
  16. func generateRandString(length int, charset string) (string, error) {
  17. var chars = []byte(charset)
  18. clen := len(chars)
  19. if clen < 2 || clen > 256 {
  20. return "", ErrInvalidCharsetLength
  21. }
  22. maxRb := 255 - (256 % clen)
  23. b := make([]byte, length)
  24. r := make([]byte, length+(length/4)) // storage for random bytes.
  25. i := 0
  26. for {
  27. n, err := rand.Read(r)
  28. if err != nil {
  29. log.Printf("读取随机字节出错: %v", err)
  30. return "", err
  31. }
  32. if n != len(r) {
  33. log.Printf("未预期的随机字节数量: %d", n)
  34. return "", errors.New("随机字节长度不正确")
  35. }
  36. for _, rb := range r {
  37. c := int(rb)
  38. if c > maxRb {
  39. continue // Skip this number to avoid modulo bias.
  40. }
  41. b[i] = chars[c%clen]
  42. i++
  43. if i == length {
  44. return string(b), nil
  45. }
  46. }
  47. }
  48. }
  49. // GenerateRandomString 生成指定长度的随机字符串
  50. func GenerateRandomString(length int, charset string) string {
  51. str, err := generateRandString(length, charset)
  52. if err != nil {
  53. log.Printf("生成随机字符串失败: %v", err)
  54. return ""
  55. }
  56. return str
  57. }
  58. // GenerateRandomKey 生成指定长度的随机字符串,使用预定义的字符集
  59. func GenerateRandomKey(length int, charsetType int) string {
  60. var charset string
  61. switch charsetType {
  62. case 1: // Symbol set
  63. charset = SymbolSet
  64. case 2: // Letter set
  65. charset = LetterSet
  66. case 3: // Number set
  67. charset = NumberSet
  68. default:
  69. log.Println("无效的字符集类型")
  70. return ""
  71. }
  72. return GenerateRandomString(length, charset)
  73. }
  74. // GenerateRandomKey20 生成20位随机字符串
  75. func GenerateRandomKey20() string {
  76. return GenerateRandomKey(20, 1)
  77. }
  78. // GenerateRandomKey16 生成16位随机字符串
  79. func GenerateRandomKey16() string {
  80. return GenerateRandomKey(16, 1)
  81. }
  82. // GenerateRandomKey6 生成6位随机字符串
  83. func GenerateRandomKey6() string {
  84. return GenerateRandomKey(6, 2)
  85. }
  86. // GenerateRandomKey4 生成4位随机字符串
  87. func GenerateRandomKey4() string {
  88. return GenerateRandomKey(4, 3)
  89. }
  90. // SetPassword 根据明文密码和加盐值生成密码
  91. func SetPassword(password string, salt string) (verify string, err error) {
  92. var rb []byte
  93. rb, err = scrypt.Key([]byte(password), []byte(salt), 16384, 8, 1, 32)
  94. if err != nil {
  95. log.Printf("生成密码哈希失败: %v", err)
  96. return
  97. }
  98. verify = hex.EncodeToString(rb)
  99. return
  100. }