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加密方法了,接下来我们继续介绍对称和非对称算法(具体Demo可以参考这里)。

在实现对称加密算法之前,先让我们了解一下对称加密的过程,假设我们有一组数据要加密那么我们可以使用一个或一组密钥对数据进行加密解密,但存在一个问题对称加密算法的密钥长度不尽相同,如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中提供四种非对称加密算法(DSAECDiffieHellman, ECDsaRSA),它们都继承于抽象类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类,这样可以大大提高我们开发效率,而且它充分的利用多态性使得加密算法灵活性和维护性大大提高。

关于作者:

[作者]:JK_Rush从事.NET开发和热衷于开源高性能系统设计,通过博文交流和分享经验,欢迎转载,请保留原文地址,谢谢。
[出处]: http://www.cnblogs.com/rush/ 
[本文基于]: 署名-非商业性使用 3.0 许可协议发布,欢迎转载,演绎,但是必须保留本文的署名 JK_Rush (包含链接),且不得用于商业目的。如您有任何疑问或者授权方面的协商,请与我联系 。

.NET中的加密算法总结(自定义加密Helper类续)的更多相关文章

  1. 微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇

    在上一篇文章中, 我介绍了企业库Cryptographer模块的一些重要类,同时介绍了企业库Cryptographer模块为我们提供的扩展接口,今天我就要根据这些 接口来进行扩展开发,实现2个加密解密 ...

  2. drf框架中jwt认证,以及自定义jwt认证

    0909自我总结 drf框架中jwt 一.模块的安装 官方:http://getblimp.github.io/django-rest-framework-jwt/ 他是个第三方的开源项目 安装:pi ...

  3. 浅谈Shiro框架中的加密算法,以及校验

    在涉及到密码存储问题上,应该加密/生成密码摘要存储,而不是存储明文密码.为什么要加密:网络安全问题是一个很大的隐患,用户数据泄露事件层出不穷,比如12306账号泄露. Shiro提供了base64和1 ...

  4. 如果你的application.properties中还存在明文密码----加密Spring Boot中的application.properties

    1 概述 什么?都2020年了还在Spring Boot的配置文件中写明文密码? 虽然是小项目,明文也没人看. 明文简单快捷方便啊!!! 你看直接用户名root密码123456多么简单!!! ... ...

  5. nodejs中常用加密算法

    在常用的nodejs+express工程中,为了安全在登录及表单传输时,应该都需进行加密传输,目前个人常用到的加密方式有下列几种: 1.Hash算法加密: 创建一个nodejs文件hash.js,输入 ...

  6. MVC中使用HTML Helper类扩展HTML控件

    文章摘自:http://www.cnblogs.com/zhangziqiu/archive/2009/03/18/1415005.html MVC在view页面,经常需要用到很多封装好的HTML控件 ...

  7. https原理及其中所包含的对称加密、非对称加密、数字证书、数字签名

    声明:本文章已授权公众号Hollis转载,如需转载请标明转载自https://www.cnblogs.com/wutianqi/p/10654245.html(安静的boy) 一.为什么要使用http ...

  8. 关于对springboot程序配置文件使用jasypt开源工具自定义加密

    一.前言 在工作中遇到需要把配置文件加密的要求,很容易就在网上找到了开源插件 jasypt  (https://github.com/ulisesbocchio/jasypt-spring-boot# ...

  9. 单点登录(十五)-----实战-----cas4.2.x登录mongodb验证方式实现自定义加密

    我们在前一篇文章中实现了cas4.2.x登录使用mongodb验证方式. 单点登录(十三)-----实战-----cas4.2.X登录启用mongodb验证方式完整流程 也学习参考了cas5.0.x版 ...

随机推荐

  1. div居中的三种方法

    方法1: #div1{ width:200px; height:200px; background:green; position:absolute; left:0; top:0; right:0; ...

  2. Javascript中new

    // 加不加new结果都一样 var obj = new Function('var temp = 100;this.temp = 200;return temp + this.temp;'); al ...

  3. nodejs中package.json文件模块依赖的版本格式

    version 完全匹配 >version 大于这个版本 >=version大于或等于这个版本 <version 小于这个版本 <=version 小于等于这个版本 ~vers ...

  4. 一些实用的js高级技巧

    技巧一之setTimeout. 应用案例:比如你想一个函数循环执行10次,怎么办?以前通常是先setInterval,然后clearInterval,技巧一就是克服这个问题 (function () ...

  5. http协议与内容压缩

    为了加快网络上的传输的速度,可以将服务器传输的内容进行压缩,服务器的压缩方式有gzip压缩 deflate压缩 compress压缩 content-length:压缩后的长度 如何启动压缩功能 1, ...

  6. MVC (M-V-C启动程序调用关系)

    在网上有很多mvc程序启动,调用之间的关系与顺序.而且还有很多很不错的网站.推荐一个      http://www.cnblogs.com/QLeelulu/archive/2008/09/30/1 ...

  7. Linux中Oracle数据库备份还原

    一.备份Oracle数据库 1.使用数据库管理员账户登录 sqlplus system/system@orcl as sysdba; 2.创建备份目录,并指定备份目录(bak_dir)的物理路径 cr ...

  8. Objective-C 学习笔记(Day 2)

    ------------------------------------------- 如何根据题目准确完整清晰的声明一个类并实现给定的行为 /*  //下面这个程序教大家如何根据题目去声明一个类,并 ...

  9. bzoj2287:[POJ Challenge]消失之物

    思路:首先先背包预处理出f[x]表示所有物品背出体积为x的方案数.然后统计答案,利用dp. C[i][j]表示不用物品i,组成体积j的方案数. 转移公式:C[i][j]=f[j]-C[i][j-w[i ...

  10. jQuery.hhLRSlider 左右滚动图片插件

    /**  * jQuery.hhLRSlider 左右滚动图片插件  * User: huanhuan  * QQ: 651471385  * Email: th.wanghuan@gmail.com ...