如上图所示,此种方式属于对称加密,双方拥有相同的密钥,信息得到安全传输,但此种方式的缺点是:
(1)不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高
(2)因每个客户端、服务器的安全级别不同,密钥极易泄露
这里举例一个使用DES算法来实现对称加密的例子:
public class DESUtils {
public byte[] initKey(){
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(56);
SecretKey secretKey = keyGenerator.generateKey();
return secretKey.getEncoded();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* @Method: encrypt
* @Description: 加密算法
* @param data 被加密字节数组
* @param key 随机对称密钥
* @return
* 返回类型:byte[]
*/
public byte[] encrypt(byte[] data,byte[] key){
SecretKey secretKey = new SecretKeySpec(key, "DES");
Cipher cipher;
try {
cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @Method: decode
* @Description: TODO
* @param 被解密的字节数组
* @param key 随机对称密钥(和加密密钥务必保持一致)
* @return
* 返回类型:byte[]
*/
public byte[] decode(byte[] data,byte[] key){
SecretKey secretKey = new SecretKeySpec(key, "DES");
Cipher cipher;
try {
cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
测试代码为:
public static void testDes(){
DESUtils desUtils = new DESUtils();
byte[] key = desUtils.initKey(); //
String originData = "123456";
System.out.println("原始数据:"+originData);
try {
// 将原始数据转化为字符串
byte[] arrayOrigin = originData.getBytes("utf-8");
// 对原始数据进行加密
byte[] encryption = desUtils.encrypt(arrayOrigin, key);
// 通过BASE64Encoder转化处理
String encryptionStr = new BASE64Encoder().encode(encryption);
System.out.println("经过加密之后的字符串:"+encryptionStr);
try {
// 使用BASE64Decoder进行转化处理
byte[] decoceOrigin = new BASE64Decoder().decodeBuffer(encryptionStr);
// 使用DES进行解密操作
byte[] decode = desUtils.decode(decoceOrigin, key);
// 把字节数组转化为字符串
String decodeStr = new String(decode,"utf-8");
System.out.println("对加密字符串进行解密:"+decodeStr);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
运行结果如下:
原始数据:123456
经过加密之后的字符串:jaKOVkHJtOQ=
对加密字符串进行解密:123456
如上图所示,客户端用公钥对请求内容加密,服务器使用私钥对内容解密,反之亦然,但上述过程也存在缺点:
公钥是公开的(也就是黑客也会有公钥),所以第 ④ 步私钥加密的信息,如果被黑客截获,其可以使用公钥进行解密,获取其中的内容。
实现非对称加密算法例子:
public class AsymmetricEncryption {
public static final String KEY_ALGORITHM = "RSA";
/** 貌似默认是RSA/NONE/PKCS1Padding,未验证 */
public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
public static final String PUBLIC_KEY = "publicKey";
public static final String PRIVATE_KEY = "privateKey";
/** RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024 */
public static final int KEY_SIZE = 2048;
public static final String PLAIN_TEXT = "hello world!";
/**
* @Method: generateKeyBytes
* @Description: 首先产生一个公钥和私钥对,使用HashMap保存起来
* @return 返回类型:Map
*/
public static Map
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator
.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map
keyMap.put(PUBLIC_KEY, publicKey.getEncoded());
keyMap.put(PRIVATE_KEY, privateKey.getEncoded());
return keyMap;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* 还原公钥,X509EncodedKeySpec 用于构建公钥的规范
*
* @param keyBytes
* @return
*/
public static PublicKey restorePublicKey(byte[] keyBytes) {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
try {
KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec);
return publicKey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 还原私钥,PKCS8EncodedKeySpec 用于构建私钥的规范
*
* @param keyBytes
* @return
*/
public static PrivateKey restorePrivateKey(byte[] keyBytes) {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
keyBytes);
try {
KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = factory
.generatePrivate(pkcs8EncodedKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 加密,三步走。
*
* @param key
* @param plainText
* @return
*/
public static byte[] RSAEncode(PublicKey key, byte[] plainText) {
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String RSADecode(PrivateKey key, byte[] encodedText) {
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(encodedText));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
测试代码如下:
public static void tesRSA(){
Map
// 加密
PublicKey publicKey = AsymmetricEncryption.restorePublicKey(keyMap.get(AsymmetricEncryption.PUBLIC_KEY));
byte[] encodedText = AsymmetricEncryption.RSAEncode(publicKey, AsymmetricEncryption.PLAIN_TEXT.getBytes());
String rsaString = new BASE64Encoder().encode(encodedText);
System.out.println("RSA encoded: " + rsaString);
PrivateKey privateKey = AsymmetricEncryption.restorePrivateKey(keyMap.get(AsymmetricEncryption.PRIVATE_KEY));
System.out.println("RSA decoded: "+ AsymmetricEncryption.RSADecode(privateKey, encodedText));
}
运行结果如下所示:
RSA encoded: e7wIyV32VtiJhiraQGIYxD2TKtC4O6dRJx0lgVuEUsjCTSjqNFmEVNlYmFzd3ohIiW67XyIfEzWD
W9YFpFnDekRFLgeerh7c5gXMLVsVkf7k7XuTbiGmQOlOBUmL8VWpWVWTk8Rgn7Y+G7/dz9+DOEnH
csMnssKC/MBM80Ad5Za+QHqgb6BdZNHjZYzWpDIztBEUf/yHWfkGhmJahxo6Ff6y8er/shiP+qL3
hMJlw70TTGoGlrAWQqxUMYGPrv4IELi/iNSednXxo5bNNatJYke7FhKnuy8GEOWNH/K8Q52vl24L
cururJGLEJR6Hn/oaGxnXQbs2Fzo3vUziDj1cQ==
RSA decoded: hello world!
第三 非对称和对称完美结合
非对称加密既然也有缺陷,那我们就将对称加密,非对称加密两者结合起来,取其精华、去其糟粕,发挥两者的各自的优势:
如上图所示
(1)第 ③ 步时,客户端说:(咱们后续回话采用对称加密吧,这是对称加密的算法和对称密钥)这段话用公钥进行加密,然后传给服务器
(2)服务器收到信息后,用私钥解密,提取出对称加密算法和对称密钥后,服务器说:(好的)对称密钥加密
(3)后续两者之间信息的传输就可以使用对称加密的方式了
这是个非常非常经典的数据传输过程,也是Https传输协议里面最经典的部分。也是把对称加密和非对称加密的作用发挥到了很好的地方。在https传输的过程中,如果单独只用对称加密,或者单独使用非对称加密都会出现问题。