You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

common.go 2.9KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright 2018 by David A. Golden. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. package scram
  7. import (
  8. "crypto/hmac"
  9. "crypto/rand"
  10. "encoding/base64"
  11. "strings"
  12. )
  13. // NonceGeneratorFcn defines a function that returns a string of high-quality
  14. // random printable ASCII characters EXCLUDING the comma (',') character. The
  15. // default nonce generator provides Base64 encoding of 24 bytes from
  16. // crypto/rand.
  17. type NonceGeneratorFcn func() string
  18. // derivedKeys collects the three cryptographically derived values
  19. // into one struct for caching.
  20. type derivedKeys struct {
  21. ClientKey []byte
  22. StoredKey []byte
  23. ServerKey []byte
  24. }
  25. // KeyFactors represent the two server-provided factors needed to compute
  26. // client credentials for authentication. Salt is decoded bytes (i.e. not
  27. // base64), but in string form so that KeyFactors can be used as a map key for
  28. // cached credentials.
  29. type KeyFactors struct {
  30. Salt string
  31. Iters int
  32. }
  33. // StoredCredentials are the values that a server must store for a given
  34. // username to allow authentication. They include the salt and iteration
  35. // count, plus the derived values to authenticate a client and for the server
  36. // to authenticate itself back to the client.
  37. //
  38. // NOTE: these are specific to a given hash function. To allow a user to
  39. // authenticate with either SCRAM-SHA-1 or SCRAM-SHA-256, two sets of
  40. // StoredCredentials must be created and stored, one for each hash function.
  41. type StoredCredentials struct {
  42. KeyFactors
  43. StoredKey []byte
  44. ServerKey []byte
  45. }
  46. // CredentialLookup is a callback to provide StoredCredentials for a given
  47. // username. This is used to configure Server objects.
  48. //
  49. // NOTE: these are specific to a given hash function. The callback provided
  50. // to a Server with a given hash function must provide the corresponding
  51. // StoredCredentials.
  52. type CredentialLookup func(string) (StoredCredentials, error)
  53. func defaultNonceGenerator() string {
  54. raw := make([]byte, 24)
  55. nonce := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
  56. rand.Read(raw)
  57. base64.StdEncoding.Encode(nonce, raw)
  58. return string(nonce)
  59. }
  60. func encodeName(s string) string {
  61. return strings.Replace(strings.Replace(s, "=", "=3D", -1), ",", "=2C", -1)
  62. }
  63. func decodeName(s string) (string, error) {
  64. // TODO Check for = not followed by 2C or 3D
  65. return strings.Replace(strings.Replace(s, "=2C", ",", -1), "=3D", "=", -1), nil
  66. }
  67. func computeHash(hg HashGeneratorFcn, b []byte) []byte {
  68. h := hg()
  69. h.Write(b)
  70. return h.Sum(nil)
  71. }
  72. func computeHMAC(hg HashGeneratorFcn, key, data []byte) []byte {
  73. mac := hmac.New(hg, key)
  74. mac.Write(data)
  75. return mac.Sum(nil)
  76. }
  77. func xorBytes(a, b []byte) []byte {
  78. // TODO check a & b are same length, or just xor to smallest
  79. xor := make([]byte, len(a))
  80. for i := range a {
  81. xor[i] = a[i] ^ b[i]
  82. }
  83. return xor
  84. }