Decryption Stops working after convert to json and convert back - c#

I have an encryption class that I'm using in the UI and in the server.
Encryption Class
public class AesEncryption
{
private const string Password = "464DA0FE-A4B6-4D86-B68B-C5913779918B"; //TODO: change to long string
private const int AesBlockByteSize = 128 / 8;
private const int PasswordSaltByteSize = 128 / 8;
private const int PasswordByteSize = 256 / 8;
private const int PasswordIterationCount = 100;
private static readonly Encoding StringEncoding = Encoding.UTF8;
private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();
public static byte[] EncryptString(string toEncrypt)
{
using var aes = Aes.Create();
var keySalt = GenerateRandomBytes(PasswordSaltByteSize);
var key = GetKey(Password, keySalt);
var iv = GenerateRandomBytes(AesBlockByteSize);
using var encryptor = aes.CreateEncryptor(key, iv);
var plainText = StringEncoding.GetBytes(toEncrypt);
var cipherText = encryptor
.TransformFinalBlock(plainText, 0, plainText.Length);
var result = MergeArrays(keySalt, iv, cipherText);
return result;
}
public static string EncryptToBase64(string toEncrypt)
{
var bytes = EncryptString(toEncrypt);
return Convert.ToBase64String(bytes);
}
public static string DecryptBase64(string base64)
{
var bytes = Convert.FromBase64String(base64);
return DecryptString(bytes);
}
public static string DecryptString(byte[] encryptedData)
{
using var aes = Aes.Create();
var keySalt = encryptedData.Take(PasswordSaltByteSize).ToArray();
var key = GetKey(Password, keySalt);
var iv = encryptedData
.Skip(PasswordSaltByteSize).Take(AesBlockByteSize).ToArray();
var cipherText = encryptedData
.Skip(PasswordSaltByteSize + AesBlockByteSize).ToArray();
using var encryptor = aes.CreateDecryptor(key, iv);
var decryptedBytes = encryptor
.TransformFinalBlock(cipherText, 0, cipherText.Length);
return StringEncoding.GetString(decryptedBytes);
}
private static byte[] GetKey(string password, byte[] passwordSalt)
{
var keyBytes = StringEncoding.GetBytes(password);
using var derivator = new Rfc2898DeriveBytes(
keyBytes, passwordSalt,
PasswordIterationCount, HashAlgorithmName.SHA256);
return derivator.GetBytes(PasswordByteSize);
}
private static byte[] GenerateRandomBytes(int numberOfBytes)
{
var randomBytes = new byte[numberOfBytes];
Random.GetBytes(randomBytes);
return randomBytes;
}
private static byte[] MergeArrays(params byte[][] arrays)
{
var merged = new byte[arrays.Sum(a => a.Length)];
var mergeIndex = 0;
for (int i = 0; i < arrays.GetLength(0); i++)
{
arrays[i].CopyTo(merged, mergeIndex);
mergeIndex += arrays[i].Length;
}
return merged;
}
public static string DecryptFromBase64(string base64)
{
var bytes = Convert.FromBase64String(base64);
return DecryptString(bytes);
}
}
LoginModel
public class LoginModel
{
public LoginModel(string userName, string password)
{
UserName = AesEncryption.EncryptToBase64(userName);
Password = AesEncryption.EncryptToBase64(password);
}
public string UserName { get; }
public string Password { get; }
public string GetDecryptedPassword() => AesEncryption.DecryptFromBase64(Password);
public string GetDecryptedUserName() => AesEncryption.DecryptFromBase64(UserName);
public void Deconstruct(out string username, out string password)
{
username = GetDecryptedUserName();
password = GetDecryptedPassword();
}
}
When I run these 2 Unit Tests everything works as expected.
[Fact]
public void ShouldEncryptAndDecrypt()
{
var password = "Test";
var encryption = AesEncryption.EncryptToBase64(password);
var decrypt = AesEncryption.DecryptFromBase64(encryption);
decrypt.Should().Be(password);
}
[Fact]
public void LoginModel_ShouldDecriptAndEncrypt()
{
var userName = "test";
var password = "hopethisworks";
var model = new LoginModel(userName,password);
userName.Should().NotBe(model.UserName);
password.Should().NotBe(model.Password);
var (decryptedUserName, decryptedPassword) = model;
userName.Should().Be(decryptedUserName);
password.Should().Be(decryptedPassword);
}
But when I run this test it stops decrypting
[Fact]
public void LoginModel_ConverterAndParsed()
{
var userName = "test";
var password = "hopethisworks";
var model = new LoginModel(userName,password);
var json = JsonConvert.SerializeObject(model);
var parsedJsonModel = JsonConvert.DeserializeObject<LoginModel>(json);
var (decryptedUserName, decryptedPassword) = parsedJsonModel;
userName.Should().Be(decryptedUserName);
password.Should().Be(decryptedPassword);
}
I am using Newtonsoft.Json XUnit and FluentAssertions
My question: What would cause this to stop working when I Serialize and Deserialize the LoginModel?

In constructor of login model you encrypt username and password, so UserName and Password properties are in encrypted form and stored like this in json. However, to deserialize - JSON.NET has no other choice than to call that constructor again, because there is no other constructor and those properties are readonly. So on deserialization it calls this constructor again, passing encrypted username and password, and they are encrypted once again. So in result you have double encrypted username and password.
One solution is to add public constructor and make properties public too. Then JSON.NET will use that public constructor and set property values, without double encryption.
public class LoginModel
{
public LoginModel(){
}
public LoginModel(string userName, string password)
{
UserName = AesEncryption.EncryptToBase64(userName);
Password = AesEncryption.EncryptToBase64(password);
}
public string UserName { get; set;}
public string Password { get; set;}
public string GetDecryptedPassword() => AesEncryption.DecryptFromBase64(Password);
public string GetDecryptedUserName() => AesEncryption.DecryptFromBase64(UserName);
public void Deconstruct(out string username, out string password)
{
username = GetDecryptedUserName();
password = GetDecryptedPassword();
}
}
If that's not possible, you can do this:
public class LoginModel
{
[JsonProperty("UserName")]
private readonly string _userName;
[JsonProperty("Password")]
private readonly string _password;
[JsonConstructor]
private LoginModel(){
}
public LoginModel(string userName, string password)
{
_userName = AesEncryption.EncryptToBase64(userName);
_password = AesEncryption.EncryptToBase64(password);
}
[JsonIgnore]
public string UserName => _userName;
[JsonIgnore]
public string Password => _password;
public string GetDecryptedPassword() => AesEncryption.DecryptFromBase64(Password);
public string GetDecryptedUserName() => AesEncryption.DecryptFromBase64(UserName);
public void Deconstruct(out string username, out string password)
{
username = GetDecryptedUserName();
password = GetDecryptedPassword();
}
}
Basically we guiding JSON.NET to not use that constructor and instead use private parameterless one, then set our readonly fields.

Related

How can I return following values?

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());
}

Converting PHP Api call example code to a C# RestSharp Api call w/ OAuth 1.0

I am calling a 3rd party API which provided me with a PHP code example on how to call their API. I do not know PHP but it looks pretty straight forward and readable for me to try and build a similar .NET solution. The PHP example below is doing a Post but in my C# example I will be doing a Get. I have mocked up the PHP example with some dummy values.
$params = array();
$params['assertion_id'] = "b57936e4-6cea-46f4-a897-c7b3a6f01147"; // Example Assertion ID.
$params['product_id'] = "product001";
$params['product_name'] = "Useless Product";
$params['price'] = "1.99";
// Generate Signature Base String.
$params['api_key'] = "526587410g44p9kk8f7h2bb2zf3365va"; // Example Api Key.
$params['timestamp'] = "1510760624"; // Example Timestamp.
$params['nonce'] = "uilp37xh"; // Example Nonce.
ksort($params);
$url = "https://someurl.com/api/product";
$signature_base_string = 'POST&'.urlencode($url).'&'.http_build_query($params);
// Encrypt signature base string for signature.
$secret_key = "DlKST1adTpoWELS8TjjBc1pFATdlGA8qHUNEaq9MOSAUT648AlAvzK4EEC7="; // Example Secret Key.
$signature = base64_encode(hash_hmac('sha1', $signature_base_string, base64_decode($secret_key), true));
$params['signature'] = $signature;
// Send Request.
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, count($params));
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
curl_close($curl);
Here is the C# code example that I have constructed thus far utilizing RestSharp. The nonce, timestamp, and signature adhere to the OAuth 1.0 specification but I am not sure that I have handled that part correctly? I cannot provide the real values to actually test the Api call but know the code does work in the sense that it does get a response back from the 3rd party Api. However, the response states that the parameters are missing...
public class ProductApiRequest
{
private string _api;
private string _apiKey;
private string _apiSecretKey;
public ProductApiRequest()
{
_api = "https://someurl.com/api/";
_apiKey = "526587410g44p9kk8f7h2bb2zf3365va";
_apiSecretKey = "DlKST1adTpoWELS8TjjBc1pFATdlGA8qHUNEaq9MOSAUT648AlAvzK4EEC7=";
}
public class Product
{
public Guid assertion_id { get; set; }
public String api_key { get; set; }
public string product_id { get; set; }
public string product_name { get; set; }
public string price { get; set; }
public string timestamp { get; set; }
public string nonce { get; set; }
public string signature { get; set; }
}
public string getProduct()
{
try
{
Product oProduct = new Product();
oProduct.assertion_id = Guid.NewGuid();
oProduct.api_key = _apiKey;
oProduct.product_id = "product001";
oProduct.product_name = "Useless Product";
oProduct.price = "1.99";
oProduct.timestamp = GenerateTimeStamp();
oProduct.nonce = GenerateNonce();
oProduct.signature = GenerateSignature(oProduct.nonce, oProduct.timestamp, _apiSecretKey);
var path = "product";
dynamic request = new RestSharp.RestRequest(path, RestSharp.Method.GET);
request.RequestFormat = RestSharp.DataFormat.Json;
request.JsonSerializer = new RestSharp.Serializers.JsonSerializer();
request.AddJsonBody(oProduct);
var client = new RestSharp.RestClient(_api);
var response = client.Execute(request);
return "Return something.";
}
catch (Exception ex)
{
return ex.Message.ToString();
}
}
public string GenerateTimeStamp()
{
TimeSpan ts = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0));
string timeStamp = ts.TotalSeconds.ToString();
timeStamp = timeStamp.Substring(0, timeStamp.IndexOf("."));
return timeStamp;
}
public string GenerateNonce()
{
var _random = new Random();
var sb = new StringBuilder();
for (int i = 0; i < 8; i++)
{
int g = _random.Next(3);
switch (g)
{
case 0:
// lowercase alpha
sb.Append((char)(_random.Next(26) + 97), 1);
break;
default:
// numeric digits
sb.Append((char)(_random.Next(10) + 48), 1);
break;
}
}
return sb.ToString();
}
public string GenerateSignature(string nonce, string timestamp, string apisecretkey)
{
var encoder = new UTF8Encoding();
var hasher = new System.Security.Cryptography.HMACSHA1();
var vals = string.Concat(nonce, timestamp, apisecretkey);
byte[] hashedDataBytes = hasher.ComputeHash(encoder.GetBytes(vals));
return Convert.ToBase64String(hashedDataBytes);
}
}
Any help converting the PHP solution to a C# solution would be appreciated!
I did not know PHP but have managed to figured out the solution! \m/ Metal \m/
public class ProductApiRequest
{
private string _api;
private string _apiKey;
private string _apiSecretKey;
private string _resource;
public ProductApiRequest()
{
_api = "https://someurl.com/api/";
_apiKey = "526587410g44p9kk8f7h2bb2zf3365va";
_apiSecretKey = "DlKST1adTpoWELS8TjjBc1pFATdlGA8qHUNEaq9MOSAUT648AlAvzK4EEC7=";
_resource = "products";
}
public class Product
{
public Guid assertion_id { get; set; }
public String api_key { get; set; }
public string product_id { get; set; }
public string product_name { get; set; }
public string price { get; set; }
public string timestamp { get; set; }
public string nonce { get; set; }
public string signature { get; set; }
}
public string getProduct()
{
Product oProduct = new Product();
oProduct.assertion_id = Guid.NewGuid();
oProduct.api_key = _apiKey;
oProduct.product_id = "product001";
oProduct.product_name = "Useless Product";
oProduct.price = "1.99";
oProduct.timestamp = GenerateTimeStamp();
oProduct.nonce = GenerateNonce();
// Create Signature Base String.
string apiEncoded = Uri.EscapeDataString(_api + _resource);
string strSignatureBase = "GET&" + apiEncoded + "&api_key=" + oProduct.api_key + "&product_id=" + oProduct.product_id + "&product_name=" + oProduct.product_name + "&price=" + oProduct.price + "&nonce=" + oProduct.nonce + "&timestamp=" + oProduct.timestamp;
// Create Signature for OAuth 1.0
oProduct.signature = GenerateSignature(strSignatureBase, _apiSecretKey);
var client = new RestClient(_api + _resource + "?assertion_id=" + oProduct.assertion_id + "&api_key=" + oProduct.api_key + "&product_id=" + oProduct.product_id + "&product_name=" + oProduct.product_name + "&price=" + oProduct.price + "&timestamp=" + oProduct.timestamp + "&nonce=" + oProduct.nonce + "&signature=" + HttpUtility.UrlEncode(oProduct.signature));
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
return "Return whatever you want.";
}
public string GenerateTimeStamp()
{
TimeSpan ts = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0));
string timeStamp = ts.TotalSeconds.ToString();
timeStamp = timeStamp.Substring(0, timeStamp.IndexOf("."));
return timeStamp;
}
public string GenerateNonce()
{
var _random = new Random();
var sb = new StringBuilder();
for (int i = 0; i < 8; i++)
{
int g = _random.Next(3);
switch (g)
{
case 0:
// lowercase alpha
sb.Append((char)(_random.Next(26) + 97), 1);
break;
default:
// numeric digits
sb.Append((char)(_random.Next(10) + 48), 1);
break;
}
}
return sb.ToString();
}
public string GenerateSignature(string strSignatureBase, string strSecretKey)
{
byte[] signatureBaseBytes = Encoding.UTF8.GetBytes(strSignatureBase);
byte[] secretKeyDecodedBytes = Convert.FromBase64String(strSecretKey); // Decode Secret Key.
var encoder = new UTF8Encoding();
var hasher = new HMACSHA1(secretKeyDecodedBytes);
byte[] hashedDataBytes = hasher.ComputeHash(signatureBaseBytes);
return Convert.ToBase64String(hashedDataBytes);
}
}

Loop setting a variable in constructor

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);
}
}

C# Replicate This Code - JSON with Object with JSON

I'm relatively new to C# and I'm looking to replicate this following JSON expression:
{"itemData":[{"pile":"club","id":"100997087277"}]}
At present I have the following methods:
public class MoveItemValues
{
public string pile;
public Int64 id;
}
public class MoveItemRequestValues
{
public MoveItemValues itemData;
}
internal string moveItem(Int64 itemId, string pile)
{
string moveItemResponse;
MoveItemRequestValues bodyContent = new MoveItemRequestValues();
bodyContent.itemData = new MoveItemValues();
bodyContent.itemData.pile = pile;
bodyContent.itemData.id = itemId;
string jsonContent = JsonConvert.SerializeObject(bodyContent);
byte[] byteArray = Encoding.UTF8.GetBytes(jsonContent);
Console.WriteLine(jsonContent);
}
This produces:
"{"itemData":{"pile":"trade","id":100997087277}}"
But as you can see the square brackets are missing.
How would I go about finishing off achieving this?
itemData is an array in the json string.
FYI: You need to follow the C# naming guidelines. Property and method should be Pascal case.
public class MoveItemValues
{
public string Pile;
public Int64 Id;
}
public class MoveItemRequestValues
{
public IList<MoveItemValues> ItemData;
public MoveItemRequestValues()
{
ItemData = new List<MoveItemValues>();
}
}
static void MoveItem(Int64 itemId, string pile)
{
string moveItemResponse;
MoveItemRequestValues bodyContent = new MoveItemRequestValues();
bodyContent.ItemData = new List<MoveItemValues>()
{
new MoveItemValues {Pile = pile, Id = itemId}
};
var camelCaseFormatter = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
string jsonContent = JsonConvert.SerializeObject(bodyContent, camelCaseFormatter);
byte[] byteArray = Encoding.UTF8.GetBytes(jsonContent);
Console.WriteLine(jsonContent);
}
static void Main(string[] args)
{
MoveItem(100997087277, "trade");
Console.ReadLine();
}
Use List<>
public class MoveItemRequestValues
{
public List<MoveItemValues> itemData;
}

datamembers password not hashed?

I am trying to hash/salt my datamembers passwords in my datacontracts but when I add a new student and then GET that student collection the password field hasnt been hashed/salted it comes back as what I typed?
public void AddStudent(Student student)
{
student.StudentID = (++eCount).ToString();
byte[] passwordHash = Hash(student.Password, GenerateSalt());
student.TimeAdded = DateTime.Now;
students.Add(student);
}
Can anyone help fix this?
you should assign hashed pasword to student password then add student.
public void AddStudent(Student student)
{
student.StudentID = (++eCount).ToString();
byte[] passwordHash = Hash(student.Password, GenerateSalt());
StringBuilder stringBuilder = new StringBuilder();
foreach(byte b in passwordHash){
stringBuilder.AppendFormat("{0:X2}", b);
}
student.TimeAdded = DateTime.Now;
student.Password= stringBuilder.ToString();;
students.Add(student);
}
You could simply add this to your orginal question, but here is some more code:
[DataContract(Name="Student")]
public class Student
{
[DataMember(Name = "StudentID")]
public string StudentID { get; set; }
[DataMember(Name = "FirstName")]
public string FirstName { get; set; }
[DataMember(Name = "LastName")]
public string LastName { get; set; }
// local non public cache
private byte[] _password;
[DataMember(Name = "Password")]
public byte[] Password {
get { return _password; }
set {
this.Salt = GenerateSalt();
this._password = Hash(value, this.Salt);
}
};
[DataMember(Name = "Salt")]
public byte[] Salt;
// ...

Categories