非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。
X509EncodedKeySpec和PKCS8EncodedKeySpec分别对应值公钥和私钥的规范 想对算法编码和规范有更多了解的可以更深入的学习,以下例子只展示最简单的使用
public class RSAUtil {
//必须16位 否则会报错 偏移量
private static String IV = "asdfgh1234567890";
//钥匙 必须16位
private static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCA6exxuVOdLvxb6u+Gf5FvZD6zGO1sqDbW7zBgga/8LVZBktaljn0OzCjQKbfe/AQgyh/nIVi1zFO1+FC9cGSiWPGo1uX9kY5Chm0MS8UhtNfO13sOD0U/47MMOduuQ3WP+EJ0wFRvpzyGAp0vKqfCj3Hyrtaf8o7CqTGoLV7G7QIDAQAB";
private static String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIDp7HG5U50u/Fvq74Z/kW9kPrMY7WyoNtbvMGCBr/wtVkGS1qWOfQ7MKNApt978BCDKH+chWLXMU7X4UL1wZKJY8ajW5f2RjkKGbQxLxSG0187Xew4PRT/jsww5265DdY/4QnTAVG+nPIYCnS8qp8KPcfKu1p/yjsKpMagtXsbtAgMBAAECgYBXf+94BWWmg9TQgvdPYFkTtYQFRj8pCEgovTMl3gDYduFcItHEj6F8oMB3AkoGdSJMK0VaOT0gMG8FTWVoH9h9iSM5uu/wsqr7mFI13+18bGFNv0OotV4UNpvlXqSksoRmetZDtaDPhO9/6anD1zY8VrJMXzJfJXhNdGFArEjpwQJBAOBsvzNDy1w/QtLobDm+TSOVVNtoPMO5qddR5PRnRWtpKASY4dQDl/KPa1fDrNp3oGfqA5FPLrQCmd6502Mvmn0CQQCTDRgarAuH9UVgGDeR+E18lWBsZEM4mGHFi9aigeLEw0th8PqZpdrPJixSo4S2lKcopkkagljiYONLlVeznBkxAkEAvRvloZUm73x/GqmvSJkK90kGUDvtuB/i9gWUID5FSNU7W2RYJwdAKqyfjzzbktvq1qVijDdk61qlvgBoF9QtIQJAcIammVJqCIHxspUVgQfHE7yi6o7Wuaoxtx9JAVXvF65yMuJagdTe2YFWjW4/kg+y0nJcooJ4TdLiW+ZOFE0xIQJBAILYIuxY5OpAm8cMqLOtldczj4sFfZb7hhojcEm3+/0ezNhzhZWPMI6txFieDel40a/qdPr8EPZjc0uYKTtlKNc=";
public static void main(String[] args) {
// genKeyPair();
//字符串编码
System.out.println("编码结果:" + encrypt("hello world", PUBLIC_KEY));
//字符串解码
System.out.println("编码结果:" + decrypt("NEo+98UAvp0q69M1mxorD/zrL4QjhBGAFd2Wj2nGcsF8Txb9r8VnUvFqGUM7ZNwXZdcnzW/SZqbGc8rHT0mmtPGWMlzJV8jMAWUgOh9jozyablwWU8Uj4BItiderZSQTrD+3E+ZL5TkkQKwmNCmdaABmozpkUz4B893m3GzhpjQ=",PRIVATE_KEY));
}
/**
* 随机生成密钥对
*/
public static void genKeyPair() {
try {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024);
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 得到公钥字符串
String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
// 打印公钥和私钥
System.out.println("公匙:" + publicKeyString);
System.out.println("私匙:" + privateKeyString);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 加密
*/
public static String encrypt(String str, String publicKey) {
try {
byte[] bytes = str.getBytes();
//获得RSA公匙
RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey.getBytes())));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
bytes = cipher.doFinal(bytes);
return new String(Base64.getEncoder().encode(bytes));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 解密
*/
public static String decrypt(String str, String privateKey) {
try {
byte[] bytes = Base64.getDecoder().decode(str);
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes())));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
bytes = cipher.doFinal(bytes);
return new String(bytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
log
编码结果:eZxSLJKOvj0Ee/Lg9cx61ppaKuWXSRxvDU1deLR0ll2x1GEW5WO8Q9B4rO4DxDWfCLqfdmunSs2YZkm8ZDBUYi0N6VV4mqoz2SjckJyVe3pjwh4DifdrjAoO+0aYPKMhlGLjMY4Iy5SmkuSmot2AjsKHBhoqGs8bPnZoT7S6iKY=
编码结果:hello word
Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。简单的说,这是一种更高级的验证方式,用作数字签名。不单单只有公钥、私钥,还有数字签名。私钥加密生成数字签名,公钥验证数据及签名。如果数据和签名不匹配则认为验证失败!也就是说传输中的数据可以不再加密,接收方获得数据后,拿到公钥与签名比对数据是否有效!
public class DSAUtil {
private static String PUBLIC_KEY = "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAMUKDkoben3PPK01uS7hXrxKSOgJpQxVigU7mkfQL87B5GtwUKWmdKM5nMC89avU/S3qTg95+dQKjgydYqe8Ej3SVzDwnGlkZzWGgUOgs0pQ8q/cJ++4eUETH3l4svsLzwDgKIoT3fDBUef3fZ95oWbe1pIIt8RN0KRFJw8U+r4A";
private static String PRIVATE_KEY = "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUa38CMSvzE1kkWgLiBQDrKCavBEk=";
public static void main(String[] args) {
//随机生成成对密钥
genKeyPair();
String sign=sign("hello world", PRIVATE_KEY);
System.out.println("数字签名:" + sign);
//字符串解码
System.out.println("数字签名校验:" + verify("hello word",sign,PUBLIC_KEY));
}
/**
* 随机生成密钥对
*/
public static void genKeyPair() {
try {
// KeyPairGenerator类用于生成公钥和私钥对,基于DSA算法生成对象 可以使用RSA算法生成 成对出现就好
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
// 初始化密钥对生成器,密钥大小为96-1024位 可自定义随机产生器 SecureRandom
keyPairGen.initialize(1024);
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
DSAPrivateKey privateKey = (DSAPrivateKey) keyPair.getPrivate();
// 得到公钥
DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic();
// 得到公钥字符串
String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
// 打印公钥和私钥
System.out.println("公匙:" + publicKeyString);
System.out.println("私匙:" + privateKeyString);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 用私钥对信息生成数字签名
*/
public static String sign(String str, String privateKey) {
try {
byte[] bytes = str.getBytes();
//获得DSA公匙
DSAPrivateKey keyFactory = (DSAPrivateKey) KeyFactory.getInstance("DSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes())));
Signature signature=Signature.getInstance("DSA");
signature.initSign(keyFactory);
signature.update(bytes);
return new String(Base64.getEncoder().encode(signature.sign()));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 校验数字签名
*/
public static boolean verify(String str, String sign,String publicKey) {
try {
byte[] bytes =Base64.getDecoder().decode(sign);
DSAPublicKey keyFactory = (DSAPublicKey) KeyFactory.getInstance("DSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey.getBytes())));
Signature signature=Signature.getInstance("DSA");
signature.initVerify(keyFactory);
signature.update(str.getBytes());
return signature.verify(bytes);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
log
公匙:MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGANQY1Hf9XoQcFocGugqaEP6xPgxPsZ1C63Zs1WWg4Fk6CV8xuK78hgk+BhVit2/h97DWp7LyTDT4gVjCHLuV58TUmZyiupeo0FZrKqrAr+t3Der9+MmBDzfvkgPPIIZudhoqJcTpox8UNdJ4yyvgXxMN4DSoWJ4O28q0jBaxC/Mk=
私匙:MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUcsPeT/5R1AiwvTpJmzv5TQxq65Q=
数字签名:MCwCFGB6J9g/R5su1o3TbZYMAcroY6YIAhQTtbtXUH47pGRDzMCu74eq0sOMCg==
数字签名校验:true
非对称性加密还有很多,RSA和DSA是比较常用和常见的加密方式,安全性来讲两者差不多,DSA只是一种算法,和RSA不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,它比RSA要快很多,RSA啥都好,但是RSA算法的秘钥很长,加密的计算量比较大,安全性较高,但是加密速度比较慢,所以RSA加密常用于少量的核心数据的加密。
如果你看到了这里,觉得文章写得不错就给个赞呗!欢迎大家评论讨论!如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足,定期免费分享技术干货。谢谢!