18
18
using System . Runtime . InteropServices ;
19
19
using System . Security ;
20
20
using System . Security . Cryptography ;
21
- using System . Text ;
22
21
using MongoDB . Bson ;
23
22
using MongoDB . Bson . IO ;
24
23
using MongoDB . Driver . Core . Misc ;
24
+ using MongoDB . Shared ;
25
25
26
26
namespace MongoDB . Driver
27
27
{
@@ -32,7 +32,6 @@ public sealed class PasswordEvidence : MongoIdentityEvidence
32
32
{
33
33
// private fields
34
34
private readonly SecureString _securePassword ;
35
- private readonly string _digest ; // used to implement Equals without referring to the SecureString
36
35
37
36
// constructors
38
37
/// <summary>
@@ -41,18 +40,20 @@ public sealed class PasswordEvidence : MongoIdentityEvidence
41
40
/// <param name="password">The password.</param>
42
41
public PasswordEvidence ( SecureString password )
43
42
{
43
+ Ensure . IsNotNull ( password , nameof ( password ) ) ;
44
44
_securePassword = password . Copy ( ) ;
45
45
_securePassword . MakeReadOnly ( ) ;
46
- _digest = GenerateDigest ( password ) ;
47
46
}
48
47
49
48
/// <summary>
50
49
/// Initializes a new instance of the <see cref="PasswordEvidence" /> class.
51
50
/// </summary>
52
51
/// <param name="password">The password.</param>
53
52
public PasswordEvidence ( string password )
54
- : this ( CreateSecureString ( password ) )
55
- { }
53
+ {
54
+ Ensure . IsNotNull ( password , nameof ( password ) ) ;
55
+ _securePassword = CreateSecureString ( password ) ;
56
+ }
56
57
57
58
// public properties
58
59
/// <summary>
@@ -74,18 +75,26 @@ public SecureString SecurePassword
74
75
public override bool Equals ( object rhs )
75
76
{
76
77
if ( object . ReferenceEquals ( rhs , null ) || GetType ( ) != rhs . GetType ( ) ) { return false ; }
77
- return _digest == ( ( PasswordEvidence ) rhs ) . _digest ;
78
+
79
+ using ( var lhsDecryptedPassword = new DecryptedSecureString ( _securePassword ) )
80
+ using ( var rhsDecryptedPassword = new DecryptedSecureString ( ( ( PasswordEvidence ) rhs ) . _securePassword ) )
81
+ {
82
+ return lhsDecryptedPassword . GetChars ( ) . SequenceEqual ( rhsDecryptedPassword . GetChars ( ) ) ;
83
+ }
78
84
}
79
85
80
86
/// <summary>
81
87
/// Returns a hash code for this instance.
82
88
/// </summary>
83
89
/// <returns>
84
- /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
90
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
85
91
/// </returns>
86
92
public override int GetHashCode ( )
87
93
{
88
- return _digest . GetHashCode ( ) ;
94
+ using ( var decryptedPassword = new DecryptedSecureString ( _securePassword ) )
95
+ {
96
+ return new Hasher ( ) . HashStructElements ( decryptedPassword . GetChars ( ) ) . GetHashCode ( ) ;
97
+ }
89
98
}
90
99
91
100
// internal methods
@@ -97,94 +106,25 @@ public override int GetHashCode()
97
106
internal string ComputeMongoCRPasswordDigest ( string username )
98
107
{
99
108
using ( var md5 = MD5 . Create ( ) )
109
+ using ( var decryptedPassword = new DecryptedSecureString ( _securePassword ) )
100
110
{
101
111
var encoding = Utf8Encodings . Strict ;
102
112
var prefixBytes = encoding . GetBytes ( username + ":mongo:" ) ;
103
- var hash = ComputeHash ( md5 , prefixBytes , _securePassword ) ;
113
+ var hash = ComputeHash ( md5 , prefixBytes , decryptedPassword . GetUtf8Bytes ( ) ) ;
104
114
return BsonUtils . ToHexString ( hash ) ;
105
115
}
106
116
}
107
117
108
118
// private static methods
109
- private static SecureString CreateSecureString ( string str )
110
- {
111
- if ( str != null )
112
- {
113
- var secureStr = new SecureString ( ) ;
114
- foreach ( var c in str )
115
- {
116
- secureStr . AppendChar ( c ) ;
117
- }
118
- secureStr . MakeReadOnly ( ) ;
119
- return secureStr ;
120
- }
121
-
122
- return null ;
123
- }
124
-
125
- /// <summary>
126
- /// Computes the hash value of the secured string
127
- /// </summary>
128
- private static string GenerateDigest ( SecureString password )
129
- {
130
- using ( var sha256 = SHA256 . Create ( ) )
131
- {
132
- var hash = ComputeHash ( sha256 , new byte [ 0 ] , password ) ;
133
- return BsonUtils . ToHexString ( hash ) ;
134
- }
135
- }
136
-
137
- private static byte [ ] ComputeHash ( HashAlgorithm algorithm , byte [ ] prefixBytes , SecureString password )
119
+ private static SecureString CreateSecureString ( string value )
138
120
{
139
- if ( password . Length == 0 )
140
- {
141
- return ComputeHash ( algorithm , prefixBytes , new byte [ 0 ] ) ;
142
- }
143
- else
144
- {
145
- #if NET45
146
- var passwordIntPtr = Marshal . SecureStringToGlobalAllocUnicode ( password ) ;
147
- #else
148
- var passwordIntPtr = SecureStringMarshal . SecureStringToGlobalAllocUnicode ( password ) ;
149
- #endif
150
- try
151
- {
152
- var passwordChars = new char [ password . Length ] ;
153
- var passwordCharsHandle = GCHandle . Alloc ( passwordChars , GCHandleType . Pinned ) ;
154
- try
155
- {
156
- Marshal . Copy ( passwordIntPtr , passwordChars , 0 , password . Length ) ;
157
-
158
- return ComputeHash ( algorithm , prefixBytes , passwordChars ) ;
159
- }
160
- finally
161
- {
162
- Array . Clear ( passwordChars , 0 , passwordChars . Length ) ;
163
- passwordCharsHandle . Free ( ) ;
164
- }
165
- }
166
- finally
167
- {
168
- Marshal . ZeroFreeGlobalAllocUnicode ( passwordIntPtr ) ;
169
- }
170
- }
171
- }
172
-
173
- private static byte [ ] ComputeHash ( HashAlgorithm algorithm , byte [ ] prefixBytes , char [ ] passwordChars )
174
- {
175
- var passwordBytes = new byte [ Utf8Encodings . Strict . GetByteCount ( passwordChars ) ] ;
176
- var passwordBytesHandle = GCHandle . Alloc ( passwordBytes , GCHandleType . Pinned ) ;
177
- try
178
- {
179
- Utf8Encodings . Strict . GetBytes ( passwordChars , 0 , passwordChars . Length , passwordBytes , 0 ) ;
180
-
181
- return ComputeHash ( algorithm , prefixBytes , passwordBytes ) ;
182
- }
183
- finally
121
+ var secureString = new SecureString ( ) ;
122
+ foreach ( var c in value )
184
123
{
185
- Array . Clear ( passwordBytes , 0 , passwordBytes . Length ) ;
186
- passwordBytesHandle . Free ( ) ;
124
+ secureString . AppendChar ( c ) ;
187
125
}
126
+ secureString . MakeReadOnly ( ) ;
127
+ return secureString ;
188
128
}
189
129
190
130
private static byte [ ] ComputeHash ( HashAlgorithm algorithm , byte [ ] prefixBytes , byte [ ] passwordBytes )
0 commit comments