java加密与数字证书
数字摘要
数字摘要就是采用单项Hash函数将需要加密的明文“摘要”成一串固定长度(128位)的密文,这一串密文又称为数字指纹,HASH值或摘要值 ,它有固定的长度,而且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。
目前常用的摘要算法为MD5、SHA1、SHA256等。其中MD5系列算法已经破解,一般不再建议使用。
MD5:Message-Digest Algorithm 5;
SHA1:Secure Hash Algorithm;
密钥加密技术
以用钥匙锁门为例,钥匙我们可以看做密钥,锁门的过程可以看做加密过程,锁门过程中所用到的原理就是加密算法
私用密钥(对称加密)
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。它的最大优势是加/解密速度快,适合于对大数据量进行加密,但密钥管理困难。
公共密钥(非对称加密)
使用不同的密钥来分别完成加密和解密操作,一个公开发布,即公开密钥,另一个由用户自己秘密保存,即私用密钥。信息发送者用公开密钥去加密,而信息接收者则用私用密钥去解密。公钥机制灵活,但加密和解密速度却比对称密钥加密慢得多。
非对称加密的典型应用是数字签名,加密密钥。
数字签名
数字签名就是附加在数据单元上的一些数据,或是对数据单元所作的密码变换。这种数据或变换允许数据单元的接收者用以确认数据单元的来源和数据单元的完整性并保护数据,防止被人(例如接收者)进行伪造。
签名过程:发送报文时,发送方用一个哈希函数从报文文本中生成报文摘要,然后用自己的私人密钥对这个摘要进行加密,这个加密后的摘要将作为报文的数字签名和报文一起发送给接收方。
验签过程:接收方首先用与发送方一样的哈希函数从接收到的原始报文中计算出报文摘要,接着再用发送方的公用密钥来对报文附加的数字签名进行解密,如果这两个摘要相同、那么接收方就能确认该数字签名是发送方的。
数字签名有两种功效:一是能确定消息确实是由发送方签名并发出来的;二是数字签名能确定消息的完整性。
数字签名是非对称密钥加密技术与数字摘要技术的应用。
下面是欧姆社系列图书《漫画密码》截图
数字证书
数字证书提供了一种在Internet上验证通信实体身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。它是由权威机构CA发行,人们可以在网上用它来识别对方的身份。最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名,此外,数字证书只在特定的时间段内有效。
数字证书是一个经证书授权中心数字签名的包含公钥拥有者信息以及公钥的文件。
X.509标准
X.509是由国际电信联盟(ITU-T)制定的数字证书标准。
扩展文件:
- .cer, .crt - 通常被用于二进制的DER文件格式(同于.der),不过也被用于Base64编码的文件 (例如 .pem),保存证书的公钥
- .P7B - 同于 .p7c
- .P7C - PKCS#7证书格式,仅仅包含证书和CRL列表信息,没有私钥。
- .PFX - 同于 .p12
- .P12 -PKCS#12文件,包含证书(公钥)和私钥(受密码保护),已经完整的证书链信
- .jks - JAVA的keytools证书工具支持的证书私钥格式
工具
keytool
keytool 是个密钥和证书管理工具,它将密钥和证书储存在一个所谓的密钥仓库中。
- 密钥实体(Key entity):密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)
- 可信任的证书实体(trusted certificate entries):只包含公钥
keytool常用命令:
command | description |
---|---|
-genkey | 生成密钥 |
-alias | 指定密钥别名 |
-keystore | 指定密钥库的名称 |
-storepass | 指定密钥库的密码 |
-validity | 指定证书有效期 |
-keyalg | 指定密钥的算法,默认采用DSA |
-keysize | 指定密钥长度 |
-keypass | 指定别名对应密钥的密码(私钥的密码) |
-dname | 指定证书所有者信息 |
-list | 显示密钥库中的证书信息 |
-v | 显示密钥库中的证书详细信息 |
-file | 指定证书的路径名称 |
-delete | 删除密钥库中某条目 |
-printcert | 查看导出的证书信息 |
-keypasswd | 修改密钥库中指定条目口令 |
-export | 将别名指定的证书导出到文件 |
-import | 将已签名数字证书导入密钥库 |
修改密钥别名:
keytool -changealias -alias ORIGALIAS -destalias NEWALIAS -keystore x.keystore
输入密钥库口令:密钥库密码
输入<ORIGALIAS>的密钥口令:密钥密码
导出证书
keystore中的private key实体不包含公钥,可以通过导出到证书,再从证书中得到公钥:
keytool -export -alias ALIAS -keystore KEYSTORE -file PATH
输入密钥库口令:密钥库密码
示例代码
加密解密
密钥库准备
使用keytool工具生成一个密钥实体:
keytool -genkey -alias origalias -keystore x.keystore
然后需要将密钥实体导出成证书,包含对应的公钥:
keytool -export -alias origalias -keystore x.keystore -file origalias.cer
代码
public class Demo { private static String STOREPATH = "C:/Users/Hang/x.keystore"; private static String STOREPASS = "123456"; private static String KEYALIAS = "origalias"; private static String KEYPASS = "111111"; private static String CERTPATH = "C:/Users/Hang/origalias.cer"; private static String CERTPASS = "111111"; private static String SignAlg = "SHA256withRSA"; /* 抛出异常:KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, NoSuchProviderException, UnrecoverableKeyException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, SignatureException */ public static void main(String[] args) throws Exception { //根据密钥库类型JKS得到密钥库实例 KeyStore keyStore = KeyStore.getInstance("JKS","SUN"); InputStream in = new FileInputStream(STOREPATH); keyStore.load(in, STOREPASS.toCharArray()); //根据alias从keystone中取出密钥对 PrivateKey privateKey = null; if(keyStore.isKeyEntry(KEYALIAS)){ privateKey = (PrivateKey) keyStore.getKey(KEYALIAS, KEYPASS.toCharArray()); } //使用命令导出密钥的证书`keytool -export -alias origalias -keystore x.keystore -file origalias.jks` //加载证书 //证书格式为X509 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); //读取证书文件的输入流 InputStream certin = new FileInputStream(CERTPATH); Certificate certificate = certificateFactory.generateCertificate(certin); //从证书中得到公钥 PublicKey publicKey = certificate.getPublicKey(); System.out.println("私钥:\r\n"+privateKey); System.out.println("公钥:\r\n"+publicKey); String source = "X.509是由国际电信联盟(ITU-T)制定的数字证书标准。"; Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); cipher.update("数字签名是 非对称密钥加密技术与数字摘要技术的应用。\r\n".getBytes("UTF-8")); byte[] cipherByte = cipher.doFinal(source.getBytes("UTF-8")); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] decrpytByte = cipher.doFinal(cipherByte); System.out.println(new String(decrpytByte,"UTF-8")); } }
签名验签
代码
签名验签中使用的还是上面代码中的公钥和私钥
Signature signature = Signature.getInstance(SignAlg); signature.initSign(privateKey); signature.update("数字签名是 非对称密钥加密技术与数字摘要技术的应用。\r\n".getBytes("UTF-8")); signature.update(source.getBytes("UTF-8")); byte[] signByte = signature.sign(); signature.initVerify(certificate); //certificate 和 publicKey都可以验签 signature.update("数字签名是 非对称密钥加密技术与数字摘要技术的应用。\r\n".getBytes("UTF-8")); signature.update(source.getBytes("UTF-8")); boolean verified = signature.verify(signByte); System.out.println(verified);**
来自:http://my.oschina.net/sherwayne/blog/353818