第一 对称加密:


对称加密是指,加密方和解密方使用同样的秘钥来进行加密和解密。


在对称加密算法中,数据发信方将明文( 原始数据 )和加密 密钥 (mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。常用的 对称加密算法:AES,RC4,3DES


传输的示意图如下所示:


linux C 对称加密算法 对称加密算法举例_对称加密


如上图所示,此种方式属于对称加密,双方拥有相同的密钥,信息得到安全传输,但此种方式的缺点是:

(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


第二 、非对称加密:


非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。 非对称加密算法:RSA,DSA/DSS 


linux C 对称加密算法 对称加密算法举例_ci_02

如上图所示,客户端用公钥对请求内容加密,服务器使用私钥对内容解密,反之亦然,但上述过程也存在缺点:

公钥是公开的(也就是黑客也会有公钥),所以第 ④ 步私钥加密的信息,如果被黑客截获,其可以使用公钥进行解密,获取其中的内容。

实现非对称加密算法例子:

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<String,byte[]>
  */
 public static Map<String, byte[]> generateKeyBytes() {


 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<String, byte[]> keyMap = new HashMap<String, byte[]>();
 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<String, byte[]> keyMap = AsymmetricEncryption.generateKeyBytes();
 
 // 加密
 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!

第三 非对称和对称完美结合

非对称加密既然也有缺陷,那我们就将对称加密,非对称加密两者结合起来,取其精华、去其糟粕,发挥两者的各自的优势:

linux C 对称加密算法 对称加密算法举例_对称加密_03


如上图所示

(1)第 ③ 步时,客户端说:(咱们后续回话采用对称加密吧,这是对称加密的算法和对称密钥)这段话用公钥进行加密,然后传给服务器

(2)服务器收到信息后,用私钥解密,提取出对称加密算法和对称密钥后,服务器说:(好的)对称密钥加密

(3)后续两者之间信息的传输就可以使用对称加密的方式了

这是个非常非常经典的数据传输过程,也是Https传输协议里面最经典的部分。也是把对称加密和非对称加密的作用发挥到了很好的地方。在https传输的过程中,如果单独只用对称加密,或者单独使用非对称加密都会出现问题。