无论c#加密还是sql语句加密,sql和c#都可以解秘,实现方法是采用数字证书方法.实现加密传输
感谢本文章作者
http://www.itstrike.cn/Question/acdd965a-c6d9-43ce-ad0d-af1484455671.html
感谢一个英文翻译后让中国人和外国人都看不懂的百度翻译.
我将该文章的方法及遇到的问题,做一个详细说明,本人技术有限,有错误的地方欢迎指正,废话不多说,进入正题.
因业务需要,c#对字符串加密后存入数据库,sql语句(sql2008数据库)需要解密.我选择使用数字证书加密,数字证书采用RSA加密算法进行加密,有公钥和私钥,公钥加密,私钥解密
一:创建自己的数字证书
(也可以购买被认可的数字证书)
需要使用的软件makecert.exe和pvk2pfx.exe(百度一搜一大片)
打开windows命令处理程序(dos命令)
C:\Users>j:
进入存放软件的目录下
然后运行一下命令”makecert -sv PrivateKey.pvk -n “cn=TestCertificate” TestCertificate.cer -b 01/01/2013 -e 01/01/2024 -sky Exchange”创建一个证书,生成的证书位置和你软件的位置一样
J:>makecert -sv PrivateKey.pvk -n “cn=TestCertificate” TestCertificate.cer -b 01/01/2013 -e 01/01/2024 -sky Exchange
注意:如果提示makecert不是内部或外部命令,也不是可运行的程序或批处理文件,遇到这种问题请用”管理员身份”打开dos,如果还是报错请查看该目录下软件名是否正确
选择”无”
出现succeeded代表创建成功以上创建两个文件PrivateKey.pvk(这个是私钥文件)和TestCertificate.cer(数字证书文件),这两个文件需要数据库使用
dos命令输入”pvk2pfx -pvk PrivateKey.pvk -spc TestCertificate.cer -po TestEncryption123”
这个命令是创建pfx文件,这个文件是c#程序使用的,加密解密都需要这个文件
点击”下一步”
选择”是,导出私钥”,点击”下一步”
选择
• 如果可能,将所有证书都包括证书路径中
• 导出所有的 extendend 属性
点击”下一步”
设置密码,这个密码在代码打开数字证书时使用,下一步
下一步
完成
现在创建成功
下面打开数据库
USE master
GO
–创建数据库
CREATE DATABASE TestEncryptionDecryption
GO
USE TestEncryptionDecryption
–创建表
CREATE TABLE Encrypt
(
intCol int,
clearTextCol varchar(128)
)
GO
–向表里插入数据
INSERT INTO Encrypt (intCol, clearTextCol)
VALUES
(‘1’, ‘Links’),
(‘2’, ‘Zwo’),
(‘3’, ‘Drei’),
(‘4’, ‘Vier’),
(‘5’, ‘Fünf’),
(‘6’, ‘5ech5’)
GO
–导入证书,这个证书就是上面创建的TestCertificate.cer和PrivateKey.pvk文件
CREATE CERTIFICATE TestCertificate
FROM FILE = ‘C:\temp\createCert\TestCertificate.cer’
WITH PRIVATE KEY (
FILE = ‘C:\temp\createCert\PrivateKey.pvk’,
–ENCRYPTION BY PASSWORD = ‘TestEncryption123’
–以上语句是设置私钥密码,如果通过数据库解密就需要提供该密码
,加密不需要,现在不需要设置
)
GO
–查看证书是否添加成功
SELECT * FROM sys.certificates
–将clearTextCol列内的数值通过数据库加密后放入encryptedCol里
UPDATE Encrypt
SET
encryptedCol = ENCRYPTBYCERT
(
CERT_ID(‘TestCertificate’),
clearTextCol
)
GO
–通过sql语句解密刚才加密的列
–DECLARE @Passwd nvarchar(128) = ‘TestEncryption123’
–因为前面没有设置密码,所以现在也不用提供密码
SELECT intCol,
clearTextCol,
encryptedCol,
CAST
(
DECRYPTBYCERT
(
CERT_ID(‘TestCertificate’),
encryptedCol,
– @Passwd
) AS varchar(128)
) AS decryptedCol
FROM dbo.EncryptGO
如果出现这种界面代表数据库加解密成功,相同的字符串,每次加密后的值(encryptedCol列)不会相同
注意:导入证书报” 证书、非对称密钥或私钥文件不存在或格式无效。”错误,
出错原因
一: 请查看路径名是否正确,文件名是否正确
二:
(mycertificate.cer是数据库创建的数字证书, TestCertificate.cer是我创建的证书)
比较两个证书的”组或用户名”发现缺少OWNER和SQL..这两个用户名
请将TestCertificate.cer的文件添加这两个用户. 权限设置”完全控制”
Pvk一样也需要添加这两个用户,并且权限设置”完全控制”
C#源代码
解密方法:
// pfxFilePath—传入pfx存放在电脑的位置
// password—-传入用dos创建pfx时设置的密码
// EncryptedDocID—传入从数据库取出的加密过的数据
public string jiemi(string pfxFilePath, string password, byte[] EncryptedDocID)
{
System.Security.SecureString securePassword = new System.Security.SecureString();
foreach (char keyChar in password.ToCharArray())
securePassword.AppendChar(keyChar);
//反转一维 Array 或部分 Array 中元素的顺序,
//获取的数据库的字段必须反转元素,c#才能通过证书解密,不反转,提示传入的值无效
//c#加密的后的元素也必须反转,才能被sql语句解密,否则解密失败
Array.Reverse(EncryptedDocID);
string DecryptedDocID = "";
//load certificate from filesystem and open it with provided password
//实例化证书
X509Certificate2 cert = new X509Certificate2(pfxFilePath, password);
//判断证书是否打开成功
if (cert == null)
{
throw new Exception(“Certificate ” + pfxFilePath + ” Does not exist”);
}
//获取私钥,证书是非对称RSA算法加密的,私钥解密,公钥加密,这里获取私钥进//行解密,
if (cert.HasPrivateKey)
{
RSACryptoServiceProvider RsaCSP = (RSACryptoServiceProvider)cert.PrivateKey;//通过Decrypt解密,
//Decrypt第二个参数含义,如果为 true,则使用 OAEP 填充(仅可用于运行 Microsoft //Windows XP 及更高版本的计//算机)执行直接 RSA 解密;否则,如果为 false则使用 PKCS#1 v1.5 填充。
byte[] ret = RsaCSP.Decrypt(EncryptedDocID, false);
if (ret == null)
{
throw new Exception(“Decryption with RSA failed”);
}
//进行转码,需要用什么编码格式请查看下面加密方法相同的字段注释
DecryptedDocID = Encoding.GetEncoding(“GBK”).GetString(ret);
}
else
{
throw new Exception(“Certificate ” + pfxFilePath + ” has no Private Key; “);
}
return DecryptedDocID;
}
加密方法
// pfxFilePath—传入pfx存放在电脑的位置
// password—-传入用dos创建pfx时设置的密码
// StringMessage—需要加密的字符串public byte[] jiami(string pfxFilePath, string password, string StringMessage)
{
X509Certificate2 cert = new X509Certificate2(pfxFilePath, password);
if (cert == null)
{
throw new Exception(“Certificate ” + pfxFilePath + ” Does not exist”);
}
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
byte[] BytesMessage = Encoding.GetEncoding(“GBK”).GetBytes(StringMessage);
//转码
//获取公钥,公钥加密,私钥解密, 数据库就是通过私钥解密,所以这里需要获取公钥进行加密,
string keyPublic = cert.PublicKey.Key.ToXmlString(false);
provider.FromXmlString(keyPublic);
//加密方法
byte[] by = provider.Encrypt(BytesMessage, false);
//反转一维 Array 或部分 Array 中元素的顺序,这个无论加密解密必须得有否则失败
Array.Reverse(by);
return by;
}
注:如何判断Encoding.GetEncoding(“”)方法使用什么字符
数据库执行” SELECT COLLATIONPROPERTY(‘Chinese_PRC_Stroke_CI_AI_KS_WS’, ‘CodePage’)” 对应返回的数值就可得出数据库默认的编码方式,我的电脑返回936所以是GBK编码,所以ncoding.GetEncoding()设置GBK
下面是查询结果:
936 简体中文GBK
950 繁体中文BIG5
437 美国/加拿大英语
932 日文
949 韩文
866 俄文
65001 unicode UFT-8