blob: 2af9e4a695f56f085df11ff667a5b0caa428677d [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001package sarama
2
3import (
4 "crypto/hmac"
5 "crypto/sha256"
6 "crypto/sha512"
7 "hash"
8)
9
10// ScramFormatter implementation
11// @see: https://github.com/apache/kafka/blob/99b9b3e84f4e98c3f07714e1de6a139a004cbc5b/clients/src/main/java/org/apache/kafka/common/security/scram/internals/ScramFormatter.java#L93
12type scramFormatter struct {
13 mechanism ScramMechanismType
14}
15
16func (s scramFormatter) mac(key []byte) (hash.Hash, error) {
17 var m hash.Hash
18
19 switch s.mechanism {
20 case SCRAM_MECHANISM_SHA_256:
21 m = hmac.New(sha256.New, key)
22
23 case SCRAM_MECHANISM_SHA_512:
24 m = hmac.New(sha512.New, key)
25 default:
26 return nil, ErrUnknownScramMechanism
27 }
28
29 return m, nil
30}
31
32func (s scramFormatter) hmac(key []byte, extra []byte) ([]byte, error) {
33 mac, err := s.mac(key)
34 if err != nil {
35 return nil, err
36 }
37
38 if _, err := mac.Write(extra); err != nil {
39 return nil, err
40 }
41 return mac.Sum(nil), nil
42}
43
44func (s scramFormatter) xor(result []byte, second []byte) {
45 for i := 0; i < len(result); i++ {
46 result[i] = result[i] ^ second[i]
47 }
48}
49
50func (s scramFormatter) saltedPassword(password []byte, salt []byte, iterations int) ([]byte, error) {
51 mac, err := s.mac(password)
52 if err != nil {
53 return nil, err
54 }
55
56 if _, err := mac.Write(salt); err != nil {
57 return nil, err
58 }
59 if _, err := mac.Write([]byte{0, 0, 0, 1}); err != nil {
60 return nil, err
61 }
62
63 u1 := mac.Sum(nil)
64 prev := u1
65 result := u1
66
67 for i := 2; i <= iterations; i++ {
68 ui, err := s.hmac(password, prev)
69 if err != nil {
70 return nil, err
71 }
72
73 s.xor(result, ui)
74 prev = ui
75 }
76
77 return result, nil
78}