如何创建“可升级”加密类

时间:2009-04-14 08:58:58

标签: c# asp.net security encryption

这个想法是生成实用程序类,因此每当这些人破解当前已知的最佳算法并且新的算法进入市场时,开发人员必须做的唯一想法是添加NewHighTechEncryptingAlgorithm_Encryptor类并更改全局应用程序设置NewHighTechEncryptingAlgorithm_As_String

这样就可以了     string myNewEncryptedString = Encryptor.Encrypt(StringToEncrypt,strAlgorithmName)

编辑:我删除了旧代码并粘贴了答案,由rwwilden提供了调用代码

我认为正确的措辞是“Enhashing”反对“加密”,因为这里没有盐...这似乎是根据提议的“规范”的最佳解决方案

 using System;
 using System.Text;
 using System.Security.Cryptography;

 namespace GenApp.Utils.Security
 {

 /// <summary>
 /// Summary description for Encrypter
 /// </summary>
 public class Encrypter 
 {
 /// <summary>
 /// Encrypts according to the passed plain name for hasing algorithm
 /// see CryptoConfig class from MSDN for more details
 /// </summary>
 /// <param name="strPlainTxt">the plain text to encrypt</param>
 /// <param name="strAlgorithmName">The plain name of the hashing algorithm </param>
 /// <returns> the encrypted string </returns>
 public static string Encrypt ( string strPlainTxt, string strAlgorithmName )
 {
  string strHashedTxt = String.Empty;
  byte[] bytPlain = System.Text.Encoding.UTF8.GetBytes ( strPlainTxt );


  using (HashAlgorithm objAlgorithm = HashAlgorithm.Create ( strAlgorithmName ))
  {
   byte[] bytHash = objAlgorithm.ComputeHash ( bytPlain );
   strHashedTxt = Convert.ToBase64String ( bytHash );
   return strHashedTxt; 
  } 

 } //eof method 


 ///// OLD CODE - REQUIRES RECODING 
 ///// <summary>
 ///// Encrypts according to the passed plain name for hasing algorithm
 ///// see CryptoConfig class from MSDN for more details
 ///// </summary>
 ///// <param name="strPlainTxt">the plain text to encrypt</param>
 ///// <param name="strAlgorithmName">The plain name of the hashing algorithm </param>
 ///// <returns> the encrypted string </returns>
 //public static string Encrypt ( string strPlainTxt, string strAlgorithmName )
 //{
 //  string strHashedTxt = String.Empty;
 //  byte[] bytPlains = System.Text.Encoding.UTF8.GetBytes ( strPlainTxt );
 //  byte[] bytHash;
 //  //CryptoConfig objCryptoConfig = new CryptoConfig ();


 //  switch (strAlgorithmName)
 //  {
 //    case "SHA1":
 //      SHA1CryptoServiceProvider objProvForSHA1alg =
 //        (SHA1CryptoServiceProvider)CryptoConfig.CreateFromName ( strAlgorithmName );


 //      bytHash = objProvForSHA1alg.ComputeHash ( bytPlains );
 //      objProvForSHA1alg.Clear ();
 //      strHashedTxt = Convert.ToBase64String ( bytHash );

 //      break;
 //    case "MD5" :

 //      MD5CryptoServiceProvider objProvForMD5alg =
 //        (MD5CryptoServiceProvider)CryptoConfig.CreateFromName ( strAlgorithmName );

 //      bytHash = objProvForMD5alg.ComputeHash ( bytPlains );
 //      strHashedTxt = Convert.ToBase64String ( bytHash );
 //      objProvForMD5alg.Clear ();


 //      break; 

 //  } //eof switch

 //  if (String.IsNullOrEmpty ( strHashedTxt ))
 //    throw new Exception ( "Encryption provider called by invalide simple name " );


 //  return strHashedTxt;
 //} //eof method 


 } //eof class 


 class Program
 {
 static void Main ( string[] args )
 {
  string strPlainTxt = "UnEncryptedText";
  string strAlgorithmName = "SHA1"; //the type of al
  string strHashedTxt = String.Empty;

  //START WITH ONE ALGORITHM
  Console.WriteLine ( "Using the " + strAlgorithmName + " START " );
  Console.WriteLine ( "The plain text is " + strPlainTxt );
  Console.WriteLine ( "The encrypting algorithm is " + strAlgorithmName );
  strHashedTxt = Encrypter.Encrypt ( strPlainTxt, strAlgorithmName );
  Console.WriteLine ( "The hashed text is " + strHashedTxt );
  Console.WriteLine ( "Using the " + strAlgorithmName + " END " );

  //NOW CHANGE THE ALGORITHM
  strAlgorithmName = "MD5";
  Console.WriteLine ( "Using the " + strAlgorithmName + " START " );
  Console.WriteLine ( "The plain text is " + strPlainTxt );
  Console.WriteLine ( "The encrypting algorithm is " + strAlgorithmName );
  strHashedTxt = Encrypter.Encrypt ( strPlainTxt, strAlgorithmName );
  Console.WriteLine ( "The hashed text is " + strHashedTxt );
  Console.WriteLine ( "Using the " + strAlgorithmName + " END " );


  strAlgorithmName = "SHA256";
  Console.WriteLine ( "Using the " + strAlgorithmName + " START " );
  Console.WriteLine ( "The plain text is " + strPlainTxt );
  Console.WriteLine ( "The encrypting algorithm is " + strAlgorithmName );
  strHashedTxt = Encrypter.Encrypt ( strPlainTxt, strAlgorithmName );
  Console.WriteLine ( "The hashed text is " + strHashedTxt );
  Console.WriteLine ( "Using the " + strAlgorithmName + " END " );


  Console.WriteLine ( "Hit enter to exit" );
  Console.ReadLine ();
 }

 }
 } //eof namespace 

3 个答案:

答案 0 :(得分:2)

你应该看一下CryptoConfig课程。特别是方法CreateFromName。它提供了一种基于名称(您在配置中提供)获取加密算法的方法。更改配置中的名称会自动更改使用的算法。

如果您已选择是使用对称加密还是非对称加密,则应使用更具体的SymmetricAlgorithm.Create(string)AsymmetricAlgorithm.Create(string)方法。

由于您需要散列解决方案,因此应使用HashAlgorithm.Create(string)。实现它的原因如下所示,当您决定使用其他哈希算法时,您不必更改任何代码。在您的代码中,您必须添加另一个case语句。

public static string Encrypt(string toEncrypt, string algorithmName)
{
    byte[] bytePlain = System.Text.Encoding.UTF8.GetBytes ( strPlainTxt );
    using (HashAlgorithm algorithm = HashAlgorithm.Create(algorithm))
    {
        byte[] byteHash = algorithm.ComputeHash(bytePlain);
        string strHashedTxt = Convert.ToBase64String (byteHash);
        return strHashedTxt;
    }
}

答案 1 :(得分:2)

我建议使用Resharper或Coderush的副本来修复编码器失明的问题。大括号突出显示在框中。

此外,这是经典或基本的接口+工厂模式。正如其他人所说,MEF和ICryptoTransform很可能是最干净的起点,因为框架为您提供,但如果您想了解基础知识:

制作界面:

public interface IEncrypter {
  string Encrypt(string plaintext);
}

然后实施它:

public class MD5Encrypter : IEncrypter {
  public string Encrypt(string plaintext) {
    //code goes here.
  }
}

public class SHA1Encrypter : IEncrypter {
  public string Encrypt(string plaintext) {
    //code goes here.
  }
}

然后,建立工厂:

public class EncryptionFactory {
  public static IEncrypter GetEncrypter() {
    //work out which one to return, maybe based on a config value?

    // I'm just going to return an MD5, but you'd want to use a switch statement etc
    // to decide which one to return.

    return new MD5Encrypter();
  }
}

并像这样使用它:

IEncrypter encrypter = EncryptionFactory.GetEncrypter();
string garbageText = encrypter.Encrypt("Hello, world");

你改变的只是工厂,或者更好的是,工厂读入的配置,使其使用其他东西。如果你真的想要的话,你可以把它放在一天中的时间:)你编写的使用接口的代码并不关心对象实际上是什么 - 它只关心它有一个:string Encrypt(string)方法。

MEF在某些方面为你做这件事。

使用接口还意味着你可以返回一个假的IEncrypter,它什么都不做,所以你可以针对它编写单元测试,而不需要实际进行加密。在这种情况下不是超级有用,但总的来说这是很好的做法。

另外,您可以在Factory中使用@rwwilden的建议来生成它 - 您从config读取一个字符串,并使用他正在讨论的Asymetric / Symetric创建方法来创建底层类.....

答案 2 :(得分:1)

//eof class//eof namespace垃圾箱有什么意义?

为了记录:你想要实现的基本上是一个有限的插件架构。请参阅MEF了解如何做到这一点。

顺便说一下,你知道ICryptoTransform吗?