Vitor, I will completely evade your problem, but I want to point out a basic error in your solution.:
You are using MD5 to store a Password.
Understand, No hash algorithm, no matter how large the blocks are, no matter how small the chance of collision, is safe enough to protect a password.
Below is an implementation I used for some time (Pbkdf2 + SHA512):
Model of the Database
CREATE TABLE [dbo].[Usuario](
[UsuarioGUID] [uniqueidentifier] NOT NULL,
[UserName] [varchar](50) NOT NULL,
[Password] [binary](64) NOT NULL,
[Salt] [binary](16) NOT NULL,
[Email] [varchar](50) NOT NULL,
[DataCriacao] [datetime2](7) NOT NULL CONSTRAINT [DF_Pessoa_DataCriacao] DEFAULT (sysdatetime()),
CONSTRAINT [PK_Pessoa] PRIMARY KEY CLUSTERED
(
[UsuarioGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Note that in the above example I store the password as an array of 64 bytes, and Salt in an array of 16 bytes.
The function of Salt here is to make the password unique, even if two users choose to use the same password.
Entity - Entity Framework
[Table("Usuario")]
public partial class Usuario
{
[Key]
public Guid UsuarioGUID { get; set; }
[Required]
[StringLength(50)]
public string UserName { get; set; }
[Required]
[MaxLength(64)]
public byte[] Password { get; set; }
[Required]
[MaxLength(16)]
public byte[] Salt { get; set; }
[Required]
[StringLength(50)]
public string Email { get; set; }
[Column(TypeName = "datetime2")]
public DateTime DataCriacao { get; set; }
}
DTO
[DataContract]
public partial class Usuario
{
[DataMember(EmitDefaultValue = false)]
public Guid UsuarioGUID { get; set; }
[DataMember(EmitDefaultValue = false)]
public string UserName { get; set; }
[DataMember(EmitDefaultValue = false)]
public string Password { get; set; }
[DataMember(EmitDefaultValue = false)]
public string Email { get; set; }
[DataMember(EmitDefaultValue = false)]
public DateTime DataCriacao { get; set; }
}
Note that in my entity I have a property byte[] Password
and another call byte[] Salt
, while in my DTO I have only the field string Password
.
User controller
private byte[] CreateSalt()
{
var salt = new byte[16];
using (var provider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
provider.GetBytes(salt);
}
return salt;
}
[HttpPut]
public async Task<int> Inserir(DTO.Pessoa dto)
{
var entity = default(Models.Pessoa);
try
{
var password = new System.Security.Cryptography.HMACSHA512() {
Key = Encoding.UTF8.GetBytes(dto.Password)
};
entity = MapperConfig.Mapper.Map<Models.Pessoa>(dto);
entity.Salt = this.CreateSalt();
entity.Password = Pbkdf2.ComputeDerivedKey(password, entity.Salt, UInt16.MaxValue, password.HashSize / 8);
}
catch (Exception err)
{
return -1;
}
}
In the above example I used the following Nuget package: Cryptsharp
When comparing passwords, you should recover the Salt
and call the method Pbkdf2.ComputeDerivedKey
again passing the same parameters.
Why not create the hash inside the loop and use
.Append()
out of the loop?– StillBuggin