Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

crypto.go 2.5KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // Copyright (c) 2018 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package utils
  4. import (
  5. "crypto/rand"
  6. "crypto/subtle"
  7. "encoding/base32"
  8. "encoding/base64"
  9. "encoding/hex"
  10. "errors"
  11. "strings"
  12. )
  13. var (
  14. // slingamn's own private b32 alphabet, removing 1, l, o, and 0
  15. B32Encoder = base32.NewEncoding("abcdefghijkmnpqrstuvwxyz23456789").WithPadding(base32.NoPadding)
  16. ErrInvalidCertfp = errors.New("Invalid certfp")
  17. )
  18. const (
  19. SecretTokenLength = 26
  20. )
  21. // generate a secret token that cannot be brute-forced via online attacks
  22. func GenerateSecretToken() string {
  23. // 128 bits of entropy are enough to resist any online attack:
  24. var buf [16]byte
  25. rand.Read(buf[:])
  26. // 26 ASCII characters, should be fine for most purposes
  27. return B32Encoder.EncodeToString(buf[:])
  28. }
  29. // "munge" a secret token to a new value. requirements:
  30. // 1. MUST be roughly as unlikely to collide with `GenerateSecretToken` outputs
  31. // as those outputs are with each other
  32. // 2. SHOULD be deterministic (motivation: if a JOIN line has msgid x,
  33. // create a deterministic msgid y for the fake HistServ PRIVMSG that "replays" it)
  34. // 3. SHOULD be in the same "namespace" as `GenerateSecretToken` outputs
  35. // (same length and character set)
  36. func MungeSecretToken(token string) (result string) {
  37. bytes, err := B32Encoder.DecodeString(token)
  38. if err != nil {
  39. // this should never happen
  40. return GenerateSecretToken()
  41. }
  42. // add 1 with carrying
  43. for i := len(bytes) - 1; 0 <= i; i -= 1 {
  44. bytes[i] += 1
  45. if bytes[i] != 0 {
  46. break
  47. } // else: overflow, carry to the next place
  48. }
  49. return B32Encoder.EncodeToString(bytes)
  50. }
  51. // securely check if a supplied token matches a stored token
  52. func SecretTokensMatch(storedToken string, suppliedToken string) bool {
  53. // XXX fix a potential gotcha: if the stored token is uninitialized,
  54. // then nothing should match it, not even supplying an empty token.
  55. if len(storedToken) == 0 {
  56. return false
  57. }
  58. return subtle.ConstantTimeCompare([]byte(storedToken), []byte(suppliedToken)) == 1
  59. }
  60. // generate a 256-bit secret key that can be written into a config file
  61. func GenerateSecretKey() string {
  62. var buf [32]byte
  63. rand.Read(buf[:])
  64. return base64.RawURLEncoding.EncodeToString(buf[:])
  65. }
  66. // Normalize openssl-formatted certfp's to oragono's format
  67. func NormalizeCertfp(certfp string) (result string, err error) {
  68. result = strings.ToLower(strings.Replace(certfp, ":", "", -1))
  69. decoded, err := hex.DecodeString(result)
  70. if err != nil || len(decoded) != 32 {
  71. return "", ErrInvalidCertfp
  72. }
  73. return
  74. }