欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对称加密与非对称加密

程序员文章站 2022-06-05 09:01:09
...

RPC远程通讯的时候,保证数据安全性问题,针对于数据加密。

单项加密:MD5 一般用于密码加密

对称加密

为什么数据要对称加密呢?

防止别人抓包分析 Http 请求,获取铭文数据和篡改数据。

对称密码技术:发件人和收件人使用其共同拥有的单个** ,这种**既用于加密,也用于解密,叫做机***(也称为对称**或会话**)。

能够提供信息机密性(没有**信息不能被解密)、完整性(被改变的信息不能被解密)的服务。

对称式密码学又称:单钥密码学、秘***密码学、会话**密码学、私钥密码学、共享秘钥密码学

常见的对称式加密技术
  • DES(数据加密标准):分组式加密,算法源于Lucifer,作为NIST对称式加密标准;64位(有效位56位、校验8位),分组算法
  • 3DES:128位,分组算法
  • IDEA(国际数据加密算法):128位,比DES快,分组算法
  • Blowfish:32-448位,算法公开,分组算法
  • RC4:流密码,**长度可变
  • RC5:分组密码,**长度可变,最大2048位
  • Rijndael:128位/196位/256位
  • AES(高级加密标准):DES升级版,算法出自Rinjindael
对称密码的优点

用户只需记忆一个**,就可用于加密、解密;
与非对称加密方法相比,加密解密的计算量小,速度快,简单易用,适合于对海量数据进行加密处理 。

对称密码的缺点

如果**交换不安全,**的安全性就会丧失。特别是在电子商务环境下,当客户是未知的、不可信的实体时,如何使客户安全地获得**就成为一大难题。
如果用户较多情况下的**管理问题。N*(N-1)/2
如果**多个用户被共享,不能提供抗抵赖性

对称密码案例

假设Alice和Bob是认识的,两人为了保证通信消息不被其它人截取,预先约定了一个密码,用来加密在他们之间传送的消息,这样即使有人截取了消息没有密码也无法知道消息的内容。由此便实现了机密性。

应用场景:机构网站与机构网站进行合作的情况可以使用对称加密

基于DES实现加密和解密
package com.xiaoming.des;

import java.security.SecureRandom;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import javax.crypto.Cipher;

/**
 * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同**的算法。DES加密算法出自IBM的研究,
 * 后来被美国*正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位**,以现代计算能力,
 * 24小时内即可被**。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。
 * 注意:DES加密和解密过程中,**长度都必须是8的倍数
 */
public class DES {
	public DES() {
	}

	// 测试
	public static void main(String args[]) throws Exception {
		// 待加密内容
		String str = "xiaoming";
		// 密码,长度要是8的倍数 **随意定
		String password = "95880288";
		byte[] encrypt = encrypt(str.getBytes(), password);
		System.out.println("加密后:" + new String(encrypt));
		// 解密
		byte[] decrypt = decrypt(encrypt, password);
		System.out.println("解密后:" + new String(decrypt));
	}

	/**
	 * 加密
	 * 
	 * @param datasource
	 *            byte[]
	 * @param password
	 *            String
	 * @return byte[]
	 */
	public static byte[] encrypt(byte[] datasource, String password) {
		try {
			SecureRandom random = new SecureRandom();
			DESKeySpec desKey = new DESKeySpec(password.getBytes());
			// 创建一个密匙工厂,然后用它把DESKeySpec转换成
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey securekey = keyFactory.generateSecret(desKey);
			// Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance("DES");
			// 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
			cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
			// 现在,获取数据并加密
			// 正式执行加密操作
			return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密
	 * 
	 * @param src
	 *            byte[]
	 * @param password
	 *            String
	 * @return byte[]
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] src, String password) throws Exception {
		// DES算法要求有一个可信任的随机数源
		SecureRandom random = new SecureRandom();
		// 创建一个DESKeySpec对象
		DESKeySpec desKey = new DESKeySpec(password.getBytes());
		// 创建一个密匙工厂
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的
																			// Cipher
																			// 对象
		// 将DESKeySpec对象转换成SecretKey对象
		SecretKey securekey = keyFactory.generateSecret(desKey);
		// Cipher对象实际完成解密操作
		Cipher cipher = Cipher.getInstance("DES");
		// 用密匙初始化Cipher对象
		cipher.init(Cipher.DECRYPT_MODE, securekey, random);
		// 真正开始解密操作
		return cipher.doFinal(src);
	}
}

密码不可能使用对称加密。按照互联网隐私情况,密码是不能被解密出来的。密码还是使用单向加密,单向特征:不可能被逆向,不可被解密。注意:密码使用 MD5 加密再加盐

非对称加密

使用一对**:一个用于加密信息,另一个则用于解密信息。

两个**之间存在着相互依存关系:即用其中任一个**加密的信息只能用另一个**进行解密。

其中加***不同于解***,公钥加密私钥解密,反之也可私钥加密公钥解密。

**依据性质划分,将其中的一个向外界公开,称为公钥;另一个则自己保留,称为私钥。公钥(Public key)常用于数据加密(用对方公钥加密)或签名验证(用对方公钥解密),私钥(Private key)常用于数据解密(发送方用接收方公钥加密)或数字签名(用自己私钥加密)。

使用过程

乙方生成两把**(公钥和私钥),甲方获取乙方的公钥,然后用它对信息加密。乙方得到加密后的信息,用私钥解密,乙方也可用私钥加密字符串,甲方获取乙方私钥加密数据,用公钥解密

优点:难**
缺点: 加密速度慢

常用算法:

RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)

RSA 工具类
package com.xiaoming.rsa;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

/**
 * RSA加解密工具类
 *
 * 
 */
public class RSAUtil {

   public static String publicKey; // 公钥
   public static String privateKey; // 私钥

   /**
    * 生成公钥和私钥
    */
   public static void generateKey() {
      // 1.初始化秘钥
      KeyPairGenerator keyPairGenerator;
      try {
         keyPairGenerator = KeyPairGenerator.getInstance("RSA");
         SecureRandom sr = new SecureRandom(); // 随机数生成器
         keyPairGenerator.initialize(512, sr); // 设置512位长的秘钥
         KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 开始创建
         RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
         RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
         // 进行转码
         publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
         // 进行转码
         privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
      } catch (NoSuchAlgorithmException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }

   /**
    * 私钥匙加密或解密
    * 
    * @param content
    * @param privateKeyStr
    * @return
    */
   public static String encryptByprivateKey(String content, String privateKeyStr, int opmode) {
      // 私钥要用PKCS8进行处理
      PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
      KeyFactory keyFactory;
      PrivateKey privateKey;
      Cipher cipher;
      byte[] result;
      String text = null;
      try {
         keyFactory = KeyFactory.getInstance("RSA");
         // 还原Key对象
         privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
         cipher = Cipher.getInstance("RSA");
         cipher.init(opmode, privateKey);
         if (opmode == Cipher.ENCRYPT_MODE) { // 加密
            result = cipher.doFinal(content.getBytes());
            text = Base64.encodeBase64String(result);
         } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
            result = cipher.doFinal(Base64.decodeBase64(content));
            text = new String(result, "UTF-8");
         }

      } catch (Exception e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      return text;
   }

   /**
    * 公钥匙加密或解密
    * 
    * @param content
    * @param privateKeyStr
    * @return
    */
   public static String encryptByPublicKey(String content, String publicKeyStr, int opmode) {
      // 公钥要用X509进行处理
      X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
      KeyFactory keyFactory;
      PublicKey publicKey;
      Cipher cipher;
      byte[] result;
      String text = null;
      try {
         keyFactory = KeyFactory.getInstance("RSA");
         // 还原Key对象
         publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
         cipher = Cipher.getInstance("RSA");
         cipher.init(opmode, publicKey);
         if (opmode == Cipher.ENCRYPT_MODE) { // 加密
            result = cipher.doFinal(content.getBytes());
            text = Base64.encodeBase64String(result);
         } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
            result = cipher.doFinal(Base64.decodeBase64(content));
            text = new String(result, "UTF-8");
         }
      } catch (Exception e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      return text;
   }

   // 测试方法
   public static void main(String[] args) {
      /**
       * 注意: 私钥加密必须公钥解密 公钥加密必须私钥解密
       */
      System.out.println("-------------生成两对秘钥,分别发送方和接收方保管-------------");
      RSAUtil.generateKey();
      System.out.println("公钥匙给接收方:" + RSAUtil.publicKey);
      System.out.println("私钥给发送方:" + RSAUtil.privateKey);

      System.out.println("-------------第一个栗子,私钥加密公钥解密-------------");
      // String textsr = "早啊,你吃早饭了吗?O(∩_∩)O~";
      // // 私钥加密
      // String cipherText = RSAUtil.encryptByprivateKey(textsr,
      // RSAUtil.privateKey, Cipher.ENCRYPT_MODE);
      // System.out.println("发送方用私钥加密后:" + cipherText);
      // // 公钥解密
      // String text = RSAUtil.encryptByPublicKey(cipherText,
      // RSAUtil.publicKey, Cipher.DECRYPT_MODE);
      // System.out.println("接收方用公钥解密后:" + text);

      System.out.println("-------------第二个栗子,公钥加密私钥解密-------------");
      // 公钥加密
      String textsr = "吃过啦!你吃了吗?O(∩_∩)O~";

      String cipherText = RSAUtil.encryptByPublicKey(textsr, RSAUtil.publicKey, Cipher.ENCRYPT_MODE);
      System.out.println("接收方用公钥加密后:" + cipherText);
      // 私钥解密
      String text = RSAUtil.encryptByprivateKey(cipherText, RSAUtil.privateKey, Cipher.DECRYPT_MODE);
      System.out.print("发送方用私钥解密后:" + text);
   }

}

使用公钥加密和私钥解密案例

/**
 * 1.生成公钥和私钥**对
 * 2.使用公钥进行加密
 * 3.使用私钥进行解密
 * @author xiaoming
 * @Date 2019/10/11
 */
public class Test001 {
    public static void main(String[] args) {
        //1.生成公钥和私钥**对
        RSAUtil.generateKey();
        System.out.println("公钥:" + RSAUtil.publicKey);
        System.out.println("私钥:" + RSAUtil.privateKey);

        //2.使用公钥进行加密
        String content = "xiaoming";
        String encryptByPublicKey = RSAUtil.encryptByPublicKey(content, RSAUtil.publicKey, Cipher.ENCRYPT_MODE);
        System.out.println("加密后:" + encryptByPublicKey);

        //3.使用私钥进行解密
        String encryptByprivateKey = RSAUtil.encryptByprivateKey(encryptByPublicKey, RSAUtil.privateKey, Cipher.DECRYPT_MODE);
        System.out.println("解密后:" + encryptByprivateKey);
    }
}