1
1
using System . Diagnostics ;
2
+ using System . Text ;
2
3
using Bit . Core ;
3
4
using Bit . Core . Auth . Enums ;
4
5
using Bit . Core . Auth . Models . Api . Request . Accounts ;
15
16
using Bit . Core . Models . Data ;
16
17
using Bit . Core . Repositories ;
17
18
using Bit . Core . Services ;
19
+ using Bit . Core . Settings ;
18
20
using Bit . Core . Tokens ;
19
21
using Bit . Core . Tools . Enums ;
20
22
using Bit . Core . Tools . Models . Business ;
@@ -44,6 +46,41 @@ public class AccountsController : Controller
44
46
private readonly IFeatureService _featureService ;
45
47
private readonly IDataProtectorTokenFactory < RegistrationEmailVerificationTokenable > _registrationEmailVerificationTokenDataFactory ;
46
48
49
+ private readonly byte [ ] _defaultKdfHmacKey = null ;
50
+ private static readonly List < UserKdfInformation > _defaultKdfResults =
51
+ [
52
+ // The first result (index 0) should always return the "normal" default.
53
+ new ( )
54
+ {
55
+ Kdf = KdfType . PBKDF2_SHA256 ,
56
+ KdfIterations = AuthConstants . PBKDF2_ITERATIONS . Default ,
57
+ } ,
58
+ // We want more weight for this default, so add it again
59
+ new ( )
60
+ {
61
+ Kdf = KdfType . PBKDF2_SHA256 ,
62
+ KdfIterations = AuthConstants . PBKDF2_ITERATIONS . Default ,
63
+ } ,
64
+ // Add some other possible defaults...
65
+ new ( )
66
+ {
67
+ Kdf = KdfType . PBKDF2_SHA256 ,
68
+ KdfIterations = 100_000 ,
69
+ } ,
70
+ new ( )
71
+ {
72
+ Kdf = KdfType . PBKDF2_SHA256 ,
73
+ KdfIterations = 5_000 ,
74
+ } ,
75
+ new ( )
76
+ {
77
+ Kdf = KdfType . Argon2id ,
78
+ KdfIterations = AuthConstants . ARGON2_ITERATIONS . Default ,
79
+ KdfMemory = AuthConstants . ARGON2_MEMORY . Default ,
80
+ KdfParallelism = AuthConstants . ARGON2_PARALLELISM . Default ,
81
+ }
82
+ ] ;
83
+
47
84
public AccountsController (
48
85
ICurrentContext currentContext ,
49
86
ILogger < AccountsController > logger ,
@@ -55,7 +92,8 @@ public AccountsController(
55
92
ISendVerificationEmailForRegistrationCommand sendVerificationEmailForRegistrationCommand ,
56
93
IReferenceEventService referenceEventService ,
57
94
IFeatureService featureService ,
58
- IDataProtectorTokenFactory < RegistrationEmailVerificationTokenable > registrationEmailVerificationTokenDataFactory
95
+ IDataProtectorTokenFactory < RegistrationEmailVerificationTokenable > registrationEmailVerificationTokenDataFactory ,
96
+ GlobalSettings globalSettings
59
97
)
60
98
{
61
99
_currentContext = currentContext ;
@@ -69,6 +107,11 @@ IDataProtectorTokenFactory<RegistrationEmailVerificationTokenable> registrationE
69
107
_referenceEventService = referenceEventService ;
70
108
_featureService = featureService ;
71
109
_registrationEmailVerificationTokenDataFactory = registrationEmailVerificationTokenDataFactory ;
110
+
111
+ if ( CoreHelpers . SettingHasValue ( globalSettings . KdfDefaultHashKey ) )
112
+ {
113
+ _defaultKdfHmacKey = Encoding . UTF8 . GetBytes ( globalSettings . KdfDefaultHashKey ) ;
114
+ }
72
115
}
73
116
74
117
[ HttpPost ( "register" ) ]
@@ -217,11 +260,7 @@ public async Task<PreloginResponseModel> PostPrelogin([FromBody] PreloginRequest
217
260
var kdfInformation = await _userRepository . GetKdfInformationByEmailAsync ( model . Email ) ;
218
261
if ( kdfInformation == null )
219
262
{
220
- kdfInformation = new UserKdfInformation
221
- {
222
- Kdf = KdfType . PBKDF2_SHA256 ,
223
- KdfIterations = AuthConstants . PBKDF2_ITERATIONS . Default ,
224
- } ;
263
+ kdfInformation = GetDefaultKdf ( model . Email ) ;
225
264
}
226
265
return new PreloginResponseModel ( kdfInformation ) ;
227
266
}
@@ -240,4 +279,26 @@ public WebAuthnLoginAssertionOptionsResponseModel GetWebAuthnLoginAssertionOptio
240
279
Token = token
241
280
} ;
242
281
}
282
+
283
+ private UserKdfInformation GetDefaultKdf ( string email )
284
+ {
285
+ if ( _defaultKdfHmacKey == null )
286
+ {
287
+ return _defaultKdfResults [ 0 ] ;
288
+ }
289
+ else
290
+ {
291
+ // Compute the HMAC hash of the email
292
+ var hmacMessage = Encoding . UTF8 . GetBytes ( email . Trim ( ) . ToLowerInvariant ( ) ) ;
293
+ using var hmac = new System . Security . Cryptography . HMACSHA256 ( _defaultKdfHmacKey ) ;
294
+ var hmacHash = hmac . ComputeHash ( hmacMessage ) ;
295
+ // Convert the hash to a number
296
+ var hashHex = BitConverter . ToString ( hmacHash ) . Replace ( "-" , string . Empty ) . ToLowerInvariant ( ) ;
297
+ var hashFirst8Bytes = hashHex . Substring ( 0 , 16 ) ;
298
+ var hashNumber = long . Parse ( hashFirst8Bytes , System . Globalization . NumberStyles . HexNumber ) ;
299
+ // Find the default KDF value for this hash number
300
+ var hashIndex = ( int ) ( Math . Abs ( hashNumber ) % _defaultKdfResults . Count ) ;
301
+ return _defaultKdfResults [ hashIndex ] ;
302
+ }
303
+ }
243
304
}
0 commit comments