证书(Certificates)全称是公钥证书,是一种数字签名语句,它把公钥的值绑定到用户、设备或服务的ID上,这些用户、设备或服务ID拥有私钥,而私钥用于对数据进行解密。SQL Server中的证书同时包含公钥和密钥,前者用来加密,后者解密。为了保证私钥的安全,证书的私钥会被加密,可以使用数据库主密钥或密码对证书的私钥进行加密。视图 sys.certificates的字段 pvt_key_encryption_type 表示私钥加密的方式。
一,证书的应用和包含内容
证书实际上是一个非对称密钥,公钥绑定到个人用户,私钥由证书发行机构保存。为了避免数据在传输的过程中被窃取,通常情况下,使用证书来加密对称密钥,而使用对称密钥来加密和解密数据。用户使用证书的公钥来加密对称密钥,并把对称密钥(由证书加密)和数据(由对称密钥加密)发送到证书发行结构;证书发行机构通过用户的ID来识别证书,通过证书的私钥来解密对称密钥,并通过对称密钥来解密数据。
接收证书的实体是证书的主题(Subject),证书包含的信息:
- 主题的公钥
- 主题的标识符信息,例如名称和电子邮件地址。
- 有效期,证书可用的开始和过期日期
- 证书发行机构的标识符信息
- 证书发行结构的数字签名,该签名证明了公钥与主题的标识符信息之间的绑定的有效性。
签名是指:对信息进行数字签名的过程,需要把信息和发件人持有的秘密信息转换为标签,这个标签就叫做签名。
证书实际上是非对称密钥,包含一对密钥。把公钥授权给用户,用户使用公钥加密;发行人用私钥解密。
SQL Server可以在内部生成证书(即自签名证书),也可以从外部文件或程序集载入。由于可以对证书进行备份,然后从文件中载入证书,这使得证书比非对称密钥更易于移植,而非对称密钥却做不到,这意味着可以在数据库中方便地重用同一个证书。
二,创建自签名的证书
管理员使用CREATE CERTIFICATE命令来创建证书,以下命令用于创建自签名的证书:
CREATE CERTIFICATE certificate_name [ ENCRYPTION BY PASSWORD = 'password' ] WITH SUBJECT = 'certificate_subject_name' [ , START_DATE = 'datetime' | EXPIRY_DATE = 'datetime']
参数注释:
- ENCRYPTION BY PASSWORD ='password':指定用于加密私钥的密码。只有在使用密码对证书进行加密证书时才会使用该选项;如果省略该选项,那么使用数据库主密钥(Database Master Key)来加密私钥。
- SUBJECT ='certificate_subject_name':证书的主题名称
- START_DATE 和 EXPIRY_DATE:用于指定证书的有效期
当创建自签名的证书时,私钥也会被创建,当使用ENCRYPTION BY PASSWORD = 'password' 时,表明使用密码对私钥进行加密;当省略该语句时,表明使用DMK对私钥进行加密。
三,从文件创建证书
从已有的文件中创建证书,文件是CA颁发的证书,通过文件把证书加载到SQL Server中:
CREATE CERTIFICATE certificate_name FROMFILE = 'path_to_file' [ WITH PRIVATE KEY ( <private_key_options> ) ]<private_key_options> ::= { FILE = 'path_to_private_key' [ , DECRYPTION BY PASSWORD = 'password' ] [ , ENCRYPTION BY PASSWORD = 'password' ] }
参数注释:
- File = 'paht_to_file':用于制定一个包含证书的DER编码的文件,扩展名是.cer。
- WITH PRIVATE KEY:指定把证书的私钥加载到SQL Server中。
- FILE ='path_to_private_key':用于制定私钥的路径
- DECRYPTION BY PASSWORD = 'key_password':指定密钥,用于解密文件中的私钥。如果私钥不受密码的保护,则此子句是可选的。不建议把私钥保存到没有密码保护的文件中。
- ENCRYPTION BY PASSWORD = 'password':用于指定加密私钥的密码,只有当你想要通过密码来加密私钥时,使用该选项。如果省略该子句,SQL Server默认使用数据库主密钥来加密私钥。
举个例子,从已有的.cer文件来创建证书:
CREATE CERTIFICATE Shipping11 FROM FILE = 'c:ShippingCertsShipping11.cer' WITH PRIVATE KEY (FILE = 'c:ShippingCertsShipping11.pvk', DECRYPTION BY PASSWORD = 'sldkflk34et6gs%53#v00'); GO
还有其他方式来创建证书,详细信息,请阅读微软文档:CREATE CERTIFICATE (Transact-SQL)
四,证书重编码
把证书和私钥编码为二进制,以二进制格式返回证书的公钥部分:
CERTENCODED ( cert_id )
以二进制格式返回证书的私钥部分,该函数以PVK格式来返回私钥:
CERTPRIVATEKEY ( cert_ID , ' encryption_password ' [ , ' decryption_password ' ] )
证书ID可以通过函数Cert_ID('name')来获得,也可以通过 sys.certificates 查询获得:
Cert_ID()
例子1:返回证书的二进制
在当前数据库中创建自签名证书,并返回证书的二进制形式:
CREATE CERTIFICATE Shipping04 ENCRYPTION BY PASSWORD = 'pGFD4bb925DGvbd2439587y' WITH SUBJECT = 'Sammamish Shipping Records', EXPIRY_DATE = '20401031'; GO SELECT CERTENCODED(CERT_ID('Shipping04')); SELECT CERTPRIVATEKEY(CERT_ID('Shipping04'), 'jklalkaa/; uia3dd');
例子2,使用证书的二进制来创建证书
在另一个数据库中,利用证书和私钥的二进制来创建证书
CREATE CERTIFICATE TARGET_CERT FROM BINARY = <insert the binary value of the @CERTENC variable> WITH PRIVATE KEY ( BINARY = <insert the binary value of the @CERTPVK variable> , DECRYPTION BY PASSWORD = 'jklalkaa/; uia3dd');
五,证书的加密和解密
证书本质上是一个非对称密钥,可以使用证书来加密和解密数据。
1,使用证书来加密
时使用证书的公钥来加密数据,返回值的类型是varbinary,最大长度是8000Bytes。
EncryptByCert ( certificate_ID , { 'cleartext' | @cleartext } )
2,使用证书来解密
使用证书的私钥来解密,私钥是自动调用的:
DecryptByCert ( certificate_ID , { 'ciphertext' | @ciphertext } [ , { 'cert_password' | @cert_password } ] )
六,管理证书
证书的授权
证书是数据库级别的Securable,管理员可以把已创建的证书授权给相应的人员来使用:
GRANT permission [ ,...n ] ON CERTIFICATE :: certificate_name TO principal [ ,...n ]
证书的备份
使用BACKUP CERTIFICATE导出证书,把证书存放在安全的地方保存:
BACKUP CERTIFICATE certname TO FILE = 'path_to_file' [ WITH PRIVATE KEY ( FILE = 'path_to_private_key_file' , ENCRYPTION BY PASSWORD = 'encryption_password' [ , DECRYPTION BY PASSWORD = 'decryption_password' ] ) ]
参数注释:
- TO FILE = 'path_to_file':把证书的公钥保存到文件中
- WITH PRIVATE KEY :把证书的私钥保存到文件:
- ENCRYPTION BY PASSWORD = 'encryption_password':用于加密私钥的密码,在把私钥写入到备份文件之前,使用密码对私钥进行加密。
- DECRYPTION BY PASSWORD = 'decryption_password':用于解密私钥的密码,在把私钥写入到备份文件之前,使用密钥对私钥进行解密。如果使用数据库主密钥对私钥进行加密,那么该参数省略。
举个例子,把证书的公钥和私钥都进行备份,私钥使用密码进行解密和加密:
BACKUP CERTIFICATE sales09 TO FILE = 'c:storedcertssales09cert' WITH PRIVATE KEY ( DECRYPTION BY PASSWORD = '9875t6#6rfid7vble7r' , FILE = 'c:storedkeyssales09key' , ENCRYPTION BY PASSWORD = '9n34khUbhk$w4ecJH5gh' ); GO
参考文档: