一、 原理概念
OpenSSL定义:
OpenSSL是为网络通信提供安全及数据完整性的一种安全协议,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。
OpenSSL整个软件包大概可以分成三个主要的功能部分:密码算法库、SSL协议库以及应用程序。OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。
作为一个基于密码学的安全开发包,OpenSSL提供的功能相当强大和全面,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。
功能:
基本功能
OpenSSL整个软件包大概可以分成三个主要的功能部分:密码算法库、SSL协议库以及应用程序。OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。
作为一个基于密码学的安全开发包,OpenSSL提供的功能相当强大和全面,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。
辅助功能
BIO机制是OpenSSL提供的一种高层IO接口,该接口封装了几乎所有类型的IO接口,如内存访问、文件访问以及Socket等。这使得代码的重用性大幅度提高,OpenSSL提供API的复杂性也降低了很多。
OpenSSL对于随机数的生成和管理也提供了一整套的解决方法和支持API函数。随机数的好坏是决定一个密钥是否安全的重要前提。
OpenSSL还提供了其它的一些辅助功能,如从口令生成密钥的API,证书签发和管理中的配置文件机制等等。如果你有足够的耐心,将会在深入使用OpenSSL的过程慢慢发现很多这样的小功能,让你不断有新的惊喜。
1.对称加密:
(1)甲方选择某一种加密规则,对信息进行加密;
(2)乙方使用同一种规则,对信息进行解密。
这种加密模式有一个最大弱点:甲方必须把加密规则告诉乙方,否则无法解密。保存和传递密钥,就成了最头疼的问题
2.非对称加密:
(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
(2)甲方获取乙方的公钥,然后用它对信息加密。
(3)乙方得到加密后的信息,用私钥解密。
如果公钥加密的信息只有私钥解得开,那么只要私钥不泄漏,通信就是安全的。
公钥用于加密,私钥用于解密
二、 密钥生成步骤
RSA加密有如下几个步骤.
1. 生成公钥与私钥
2. 用公钥对需要加密的字符串等进行加密
3. 在需要解密的地方,用私钥进行解密
三、 流程及命令
- 首先使用OpenSSL生成私钥:openssl genrsa –out rsa_private_key.pem 1024
- 根据生成的私钥生成公钥:
- openssl rsa –in rsa_private_key.pem -out rsa_public_key.pem –pubout writing RSA key
- 这时候的私钥还不能直接被使用,需要进行PKCS#8编码:
- openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem –nocrypt
注意:命令中指明了输入私钥文件为rsa_private_key.pem,输出私钥文件为pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)
至此,可用的密钥对已经生成好了,私钥使用pkcs8_rsa_private_key.pem,公钥采用rsa_public_key.pem。
四、 Java
未进行抽出方法的代码:
1 package jdk_RSA; 2 3 import java.io.ByteArrayOutputStream; 4 import java.security.KeyFactory; 5 import java.security.KeyPair; 6 import java.security.KeyPairGenerator; 7 import java.security.PrivateKey; 8 import java.security.PublicKey; 9 import java.security.interfaces.RSAPrivateKey; 10 import java.security.interfaces.RSAPublicKey; 11 import java.security.spec.PKCS8EncodedKeySpec; 12 import java.security.spec.X509EncodedKeySpec; 13 import java.util.Base64; 14 15 import javax.crypto.Cipher; 16 17 public class JdkRsa { 18 //特别注意:RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。 19 public static void main(String[] args) { 20 String str = "hello world!"; 21 System.out.println(str.length()); 22 // 初始化密钥 23 PublicKey keyPublic = null; 24 PrivateKey keyPrivate = null; 25 byte[] prikey = null; 26 byte[] pubkey = null; 27 try { 28 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 29 keyPairGenerator.initialize(1024); 30 KeyPair keyPair = keyPairGenerator.generateKeyPair(); 31 keyPublic = keyPair.getPublic(); 32 keyPrivate = keyPair.getPrivate(); 33 pubkey = keyPublic.getEncoded(); 34 prikey = keyPrivate.getEncoded(); 35 System.out.println("keyPublic:"+Base64.getEncoder().encodeToString(pubkey)); 36 System.out.println("keyPrivate:"+Base64.getEncoder().encodeToString(prikey)); 37 } catch (Exception e) { 38 e.printStackTrace(); 39 } 40 // 此时的私密还不能用,需要通过PKCS8转换为RSAPrivateKey 41 RSAPrivateKey privateKey = null; 42 try { 43 KeyFactory factory = KeyFactory.getInstance("RSA"); 44 PKCS8EncodedKeySpec pkcs8PrivateKey = new PKCS8EncodedKeySpec(prikey); 45 privateKey = (RSAPrivateKey) factory.generatePrivate(pkcs8PrivateKey); 46 System.out.println("转化为RSAPrivateKey的值:"+Base64.getEncoder().encodeToString(privateKey.getEncoded())); 47 } catch (Exception e) { 48 // TODO Auto-generated catch block 49 e.printStackTrace(); 50 } 51 52 // 通过x509转换公钥为RSAPublicKey 53 RSAPublicKey publicKey = null; 54 try { 55 KeyFactory factory = KeyFactory.getInstance("RSA"); 56 X509EncodedKeySpec x509PublicKey = new X509EncodedKeySpec(pubkey); 57 publicKey = (RSAPublicKey) factory.generatePublic(x509PublicKey); 58 System.out.println("转化为RSAPublicKey的值:"+Base64.getEncoder().encodeToString(privateKey.getEncoded())); 59 } catch (Exception e) { 60 // TODO Auto-generated catch block 61 e.printStackTrace(); 62 } 63 // 通过Cipher对象进行加密——————公钥加密 64 String result = null; 65 try { 66 Cipher cipher = Cipher.getInstance("RSA"); 67 cipher.init(Cipher.ENCRYPT_MODE, publicKey); 68 byte[] encodes = cipher.doFinal(str.getBytes()); 69 result = Base64.getUrlEncoder().encodeToString(encodes); 70 System.out.println("公钥加密后的值:"+Base64.getUrlEncoder().encodeToString(encodes)); 71 } catch (Exception e) { 72 // TODO Auto-generated catch block 73 e.printStackTrace(); 74 } 75 76 // 通过Cipher对象进行加密—————私钥解密 77 try { 78 // 注意:这里是用base64解密后的字节数组 79 byte[] decoderData = Base64.getUrlDecoder().decode(result.getBytes()); 80 Cipher cipher = Cipher.getInstance("RSA"); 81 cipher.init(Cipher.DECRYPT_MODE, privateKey); 82 System.out.println("要解密长度:"+result.getBytes().length); 83 int inputLen = decoderData.length; 84 ByteArrayOutputStream out = new ByteArrayOutputStream(); 85 int offSet = 0; 86 byte[] cache; 87 int i = 0; 88 // 对数据分段解密 89 while (inputLen - offSet > 0) { 90 if (inputLen - offSet > 128) { 91 cache = cipher.doFinal(decoderData, offSet, 128); 92 } else { 93 cache = cipher.doFinal(decoderData, offSet, inputLen - offSet); 94 } 95 out.write(cache, 0, cache.length); 96 i++; 97 offSet = i * 128; 98 } 99 byte[] decryptedData = out.toByteArray(); 100 out.close(); 101 System.out.println(Base64.getUrlEncoder().encodeToString(decryptedData).length()); 102 System.out.println("私钥解密后的值:"+new String(decryptedData)); 103 } catch (Exception e) { 104 // TODO Auto-generated catch block 105 e.printStackTrace(); 106 } 107 } 108 }
运行结果:
1 12 2 keyPublic:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqfHs1bBZgzgkCnKlxWEg1QLZfB+mIOH7TJ2Euew4t5gXzBDTSqXh36EPC2AzJqPRH6Eh6lcXWvRk9SV0jHuuq+yD3GxxV3sqdozYoRJIOCgmHWoXIbIqBPbefbbnNu3TeicAlZuytobit3bLSo8MZhS1tlv3Hfju/ZDiRWzGS+wIDAQAB 3 keyPrivate:MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKp8ezVsFmDOCQKcqXFYSDVAtl8H6Yg4ftMnYS57Di3mBfMENNKpeHfoQ8LYDMmo9EfoSHqVxda9GT1JXSMe66r7IPcbHFXeyp2jNihEkg4KCYdahchsioE9t59tuc27dN6JwCVm7K2huK3dstKjwxmFLW2W/cd+O79kOJFbMZL7AgMBAAECgYArIs/x1mVbHQZ+mLDuss2iW7tJFDFsfA7q0j3uisgtqNO8h0XuP17xx9zNQekKZStZvlYIXjjuem4WaaedKUerUjJa6mktj5+lhRCbqnFjRk6Jw0QJlMAyE3AuRkauKJl121vHD+EzcSiWtT2LE9AsKLlTdAzsZ2RKvaYfaXBsYQJBAPZd5uMtP4FhHLU1wQr08KqSr8H0h1m8V05UFuslR/wZ5ACX/5Eoo7rqGDGuGY3B+4zZE1ZiCoyT1oKLLh+N/okCQQCxJwaC5sgsHTB0IO+nVXQ0DeQC8PWZJ2qBF7wo9faNP4Wne8llH3m7ZMWQiL9dJ/3QOnmaHVI6i5/b1AdxXgRjAkA2TTovxnBh5vK56jAzZwuIvS4qFOikWcPwis5GZAA6y8Yab2YwK4HzF9ffU11khmYYhFwjxRZIJ+m2+lBfOh/pAkEAg0tlLAdXPDq1+puegup2oU3aO8PSgpwP93Vb4w/Il48Iw8Se0u+tDRH2ytRO4AAPwRBVp78rfnCVHhvbGE6R+QJABLGkGvDaAe7LCIwjLweu+Z5jT6qCyLSOp/PcZkdQMXiRW4X8hZlZvl7+zW3lCcTUSq49NlWbN/mVSFGK7Dznwg== 4 转化为RSAPrivateKey的值:MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKp8ezVsFmDOCQKcqXFYSDVAtl8H6Yg4ftMnYS57Di3mBfMENNKpeHfoQ8LYDMmo9EfoSHqVxda9GT1JXSMe66r7IPcbHFXeyp2jNihEkg4KCYdahchsioE9t59tuc27dN6JwCVm7K2huK3dstKjwxmFLW2W/cd+O79kOJFbMZL7AgMBAAECgYArIs/x1mVbHQZ+mLDuss2iW7tJFDFsfA7q0j3uisgtqNO8h0XuP17xx9zNQekKZStZvlYIXjjuem4WaaedKUerUjJa6mktj5+lhRCbqnFjRk6Jw0QJlMAyE3AuRkauKJl121vHD+EzcSiWtT2LE9AsKLlTdAzsZ2RKvaYfaXBsYQJBAPZd5uMtP4FhHLU1wQr08KqSr8H0h1m8V05UFuslR/wZ5ACX/5Eoo7rqGDGuGY3B+4zZE1ZiCoyT1oKLLh+N/okCQQCxJwaC5sgsHTB0IO+nVXQ0DeQC8PWZJ2qBF7wo9faNP4Wne8llH3m7ZMWQiL9dJ/3QOnmaHVI6i5/b1AdxXgRjAkA2TTovxnBh5vK56jAzZwuIvS4qFOikWcPwis5GZAA6y8Yab2YwK4HzF9ffU11khmYYhFwjxRZIJ+m2+lBfOh/pAkEAg0tlLAdXPDq1+puegup2oU3aO8PSgpwP93Vb4w/Il48Iw8Se0u+tDRH2ytRO4AAPwRBVp78rfnCVHhvbGE6R+QJABLGkGvDaAe7LCIwjLweu+Z5jT6qCyLSOp/PcZkdQMXiRW4X8hZlZvl7+zW3lCcTUSq49NlWbN/mVSFGK7Dznwg== 5 转化为RSAPublicKey的值:MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKp8ezVsFmDOCQKcqXFYSDVAtl8H6Yg4ftMnYS57Di3mBfMENNKpeHfoQ8LYDMmo9EfoSHqVxda9GT1JXSMe66r7IPcbHFXeyp2jNihEkg4KCYdahchsioE9t59tuc27dN6JwCVm7K2huK3dstKjwxmFLW2W/cd+O79kOJFbMZL7AgMBAAECgYArIs/x1mVbHQZ+mLDuss2iW7tJFDFsfA7q0j3uisgtqNO8h0XuP17xx9zNQekKZStZvlYIXjjuem4WaaedKUerUjJa6mktj5+lhRCbqnFjRk6Jw0QJlMAyE3AuRkauKJl121vHD+EzcSiWtT2LE9AsKLlTdAzsZ2RKvaYfaXBsYQJBAPZd5uMtP4FhHLU1wQr08KqSr8H0h1m8V05UFuslR/wZ5ACX/5Eoo7rqGDGuGY3B+4zZE1ZiCoyT1oKLLh+N/okCQQCxJwaC5sgsHTB0IO+nVXQ0DeQC8PWZJ2qBF7wo9faNP4Wne8llH3m7ZMWQiL9dJ/3QOnmaHVI6i5/b1AdxXgRjAkA2TTovxnBh5vK56jAzZwuIvS4qFOikWcPwis5GZAA6y8Yab2YwK4HzF9ffU11khmYYhFwjxRZIJ+m2+lBfOh/pAkEAg0tlLAdXPDq1+puegup2oU3aO8PSgpwP93Vb4w/Il48Iw8Se0u+tDRH2ytRO4AAPwRBVp78rfnCVHhvbGE6R+QJABLGkGvDaAe7LCIwjLweu+Z5jT6qCyLSOp/PcZkdQMXiRW4X8hZlZvl7+zW3lCcTUSq49NlWbN/mVSFGK7Dznwg== 6 公钥加密后的值:Q7i6NzerRdcCSfSTO9yLDza9RE__-D-E_2APn-2QRXe3Yfr2tUsG5oq2PtK2f27-mTX0C6pKA3R3P_8pijhhyOwFO6eV8uJbnW0A0njKihYZUQJe-0-OiNcpLPOr_PtOgBFQh3bM7uBnclDRqeJKMBqQSmjQoDokiipePHmCccA= 7 要解密长度:172 8 16 9 私钥解密后的值:hello world!
抽出方法的代码
1 package jdk_RSA; 2 3 import java.io.ByteArrayOutputStream; 4 import java.security.KeyFactory; 5 import java.security.KeyPair; 6 import java.security.KeyPairGenerator; 7 import java.security.NoSuchAlgorithmException; 8 import java.security.PrivateKey; 9 import java.security.PublicKey; 10 import java.security.interfaces.RSAPrivateKey; 11 import java.security.interfaces.RSAPublicKey; 12 import java.security.spec.PKCS8EncodedKeySpec; 13 import java.security.spec.X509EncodedKeySpec; 14 import java.util.Base64; 15 16 import javax.crypto.Cipher; 17 18 public class RSAjdk { 19 public static void main(String[] args) { 20 String content = "hello world!"; 21 System.out.println(content.getBytes().length); 22 RSAjdk rsa = new RSAjdk(); 23 KeyPair keyPair = rsa.genPairKey(); 24 PrivateKey privateKey = keyPair.getPrivate(); 25 PublicKey publicKey = keyPair.getPublic(); 26 RSAPrivateKey priKey = rsa.getPrivateKey(privateKey); 27 RSAPublicKey pubKey = rsa.getPublicKey(publicKey); 28 String encoderContent = rsa.enCoder(pubKey, content); 29 System.out.println("加密后的字符串:"+encoderContent); 30 String decoderContent = rsa.deCoder(priKey,encoderContent); 31 System.out.println("解密后的字符串:"+decoderContent); 32 } 33 34 // 初始化密钥对儿,不用KeyPair也可以返回void 35 public KeyPair genPairKey() { 36 KeyPairGenerator keyPairGenerator = null; 37 try { 38 keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 39 } catch (NoSuchAlgorithmException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 } 43 // 初始化生成的密钥对最大长度 44 keyPairGenerator.initialize(1024); 45 KeyPair keyPair = keyPairGenerator.generateKeyPair(); 46 return keyPair; 47 } 48 49 // 取得私钥并经过Base64转化为RSAPrivateKey 50 public RSAPrivateKey getPrivateKey(PrivateKey privateKey) { 51 KeyFactory factory = null; 52 RSAPrivateKey priKey = null; 53 try { 54 factory = KeyFactory.getInstance("RSA"); 55 PKCS8EncodedKeySpec pkcs8PrivateKey = new PKCS8EncodedKeySpec(privateKey.getEncoded()); 56 priKey = (RSAPrivateKey) factory.generatePrivate(pkcs8PrivateKey); 57 } catch (Exception e) { 58 // TODO Auto-generated catch block 59 e.printStackTrace(); 60 } 61 return priKey; 62 } 63 64 // 取得公钥并经过Base64转化为RSAPublicKey 65 public RSAPublicKey getPublicKey(PublicKey publicKey) { 66 KeyFactory factory = null; 67 RSAPublicKey pubKey = null; 68 try { 69 factory = KeyFactory.getInstance("RSA"); 70 X509EncodedKeySpec x509PublicKey = new X509EncodedKeySpec(publicKey.getEncoded()); 71 pubKey = (RSAPublicKey) factory.generatePublic(x509PublicKey); 72 } catch (Exception e) { 73 // TODO Auto-generated catch block 74 e.printStackTrace(); 75 } 76 return pubKey; 77 } 78 79 // 公钥加密 80 public String enCoder(RSAPublicKey key,String content) { 81 Cipher cipher = null; 82 byte[] encoderData = null; 83 String result = null; 84 try { 85 cipher = Cipher.getInstance("RSA"); 86 cipher.init(Cipher.ENCRYPT_MODE, key); 87 encoderData = cipher.doFinal(content.getBytes()); 88 result = Base64.getUrlEncoder().encodeToString(encoderData); 89 } catch (Exception e) { 90 // TODO Auto-generated catch block 91 e.printStackTrace(); 92 } 93 return result; 94 } 95 // 私钥解密 96 public String deCoder(RSAPrivateKey key,String content) { 97 String result = null; 98 Cipher cipher; 99 byte[] decoderData = Base64.getUrlDecoder().decode(content.getBytes()); 100 byte[] decoderedData = null; 101 ByteArrayOutputStream out = new ByteArrayOutputStream(); 102 try { 103 cipher = Cipher.getInstance("RSA"); 104 cipher.init(Cipher.DECRYPT_MODE, key); 105 int end = decoderData.length; 106 byte[] cache = null; 107 int offset = 0; 108 int index = 0; 109 while(end - offset > 0) { 110 if(end - offset > 128) { 111 cache = cipher.doFinal(decoderData, offset, 128); 112 }else { 113 cache = cipher.doFinal(decoderData, offset, end-offset); 114 } 115 out.write(cache, 0, cache.length); 116 index++; 117 offset = index*128; 118 } 119 decoderedData = out.toByteArray(); 120 } catch (Exception e) { 121 // TODO Auto-generated catch block 122 e.printStackTrace(); 123 } 124 if(decoderedData!=null && decoderData.length!=0) { 125 result = new String(decoderedData); 126 } 127 return result; 128 } 129 }
运行结果:
1 12 2 加密后的字符串:m6RE8lEQYBw12u69lyYjxFkr6Lr4EuMv2fmezt7PY-Ty5nY8ld7bMnENodanPnr_b1iaAqm6YfCBUz3lF8ulOPKol8wUts9i1gV-vjMtJmDquWxiaTc7xzS4Z0uWZvAyLKAzTX2rxPjJi3WqqtjkkEkqOfYgwDMDRD-VCVEgN8c= 3 解密后的字符串:hello world!