I'm trying to set the variable Senha (password of my system) as a md5 hash of the original value.
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();
}
}
But what is happening is that the class enter in a loop and makes hashes of the original hash.
E.g.: value = 123
value1 = 202CB962AC59075B964B07152D234B70 (hash of value)
value2 = D9840773233FA6B19FDE8CAF765402F5 (hash of value1)
How can I stop this loop and just trigger the function once ?
Your property is not defined correctly. Not only is your setter calling itself, your getter is calling itself too and will cause a stack overflow.
Instead, you need to provide a backing 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);
}
}
By the way, since you specifically mention the word 'password', using MD5 for passwords is a bad idea, so unless you're using this to access a legacy system you should really do it the right way.
You need to define property with backing field in this case.
private string _senha;
public string Senha
{
get { return _senha; }
set { Console.WriteLine("valor"+value );
_senha = CalculateMD5Hash(value);
}
}
Related
Is there any kind of text serializer in C#, which is able to serialize / deserialize this shortened example...
public class Record
{
// Letters 1-4
public string Identifier { get; set; }
// Letters 5-12
public string ProcessAbbreviation { get; set; }
// Letters 13-16
public string Name { get; set; }
}
... into this string?
AAAABBBB CCCC
Note, that the string must contain whitespaces if the property hasn't the desired length.
Although it must be possible to serialize / deserialize into the other direction, e.g. string into object.
I've already tried to find something, which suits my requirement, but I couldn't find anything.
I highly appreciate any kind of help, cheers! :)
There's not going to be an existing library to do this, but it's very easy to write your own serialisation and deserialisation:
public class Record
{
// Letters 1-4
public string Identifier { get; set; }
// Letters 5-12
public string ProcessAbbreviation { get; set; }
// Letters 13-16
public string Name { get; set; }
public string Serialize()
{
return $"{Identifier, -4}{ProcessAbbreviation, -8}{Name, -4}";
}
public static Record Deserialize(string input)
{
if (input is not { Length: 16 })
throw new ArgumentException("input must be 16 characters long");
return new Record
{
Identifier = input.Substring( 0, 4).Trim(),
ProcessAbbreviation = input.Substring( 4, 8).Trim(),
Name = input.Substring(12, 4).Trim()
};
}
}
Test code:
public static void Main()
{
var rec = new Record { Identifier = "AAAA", ProcessAbbreviation = "BBBB", Name = "CCCC" };
var serialised = rec.Serialize();
Console.WriteLine("|" + serialised + "|");
var r = Record.Deserialize(serialised);
Console.WriteLine($"|{r.Identifier}|{r.ProcessAbbreviation}|{r.Name}|");
}
Try it on DotNetFiddle
I want to read out the header of a file and compare it to a given signature. The start of the signature can have an offset.
This is my current function:
public FileTypeVerifyResult Verify(Stream stream)
{
stream.Position = 0;
var reader = new BinaryReader(stream);
var headerBytes = reader.ReadBytes(SignatureLength + this.OffSet);
return new FileTypeVerifyResult
{
Name = Name,
Description = Description,
IsVerified = Signatures.Any(signature =>
headerBytes.Skip(this.OffSet).Take(signature.Length)
.SequenceEqual(signature)
)
};
}
This currently works with one offset but extensions exists that can have multiple offsets. So my first thought was to make the OffSet property an int[] with all offsets but then I don't know if this can be easily build into this linq expression.
Also, the file can have the offset any (or any other value that means anywhere in the file like just -1). How could such a thing build in?
To be able to handle more offsets, this is my solution:
protected List<int> OffSets { get; set; }
public int OffSetLength => OffSets.Max(m => m);
public FileTypeVerifyResult Verify(Stream stream)
{
stream.Position = 0;
var reader = new BinaryReader(stream);
var headerBytes = reader.ReadBytes(SignatureLength + OffSetLength);
reader.Close();
return new FileTypeVerifyResult
{
Name = Name,
Description = Description,
IsVerified = Signatures.Any(signature =>
OffSets.Any(offSet =>
headerBytes.Skip(offSet).Take(signature.Length)
.SequenceEqual(signature))
)
};
}
I don't think I can get the any/-1 offset in this function without rewriting everything.
I think this is the case where a swiss knife is not what you want, Linq is good for many things, but it really doesn't add any value to the problem at hand IMHO because writing such a query will make ones eyeballs bleed, but here is my take at the problem itself with a sparse use of LINQ if at all :)
I have allowed myself to deduct missing items that were not supplied and rationalize naming a bit.
public class FileType
{
public class FileTypeVerifyResult
{
public string Name { get; set; }
public string Description { get; set; }
public bool IsVerified { get; set; }
}
public class Signature
{
/// <summary>
/// Actual signature
/// </summary>
public byte[] Payload { get; set; }
public int Length { get => Payload.Length; }
public List<int> OffSets { get; set; }
}
public string Name { get; set; }
public string Description { get; set; }
public List<Signature> Signatures { get; set; }
public FileTypeVerifyResult Verify(Stream stream)
{
if (stream == null) throw new ArgumentException(nameof(stream));
if(stream.CanSeek)
stream.Position = 0;
else
//TODO: Consider if we need this: throw new ArgumentException("Stream does not support seek", nameof(stream));
var bytes = new byte[stream.Length];
int wasRead = stream.Read(bytes, 0, (int)stream.Length);
if (wasRead == 0) throw new ArgumentException("Unable to read from stream");
foreach (var signature in Signatures)
{
foreach(var offset in signature.OffSets)
{
if(offset == -1)
{
//TODO: read signature length from each position first 0, then 1 until what is left is less than length of signature and if it fits
return createResultObject(true);
}
var candidateBytes = new byte[signature.Length];
candidateBytes = bytes.Skip(offset).Take(signature.Length).ToArray();
// I'd not use linq, instead Array.Copy(bytes, offset, candidateBytes, 0, signature.Length);
if(signature.Payload.Equals(candidateBytes))
{
return createResultObject(true);
}
}
}
return createResultObject();
FileTypeVerifyResult createResultObject(bool isValid = false)
{
return new FileTypeVerifyResult
{
Name = Name,
Description = Description,
IsVerified = isValid
};
}
}
}
I used the model with byte[] attribute that should be convert to short[] before used.
I add two properties to convert byte[] to short[] using get property and its work well.
my problem is when i try to use Set property to do the opposite and set byte[] array when changing the short[] my code not work and when i debug the code it doesn't call the Set Function at all.
public class TestModel
{
public byte[] Data { get; set; } // The original data
private short[] _DataConverted { get; set; }
public short[] DataConvert
{
get => _DataConverted ?? (_DataConverted = Data.GetShiftShort());
set
{
Data = value.GetShiftByteFShort();
_DataConverted = value;
}
}
}
public void Main()
{
TestModel modal =new TestModel()
{
Data = new byte[] {0,1,0,2,0,3}
};
modal.DataConvert[0] ++;
modal.DataConvert[1] +=1;
modal.DataConvert[2] = modal.DataConvert[2] + 1 ;
}
And the result is:
_DataConverted {2,3,4}
DataConvert {2,3,4}
But the Data don't change {0,1,0,2,0,3}
I'm working on my project but I can't go on. My project should generate two code parts and convert these to two hashes. Thats all working. But now, I'd like to print the values out in the browser.
Thant is my unfinished code:
The Model:
namespace myapplication.test.Backend.Models
{
public class CodeContainer
{
public string CodePartA { get; set; }
public string CodePartB { get; set; }
public string HashAB { get; set; }
public string HashBA { get; set; }
}
}
The Class where I generate my codes and hashes:
namespace myapplication.test.Backend.Utilities
{
public static class VerificationCodeUitillity
{
private static string GenerateHash(string input)
{
string hash = string.Empty;
using (MD5 md5Hash = MD5.Create())
{
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
hash = sBuilder.ToString();
}
return hash;
}
private static string GenerateCodePart(int lenght)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random code = new Random();
return new string(Enumerable.Repeat(chars, lenght).Select(s => s[code.Next(s.Length)]).ToArray());
}
public static CodeContainer GeneratePVCode()
{
CodeContainer result = new CodeContainer();
result.CodePartA = GenerateCodePart(4);
result.CodePartB = GenerateCodePart(4);
result.HashAB = GenerateHash(result.CodePartA + result.CodePartB);
result.HashBA = GenerateHash(result.CodePartB + result.CodePartA);
return result;
}
}
}
And here in my Demo Controller I'd like to return the values CodePartA, CodePartB, HashAB and HashBA.
// GET api/demo/code
[HttpGet]
[Route("code")]
public string Code()
{
//return values here
}
Thanks for your help in advance!!
Cheers
Like that it should work:
// GET api/demo/code
[HttpGet]
[Route("code")]
public CodeContainer PVCodeGen()
{
return VerificationCodeUitillity.GeneratePVCode();
}
You should return the IHttpActionResult Interface in api-methods.
// GET api/demo/code
[HttpGet]
[Route("code")]
public IHttpActionResult PVCodeGen()
{
return this.Ok<CodeContainer>(VerificationCodeUitillity.GeneratePVCode());
}
Here's the code.
[Serializable]
public class HostedGame
{
public int ID { get; set; }
public int UID { get; set; }
public String Name { get; set; }
public Boolean Available { get; set; }
public String Description { get; set; }
public List<int> Users { get; set; }
public int Port { get; set; }
public HostedGame(int uid, String name, String description, int port)
{
UID = uid;
Name = name;
Description = description;
Available = true;
Port = port;
Users = new List<int>();
}
public int CompareTo(Object obj)
{
int result = 1;
if(obj != null && obj is HostedGame)
{
HostedGame w = obj as HostedGame;
result = this.ID.CompareTo(w.ID);
}
return result;
}
static public int Compare(HostedGame x, HostedGame y)
{
int result = 1;
if(x != null && y != null)
{
result = x.CompareTo(y);
}
return result;
}
public static HostedGame DeSerialize(byte[] data)
{
MemoryStream ms = new MemoryStream(data);
BinaryFormatter bff = new BinaryFormatter();
return (HostedGame)bff.Deserialize(ms);
}
public static byte[] Serialize(HostedGame obj)
{
BinaryFormatter bff = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bff.Serialize(ms, obj);
return ms.ToArray();
}
}
The code bellow doesn't seem to work right:
HostedGame hs = new HostedGame(12,"Name", "Description", 8088);
String s = Encoding.ASCII.GetString(HostedGame.Serialize(hs));
HostedGame HACK = HostedGame.DeSerialize(Encoding.ASCII.GetBytes(s));
HACK.Port for some reason comes out being 7999?
When I just do this...
HostedGame HACK = HostedGame.DeSerialize(HostedGame.Serialize(hs));
It works fine.
So, what I'm asking is
Why am I getting a wrong value?
Is there a better way to convert the bytes to a string and back again?
You cannot use Encoding.ASCII.GetString to convert any byte array to a string. You are losing some data when you do this. Use Convert.ToBase64String instead. This one will make a string from any byte sequence without losing the data.
HostedGame hs = new HostedGame(12,"Name", "Description", 8088);
String s = Convert.ToBase64String(HostedGame.Serialize(hs));
HostedGame HACK= HostedGame.DeSerialize(Convert.FromBase64String(s));
Here is an example, that shows how using Encoding.ASCII loses the data.
var testBytes = new byte[] { 250, 251, 252 };
var text = Encoding.ASCII.GetString(testBytes);
var bytes = Encoding.ASCII.GetBytes(result); // will be 63, 63, 63
Binary serialization generates a byte array which is not (necessarily) a valid string in any encoding.
When you try to read it as ASCII text, the ASCII decoder will convert any invalid bytes (> 128) into ? characters.
Therefore, when you turn it back into ASCII bytes, you end up with a different set of bytes.
In short, don't treat binary data as ASCII, or as any other text encoding.
If you need to send binary data as plain text, use Base64 to safely convert it to text.