Click here to Skip to main content
15,881,898 members
Articles / Programming Languages / C#

LumiSoft MailServer

Rate me:
Please Sign up or sign in to vote.
3.79/5 (22 votes)
17 Nov 2006CPOL1 min read 320.1K   4.9K   74  
Full featured SMTP/POP3/IMAP server
using System;
using System.Text;
using System.Security.Cryptography;

namespace LumiSoft.Net.AUTH
{
	/// <summary>
	/// Provides helper methods for authentications(APOP,CRAM-MD5,DIGEST-MD5).
	/// </summary>
	public class AuthHelper
	{
		#region method Apop

		/// <summary>
		/// Calculates APOP authentication compare value.
		/// </summary>
		/// <param name="password">Password.</param>
		/// <param name="passwordTag">Password tag.</param>
		/// <returns>Returns value what must be used for comparing passwords.</returns>
		public static string Apop(string password,string passwordTag)
		{
			/* RFC 1939 7. APOP
			 *
			 * value = Hex(Md5(passwordTag + password))
			*/

			return Hex(Md5(passwordTag + password));
		}

		#endregion


		#region method Cram_Md5

		/// <summary>
		/// Calculates CRAM-MD5 authentication compare value.
		/// </summary>
		/// <param name="password">Password.</param>
		/// <param name="hashKey">Hash calculation key</param>
		/// <returns>Returns value what must be used for comparing passwords.</returns>
		public static string Cram_Md5(string password,string hashKey)
		{
			/* RFC 2195 AUTH CRAM-MD5
			 * 
			 * value = Hex(HmacMd5(hashKey,password))
			*/
		
			return Hex(HmacMd5(hashKey,password));
		}

		#endregion


		#region method Digest_Md5

		/// <summary>
		/// Calculates DIGEST-MD5 authentication compare value.
		/// </summary>
		/// <param name="client_server">Specifies if client or server value calculated. 
		/// Client and server has diffrent calculation method.</param>
		/// <param name="realm">Use domain or machine name for this.</param>
		/// <param name="userName">User name.</param>
		/// <param name="password">Password.</param>
		/// <param name="nonce">Server password tag.</param>
		/// <param name="cnonce">Client password tag.</param>
		/// <param name="digest_uri"></param>
		/// <returns>Returns value what must be used for comparing passwords.</returns>
		public static string Digest_Md5(bool client_server,string realm,string userName,string password,string nonce,string cnonce,string digest_uri)
		{
			/* RFC 2831 AUTH DIGEST-MD5
			 * 
			 * qop = "auth";      // We support auth only auth-int and auth-conf isn't supported
			 * nc  = "00000001"
			 * 
			 * A1 = Md5(userName + ":" + realm + ":" + passw) + ":" + nonce + ":" + cnonce
			 * A2(client response) = "AUTHENTICATE:" + digest_uri
			 * A2(server response) = ":" + digest_uri
			 * 
			 * resp-value = Hex(Md5(Hex(Md5(a1)) + ":" + (nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + Hex(Md5(a2)))));
			*/

			//	string realm      = "elwood.innosoft.com";
			//	string userName   = "chris";			
			//	string passw      = "secret";
			//	string nonce      = "OA6MG9tEQGm2hh";
			//	string cnonce     = "OA6MHXh6VqTrRk";
			//	string digest_uri = "imap/elwood.innosoft.com";

			string qop = "auth";
			string nc  = "00000001";

			string a1 = Md5(userName + ":" + realm + ":" + password) + ":" + nonce + ":" + cnonce;
			string a2 = "";
			if(client_server){
				a2 = "AUTHENTICATE:" + digest_uri;
			}
			else{
				a2 = ":" + digest_uri;
			}

			return Hex(Md5(Hex(Md5(a1)) + ":" + (nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + Hex(Md5(a2)))));
		}

		#endregion

		#region method Create_Digest_Md5_ServerResponse

		/// <summary>
		/// Creates AUTH Digest-md5 server response what server must send to client.
		/// </summary>
		/// <param name="realm">Use domain or machine name for this.</param>
		/// <param name="nonce">Server password tag. Random hex string is suggested.</param>
		/// <returns></returns>
		public static string Create_Digest_Md5_ServerResponse(string realm,string nonce)
		{
			return "realm=\"" + realm + "\",nonce=\"" + nonce + "\",qop=\"auth\",algorithm=md5-sess";
		}

		#endregion

		#region method GenerateNonce

		/// <summary>
		/// Generates random nonce value.
		/// </summary>
		/// <returns></returns>
		public static string GenerateNonce()
		{
			return Guid.NewGuid().ToString().Replace("-","").Substring(0,16);
		}

		#endregion


		#region method HmacMd5

		/// <summary>
		/// Calculates keyed md5 hash from specifieed text and with specified hash key.
		/// </summary>
		/// <param name="hashKey"></param>
		/// <param name="text"></param>
		/// <returns></returns>
		public static string HmacMd5(string hashKey,string text)
		{
			HMACMD5 kMd5 = new HMACMD5(Encoding.Default.GetBytes(text));			
			return Encoding.Default.GetString(kMd5.ComputeHash(Encoding.ASCII.GetBytes(hashKey)));
		}

		#endregion

		#region method Md5

		/// <summary>
		/// Calculates md5 hash from specified string.
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns>
		public static string Md5(string text)
		{
			MD5 md5 = new MD5CryptoServiceProvider();			
			byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(text));

			return System.Text.Encoding.Default.GetString(hash);
		}

		#endregion

		#region method Hex

		/// <summary>
		/// Converts specified string to hexa string.
		/// </summary>
		/// <param name="text"></param>
		/// <returns></returns> 
		public static string Hex(string text)
		{
			return BitConverter.ToString(Encoding.Default.GetBytes(text)).ToLower().Replace("-","");
		}

		#endregion

		#region method Base64en

		/// <summary>
		/// Encodes specified string to base64 string.
		/// </summary>
		/// <param name="text">Text to encode.</param>
		/// <returns>Returns encoded string.</returns>
		public static string Base64en(string text)
		{
			return Convert.ToBase64String(Encoding.Default.GetBytes(text));
		}

		#endregion

		#region method Base64de

		/// <summary>
		/// Decodes specified base64 string.
		/// </summary>
		/// <param name="text">Base64 string to decode.</param>
		/// <returns>Returns decoded string.</returns>
		public static string Base64de(string text)
		{
			return Encoding.Default.GetString(Convert.FromBase64String(text));
		}

		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Estonia Estonia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions