1
- /* Copyright 2018–present MongoDB Inc.
1
+ /* Copyright 2018–present MongoDB Inc.
2
2
*
3
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
4
* you may not use this file except in compliance with the License.
@@ -72,8 +72,8 @@ protected ScramShaAuthenticator(UsernamePasswordCredential credential,
72
72
H h ,
73
73
Hi hi ,
74
74
Hmac hmac )
75
- : this ( credential , hashAlgorithmName , new DefaultRandomStringGenerator ( ) , h , hi , hmac ) { }
76
-
75
+ : this ( credential , hashAlgorithmName , new DefaultRandomStringGenerator ( ) , h , hi , hmac , new ScramCache ( ) ) { }
76
+
77
77
/// <summary>
78
78
/// Initializes a new instance of the <see cref="ScramShaAuthenticator"/> class.
79
79
/// </summary>
@@ -83,14 +83,16 @@ protected ScramShaAuthenticator(UsernamePasswordCredential credential,
83
83
/// <param name="h">The H function to use.</param>
84
84
/// <param name="hi">The Hi function to use.</param>
85
85
/// <param name="hmac">The Hmac function to use.</param>
86
+ /// <param name="cache">The cache to use.</param>
86
87
internal ScramShaAuthenticator (
87
88
UsernamePasswordCredential credential ,
88
89
HashAlgorithmName hashAlgorithName ,
89
90
IRandomStringGenerator randomStringGenerator ,
90
91
H h ,
91
92
Hi hi ,
92
- Hmac hmac )
93
- : base ( new ScramShaMechanism ( credential , hashAlgorithName , randomStringGenerator , h , hi , hmac ) )
93
+ Hmac hmac ,
94
+ ScramCache cache )
95
+ : base ( new ScramShaMechanism ( credential , hashAlgorithName , randomStringGenerator , h , hi , hmac , cache ) )
94
96
{
95
97
_databaseName = credential . Source ;
96
98
}
@@ -108,14 +110,16 @@ private class ScramShaMechanism : ISaslMechanism
108
110
private readonly Hi _hi ;
109
111
private readonly Hmac _hmac ;
110
112
private readonly string _name ;
113
+ private ScramCache _cache ;
111
114
112
115
public ScramShaMechanism (
113
116
UsernamePasswordCredential credential ,
114
117
HashAlgorithmName hashAlgorithmName ,
115
118
IRandomStringGenerator randomStringGenerator ,
116
119
H h ,
117
120
Hi hi ,
118
- Hmac hmac )
121
+ Hmac hmac ,
122
+ ScramCache cache )
119
123
{
120
124
_credential = Ensure . IsNotNull ( credential , nameof ( credential ) ) ;
121
125
_h = h ;
@@ -127,6 +131,7 @@ public ScramShaMechanism(
127
131
}
128
132
_name = $ "SCRAM-SHA-{ hashAlgorithmName . ToString ( ) . Substring ( 3 ) } ";
129
133
_randomStringGenerator = Ensure . IsNotNull ( randomStringGenerator , nameof ( randomStringGenerator ) ) ;
134
+ _cache = cache ;
130
135
}
131
136
132
137
public string Name => _name ;
@@ -143,9 +148,9 @@ public ISaslStep Initialize(IConnection connection, SaslConversation conversatio
143
148
144
149
var clientFirstMessageBare = username + "," + nonce ;
145
150
var clientFirstMessage = gs2Header + clientFirstMessageBare ;
146
- var clientFirstMessageBytes = Utf8Encodings . Strict . GetBytes ( clientFirstMessage ) ;
151
+ var clientFirstMessageBytes = Utf8Encodings . Strict . GetBytes ( clientFirstMessage ) ;
147
152
148
- return new ClientFirst ( clientFirstMessageBytes , clientFirstMessageBare , _credential , r , _h , _hi , _hmac ) ;
153
+ return new ClientFirst ( clientFirstMessageBytes , clientFirstMessageBare , _credential , r , _h , _hi , _hmac , _cache ) ;
149
154
}
150
155
151
156
private string GenerateRandomString ( )
@@ -163,7 +168,7 @@ private string PrepUsername(string username)
163
168
164
169
private class ClientFirst : ISaslStep
165
170
{
166
-
171
+
167
172
private readonly byte [ ] _bytesToSendToServer ;
168
173
private readonly string _clientFirstMessageBare ;
169
174
private readonly UsernamePasswordCredential _credential ;
@@ -173,14 +178,17 @@ private class ClientFirst : ISaslStep
173
178
private readonly Hi _hi ;
174
179
private readonly Hmac _hmac ;
175
180
181
+ private ScramCache _cache ;
182
+
176
183
public ClientFirst (
177
184
byte [ ] bytesToSendToServer ,
178
185
string clientFirstMessageBare ,
179
186
UsernamePasswordCredential credential ,
180
187
string rPrefix ,
181
188
H h ,
182
189
Hi hi ,
183
- Hmac hmac )
190
+ Hmac hmac ,
191
+ ScramCache cache )
184
192
{
185
193
_bytesToSendToServer = bytesToSendToServer ;
186
194
_clientFirstMessageBare = clientFirstMessageBare ;
@@ -189,6 +197,7 @@ public ClientFirst(
189
197
_hi = hi ;
190
198
_hmac = hmac ;
191
199
_rPrefix = rPrefix ;
200
+ _cache = cache ;
192
201
}
193
202
194
203
public byte [ ] BytesToSendToServer => _bytesToSendToServer ;
@@ -214,19 +223,31 @@ public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedF
214
223
var nonce = "r=" + r ;
215
224
var clientFinalMessageWithoutProof = channelBinding + "," + nonce ;
216
225
217
- var saltedPassword = _hi (
218
- _credential ,
219
- Convert . FromBase64String ( s ) ,
220
- int . Parse ( i ) ) ;
226
+ var salt = Convert . FromBase64String ( map [ 's' ] ) ;
227
+ var iterations = int . Parse ( map [ 'i' ] ) ;
228
+
229
+ byte [ ] clientKey ;
230
+ byte [ ] serverKey ;
231
+
232
+ var cacheKey = new ScramCacheKey ( _credential . SaslPreppedPassword , salt , iterations ) ;
233
+ if ( _cache . TryGet ( cacheKey , out var cacheEntry ) )
234
+ {
235
+ clientKey = cacheEntry . ClientKey ;
236
+ serverKey = cacheEntry . ServerKey ;
237
+ }
238
+ else
239
+ {
240
+ var saltedPassword = _hi ( _credential , salt , iterations ) ;
241
+ clientKey = _hmac ( encoding , saltedPassword , "Client Key" ) ;
242
+ serverKey = _hmac ( encoding , saltedPassword , "Server Key" ) ;
243
+ _cache . Add ( cacheKey , new ScramCacheEntry ( clientKey , serverKey ) ) ;
244
+ }
221
245
222
- var clientKey = _hmac ( encoding , saltedPassword , "Client Key" ) ;
223
246
var storedKey = _h ( clientKey ) ;
224
247
var authMessage = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof ;
225
248
var clientSignature = _hmac ( encoding , storedKey , authMessage ) ;
226
249
var clientProof = XOR ( clientKey , clientSignature ) ;
227
- var serverKey = _hmac ( encoding , saltedPassword , "Server Key" ) ;
228
250
var serverSignature = _hmac ( encoding , serverKey , authMessage ) ;
229
-
230
251
var proof = "p=" + Convert . ToBase64String ( clientProof ) ;
231
252
var clientFinalMessage = clientFinalMessageWithoutProof + "," + proof ;
232
253
@@ -243,7 +264,6 @@ private byte[] XOR(byte[] a, byte[] b)
243
264
244
265
return result ;
245
266
}
246
-
247
267
}
248
268
249
269
private class ClientLast : ISaslStep
@@ -287,4 +307,4 @@ private bool ConstantTimeEquals(byte[] a, byte[] b)
287
307
}
288
308
}
289
309
}
290
- }
310
+ }
0 commit comments