65.9K
CodeProject 正在变化。 阅读更多。
Home

FIPS 加密算法以及 C# 和 SQL Server 2008 中 AES 的实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (8投票s)

2013年10月2日

CPOL

6分钟阅读

viewsIcon

44943

C# 和 SQL Server 2008 中的 AES 实现。

FIPS 加密算法详解

FIPS PUB 140-2 附录

附录 A:批准的安全功能(草案 2011-01-04)

  1. 对称密钥
    1. 高级加密标准 (AES)
    2. 三重 DES 加密算法 (TDEA)
    3. 密钥托管加密标准 (EES)
  2. 非对称密钥 (DSS – DSA, RSA 和 ECDSA)
    1. 数字签名标准 (DSS)
  3. 安全散列标准 (SHS)
    1. 安全散列标准 (SHS) (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224 和 SHA-512/256)
  4. 随机数生成器 (RNG 和 DRBG)
    1. 附录 C:批准的随机数生成器
  5. 消息认证 (三重 DES, AES 和 SHS)
    1. 三重 DES
    2. AES
    3. SHS

附录 B:批准的保护配置文件(草案 2007-06-14)

附录 B 提供了适用于 FIPS PUB 140-2 的批准保护配置文件的列表。

附录 C:批准的随机数生成器(草案 2010-11-22)

  1. 确定性随机数生成器
  2. 非确定性随机数生成器

附录 D:批准的密钥建立技术(草案 2011-01-04)

  1. 密钥建立技术

消息认证 (三重 DES 和 AES)

高级加密标准 (AES) 和三重 DES (TDES 或 3DES) 是常用的分组密码。您选择 AES 还是 3DES 取决于您的需求。

三重 DES

由于 3DES 基于 DES 算法,我们先讨论 DES。DES 于 1977 年开发,经过精心设计,以便在硬件中比在软件中表现更好。DES 在其 16 个轮次的置换和替换框中执行大量位操作。例如,在硬件中交换位 30 和位 16 比在软件中简单得多。DES 以 64 位分组大小加密数据,并使用有效 56 位的密钥。56 位密钥空间约有 7.2 亿亿种可能性。尽管看起来很大,但根据当今的计算能力,它并不足够,容易受到暴力破解攻击。因此,DES 无法跟上技术进步的步伐,不再适合安全。

由于当时 DES 被广泛使用,快速解决方案是引入 3DES,它足以满足当今大多数用途。3DES 是按顺序应用三次 DES 的结构。使用三个不同密钥(K1、K2 和 K3)的 3DES 有效密钥长度为 168 位(推荐使用三个不同的密钥进行 3DES)。另一种变体称为双密钥(K1 和 K3 相同)的 3DES 将有效密钥大小减至 112 位,安全性较低。双密钥 3DES 在电子支付行业中被广泛使用。3DES 比其前身需要三倍的 CPU 功耗,这是性能上的显着损失。

AES

Rijndael 算法已被选为高级加密标准 (AES),以取代 3DES。AES 是 Rijndael 算法的修改版本。高级加密标准评估标准包括:

  • 安全
  • 软件和硬件性能
  • 在受限空间环境中的适用性
  • 抗电力分析和其他实现攻击的能力

Rijndael 由 Joan Daemen 和 Vincent Rijmen 提交。综合来看,Rijndael 在安全性、性能、效率、可实现性和灵活性方面的结合使其成为 AES 的合适选择。

AES 在设计上速度更快,软件运行效率高,硬件运行效率高。它在智能手机、智能卡等小型设备上也能快速运行。AES 提供更高的安全性,因为其分组大小更大,密钥更长。AES 使用 128 位固定分组大小,并支持 128、192 和 256 位密钥。Rijndael 算法本身足够灵活,可以处理任何 32 位倍数的密钥和分组大小,最小为 128 位,最大为 256 位。

 

三重 DES

AES

描述

三重数据加密标准

高级加密标准

Timeline

标准化于 1977 年

自 2001 年起成为官方标准

算法类型

对称

对称

密钥大小(以位为单位)

168

192

速度

低功耗

破解所需时间(假设一台机器每秒可尝试 255 个密钥 - NIST)

46 亿年

149 万亿年

资源消耗

媒体

低功耗

使用 C# .NET 4.5 实现 AES

using System;
using System.IO;
using System.Security.Cryptography;
namespace Aes_Example
{
    class AesExample
    {
        public static void Main()
        {
            try
            {
                string original = "Here is some data to encrypt!";
                // Create a new instance of the AesCryptoServiceProvider 
                // class.  This generates a new key and initialization  
                // vector (IV). 
                using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
                {
                    // Encrypt the string to an array of bytes. 
                    byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
                    // Decrypt the bytes to a string. 
                    string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
                    //Display the original data and the decrypted data.
                    Console.WriteLine("Original:   {0}", original);
                    Console.WriteLine("Round Trip: {0}", roundtrip);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }
        }
        static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");
            byte[] encrypted;
            // Create an AesCryptoServiceProvider object 
            // with the specified key and IV. 
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                // Create the streams used for encryption. 
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = 
                            new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            // Return the encrypted bytes from the memory stream. 
            return encrypted;
        }
        static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            // Declare the string used to hold 
            // the decrypted text. 
            string plaintext = null;
            // Create an AesCryptoServiceProvider object 
            // with the specified key and IV. 
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                // Create the streams used for decryption. 
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = 
                            new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            // Read the decrypted bytes from the decrypting stream 
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            return plaintext;
        }
    }
}

SQL Server 2008R2 中的 AES 实现

步骤 1:创建主密钥

SQL Server 中的数据库级别加密功能依赖于数据库主密钥。每个数据库只能有一个主密钥,并且必须由管理员手动创建,因为它在安装过程中不会自动创建。

数据库主密钥是一个对称密钥,用于保护数据库中的证书和非对称密钥的私钥。

默认情况下,主密钥使用三重 DES 算法和一个用户提供的密码进行加密。可以通过使用 `ALTER MASTER KEY` 的 `DROP ENCRYPTION BY SERVICE MASTER KEY` 选项来更改此默认值。未由服务主密钥加密的主密钥必须使用 `OPEN MASTER KEY` 语句和密码打开。

CREATE MASTER KEY ENCRYPTION 
BY PASSWORD = '23987hxJ#KL95234Chinna';

PASSWORD --> 指定用于加密或解密数据库主密钥的密码。密码必须符合运行 SQL Server 实例的计算机的 Windows 密码策略要求。

示例:在创建主密钥之前,请使用以下查询检查它是否已创建。

SELECT * FROM sys.symmetric_keys 
--WHERE symmetric_key_id = 101
GO
-- PASSWORD should meet the SQL Server BOX OS
-- Password policy
CREATE MASTER KEY ENCRYPTION
BY PASSWORD ='Password!2'
GO

步骤 2:创建证书

证书是符合 X.509 标准的数据库级别安全对象。

`CREATE CERTIFICATE` 还可以从文件或程序集中加载证书。此语句还可以生成密钥对并创建自签名证书。SQL Server 生成的私钥长度为 1024 位。从外部源导入的私钥长度最短为 384 位,最长为 3456 位。导入的私钥长度必须是 64 位的整数倍。

CREATE CERTIFICATE Certificate_Password
ENCRYPTION BY PASSWORD = 'Password!2'
WITH SUBJECT = 'Password protection',
EXPIRY_DATE = '12/31/2099'
GO

执行并检查证书创建

SELECT * FROM sys.certificates
GO

步骤 3:创建对称密钥

对称密钥必须使用以下一项或多项密钥进行加密。它们是证书、密码、对称密钥、非对称密钥或提供程序。

当对称密钥使用密码而不是数据库主密钥的公钥加密时,将使用 TRIPLE DES 加密算法。因此,使用 AES 等强加密算法创建的密钥本身由较弱的算法保护。创建对称密钥的选项还有很多,但我在这里只展示一种简单的方法。

CREATE SYMMETRIC KEY System_password
WITH ALGORITHM = AES_256
ENCRYPTION BY CERTIFICATE Certificate_Password;
GO

检查数据库是如何创建的

SELECT * FROM sys.symmetric_keys
--WHERE symmetric_key_id = 256
GO

步骤 4:加密数据

现在是时候加密一些测试数据并查看其工作原理了。要加密数据,我们首先必须打开对称密钥,然后使用证书加密数据。请确保关闭对称密钥。

如果证书是用密码创建的,那么我们将需要使用密码来打开证书。

OPEN SYMMETRIC KEY System_password
      DECRYPTION BY CERTIFICATE Certificate_Password WITH PASSWORD = 'Password!2';
            INSERT INTO UserDetails1 (Username, Password, FirstName, LastName)
            VALUES ('dnyaneshwarp',ENCRYPTBYKEY(KEY_GUID(N'System_password'), 
            'dnyaneshwarp@gmail.com'), 'Dnyaneshwar', 'Pawar')
CLOSE SYMMETRIC KEY System_password;
GO

步骤 5:解密数据

现在我们看看如何将相同的数据解密回文本。要解密数据,我们首先必须打开对称密钥,然后使用证书加密数据。请确保关闭对称密钥。

如果证书是用密码创建的,那么我们将需要使用密码来打开证书。

OPEN SYMMETRIC KEY System_password
DECRYPTION BY CERTIFICATE Certificate_Password WITH PASSWORD = 'Password!2';
      SELECT USERID, USERNAME, CAST(DECRYPTBYKEY([Password]) as varchar(200)) AS Password,
               FIRSTNAME, LASTNAME
      FROM UserDetails1
CLOSE SYMMETRIC KEY System_password;
GO

© . All rights reserved.