Is it possible to modify triple DES so as not to include forward and backward slashes when encrypting/decrypting?
I had this actionlink on mvc which works without encryption however when I tried to encrypt the id passed to the controller method, the id was being encrypted and included some forward slashes (/vO5Ppr4+Phzx+lHD4Jp6JubZlYXK0Az9OA9J8urf+MJFw62c3Y0Q/Q==) thus I am getting a 404 not found and the controller method is not being called.
MVC ActionLink:
<span> | </span> #Html.ActionLink("Student Rights", "StudentRights","Threads", new { id = CommonLayer.Securities.Encryption.EncryptTripleDES(item.ID) }, null)
Encryption Method:
private static byte[] KEY_192 =
{
111,21,12,65,21,12,2,1,
5,30,34,78,98,1,32,122,
123,124,125,126,212,212,213,214
};
private static byte[] IV_192 =
{
1,2,3,4,5,12,13,14,
13,14,15,13,17,21,22,23,
24,25,121,122,122,123,124,124
};
/// <summary>
/// Encrypt using TripleDES
/// </summary>
/// <param name="vl">String to Encrypt</param>
/// <returns>Encrypted String</returns>
public static String EncryptTripleDES(String vl)
{
if (vl != "")
{
TripleDESCryptoServiceProvider cryptoprovider = new TripleDESCryptoServiceProvider();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, cryptoprovider.CreateEncryptor(KEY_192, IV_192), CryptoStreamMode.Write);
StreamWriter sw = new StreamWriter(cs);
sw.Write(vl);
sw.Flush();
cs.FlushFinalBlock();
ms.Flush();
return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
}
return "";
}
/// <summary>
/// Decrypt using TripleDES
/// </summary>
/// <param name="vl">String to Decrypt</param>
/// <returns>Decrypted String</returns>
public static String DecryptTripleDES(String vl)
{
if (vl != "")
{
TripleDESCryptoServiceProvider cryptoprovider = new TripleDESCryptoServiceProvider();
Byte[] buffer = Convert.FromBase64String(vl);
MemoryStream ms = new MemoryStream(buffer);
CryptoStream cs = new CryptoStream(ms, cryptoprovider.CreateDecryptor(KEY_192, IV_192), CryptoStreamMode.Read);
StreamReader sw = new StreamReader(cs);
return sw.ReadToEnd();
}
return "";
}
Like owlstead suggests, use the url safe Base64 encoding described in RFC 4648.
My implementation produces a bit much garbage, but for short strings it shouldn't matter much as long as you don't call this a million times a second.
public static string ToUrlSafeBase64(byte[] bytes)
{
return Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').Replace("=","");
}
public static byte[] FromUrlSafeBase64(string s)
{
while (s.Length % 4 != 0)
s += "=";
s = s.Replace('-', '+').Replace('_', '/');
return Convert.FromBase64String(s);
}
Used as:
var str = ToUrlSafeBase64(bytes);
var bytes = FromUrlSafeBase64(str);
That's not the output of 3DES, that's Base 64 encoding of random (looking) binary data.
You can simply (raw) URL-encode the result or you can replace the character by any other. Check the Base 64 page on Wikipedia for ideas. Try and keep to common standards, such a replacing the + with -, and replacing / with _ as standardized by RFC 4648.
You may also want to remove the = characters at the end. This works if your base 64 library can decode such base 64, otherwise you can simply append them again until you got a string that has a multiple of 4 base 64 characters.
the following functions worked on another post why-is-base64-encode-adding-a-slash-in-the-result
function mybase64_encode($s) {
return str_replace(array('+', '/'), array(',', '-'), base64_encode($s));
}
function mybase64_decode($s) {
return base64_decode(str_replace(array(',', '-'), array('+', '/'), $s));
}
Related
public ActionResult Import(HttpPostedFileBase currencyConversionsFile)
{
string filename = "CurrencyConversion Upload_" + DateTime.Now.ToString("dd-MM-yyyy") + ".csv";
string folderPath = Server.MapPath("~/Files/");
string filePath = Server.MapPath("~/Files/" + filename);
currencyConversionsFile.SaveAs(filePath);
string[] csvData = System.IO.File.ReadAllLines(filePath);
//the later code isn't show here
}
I know the usual way to convert httppostedfilebase to String array, which will store the file in the server first, then read the data from the server. Is there anyway to get the string array directly from the httppostedfilebase with out store the file into the server?
Well you can read your file line by line from Stream like this:
List<string> csvData = new List<string>();
using (System.IO.StreamReader reader = new System.IO.StreamReader(currencyConversionsFile.InputStream))
{
while (!reader.EndOfStream)
{
csvData.Add(reader.ReadLine());
}
}
From another thread addressing the same issue, this answer helped me get the posted file to a string -
https://stackoverflow.com/a/40304761/5333178
To quote,
string result = string.Empty;
using (BinaryReader b = new BinaryReader(file.InputStream))
{
byte[] binData = b.ReadBytes(file.ContentLength);
result = System.Text.Encoding.UTF8.GetString(binData);
}
Splitting the string into an array -
string[] csvData = new string[] { };
csvData = result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
I'm trying to figure out how to join two strings that are encoded Base64 and then decode and get the combined result.
Example:
string1 Hello --- string1 Base64 SGVsbG8=
string2 World --- string2 Base64 V29ybGQ=
If I join the base64 I get something that wont decode SGVsbG8=V29ybGQ=
I want the result to say: Hello World
I don't want only this example to work but rather something that will work with any string.
This is a very simplified problem which is a step on an application I'm trying to write I'm stuck on.
What if you encode both strings to array, then combine those arrays and finally GetString from the bytes?
using System;
using System.Text;
using System.Linq;
public class Program
{
public static void Main()
{
var base1 = "SGVsbG8=";
var base2 = "V29ybGQ=";
var array1 = Convert.FromBase64String(base1);
var array2 = Convert.FromBase64String(base2);
var comb = Combine(array1, array2);
var data = Encoding.Default.GetString(comb);
Console.WriteLine(data);
}
private static byte[] Combine(byte[] first, byte[] second)
{
return first.Concat(second).ToArray();
}
}
I found a best way to do this, add plus between one string and other, and add ONE, and only ONE equals char ('=') at the end of string. The return will be "Hello>World", then remove the ">":
class Program
{
static void Main(string[] args)
{
string base64String = "SGVsbG8+V29ybGQ=";
byte[] encodedByte = Convert.FromBase64String(base64String);
var finalString = Encoding.Default.GetString(encodedByte)).Replace(">", " ");
Console.WriteLine(finalString.ToString());
}
}
(Old way) In C# I do something like this:
class Program
{
static void Main(string[] args)
{
string base64String = "SGVsbG8=V29ybGQ=";
Console.WriteLine(DecodeBase64String(base64String));
Console.ReadLine();
}
public static string DecodeBase64String(string base64String)
{
StringBuilder finalString = new StringBuilder();
foreach (var text in base64String.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries))
{
byte[] encodedByte = Convert.FromBase64String(text + "=");
finalString.Append(Encoding.Default.GetString(encodedByte));
finalString.Append(" "); //This line exists only to attend the "Hello World" case. The correct is remove this and let the one that will receive the return to decide what will do with returned string.
}
return finalString.ToString();
}
}
We are in process of migration of Google Apps Marketplace listing using the UpgradeableApp API resource but when calling
PUT https://www.googleapis.com/appsmarket/v2/upgradableApp/listingID/cwsID/domain
with signed request getting error:
81 {"error":{"errors":[{"domain":"global","reason":"backendError","message":"Backend Error"}],"code":500,"message":"Backend Error"}} 0
What i am doing wrong....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OAuth.Net.Common;
using OAuth.Net.Components;
using System.IO;
using System.Net;
using System.Security.Cryptography;
namespace Google_UpgradeableApi_Console
{
class Program
{
private static readonly ISigningProvider SigningProvider = new HmacSha1SigningProvider();
static void Main(string[] args)
{
// Setup the variables necessary to create the OAuth 1.0 signature and make the request
string httpMethod = "PUT";
string listingID = "xxxx+23453809800066606066";
string cwsID = "bbmagicjcjeblpadhhnnjahfbbbbhjk";
string domain = "xyz.com";
Uri url = new Uri(String.Format("{0}/{1}/{2}/{3}", "https://www.googleapis.com/appsmarket/v2/upgradableApp", listingID, cwsID, domain));
string consumerKey = "xyz.apps.googleusercontent.com";
string secret = "gt2sj34656U687f8qj677+GK";
string body = "";
MemoryStream requestBody = null;
string signatureMethod = SigningProvider.SignatureMethod;
HttpWebResponse response = null;
// Set the Nonce and Timestamp parameters
string nonce = getNonce();
string timestamp = getTimestamp();
// Set the request body if making a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
requestBody = new MemoryStream(Encoding.UTF8.GetBytes(body));
}
// Create the OAuth parameter name/value pair dictionary
Dictionary<string, string> oauthParams = new Dictionary<string, string>
{
{ "oauth_consumer_key", consumerKey },
{ "oauth_signature_method", signatureMethod },
{ "oauth_timestamp", timestamp },
{ "oauth_nonce", nonce },
};
// Get the OAuth 1.0 Signature
string signature = generateSignature(httpMethod, url, oauthParams, requestBody, secret);
Console.WriteLine("OAuth 1.0 Signature = " + signature + "\r\n\r\n");
// Add the oauth_signature parameter to the set of OAuth Parameters
IEnumerable<KeyValuePair<string, string>> allParams = oauthParams.Union(new[]
{
new KeyValuePair<string, string>("oauth_signature", signature)
});
// Defines a query that produces a set of: keyname="URL-encoded(value)"
IEnumerable<string> encodedParams = from param in allParams
select param.Key + "=\"" + Uri.EscapeDataString(param.Value) + "\"";
// Join all encoded parameters with a comma delimiter and convert to a string
string stringParams = String.Join(",", encodedParams);
// Build the X-Authorization request header
string xauth = String.Format("X-Authorization: OAuth realm=\"{0}\",{1}", url, stringParams);
Console.WriteLine("X-Authorization request header: \r\n" + xauth + "\r\n\r\n");
try
{
// Setup the Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = httpMethod;
request.Headers.Add(xauth);
// Set the request body if making a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
byte[] dataArray = Encoding.UTF8.GetBytes(body);
request.ContentLength = dataArray.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(dataArray, 0, dataArray.Length);
requestStream.Close();
}
// Send Request & Get Response
response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
// Get the response stream and write to console
string json = reader.ReadToEnd();
Console.WriteLine("Successful Response: \r\n" + json);
}
}
catch (WebException e)
{
// This exception will be raised if the server didn't return 200 - OK
// Retrieve more information about the error
if (e.Response != null)
{
using (HttpWebResponse err = (HttpWebResponse)e.Response)
{
Console.WriteLine("The server returned '{0}' with the status code '{1} ({2:d})'.",
err.StatusDescription, err.StatusCode, err.StatusCode);
}
}
}
finally
{
if (response != null) { response.Close(); }
}
Console.ReadLine();
}
#region Helper Functions
/// <summary>
/// Generates a random nonce.
/// </summary>
/// <returns>A unique identifier for the request.</returns>
private static string getNonce()
{
string rtn = Path.GetRandomFileName() + Path.GetRandomFileName() + Path.GetRandomFileName();
rtn = rtn.Replace(".", "");
if (rtn.Length > 32)
return rtn.Substring(0, 32);
else
return rtn;
}
/// <summary>
/// Generates an integer representing the number of seconds since the unix epoch using the
/// UTC date/time of the request.
/// </summary>
/// <returns>A timestamp for the request.</returns>
private static string getTimestamp()
{
return ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
}
/// <summary>
/// Generates an OAuth 1.0 signature.
/// </summary>
/// <param name="httpMethod">The HTTP method of the request.</param>
/// <param name="url">The URI of the request.</param>
/// <param name="oauthParams">The associative set of signable oauth parameters.</param>
/// <param name="requestBody">A stream containing the serialized message body.</param>
/// <param name="secret">Alphanumeric string used to validate the identity of the education partner (Private Key).</param>
/// <returns>A string containing the BASE64-encoded signature digest.</returns>
private static string generateSignature(
string httpMethod,
Uri url,
IDictionary<string, string> oauthParams,
Stream requestBody,
string secret
)
{
// Ensure the HTTP Method is upper-cased
httpMethod = httpMethod.ToUpper();
// Construct the URL-encoded OAuth parameter portion of the signature base string
string encodedParams = normalizeParams(httpMethod, url, oauthParams, requestBody);
// URL-encode the relative URL
string encodedUri = Uri.EscapeDataString(url.AbsolutePath);
// Build the signature base string to be signed with the Consumer Secret
string baseString = String.Format("{0}&{1}&{2}", httpMethod, encodedUri, encodedParams);
//return generateCmac(secret, baseString);
return generateHMAC(secret, baseString);
}
/// <summary>
/// Normalizes all oauth signable parameters and url query parameters according to OAuth 1.0.
/// </summary>
/// <param name="httpMethod">The upper-cased HTTP method.</param>
/// <param name="url">The request URL.</param>
/// <param name="oauthParams">The associative set of signable oauth parameters.</param>
/// <param name="requestBody">A stream containing the serialized message body.</param>
/// <returns>A string containing normalized and encoded OAuth parameters.</returns>
private static string normalizeParams(
string httpMethod,
Uri url,
IEnumerable<KeyValuePair<string, string>> oauthParams,
Stream requestBody
)
{
IEnumerable<KeyValuePair<string, string>> kvpParams = oauthParams;
// Place any Query String parameters into a key value pair using equals ("=") to mark
// the key/value relationship and join each paramter with an ampersand ("&")
if (!String.IsNullOrWhiteSpace(url.Query))
{
IEnumerable<KeyValuePair<string, string>> queryParams =
from p in url.Query.Substring(1).Split('&').AsEnumerable()
let key = Uri.EscapeDataString(p.Substring(0, p.IndexOf("=")))
let value = Uri.EscapeDataString(p.Substring(p.IndexOf("=") + 1))
select new KeyValuePair<string, string>(key, value);
kvpParams = kvpParams.Union(queryParams);
}
// Include the body parameter if dealing with a POST or PUT request
if (httpMethod == "POST" || httpMethod == "PUT")
{
MemoryStream ms = new MemoryStream();
requestBody.CopyTo(ms);
byte[] bodyBytes = ms.ToArray();
string body = Convert.ToBase64String(bodyBytes, Base64FormattingOptions.None);
body = Uri.EscapeDataString(body);
kvpParams = kvpParams.Union(new[]
{
new KeyValuePair<string, string>("body", Uri.EscapeDataString(body))
});
}
// Sort the parameters in lexicographical order, 1st by Key then by Value; separate with ("=")
IEnumerable<string> sortedParams =
from p in kvpParams
orderby p.Key ascending, p.Value ascending
select p.Key + "=" + p.Value;
// Add the ampersand delimiter and then URL-encode the equals ("%3D") and ampersand ("%26")
string stringParams = String.Join("&", sortedParams);
string encodedParams = Uri.EscapeDataString(stringParams);
return encodedParams;
}
private static string generateHMAC(string _key, string _msg)
{
string message;
string key;
key = _key;
message = _msg;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA1 hmacsha1 = new HMACSHA1(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
return ByteToString(hashmessage);
}
public static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
#endregion // Helper Functions
}
}
There are many reasons behind this, but first please check the URL must be signed with OAuth1 (not OAuth2) and must have valid values for the other parameters. The error reporting may make throw the same error for a lot of reason, but make sure your setup is correct and make sure your app is published on new chrome apps marketplace. Make sure you've submitted the Google Apps Marketplace Listing Review Request form here:
https://docs.google.com/forms/d/14QOb8PbSLKDgwIp8Zv-luoAAVurPXUqtzL0Hgikp3rk/viewform
After all is finished and google approved (you will get an email) your app then make call to UpgradeableApp API with oAuth 1.0 sign request, Here is an example you can see how to do it.
http://www.codeproject.com/Tips/359144/Legged-OAuth-Authentication-in-NET-Csharp
Hope that helps
How to implement password reset in MVC2 application?
Passwords are hashed using ASP .NET membership provider. Password recovery question is not used. Standard ASP .NET MVC2 project template with standard AccountController class is used.
If user forgots password, email with temporary link or with new password should sent to user e-mail address .
Where to find code to implement this in MVC 2 C# ?
stack overflow contains two answers which discuss methods about implementing this. There is not sample code.
I googled for "asp .net mvc password reset c# sample code download" but havent found sample code for this.
I'm new to MVC. Where to find sample code for password recovery? This is missing from VS2010 generated project template.
Update
I tried this code in Mono 2.10 but got exception:
CspParameters not supported by Mono
at line
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);
How to run it in Mono ?
Stack Trace:
System.NotSupportedException: CspParameters not supported by Mono
at System.Security.Cryptography.PasswordDeriveBytes.CryptDeriveKey (string,string,int,byte[]) [0x0001b] in /usr/src/redhat/BUILD/mono-2.10.2/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs:197
at store2.Helpers.Password.EncodeMessageWithPassword (string,string) <IL 0x00055, 0x000f3>
at store2.Helpers.AccountHelper.GetTokenForValidation (string) <IL 0x00033, 0x00089>
at MvcMusicStore.Controllers.AccountController.PasswordReminder (MvcMusicStore.Models.PasswordReminderModel) <IL 0x001ac, 0x00495>
at (wrapper dynamic-method) System.Runtime.CompilerServices.ExecutionScope.lambda_method (System.Runtime.CompilerServices.ExecutionScope,System.Web.Mvc.ControllerBase,object[]) <IL 0x00020, 0x0005b>
at System.Web.Mvc.ActionMethodDispatcher.Execute (System.Web.Mvc.ControllerBase,object[]) <IL 0x00008, 0x0001b>
at System.Web.Mvc.ReflectedActionDescriptor.Execute (System.Web.Mvc.ControllerContext,System.Collections.Generic.IDictionary`2<string, object>) <IL 0x00072, 0x00103>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod (System.Web.Mvc.ControllerContext,System.Web.Mvc.ActionDescriptor,System.Collections.Generic.IDictionary`2<string, object>) <IL 0x00003, 0x00019>
at System.Web.Mvc.ControllerActionInvoker/<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a () <IL 0x0002d, 0x00068>
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (System.Web.Mvc.IActionFilter,System.Web.Mvc.ActionExecutingContext,System.Func`1<System.Web.Mvc.ActionExecutedContext>) <IL 0x00031, 0x000b6>
--------------------------------------------------------------------------------
Version information: Mono Runtime Version: 2.10.2 (tarball Mon Apr 18 18:57:39 UTC 2011); ASP.NET Version: 2.0.50727.1433
Here is my approach. In MVC you will have an action called RetrievePassword where you will ask for the user's email address and pass it in a post
[HttpGet]
public ActionResult RetrievePassword()
{
return View();
}
[HttpPost]
public ActionResult RetrievePassword(PasswordRetrievalModel model)
{
if (ModelState.IsValid)
{
string username = Membership.GetUserNameByEmail(model.Email);
if (!String.IsNullOrEmpty(username))
{
// This is a helper function that sends an email with a token (an MD5).
NotificationsHelper.SendPasswordRetrieval(model.Email, this.ControllerContext);
}
else
{
Trace.WriteLine(String.Format("*** WARNING: A user tried to retrieve their password but the email address used '{0}' does not exist in the database.", model.Email));
}
return RedirectToAction("Index", "Home");
}
return View(model);
}
An email message will be sent with a url that redirects to http://example.com/Account/Validate?email=xxxxxxxx&token=xxxxxxxx
If the token is valid for the email, you will probably display a password reset form so they choose a new password.
So you need a Validate Action:
[HttpGet]
[CompressFilter]
public ActionResult Validate(string email, string token)
{
bool isValid = false;
if (AccountHelper.IsTokenValid(token, email))
{
string username = Membership.GetUserNameByEmail(email);
if (!String.IsNullOrEmpty(username))
{
// Get the user and approve it.
MembershipUser user = Membership.GetUser(username);
user.IsApproved = true;
Membership.UpdateUser(user);
isValid = true;
// Since it was a successful validation, authenticate the user.
FormsAuthentication.SetAuthCookie(username, false);
}
else
{
isValid = false;
}
}
return View(isValid);
}
Here are some of the helpers you see in this code:
Account Helper
/// <summary>
/// Gets the token for invitation.
/// </summary>
/// <param name="email">The email.</param>
/// <returns></returns>
public static string GetTokenForInvitation(string email)
{
if (String.IsNullOrEmpty(email))
throw new ArgumentException("The email cannot be null");
string token = Password.EncodeMessageWithPassword(String.Format("{0}#{1}", email, DateTime.Now), SEED);
return token;
}
/// <summary>
/// Gets the email from token.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="email">The email.</param>
/// <returns></returns>
public static bool GetEmailFromToken(string token, out string email)
{
email = String.Empty;
string message = Password.DecodeMessageWithPassword(token, SEED);
string[] messageParts = message.Split('#');
if (messageParts.Count() != 2)
{
return false;
// the token was not generated correctly.
}
else
{
email = messageParts[0];
return true;
}
}
/// <summary>
/// Helper function used to generate a token to be used in the message sent to users when registered the first time to confirm their email address.
/// </summary>
/// <param name="email">The email address to encode.</param>
/// <returns>The token generated from the email address, timestamp, and SEED value.</returns>
public static string GetTokenForValidation(string email)
{
if (String.IsNullOrEmpty(email))
throw new ArgumentException("The email cannot be null");
string token = Password.EncodeMessageWithPassword(String.Format("{0}#{1}", email, DateTime.Now), SEED);
return token;
}
/// <summary>
/// Validates whether a given token is valid for a determined email address.
/// </summary>
/// <param name="token">The token to validate.</param>
/// <param name="email">The email address to use in the validation.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
public static bool IsTokenValid(string token, string email)
{
return IsTokenValid(token, email, DateTime.Now);
}
/// <summary>
/// Core method to validate a token that also offers a timestamp for testing. In production mode should always be DateTime.Now.
/// </summary>
/// <param name="token">The token to validate.</param>
/// <param name="email">the email address to use in the validation.</param>
/// <param name="timestamp">The timestamp representing the time in which the validation is performed.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
public static bool IsTokenValid(string token, string email, DateTime timestamp)
{
if (String.IsNullOrEmpty(token))
throw new ArgumentException("The token cannot be null");
try
{
string message = Password.DecodeMessageWithPassword(token, SEED);
string[] messageParts = message.Split('#');
if (messageParts.Count() != 2)
{
return false;
// the token was not generated correctly.
}
else
{
string messageEmail = messageParts[0];
string messageDate = messageParts[1];
// If the emails are the same and the date in which the token was created is no longer than 5 days, then it is valid. Otherwise, it is not.
return (String.Compare(email, messageEmail, true) == 0 && timestamp.Subtract(DateTime.Parse(messageDate)).Days < 5);
}
}
catch (Exception)
{
// could not decrypt the message. The token has been tampered with.
return false;
}
}
And Finally here some code to encrypt, decript a token...
I have it in a Password class that is intended to be a helper.
/// EDIT:
Removed the two functions I referenced before and show the full helper class.
Here is the Password static class with all helper functions.
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Data;
using System.Resources;
namespace MySolution.Common.Util
{
/// <summary>
/// Implements some functions to support password manipulation or generation
/// </summary>
public class Password
{
/// <summary>
/// Takes a string and generates a hash value of 16 bytes.
/// </summary>
/// <param name="str">The string to be hashed</param>
/// <param name="passwordFormat">Selects the hashing algorithm used. Accepted values are "sha1" and "md5".</param>
/// <returns>A hex string of the hashed password.</returns>
public static string EncodeString(string str, string passwordFormat)
{
if (str == null)
return null;
ASCIIEncoding AE = new ASCIIEncoding();
byte[] result;
switch (passwordFormat)
{
case "sha1":
SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
result = sha1.ComputeHash(AE.GetBytes(str));
break;
case "md5":
MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
result = md5.ComputeHash(AE.GetBytes(str));
break;
default:
throw new ArgumentException("Invalid format value. Accepted values are 'sha1' and 'md5'.", "passwordFormat");
}
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString("x2"));
}
return sb.ToString();
}
/// <summary>
/// Takes a string and generates a hash value of 16 bytes. Uses "md5" by default.
/// </summary>
/// <param name="str">The string to be hashed</param>
/// <returns>A hex string of the hashed password.</returns>
public static string EncodeString(string str)
{
return EncodeString(str, "md5");
}
/// <summary>
/// Takes a string and generates a hash value of 16 bytes.
/// </summary>
/// <param name="str">The string to be hashed</param>
/// <param name="passwordFormat">Selects the hashing algorithm used. Accepted values are "sha1" and "md5".</param>
/// <returns>A string of the hashed password.</returns>
public static string EncodeBinary(byte[] buffer, string passwordFormat)
{
if (buffer == null)
return null;
byte[] result;
switch (passwordFormat)
{
case "sha1":
SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
result = sha1.ComputeHash(buffer);
break;
case "md5":
MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
result = md5.ComputeHash(buffer);
break;
default:
throw new ArgumentException("Invalid format value. Accepted values are 'sha1' and 'md5'.", "passwordFormat");
}
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString("x2"));
}
return sb.ToString();
}
/// <summary>
/// Encodes the buffer using the default cryptographic provider.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
public static string EncodeBinary(byte[] buffer)
{
return EncodeBinary(buffer, "md5");
}
/// <summary>
/// Creates a random alphanumeric password.
/// </summary>
/// <returns>A default length character string with the new password.</returns>
/// <remarks>The default length of the password is eight (8) characters.</remarks>
public static string CreateRandomPassword()
{
//Default length is 8 characters
return CreateRandomPassword(8);
}
/// <summary>
/// Creates a random alphanumeric password on dimension (Length).
/// </summary>
/// <param name="Length">The number of characters in the password</param>
/// <returns>The generated password</returns>
public static string CreateRandomPassword(int Length)
{
Random rnd = new Random(Convert.ToInt32(DateTime.Now.Millisecond)); //Creates the seed from the time
string Password="";
while (Password.Length < Length )
{
char newChar = Convert.ToChar((int)((122 - 48 + 1) * rnd.NextDouble() + 48));
if ((((int) newChar) >= ((int) 'A')) & (((int) newChar) <= ((int) 'Z')) | (((int) newChar) >= ((int) 'a')) & (((int) newChar) <= ((int) 'z')) | (((int) newChar) >= ((int) '0')) & (((int) newChar) <= ((int) '9')))
Password += newChar;
}
return Password;
}
/// <summary>
/// Takes a text message and encrypts it using a password as a key.
/// </summary>
/// <param name="plainMessage">A text to encrypt.</param>
/// <param name="password">The password to encrypt the message with.</param>
/// <returns>Encrypted string.</returns>
/// <remarks>This method uses TripleDES symmmectric encryption.</remarks>
public static string EncodeMessageWithPassword(string plainMessage, string password)
{
if (plainMessage == null)
throw new ArgumentNullException("encryptedMessage", "The message cannot be null");
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.IV = new byte[8];
//Creates the key based on the password and stores it in a byte array.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[0]);
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);
MemoryStream ms = new MemoryStream(plainMessage.Length * 2);
CryptoStream encStream = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
byte[] plainBytes = Encoding.UTF8.GetBytes(plainMessage);
encStream.Write(plainBytes, 0, plainBytes.Length);
encStream.FlushFinalBlock();
byte[] encryptedBytes = new byte[ms.Length];
ms.Position = 0;
ms.Read(encryptedBytes, 0, (int)ms.Length);
encStream.Close();
return Convert.ToBase64String(encryptedBytes);
}
/// <summary>
/// Takes an encrypted message using TripleDES and a password as a key and converts it to the original text message.
/// </summary>
/// <param name="encryptedMessage">The encrypted message to decode.</param>
/// <param name="password">The password to decode the message.</param>
/// <returns>The Decrypted message</returns>
/// <remarks>This method uses TripleDES symmmectric encryption.</remarks>
public static string DecodeMessageWithPassword(string encryptedMessage, string password)
{
if (encryptedMessage == null)
throw new ArgumentNullException("encryptedMessage", "The encrypted message cannot be null");
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.IV = new byte[8];
//Creates the key based on the password and stores it in a byte array.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[0]);
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, new byte[8]);
//This line protects the + signs that get replaced by spaces when the parameter is not urlencoded when sent.
encryptedMessage = encryptedMessage.Replace(" ", "+");
MemoryStream ms = new MemoryStream(encryptedMessage.Length * 2);
CryptoStream decStream = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
byte[] plainBytes;
try
{
byte[] encBytes = Convert.FromBase64String(Convert.ToString(encryptedMessage));
decStream.Write(encBytes, 0, encBytes.Length);
decStream.FlushFinalBlock();
plainBytes = new byte[ms.Length];
ms.Position = 0;
ms.Read(plainBytes, 0, (int)ms.Length);
decStream.Close();
}
catch(CryptographicException e)
{
throw new ApplicationException("Cannot decrypt message. Possibly, the password is wrong", e);
}
return Encoding.UTF8.GetString(plainBytes);
}
}
}
Set a Reset password GUID in user table. You may also use an expiration time. If user tried to reset password, update the field with a new GUID and datetime for expiration.
Send a link containing the link to reset password with the GUID.
A sample function like this can be created for that
GUID res = objPasswordResetService.resetPassword(Convert.ToInt64(objUserViewModel.UserID), restpasswordGuid, resetPasswordExpiryDateTime);
The value in res can be the GUID updated in DB. Send a link with this GUID. You can check the expiration time also. This is just an idea only
I've got an example of how to implement password recovery in a standard ASP.NET MVC application in my blog.
This blog post assumes that you already have the login process working (database and all) and that you only need to wire the password recovery process.
http://hectorcorrea.com/Blog/Password-Recovery-in-an-ASP.NET-MVC-Project
Answer to implement password reset in MVC2 application
public string ResetPassword(string userName)
{
MembershipUser user = _provider.GetUser(userName, false);
if (user.IsLockedOut)
user.UnlockUser();
user.Comment = null;
_provider.UpdateUser(user);
string newPassword = user.ResetPassword();
string friendlyPassword = GenerateNewPassword();
_provider.ChangePassword(userName, newPassword, friendlyPassword);
return friendlyPassword;
}
private string GenerateNewPassword()
{
string strPwdchar = "abcdefghijklmnopqrstuvwxyz0123456789##$ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string strPwd = "";
Random rnd = new Random();
for (int i = 0; i <= 8; i++)
{
int iRandom = rnd.Next(0, strPwdchar.Length - 1);
strPwd += strPwdchar.Substring(iRandom, 1);
}
return strPwd;
}
here the russian version password recovery
I'm trying to serve a txt file made from the database using an action. The action is the following:
public ActionResult ATxt()
{
var articulos = _articulosService.ObteTotsArticles();
return File(CatalegATxt.ATxt(articulos), "text/plain");
}
and the CatalegATxt class is:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using WebDibaelsaMVC.DTOs.Busqueda;
namespace WebDibaelsaMVC.TxtLib
{
public static class CatalegATxt
{
public static Stream ATxt(IEnumerable<ArticuloBusquedaDTO> articles)
{
var stream = new MemoryStream();
var streamWriter = new StreamWriter(stream, Encoding.UTF8);
foreach (ArticuloBusquedaDTO article in articles)
{
streamWriter.WriteLine(article.ToStringFix());
}
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
public static string ToStringFix(this ArticuloBusquedaDTO article)
{
string result = "";
result += article.CodigoArticulo.PadRight(10, ' ').Substring(0, 10);
result += article.EAN.Trim().PadLeft(13, '0').Substring(0, 13);
result += article.NombreArticulo.PadRight(100, ' ').Substring(0, 100);
result += article.Marca.PadRight(100, ' ').Substring(0, 100);
result += article.Familia.PadRight(50, ' ').Substring(0, 50);
result += article.PrecioCesion.ToStringFix();
result += article.PVP.ToStringFix();
return result;
}
private static string ToStringFix(this double numero)
{
var num = (int)Math.Round(numero * 100, 0);
string result = num.ToString().PadLeft(10, '0');
return result;
}
}
}
it just writes the file lines based on the stuff I got from the database. But when I look at the file it looks truncated. The file is about 8Mb. I also tried converting to byte[] before returning from ATxt with the same result.
Any idea?
Thanks,
Carles
Update: I also tried to serve XML from the same content and it also gets truncated. It doesn't get truncated on the data (I thought it might have been an EOF character in it) but it truncates in the middle of a label...
I was having the exact same problem. The text file would always be returned as truncated.
It crossed my mind that it might be a "flushing" problem, and indeed it was. The writer's buffer hasn't been flushed at the end of the operation - since there's no using block, or the Close() call - which would flush automatically.
You need to call:
streamWriter.Flush();
before MVC takes over the stream.
Here's how your method should look like:
public static Stream ATxt(IEnumerable<ArticuloBusquedaDTO> articles)
{
var stream = new MemoryStream();
var streamWriter = new StreamWriter(stream, Encoding.UTF8);
foreach (ArticuloBusquedaDTO article in articles)
{
streamWriter.WriteLine(article.ToStringFix());
}
// Flush the stream writer buffer
streamWriter.Flush();
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
Why are you using an ActionResult?
ASP.NET MVC 1 has a FileStreamResult for just what you are doing. It expects a Stream object, and returns it.
public FileStreamResult Test()
{
return new FileStreamResult(myMemoryStream, "text/plain");
}
Should work fine for what you want to do. No need to do any conversions.
In your case, just change your method to this:
public FileStreamResult ATxt()
{
var articulos = _articulosService.ObteTotsArticles();
return new FileStreamResult(CatalegATxt.ATxt(articulos), "text/plain");
}
You probably want to close the MemoryStream. It could be getting truncated because it expects more data still. Or to make things even simpler, try something like this:
public static byte[] ATxt(IEnumerable<ArticuloBusquedaDTO> articles)
{
using(var stream = new MemoryStream())
{
var streamWriter = new StreamWriter(stream, Encoding.UTF8);
foreach (ArticuloBusquedaDTO article in articles)
{
streamWriter.WriteLine(article.ToStringFix());
}
return stream.ToArray();
}
}