详解.NET中的加密算法总结(自定义加密Helper类续)

1.1.1 摘要

相信许多人都使用过.NET提供的加密算法,而且在使用的过程我们必须了解每种加密算法的特点(对称或非对称,密钥长度和初始化向量等等)。我也看到过很多人写过.NET中加密算法总结,但我发现个别存在一些问题,很多人喜欢罗列每种加密算法的具体实现,假设我们要求实现AES和Triple DES加密算法,的确可以很多地分别给出它们的具体实现。

那我们真的有必要给出每个加密算法的具体实现吗?而且这样的设计不符合OOP设计思想,最重要的是我们要维护多个加密算法啊!OK接下来让我们实行一个可扩展和好维护的加密算法Helper。

1.1.2 正文

图1 Hash加密算法继承层次

从上面的继承层次我们可以知道.NET中提供七种Hash加密算法,它们都继承于抽象类HashAlgorithm,而且我们经常使用MD5,SHA1和SHA256等加密算法。下面我们将给出MD5和SHA1的实现。

图2 对称加密算法继承层次

从上面的继承层次我们可以知道.NET中提供五种对称加密算法,它们都继承于抽象类SymmetricAlgorithm,下面我们将给出它们的通用实现。

图3 非对称加密算法继承层次

从上面的继承层次我们可以知道.NET中提供四种非对称加密算法,它们都继承于抽象类AsymmetricAlgorithm,下面我们将给出RSA实现。

除了以上加密算法,.NET还提供了很多其他类型的加密,这里我们主要介绍一些常用的加密算法,如果大家需要了解的话可以查阅MSDN。OK接下来让我们给出Hash加密算法的实现吧。

Hash加密算法

在给出具体的算法实现之前,首先让我们回忆一下什么是Hash加密算法?

Hash加密是通过使用hash函数对要加密的信息进行加密,然后生成相应的哈希值,那么我们可以定义一个hash()函数,要加密的信息m和加密后的哈希值h。

我们对信息m1和m2进行hash加密,就可以获取相应哈希值hash(m1)和hash(m2)。

如果信息m1=m2那么,那么将得到同一的哈希地址,但是信息m1!=m2也可能得到同一哈希地址,那么就发生了哈希冲突(collision),在一般的情况下,哈希冲突只能尽可能地减少,而不能完全避免。当发生哈希冲突时,我们要使用冲突解决方法,而主要的冲突解决方法:开放地址法、再哈希法、链地址法和建立一个公共溢出区。

图4 Hash加密过程(图片来源wiki)

现在让我们来实现通用的hash加密方法。

 /// <summary>
/// Encrypts the specified hash algorithm.
/// 1. Generates a cryptographic Hash Key for the provided text data.
/// </summary>
/// <param name="hashAlgorithm">The hash algorithm.</param>
/// <param name="dataToHash">The data to hash.</param>
/// <returns></returns>
public static string Encrypt(HashAlgorithm hashAlgorithm, string dataToHash)
{

  var tabStringHex = new string[16];
  var UTF8 = new System.Text.UTF8Encoding();
  byte[] data = UTF8.GetBytes(dataToHash);
  byte[] result = hashAlgorithm.ComputeHash(data);
  var hexResult = new StringBuilder(result.Length);

  for (int i = 0; i < result.Length; i++)
  {
    //// Convert to hexadecimal
    hexResult.Append(result[i].ToString("X2"));
  }
  return hexResult.ToString();
}

上面的加密方法包含一个HashAlgorithm类型的参数,我们可以传递继承于抽象类HashAlgorithm的具体hash算法(MD5,SHA1和SHA256等),通过继承多态性我们使得加密方法更加灵活、简单,最重要的是现在我们只需维护一个通用的加密方法就OK了。

接着我们要添加判断加密后哈希值是否相等的方法,判断哈希值是否相等的方法IsHashMatch()方法。

 /// <summary>
/// Determines whether [is hash match] [the specified hash algorithm].
/// </summary>
/// <param name="hashAlgorithm">The hash algorithm.</param>
/// <param name="hashedText">The hashed text.</param>
/// <param name="unhashedText">The unhashed text.</param>
/// <returns>
///  <c>true</c> if [is hash match] [the specified hash algorithm];
/// otherwise, <c>false</c>.
/// </returns>
public static bool IsHashMatch(HashAlgorithm hashAlgorithm,
  string hashedText, string unhashedText)
{
  string hashedTextToCompare = Encrypt(
    hashAlgorithm, unhashedText);
  return (String.Compare(hashedText,
    hashedTextToCompare, false) == 0);
}

对称加密算法

现在我们完成了通用的Hash加密方法了,接下来我们继续介绍对称和非对称算法。

在实现对称加密算法之前,先让我们了解一下对称加密的过程,假设我们有一组数据要加密那么我们可以使用一个或一组密钥对数据进行加密解密,但存在一个问题对称加密算法的密钥长度不尽相同,如DES的密钥长度为64 bit,而AES的长度可以为128bit、192bit或256 bit,难道要我们hard code每种算法的密钥长度吗?能不能动态地产生对应算法的密钥呢?

其实.NET已经提供我们根据不同的对称算法生成对应密钥的方法了,并且把这些方法都封装在PasswordDeriveBytes和Rfc2898DeriveBytes类中。

首先让我们看一下PasswordDeriveBytes类包含两个方法CryptDeriveKey和GetBytes用来产生对应算法的密钥,现在让我们看一下它们如何产生密钥。

 CryptDeriveKey:

 // The sample function.
public void Encrypt()
{
  // The size of the IV property must be the same as the BlockSize property.
  // Due to the RC2 block size is 64 bytes, so iv size also is 64 bytes.
  var iv = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };

  var pdb = new PasswordDeriveBytes("pwd", null);

  // Set the encrypted algorithm and export key algorithm.
  // Then get the key base on encrypt algorithm.
  byte[] key = pdb.CryptDeriveKey("RC2", "SHA1", 128, iv);

  Console.WriteLine(key.Length * 8);
  Console.WriteLine(new RC2CryptoServiceProvider().BlockSize);
  // Creates an RC2 object to encrypt with the derived key
  var rc2 = new RC2CryptoServiceProvider
         {
           Key = key,
           IV = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28 }
         };

  // now encrypt with it
  byte[] plaintext = Encoding.UTF8.GetBytes("NeedToEncryptData");
  using (var ms = new MemoryStream())
  {
    var cs = new CryptoStream(
      ms, rc2.CreateEncryptor(), CryptoStreamMode.Write);

    cs.Write(plaintext, 0, plaintext.Length);
    cs.Close();
    byte[] encrypted = ms.ToArray();
  }
}

示意例子一:我们使用SHA1哈希算法为RC2加密算法生成128bit的密钥,这样我们就可以根据不同对称加密算法获取相应长度的密钥了,注意我们并没用动态地生成初始化向量iv,这是为了简单起见实际中不应该这样获取初始化向量。

接下来让我们看一下通过PBKDF1和PBKDF2s算法生成密钥的实现。

PBKDF1

GetBytes:PasswordDeriveBytes的GetBytes()方法实现了PBKDF1(Password Based Key Derivation Function)。

PBKDF1算法过程:

1.拼接密钥和盐:R0 = Pwd + Salt

2.哈希加密过程:R1 = Hash(R2-1)

……..

3.哈希加密过程:Rn = Hash(Rn - 1)

4.n是迭代的次数(参考PBKDF1规范请点这里)

现在我们对PBKDF1算法的原理有了初步的了解,接下来我们将通过GetBytes()调用该算法生成密钥。

/// <summary>
/// Uses the PBKDF1 to genernate key,
/// then use it to encrypt plain text.
/// </summary>
public void PBKDF1()
{
  byte[] salt = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };

  // Creates an RC2 object to encrypt with the derived key
  var pdb = new PasswordDeriveBytes("pwd", salt)
  {IterationCount = 23, HashName = "SHA1"};

  // Gets the key and iv.
  byte[] key = pdb.GetBytes(16);
  byte[] iv = pdb.GetBytes(8);

  var rc2 = new RC2CryptoServiceProvider { Key = key, IV = iv };

  byte[] plaintext = Encoding.UTF8.GetBytes("NeedToEncryptData");

  using (var ms = new MemoryStream())
  {
    // Encrypts data.
    var cs = new CryptoStream(
      ms, rc2.CreateEncryptor(), CryptoStreamMode.Write);

    cs.Write(plaintext, 0, plaintext.Length);
    cs.Close();
    byte[] encrypted = ms.ToArray();
  }

}

示意例子二:我们使用PBKDF1算法为RC2加密算法生成128 bit的密钥和64 bit的初始化向量,要注意的是PasswordDeriveBytes的GetBytes()方法已经过时了,而它的替代项就是接下来要介绍的Rfc2898DeriveBytes的GetBytes()方法。

 PBKDF2

GetBytes:由于Rfc2898DeriveBytes的GetBytes()方法实现了PBKDF2算法,而且它也替代了PBKDF1过时的GetBytes()方法,所以我们推荐使用Rfc2898DeriveBytes的GetBytes()方法。

 /// <summary>
/// Uses the PBKDF2 to genernate key,
/// then use it to encrypt plain text.
/// </summary>
public void PBKDF2()
{
  byte[] salt = new byte[] { 23, 21, 32, 33, 46, 59, 60, 74 };
  var rfc = new Rfc2898DeriveBytes("pwd", salt, 23);

  // generate key and iv.
  byte[] key = rfc.GetBytes(16);
  byte[] iv = rfc.GetBytes(8);

  // Creates an RC2 object to encrypt with the derived key
  var rc2 = new RC2CryptoServiceProvider { Key = key, IV = iv };

  // Encrypts the data.
  byte[] plaintext = Encoding.UTF8.GetBytes("NeedToEncryptData");
  using (var ms = new MemoryStream())
  {
    var cs = new CryptoStream(
      ms, rc2.CreateEncryptor(), CryptoStreamMode.Write);

    cs.Write(plaintext, 0, plaintext.Length);
    cs.Close();
    byte[] encrypted = ms.ToArray();
  }
}

示意例子三:我们发现PBKDF2()方法和之前的PBKDF1()方法没有什么区别,就是无需指定加密密钥的哈希算法(参考PBKDF2规范请点这里)。

前面通过三种方法来动态的生成加密密钥,而且我们将使用Rfc2898DeriveBytes的GetBytes()方法来获取密钥,那么接下来让我们使用该方法实现通用的对称加密算法吧!

图5 对称算法加密过程

首先我们对加密的平文进行编码,这里默认使用UTF8对平文进行编码,也可以使用其他编码方式,接着使用相应加密算法对编码后的平文进行加密,最后把加密后的Byte数组转换为Base64格式字符串返回。

/// <summary>
/// Encrypts with specified symmetric algorithm.
/// Can be Aes, DES, RC2, Rijndael and TripleDES.
/// </summary>
/// <param name="algorithm">The symmertric algorithm (Aes, DES, RC2, Rijndael and TripleDES).</param>
/// <param name="plainText">The plain text need to be encrypted.</param>
/// <param name="key">The secret key to encrypt plain text.</param>
/// <param name="iv">The iv should be 16 bytes.</param>
/// <param name="salt">Salt to encrypt with.</param>
/// <param name="pwdIterations">The number of iterations for plain text.</param>
/// <param name="keySize">Size of the key.</param>
/// <param name="cipherMode">The cipher mode.</param>
/// <param name="paddingMode">The padding mode.</param>
/// <returns></returns>
public static byte[] Encrypt(SymmetricAlgorithm algorithm, byte[] plainText, string key, string iv,
  string salt, int pwdIterations, int keySize, CipherMode cipherMode, PaddingMode paddingMode)
{

  if (null == plainText)
    throw new ArgumentNullException("plainText");
  if (null == algorithm)
    throw new ArgumentNullException("algorithm");
  if (String.IsNullOrEmpty(key))
    throw new ArgumentNullException("key");
  if (String.IsNullOrEmpty(iv))
    throw new ArgumentNullException("iv");
  if (String.IsNullOrEmpty(salt))
    throw new ArgumentNullException("salt");

  // Note the salt should be equal or greater that 64bit (8 byte).
  var rfc = new Rfc2898DeriveBytes(key, salt.ToByteArray(), pwdIterations);
  using (SymmetricAlgorithm symmAlgo = algorithm)
  {
    symmAlgo.Mode = cipherMode;
    //symmAlgo.Padding = paddingMode;
    byte[] cipherTextBytes = null;
    using (var encryptor = symmAlgo.CreateEncryptor(
      rfc.GetBytes(keySize / 8), iv.ToByteArray()))
    {
      using (var ms = new MemoryStream())
      {
        using (var cs = new CryptoStream(
          ms, encryptor, CryptoStreamMode.Write))
        {
          cs.Write(plainText, 0, plainText.Length);
          cs.FlushFinalBlock();
          cipherTextBytes = ms.ToArray();
          ms.Close();
          cs.Close();
        }
      }
      symmAlgo.Clear();
      return cipherTextBytes;
    }
  }
}

图5 对称算法解密过程

通过上图的解密过程,我们发现解密过程恰恰是加密的反向,首先把Base64格式的密文转换为Byte数组,接着使用对应的解密算法解密密文,最后对解密后的数据进行编码返回平文(默认使用UTF8)。

/// <summary>
/// Decrypts the specified algorithm.
/// Can be Aes, DES, RC2, Rijndael and TripleDES.
/// </summary>
/// <param name="algorithm">The symmertric algorithm (Aes, DES, RC2, Rijndael and TripleDES).</param>
/// <param name="cipherText">The cipher text.</param>
/// <param name="key">The secret key to decrypt plain text.</param>
/// <param name="iv">The iv should be 16 bytes.</param>
/// <param name="salt">Salt to decrypt with.</param>
/// <param name="pwdIterations">The number of iterations for plain text.</param>
/// <param name="keySize">Size of the key.</param>
/// <param name="cipherMode">The cipher mode.</param>
/// <param name="paddingMode">The padding mode.</param>
/// <returns></returns>
public static byte[] Decrypt(SymmetricAlgorithm algorithm, byte[] cipherText,
  string key, string iv, string salt, int pwdIterations, int keySize,
  CipherMode cipherMode, PaddingMode paddingMode)
{
  if (null == cipherText)
    throw new ArgumentNullException("cipherText");
  if (null == algorithm)
    throw new ArgumentNullException("algorithm");
  if (String.IsNullOrEmpty(key))
    throw new ArgumentNullException("key");
  if (String.IsNullOrEmpty(iv))
    throw new ArgumentNullException("iv");
  if (String.IsNullOrEmpty(salt))
    throw new ArgumentNullException("salt");

  // Note the salt should be equal or greater that 64bit (8 byte).
  var rfc = new Rfc2898DeriveBytes(key, salt.ToByteArray(), pwdIterations);

  using (SymmetricAlgorithm symmAlgo = algorithm)
  {
    symmAlgo.Mode = cipherMode;
    //symmAlgo.Padding = paddingMode;
    byte[] plainTextBytes = new byte[cipherText.Length];
    int cnt = -1;
    using (var encryptor = symmAlgo.CreateDecryptor(
      rfc.GetBytes(keySize / 8), iv.ToByteArray()))
    {
      using (var ms = new MemoryStream(cipherText))
      {
        using (var cs = new CryptoStream(
          ms, encryptor, CryptoStreamMode.Read))
        {
          cnt = cs.Read(plainTextBytes, 0, plainTextBytes.Length);
          ms.Close();
          cs.Close();

        }
      }
    }
    symmAlgo.Clear();
    Array.Resize(ref plainTextBytes, cnt);
    return plainTextBytes;
  }
}

在前面的加密和解密方法,我们通过Rfc2898DeriveBytes获取密码、salt 值和迭代次数,然后通过调用GetBytes方法生成密钥。

现在我们已经完成了通用的对称加密算法,我们只需一组加密和解密方法就可以随意的使用任意一种对称加密算法了,而不是为每个加密和解密算法编写相应的加密和解密方法。

 非对称加密算法

.NET Framework中提供四种非对称加密算法(DSA,ECDiffieHellman, ECDsa和RSA),它们都继承于抽象类AsymmetricAlgorithm,接下来我们将提供RSA算法的实现。

RSA加密算法是一种非对称和双钥加密算法,在公钥加密标准和电子商业中RSA被广泛使用。

在双钥加密的情况下,密钥有两把,一把是公开的公钥,还有一把是不公开的私钥。

双钥加密的原理如下:

a) 公钥和私钥是一一对应的关系,有一把公钥就必然有一把与之对应的、独一无二的私钥,反之亦成立。

b) 所有的(公钥, 私钥)对都是不同的。

c) 用公钥可以解开私钥加密的信息,反之亦成立。

d) 同时生成公钥和私钥应该相对比较容易,但是从公钥推算出私钥,应该是很困难或者是不可能的。

现在的数字签名加密主要是使用RSA算法,什么是数字签名大家请点这里(中文)和这里(英文)。

现在我们知道RSA算法是使用公钥和密钥进行加密和解密,所以我们先定义一个方法来生成公钥和密钥。

 /// <summary>
/// Generates the RSA public and private key.
/// </summary>
/// <param name="algorithm">The algorithm to creates key.</param>
/// <returns></returns>
public static void GenerateRSAKey(RSACryptoServiceProvider algorithm)
{
  // Contains public and private key.
  RSAPrivateKey = algorithm.ToXmlString(true);

  using (var streamWriter = new StreamWriter("PublicPrivateKey.xml"))
  {
    streamWriter.Write(RSAPrivateKey);
  }

  // Only contains public key.
  RSAPubicKey = algorithm.ToXmlString(false);
  using (var streamWriter = new StreamWriter("PublicOnlyKey.xml"))
  {
    streamWriter.Write(RSAPubicKey);
  }

}

通过RSACryptoServiceProvider的ToXmlString()方法我们生成了一对公钥和密钥,当参数为true 表示同时包含 RSA 公钥和私钥,反之表示仅包含公钥。

/// <summary>
/// Encrypts with the specified RSA algorithm.
/// </summary>
/// <param name="rsa">A RSA object.</param>
/// <param name="plainText">The plain text to decrypt.</param>
/// <param name="key">The key.</param>
/// <param name="encoding">The encoding.</param>
/// <returns></returns>
public static string Encrypt(RSACryptoServiceProvider rsa,
  string plainText, string key, Encoding encoding)
{
  if (null == rsa)
    throw new ArgumentNullException("rsa");
  if (String.IsNullOrEmpty(plainText))
    throw new ArgumentNullException("plainText");
  if (String.IsNullOrEmpty(key))
    throw new ArgumentNullException("key");
  if (null == encoding)
    throw new ArgumentNullException("encoding");

  string publicKey;

  // Reads public key.
  using (var streamReader = new StreamReader("PublicOnlyKey.xml"))
  {
    publicKey = streamReader.ReadToEnd();
  }
  rsa.FromXmlString(publicKey);
  byte[] cipherBytes = rsa.Encrypt(plainText.ToBytesEncoding(encoding), true);
  rsa.Clear();
  return cipherBytes.ToBase64String();
}

接着我们定义RSA的加密方法,首先我们从流中读取密钥和公钥,然后传递给FromXmlString()方法,最后对平文进行加密。

/// <summary>
/// Decrypts with the specified RSA algorithm.
/// </summary>
/// <param name="rsa">a RSA object.</param>
/// <param name="cipherText">The cipher text to encrypt.</param>
/// <param name="key">The key.</param>
/// <param name="encoding">The encoding.</param>
/// <returns></returns>
public static string Decrypt(RSACryptoServiceProvider rsa,
  string cipherText, string key, Encoding encoding)
{
  string privateKey;
  // Reads the private key.
  using (var streamReader = new StreamReader("PublicPrivateKey.xml"))
  {
    privateKey = streamReader.ReadToEnd();
  }

  rsa.FromXmlString(privateKey);
  byte[] plainBytes = rsa.Decrypt(cipherText.FromBase64String(), true);
  rsa.Clear();
  return plainBytes.FromByteToString(encoding);
}

参照加密方法我们很快的实现RSA的解密方法,同样我们从流中读取密钥,然后传递给FromXmlString()方法,最后对密文进行解密,注意调用的是RSA算法的Decrypt()方法,在使用胶水代码时千万别忘记修改了。

现在我们终于完成了通用的加密解密方法,接下来肯定是要测试一下这些方法的效果如何,这次我使用单元测试。

[TestMethod]
public void TestStart()
{
  try
  {
    string cipherText;
    string plainText;

    #region Hash Algo

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateHashAlgoMd5(), @"您们好(Hello everyone).");
    Assert.IsTrue(CryptographyUtils.IsHashMatch(
      CryptographyUtils.CreateHashAlgoMd5(),
      cipherText, @"您们好(Hello everyone)."));

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateHashAlgoSHA1(),
      @"您们好(Hello everyone).");
    Assert.IsTrue(CryptographyUtils.IsHashMatch(
      CryptographyUtils.CreateHashAlgoSHA1(),
      cipherText, @"您们好(Hello everyone)."));

    #endregion

    #region Asymm Algo

    CryptographyUtils.GenerateRSAKey(CryptographyUtils.CreateAsymmAlgoRSA());
    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateAsymmAlgoRSA(), @"%dk>JK.RusH", @"c579D-E>?$)_");
    plainText = CryptographyUtils.Decrypt(
      CryptographyUtils.CreateAsymmAlgoRSA(), cipherText, @"c579D-E>?$)_");
    Assert.AreEqual<string>(@"%dk>JK.RusH", plainText);

    #endregion

    #region Symm Algo

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateSymmAlgoAes(),
      "JK_huangJK_huangJK_huang黄钧航",
      "JK_huangJK_huang", 256);

    plainText = CryptographyUtils.Decrypt(
      CryptographyUtils.CreateSymmAlgoAes(),
    cipherText, "JK_huangJK_huang", 256);

    Assert.AreEqual<string>("JK_huangJK_huangJK_huang黄钧航",
      plainText);

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateSymmAlgoDES(),
    "JK_huangJK_huangJK_huang黄钧航",
    "JK_huangJK_huang", 64);

    plainText = CryptographyUtils.Decrypt(
      CryptographyUtils.CreateSymmAlgoDES(),
    cipherText, "JK_huangJK_huang", 64);

    Assert.AreEqual<string>("JK_huangJK_huangJK_huang黄钧航",
      plainText);

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateSymmAlgoRC2(),
      "JK_huangJK_huangJK_huang黄钧航",
      "JK_huangJK_huang", 128);

    plainText = CryptographyUtils.Decrypt(CryptographyUtils.CreateSymmAlgoRC2(),
    cipherText, "JK_huangJK_huang", 128);

    Assert.AreEqual<string>("JK_huangJK_huangJK_huang黄钧航", plainText);

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateSymmAlgoRijndael(),
      "JK_huangJK_huangJK_huang黄钧航",
      "JK_huangJK_huang", 256);

    plainText = CryptographyUtils.Decrypt(
      CryptographyUtils.CreateSymmAlgoRijndael(),
    cipherText, "JK_huangJK_huang", 256);

    Assert.AreEqual<string>("JK_huangJK_huangJK_huang黄钧航", plainText);

    cipherText = CryptographyUtils.Encrypt(
      CryptographyUtils.CreateSymmAlgoTripleDes(),
      "JK_huangJK_huangJK_huang黄钧航",
      "JK_huangJK_huang", 192);

    plainText = CryptographyUtils.Decrypt(
      CryptographyUtils.CreateSymmAlgoTripleDes(),
    cipherText, "JK_huangJK_huang", 192);

    Assert.AreEqual<string>("JK_huangJK_huangJK_huang黄钧航", plainText);

    #endregion
  }
  catch (Exception ex)
  {
    Debug.Assert(false, ex.Message);
  }
}

图6 单元测试结果

1.1.3 总结

本文给出了.NET中的一些加密算法的通用实现(哈希加密,对称加密和非对称加密算法),由于加密和解密的方法都是比较固定,而且每中算法有具有其特性,所以这里我们给出了它们的实现,而且我们可以把上的方法封装在一个加密Helper类,这样可以大大提高我们开发效率,而且它充分的利用多态性使得加密算法灵活性和维护性大大提高。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • asp.net下常用的加密算法MD5、SHA-1应用代码

    MD5 MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2.MD3和MD4发展而来.是一种不可逆的加密算法,目前是最牢靠的加密算法之一,尚没有能够逆运算的程序被开发出来,它对应任何字符串都可以加密成一段唯一的固定长度的代码. 特性: 首先,它不可逆,没有系统的方法可以知道MD5码原来

  • 详解.NET中的加密算法总结(自定义加密Helper类续)

    1.1.1 摘要 相信许多人都使用过.NET提供的加密算法,而且在使用的过程我们必须了解每种加密算法的特点(对称或非对称,密钥长度和初始化向量等等).我也看到过很多人写过.NET中加密算法总结,但我发现个别存在一些问题,很多人喜欢罗列每种加密算法的具体实现,假设我们要求实现AES和Triple DES加密算法,的确可以很多地分别给出它们的具体实现. 那我们真的有必要给出每个加密算法的具体实现吗?而且这样的设计不符合OOP设计思想,最重要的是我们要维护多个加密算法啊!OK接下来让我们实行一个可扩展

  • 详解AngularJS中$filter过滤器使用(自定义过滤器)

    1.内置过滤器 * $filter 过滤器,是angularJs中用来处理数据以更好的方式展示给我用户.比如格式化日期,转换大小写等等. * 过滤器即有内置过滤器也支持自定义过滤器.内置过滤器很多,可以百度.关键是如何使用: * 1.在HTML中直接使用内置过滤器 * 2.在js代码中使用内置过滤器 * 3.自定义过滤器 * * (1)常用内置过滤器 * number 数字过滤器,可以设置保留数字小数点后几位等 * date 时间格式化过滤器,可自己设置时间格式 * filter 过滤的数据一般

  • 详解 Android中Libgdx使用ShapeRenderer自定义Actor解决无法接收到Touch事件的问题

    详解 Android中Libgdx使用ShapeRenderer自定义Actor解决无法接收到Touch事件的问题 今天在项目中实现了一个效果,主要是画一个圆.为了后续使用方便,将这个圆封装在一个自定义Actor(CircleActot)中,后续想显示一个圆的时候,只要创建一个CircleActor中即可. 部分代码如下所示: package com.ef.smallstar.unitmap.widget; import android.content.res.Resources; import

  • 详解ios中的SQL数据库文件加密 (使用sqlcipher)

    今天本想写一片 GAE+goAgent+SwitchySharp 的指南的!但是突然翻出了前段时间写的关于iOS中的SQL数据库文件加密的代码,于是乎决定今天就先讲讲这个!- 那么goAgent将放在周末,后续的文章中除了文件加密,还有传输数据加密,感兴趣的童鞋 敬请留意. 言归正传,sql的文件加密,我们首先要用到一个库,它就是大名鼎鼎的Sqlcipher,  奉上连接:http://sqlcipher.NET,在ios里 我们需要看的文档是这一篇http://sqlcipher.Net/io

  • 详解Java中格式化日期的DateFormat与SimpleDateFormat类

    DateFormat 1. DateFormat 介绍 DateFormat 的作用是 格式化并解析"日期/时间".实际上,它是Date的格式化工具,它能帮助我们格式化Date,进而将Date转换成我们想要的String字符串供我们使用 不过DateFormat的格式化Date的功能有限,没有SimpleDateFormat强大:但DateFormat是SimpleDateFormat的父类.所以,我们先对DateFormat有个整体了解,然后再学习SimpleDateFormat.

  • 详解Vue中的自定义指令

    除了默认设置的核心指令( v-model 和 v-show ),Vue 也允许注册自定义指令.在Vue里,代码复用的主要形式和抽象是组件.然而,有的情况下,仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令.本文将详细介绍Vue自定义指令 指令注册 以一个input元素自动获得焦点为例,当页面加载时,使用autofocus可以让元素将获得焦点 .但是autofocus在移动版Safari上不工作.现在注册一个使元素自动获取焦点的指令 指令注册类似于组件注册,包括全局指令和局部指令两

  • 详解Python中的自定义密码验证

    目录 在测试:nut_and_bolt:️之前 试验contains_character TestContainsCharacter字符 试验is_valid_size TestIsValidSize 试验is_valid_password TestIsValidPassword 重构is_valid_password 结论 这些帖子将分为三个部分. 1.密码验证功能 2.重构密码验证函数 3.对密码验证功能进行单元测试 这是Python系列中自定义密码验证的第三部分,也是最后一部分.我们将看看

  • 详解SpringBoot中自定义和配置拦截器的方法

    目录 1.SpringBoot版本 2.什么是拦截器 3.工作原理 4.拦截器的工作流程 4.1正常流程 4.2中断流程 5.应用场景 6.如何自定义一个拦截器 7.如何使其在Spring Boot中生效 8.实际使用 8.1场景模拟 8.2思路 8.3实现过程 8.4效果体验 9.总结 1.SpringBoot版本 本文基于的Spring Boot的版本是2.6.7 . 2.什么是拦截器 Spring MVC中的拦截器(Interceptor)类似于ServLet中的过滤器(Filter),它

  • 详解Java中自定义注解的使用

    目录 什么是注解 注解的注意事项 注解的本质 自定义注解使用 使用方式 1 使用方式 2 什么是注解 在早期的工作的时候 ,自定义注解写的比较多,可大多都只是因为 这样看起来 不会存在一堆代码耦合在一起的情况,所以使用了自定义注解,这样看起来清晰些, Annontation是Java5开始引入的新特征,中文名称叫注解. 它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类.方法.成员变量等)进行关联.为程序的元素(类.方法.成员变量)加上更直观.更明了的说

  • 详解Java中Collections.sort排序

    Comparator是个接口,可重写compare()及equals()这两个方法,用于比价功能:如果是null的话,就是使用元素的默认顺序,如a,b,c,d,e,f,g,就是a,b,c,d,e,f,g这样,当然数字也是这样的. compare(a,b)方法:根据第一个参数小于.等于或大于第二个参数分别返回负整数.零或正整数. equals(obj)方法:仅当指定的对象也是一个 Comparator,并且强行实施与此 Comparator 相同的排序时才返回 true. Collections.

随机推荐