1 Provider称为提供者类
1.1 负责加密算法、密钥算法
1.2 jdk本身就有10个provider
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI
常用的第三方的BouncyCastleProvider也是很强悍的,但是需要手动添加到环境
1.3 provider的结构大致如下:
一个name
一个info
多个service
一个service对应多个Algorithm:RSA AES MD5withRSA等
2 Security负责管理Provider
添加第三方provider
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
3 Key所有密钥的顶层接口
3.1 生成一个key指定两个属性
(1)它使用什么算法:如AES、DES、RSA等
密钥的码形式:X509、PKCS#8
3.2 下面接口方法可以窥伺Key结构
Key.getAlgorithm()返回算法名词:RSA
Key.getFormat返回编码格式名称:'PKCS#8'等
Key.getEncoded()返回密钥编码后的byte[],可以用base64编码后可见3.3 三大接口继承自Key
SecretKey(对称加密顶层接口),Publickey\PrivateKey(非对称加密的顶层接口)
4 对称密钥生成
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));// 种子定了,random就定了
SecretKey secretKey = kgen.generateKey();
5 非对称密钥生成
5.1 KeyPair是非对称密钥的扩展
5.2 KeyPairGenerator生成密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
5.3 KeyFactory生成私钥(公钥流程一样,配置略有不同)
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(btye[] encode);// 私钥特定编码后的btye[]KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
6 SecureRandom
为何在安全方便不能使用普通的Random?
为何在安全方便不能使用
普通的Random使用的是Linear Congruential Generator线性同余发生器,实际上这个随机数是可预测的,所以在安全领域,一般使用SecureRandom
7 Chiper 暗号
使用密钥对明文、密文实现具体的加密、解密过程。需要初始化模式
cipher.getIntance(String transformation)
transformation = “算法/工作模式/填充模式”,如AES/CBC/PKCS5Padding ,最简单为仅为 AES
ECB工作模式没有偏移量,CBC工作模式有便宜量
PKCS5Padding比PKCS7Padding效率高,PKCS7Padding可支持IOS加解密
对于对称加密
cipher.init(Cipher.DECRYPT_MODE, privateKey);// 对称加密
cipher.init(Cipher.ENCRYPT_MODE, privateKey);// 对称解密
对于非对称加密
cipher.init(Cipher.DECRYPT_MODE, publicKey);// 初始化公钥解密
cipher.init(Cipher.ENCRYPT_MODE, privateKey);// 初始化私钥加密
加密
byte[] 密文=cipher.doFinal(byte[] 明文)
解密
byte[] 明文=cipher.doFinal(byte[] 密文)
8 keySpec
密钥编码规范的顶层接口
keySpec -> EncodedKeySpec(抽象) -> 两实现类(1)X509EncodedKeySpec 构建公钥编码规范(2)PKCS8EncodedKeySpec 构建私钥编码规范keySpec -> SecretKeySpec 兼容所有的对称加密密钥编码规范 。同时SecretKeySpec 又是SecretKey接口实现类
例如:SecretKeySpec key = new SecretKeySpec(keyStr.getBytes("utf-8"), "AES"); 注意aes的key的长度(二进制)只能是128/256位等
keySpec -> DESKeySpec 仅仅是DES编码规范9 Signature
封装了签名和验签,实际上也可以自己实现杂抽和非对称算法实现
(1)指定公钥和私钥
(2)指定签名算法:MD5withRSA等
签名
String info = "i am jack";
Signature signature = Signature.getInstance("MD5withRSA", new BouncyCastleProvider());
signature.update(info.getBytes("utf-8"));
byte[] signByte = signature.sign();
String sign = Base64.encodeBase64String(signByte);
验签:
String sign = "xhajklak";
String info = "i am jack";
Signature signature = Signature.getInstance("MD5withRSA", new BouncyCastleProvider());
signature.initVerify(publicKey);
signature.update(info.getBytes("utf-8"));
boolean status = signature.verify(Base64.decodeBase64(sign));
9 贴代码
//----------------签名-------------------
PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream("privkey.pem")));
PemObject pemObject = pemReader.readPemObject();
byte[] content = pemObject.getContent();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyFactory factory = KeyFactory.getInstance("RSA","BC");
privateKey = factory.generatePrivate(privKeySpec);
String info = "i am jack";
String md5 = Base64.encodeBase64String(md5Digest.digest(info.getBytes("utf-8")));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] signByte = Base64.decodeBase64(md5);
byte[] digestByte = cipher.doFinal(signByte);
String sign = Base64.encodeBase64String(digestByte);
//--------------验签------------------
PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream("public.pem")));
PemObject pemObject = pemReader.readPemObject();
byte[] content = pemObject.getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyFactory factory = KeyFactory.getInstance("RSA","BC");// BC是使用BouncyCastle的意思
PublicKey publicKey = factory.generatePublic(pubKeySpec);
String sign = "Vl7cDe1mdiT6BBGJOt9oXIigVh4=";
String info = "i am jack";
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] signByte = Base64.decodeBase64(sign);
byte[] digestByte = cipher.doFinal(signByte);
String md5Temp = Base64.encodeBase64String(digestByte);
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
String md5 = Base64.encodeBase64String(md5Digest.digest(info.getBytes("utf-8")));
if(md5Temp.equals(md5)){
// 验签成功
}