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






4.95/5 (8投票s)
C# 和 SQL Server 2008 中的 AES 实现。
FIPS 加密算法详解
FIPS PUB 140-2 附录
附录 A:批准的安全功能(草案 2011-01-04)
- 对称密钥
- 高级加密标准 (AES)
- 三重 DES 加密算法 (TDEA)
- 密钥托管加密标准 (EES)
- 非对称密钥 (DSS – DSA, RSA 和 ECDSA)
- 数字签名标准 (DSS)
- 安全散列标准 (SHS)
- 安全散列标准 (SHS) (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224 和 SHA-512/256)
- 随机数生成器 (RNG 和 DRBG)
- 附录 C:批准的随机数生成器
- 消息认证 (三重 DES, AES 和 SHS)
- 三重 DES
- AES
- SHS
附录 B:批准的保护配置文件(草案 2007-06-14)
附录 B 提供了适用于 FIPS PUB 140-2 的批准保护配置文件的列表。
附录 C:批准的随机数生成器(草案 2010-11-22)
- 确定性随机数生成器
- 非确定性随机数生成器
附录 D:批准的密钥建立技术(草案 2011-01-04)
- 密钥建立技术
消息认证 (三重 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