Loop in constructor c #

2

I'm trying to set my Senha using md5 , but this is looping sett.

public class Usuario
{
        public int ID { get; set; }
        [Required]
        public string Nome { get; set; }
        [Required]
    public string Senha {
        get { return Senha; }
        set { Console.WriteLine("valor"+value );
            this.Senha = CalculateMD5Hash(value); }
    }

    public static String CalculateMD5Hash(String input) {

            // step 1, calculate MD5 hash from input
            MD5 md5 = MD5.Create();
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] hash = md5.ComputeHash(inputBytes);
            // step 2, convert byte array to hex string
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.Length; i++) {
                sb.Append(hash[i].ToString("X2"));
            }
            return sb.ToString();
    }
}

The class is calling the CalculateMD5Hash function multiple times as shown below. E.g .: value = 123

value1 = 202CB962AC59075B964B07152D234B70 (hash do value)

value2 = D9840773233FA6B19FDE8CAF765402F5 (hash do value1)

How do I stop the Loop and call the function of calculating MD5 only once?

    
asked by anonymous 14.06.2016 / 06:26

2 answers

1

Properties were not set correctly. For set and get were calling themselves, so as to cause overflow.

To resolve it is necessary to create a backing field field to store the value of the property:

private string _senha;
public string Senha 
{
    get { return _senha; }
    set 
    { 
        Console.WriteLine("valor"+value );
        _senha = CalculateMD5Hash(value);
    }
}
    
14.06.2016 / 06:36
1

Vitor, I will completely escape 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, however small the chance of collision, is not secure enough to protect a password.

Below is an implementation I used at some time (Pbkdf2 + SHA512):

Database Template

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 example above I store the password as a 64-byte array of bytes, and Salt in a 16-byte array of 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 , whereas in my DTO I only have the string Password field.

UserController

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 example above I used the following NuGet package: CryptSharp

When comparing passwords, you should retrieve Salt and call the Pbkdf2.ComputeDerivedKey method again by passing the same parameters.

    
14.06.2016 / 14:09