最近给华为做一个项目,用到SAML单点登录。其中涉及到非对称加密和SSL相关的东西。学习了一下,记录下。
非对称加密意思就是这套算法有2个钥匙,一个叫密钥,一个叫公钥,用密钥加密的内容,只能用公钥解密,用公钥加密的内容,只能用密钥解密。公钥是公开的,密钥是保密的。这样的特性被利用在SSL上,极大提高了网络传输的安全性。(SSL协议其实是两边拥有相同的密钥,而且这个密钥是临时生成的,并非每次都不变的。在一段生成了密钥之后如何告诉对方才不会被网络中盗取?那就是通过非对称加密来做这个事情。)
现在说说如何生成这对密钥和公钥。
我使用的是java,java SDK提供了keytool.exe 在bin 下,可以直接使用。
D:>keytool -genkey -alias huawei(别名) -keyalg RSA(加密算法) -validity 36500(证书有效期) -keysize 1024(密钥长度) -keystore D:\huawei.keystore(密钥数据库文件存放的地方) -storepass 222222(密钥数据库访问的密码) -keypass 111111(密钥数据库中密钥获取要使用的密码) -dnam e "CN=JOB,OU=企业服务部,O=北京MM科技有限公司,L=北京市,ST=北京市,C=CN"(主体的信息)
上面这行命令中小括号内的内容是注释,运行时需要去掉的。
运行之后,就会在D盘下面生成huawei.keystore 这个数据库文件。这是个数据库文件,里面可以有多个密钥公钥对,每次生成都可以存储在这个文件中,每个密码对通过 上面指定的 alias 别名区分,故不可重复。
然后就是从这个数据库文件中导出公钥,导出成 .cer 后缀的文件,这个文件就叫证书。里面包含公钥和主体信息等。
导出的命令是:
D:>keytool -export -keystore D:\huawei.keystore -alias huawei -file D:\huawei.cer
回车后,会让输入数据库文件的访问密码,即上面的storepass(569832)回车,即可导出证书。
下面是 RSA 算法加密解密的辅助类,上面部分是公开方法,下面部分是私有的辅助方法,字符串转码默认使用 UTF-8 ,对byte可视化编码默认使用 BASE64编码。要使用下面这个辅助类加密解密先需要提供 公钥(PublicKey)和秘钥(PrivateKey)(见下面第二个测试类中)。
import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; /** * 加密解密 * @author tanyf * */ public final class EncryptUtils { /** * 通过秘钥将数据加密 * @param data 原始数据 * @param privateKey 秘钥 * @return 加密后的数据 * @throws Exception TODO */ public static byte[] encrypt(byte[] data,String privateKey) throws Exception{ return encrypt(data, parsePrivateKey(privateKey)); } /** * 通过秘钥将数据加密 * @param data 原始数据 * @param privateKey 秘钥 * @return 加密过后的数据 * @throws Exception TODO */ public static byte[] encrypt(byte[] data,PrivateKey privateKey) throws Exception{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 通过公钥将数据解密 * @param data 加密后的数据 * @param publicKey 公钥 * @return 解密后的数据 * @throws Exception TODO */ public static byte[] decrypt(byte[] data,String publicKey)throws Exception{ return decrypt(data, parsePublicKye(publicKey)); } /** * 通过公钥将数据解密 * @param data 加密后的数据 * @param publicKey 公钥 * @return 解密后的数据 * @throws Exception TODO */ public static byte[] decrypt(byte[] data,PublicKey publicKey)throws Exception{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * 通过秘钥对数据进行签名 * @param data 原始数据 * @param privateKey 密钥 * @return 用PrivateKey对数据进行的签名 * @throws Exception TODO */ public static String sign(byte[] data,String privateKey)throws Exception{ Signature s = Signature.getInstance("MD5withRSA"); s.initSign(parsePrivateKey(privateKey)); s.update(data); return encodeBase64(s.sign()); } /** * 通过秘钥对数据进行签名 * @param data 原始数据 * @param privateKey 密钥 * @return 用PrivateKey对数据进行的签名 * @throws Exception TODO */ public static String sign(byte[] data,PrivateKey privateKey)throws Exception{ Signature s = Signature.getInstance("MD5withRSA"); s.initSign(privateKey); s.update(data); return encodeBase64(s.sign()); } /** * 通过公钥校验签名是否正确 * @param data 解密之后的数据 * @param sign 用privateKey 对数据进行的签名字符串 * @param publicKey 公钥 * @return 签名是否正确,这确保了数据没有被篡改过 * @throws Exception TODO */ public static boolean verifySign(byte[] data,String sign,String publicKey)throws Exception{ Signature s = Signature.getInstance("MD5withRSA"); s.initVerify(parsePublicKye(publicKey)); s.update(data); return s.verify(decodeBase64(sign)); } /** * 通过公钥校验签名是否正确 * @param data 解密之后的数据 * @param sign 用privateKey 对数据进行的签名字符串 * @param publicKey 公钥 * @return 签名是否正确,这确保了数据没有被篡改过 * @throws Exception TODO */ public static boolean verifySign(byte[] data,String sign,PublicKey publicKey)throws Exception{ Signature s = Signature.getInstance("MD5withRSA"); s.initVerify(publicKey); s.update(data); return s.verify(decodeBase64(sign)); } // --------- 下面是私有辅助方法 ------------ /** * 将秘钥字符串加工秘钥 * @param privateKeyStr 秘钥字符串 * @return 秘钥 * @throws Exception TODO */ private static PrivateKey parsePrivateKey(String privateKeyStr)throws Exception{ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodeBase64(privateKeyStr)); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePrivate(spec); } /** * 将公钥字符串加工成公钥 * @param publicKyeStr 公钥字符串 * @return 公钥 * @throws Exception TODO */ private static PublicKey parsePublicKye(String publicKyeStr)throws Exception{ X509EncodedKeySpec spec = new X509EncodedKeySpec(decodeBase64(publicKyeStr)); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePublic(spec); } /** * 用BASE64解码 * @param str 待解码的字符串 * @return 解码后的byte数据 * @throws Exception TODO */ private static byte[] decodeBase64(String str)throws Exception{ return Base64.decodeBase64(str.getBytes("UTF-8")); } /** * 用BASE64编码 * @param bs byte数据 * @return 编码后的字符串 * @throws Exception TODO */ private static String encodeBase64(byte[] bs)throws Exception{ return new String(Base64.encodeBase64(bs),"UTF-8"); } }
测试类如下:
import java.security.KeyPair; import java.security.KeyPairGenerator; import javassist.expr.NewArray; import javax.crypto.Cipher; /** * TODO * @author tanyf * */ public class Main { /** * TODO * @param args TODO * @throws NoSuchAlgorithmException TODO */ public static void main(String[] args) throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(1024); KeyPair pair = generator.generateKeyPair(); /* byte[] privateKeyBs = pair.getPrivate().getEncoded(); String privateKey = new BASE64Encoder().encode(privateKeyBs); byte[] publicKeyBs = pair.getPublic().getEncoded(); String publicKey = new BASE64Encoder().encode(publicKeyBs); System.out.println("-----秘钥-------"); System.out.println(privateKey); System.out.println("-----公钥-------"); System.out.println(publicKey); */ // 下面是使用秘钥加密,使用公钥解密 byte[] data = "ABC欧文刚".getBytes("UTF-8"); byte[] encData = EncryptUtils.encrypt(data, pair.getPrivate()); String sign = EncryptUtils.sign(data, pair.getPrivate()); System.out.println("签名字符串为:\n"+sign); byte[] decData = EncryptUtils.decrypt(encData, pair.getPublic()); String msg = new String(decData,"UTF-8"); System.out.println(msg); System.out.println("签名是否正确: "+EncryptUtils.verifySign(decData, sign, pair.getPublic())); System.out.println("--- 秘钥加密,公钥解密 done ---"); // 下面是使用公钥加密,使用秘钥解密 (为了验证下反过来加解密是否成功,所以没有使用到 EncryptUtils辅助类,代码证明,反过来也是可以的) byte[] origBs = "购物劲歌王".getBytes("UTF-8"); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pair.getPublic()); byte[] encBs = cipher.doFinal(origBs); Cipher cipher2 = Cipher.getInstance("RSA"); cipher2.init(cipher.DECRYPT_MODE, pair.getPrivate()); byte[] decBs = cipher2.doFinal(encBs); System.out.println(new String(decBs,"UTF-8")); System.out.println("---------- 公钥加密,秘钥解密 DONE -----------"); } }
助记:
要将字符串加密,先需要获取 公钥秘钥对,获取方式 通过 KeyPairGenerator来获取,得到 KeyPair ,此对象里面包含了秘钥和公钥
通过 getPrivate 和 getPublic 方法获取。 获取到的对象分别是 PrivateKey 和 PublicKey 对象。两个对象即可用于加密解密。如果需要将这些钥匙保存下来,需要弄成字符串,那么调用它们的 getEncoded() 方法获取到 byte[] 的数据,然后可以通过 BASE64 编码转成字符串。这样就方便拷贝粘贴等。当然不是硬性要求使用 BASE64 的,不过大家都习惯用它罢了。在使用的时候,再用BASE64 把字符串解码成 byte[] ,不过 byte[] 依然不能直接使用。
byte[] 需要转换成 PublicKey 或者 PrivateKey 才可以方便使用。
byte[] 转换成 PublicKey 和 PrivateKey 的方式类似,具体可见类中。
代码中可见,加密解密都使用的是 Cipher 类,不过是使用的 模式不同而已 如:cipher2.init(cipher.DECRYPT_MODE, pair.getPrivate());
相关推荐
非对称加密使用一对公钥和私钥,公钥可以公开,用于加密数据;而私钥必须保密,用于解密数据。常见的非对称加密算法有RSA、DSA(Digital Signature Algorithm)和ECC(Elliptic Curve Cryptography)。在Java中,`...
非对称加密使用一对密钥:公钥和私钥。任何人都可以获取并使用公钥进行加密,但只有持有对应私钥的人才能解密。RSA算法基于数论中的大素数分解难题,确保了加密的安全性。这种机制使得用户可以公开发布自己的公钥,...
这种特点使得 RSA 非对称加密算法非常适合在需要确保数据安全的场景中使用,如 HTTPS 认证、数字签名等。 在 RSA 非对称加密算法中,公开密钥用于加密数据,而私密密钥用于解密数据。加密过程是通过公开密钥对数据...
与对称加密不同,非对称加密使用两个密钥:公钥和私钥。这两个密钥在数学上是相互关联的,但不能从一个轻易推导出另一个。这种特性使得非对称加密在数据保密和身份验证方面具有很高的安全性。 在非对称加密中,公钥...
非对称加密使用一对密钥,即公钥和私钥。公钥可以公开,用于加密数据;私钥则必须保密,用于解密数据。任何人都可以使用接收者的公钥对信息进行加密,但只有持有相应私钥的人才能解密。这种机制确保了即使公钥被截获...
而对于密钥管理较为复杂或需要实现数字签名的应用场景,则更倾向于使用非对称加密算法。在实际操作中,经常采用混合加密模式:利用非对称加密算法交换对称加密算法的密钥,再利用对称加密算法加密实际数据,从而结合...
非对称加密使用一对密钥:公钥和私钥。任何人都可以使用公钥对数据进行加密,但只有持有对应私钥的人才能解密。这样,即使加密后的数据在传输过程中被截获,攻击者也无法解密,除非他们拥有私钥。 接下来,我们引入...
非对称加密与传统的对称加密不同,对称加密使用同一个密钥进行加解密,而非对称加密使用一对密钥:公钥和私钥。公钥可以公开给任何人,用于加密数据;私钥则需要保密,用于解密数据。这种机制确保了即使公钥被截获,...
与对称加密不同的是,非对称加密使用一对密钥:公钥和私钥。公钥可以公开分发,而私钥则必须保密。发送方使用接收方的公钥进行加密,而接收方则使用自己的私钥解密。这种机制确保了即使加密数据被截获,没有对应的...
6.用对方的公钥对称密钥进行加密(加密密钥) 7.将密文(5)和加密密钥(6)一起发给对方 接收方: 1.用自己的私钥对加密密钥进行解密,得到对称密钥--也只有自己才能解密。 2.用对称密钥对密文进行解密,得到...
登录时,用户的密码用明文传输,太不安全,应该加密传输,怎么做呢,对称加密一旦秘钥丢失则形同虚设,最好使用非对称加密的方式,由后端事先生成公钥和私钥,公钥发给前端页面,私钥后端自己保留,前端进行认证时,...
非对称加密算法流程图,使用visio绘制。
非对称加密使用一对公钥和私钥,公钥可以公开,用于加密数据;私钥必须保密,用于解密数据。著名的非对称加密算法有RSA(Rivest-Shamir-Adleman)和ECC(Elliptic Curve Cryptography)。非对称加密的主要优点是解决...
1. **密钥管理**:对称加密使用单一密钥,而非对称加密使用一对公钥和私钥。 2. **安全性**:非对称加密因公私钥分离而具有更高的安全性,但加密速度相对较慢。 3. **应用场景**:对称加密适合大量数据的快速加密,...
非对称加密算法的核心是使用一对密钥——公开密钥和私有密钥。 #### 五、非对称加密的工作原理 - **密钥对**:非对称加密算法需要两个密钥:公开密钥(public key)和私有密钥(private key)。如果用公开密钥对...
非对称加密JAVA实现,实现对超长内容进行加密
与对称加密不同,非对称加密使用一对密钥,即公钥和私钥,来实现加密和解密。这种方式提供了一种更加安全的数据交换手段。 在“good_code.rar”这个压缩包中,我们可以通过代码了解如何实现非对称加密的各种操作。...
非对称加密技术详解 非对称加密技术是一种在现代信息安全领域中占据核心地位的加密方式,相较于传统的对称加密算法,它引入了一种全新的密钥管理机制,即使用一对密钥——公钥和私钥来进行加密和解密操作。这一技术...
本实验报告主要涉及两种加密算法:对称加密算法DES(Data Encryption Standard)和非对称加密算法RSA。实验旨在帮助学生深入理解这两种算法的基本原理,并通过Python编程实现加密和解密过程。 ### **对称加密算法...
非对称加密使用一对密钥,即公钥和私钥,其中公钥用于加密,私钥用于解密。这种方式增加了安全性,但也带来了计算上的开销。 ##### 非对称加密的优缺点 - **优点**:相对于对称加密而言,非对称加密更加安全,因为...