对称加密与非对称加密

595 阅读3分钟

前言:

因为加密算法用的比较多,这里就常用的加密算法(如AES、DES、MD5、SHA1、SHA256、SHA512、RSA等加密算法)基于基本用法结合实际应用做一个总结笔记。因为加密算法的具体方法与类都在jdk中有封装好,关于里面的详细逻辑会在后面的章节里写出来,这里仅以应用为主。

一、对称加密:双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密。

优点: 速度快,对称性加密通常在消息发送方需要加密大量数据时使用,算法公开、计算量小、加密速度快、加密效率高。

缺点: 在数据传送前,发送方和接收方必须商定好秘钥,然后 使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。

1.1,  对称加密之AES加密

	//AES加密
	public static byte[] encrypt(String content, String password) {  
        try {             
                KeyGenerator kgen = KeyGenerator.getInstance("AES");  //(对称)密钥生成器
                kgen.init(128, new SecureRandom(password.getBytes()));  //显式地初始化 KeyGenerator(通过调用 init 方法)
                SecretKey secretKey = kgen.generateKey();  
                byte[] enCodeFormat = secretKey.getEncoded();  
                SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");  
                Cipher cipher = Cipher.getInstance("AES");// 创建密码器  
                byte[] byteContent = content.getBytes("utf-8");  
                cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(byteContent);  
                return result; // 加密  
        } catch (Exception e) {  
        } 
        return null;  
	}  //AES加密
	public static byte[] encrypt(String content, String password) {  
        try {             
                KeyGenerator kgen = KeyGenerator.getInstance("AES");  //(对称)密钥生成器
                kgen.init(128, new SecureRandom(password.getBytes()));  //显式地初始化 KeyGenerator(通过调用 init 方法)
                SecretKey secretKey = kgen.generateKey();  
                byte[] enCodeFormat = secretKey.getEncoded();  
                SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");  
                Cipher cipher = Cipher.getInstance("AES");// 创建密码器  
                byte[] byteContent = content.getBytes("utf-8");  
                cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(byteContent);  
                return result; // 加密  
        } catch (Exception e) {  
        } 
        return null;  
	}  

1.2,  对称加密之AES解密

	//AES解密
	public static byte[] decrypt(byte[] content, String password) {  
        try {  
                 KeyGenerator kgen = KeyGenerator.getInstance("AES");  
                 kgen.init(128, new SecureRandom(password.getBytes()));  
                 SecretKey secretKey = kgen.generateKey();  
                 byte[] enCodeFormat = secretKey.getEncoded();  
                 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");              
                 Cipher cipher = Cipher.getInstance("AES");// 创建密码器  
                cipher.init(Cipher.DECRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(content);  
                return result; // 加密  
        } catch (Exception e) {
                e.printStackTrace();  
        } 
        return null;  
	}  //AES解密
	public static byte[] decrypt(byte[] content, String password) {  
        try {  
                 KeyGenerator kgen = KeyGenerator.getInstance("AES");  
                 kgen.init(128, new SecureRandom(password.getBytes()));  
                 SecretKey secretKey = kgen.generateKey();  
                 byte[] enCodeFormat = secretKey.getEncoded();  
                 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");              
                 Cipher cipher = Cipher.getInstance("AES");// 创建密码器  
                cipher.init(Cipher.DECRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(content);  
                return result; // 加密  
        } catch (Exception e) {
                e.printStackTrace();  
        } 
        return null;  
	}  

1.3,测试结果
测试结果

1.4,应用

该AES适合加密字符串,当然也可以加密文件如音视频媒体文件、可执行文件等,但这种加密对于大的文件比较耗时,下面贴出自己平常使用中的AES加密算法,这个是另外一种AES加密,但这种对于加密字符串有缺点,

  • 密钥必须是16位的
  • 待加密内容的长度必须是16的倍数,如果不是16的倍数,就会出异常

这里是代码:

	//手机常用路径记录/sdcard/DCIM/Camera/VID_20140217_144346.mp4
	// 原文件
	private static final String filePath = "F:/惊鸿一面mv.mp4";
	// 加密后的文件
	private static final String outPath = "F:/惊鸿一面mvAES加密.mp4";
	// 加密再解密后的文件
	private static final String inPath = "F:/惊鸿一面mvAES解密.mp4";		// 原文件
	private static final String filePath = "F:/惊鸿一面mv.mp4";
	// 加密后的文件
	private static final String outPath = "F:/惊鸿一面mvAES加密.mp4";
	// 加密再解密后的文件
	private static final String inPath = "F:/惊鸿一面mvAES解密.mp4";	
	//AES加密文件算法
	private void encrypt() throws Exception{
		FileInputStream fis = new FileInputStream(filePath);
		FileOutputStream fos = new FileOutputStream(outPath);
		SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),// Length is 16 byte
				"AES");
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(Cipher.ENCRYPT_MODE, sks);
		CipherOutputStream cos = new CipherOutputStream(fos, cipher);
		int b;
		byte[] d = new byte[8];
		while ((b = fis.read(d)) != -1) {
			cos.write(d, 0, b);
		}
		// Flush and close streams.
		cos.flush();
		cos.close();
		fis.close();
	}//AES加密文件算法
	private void encrypt() throws Exception{
		FileInputStream fis = new FileInputStream(filePath);
		FileOutputStream fos = new FileOutputStream(outPath);
		SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),// Length is 16 byte
				"AES");
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(Cipher.ENCRYPT_MODE, sks);
		CipherOutputStream cos = new CipherOutputStream(fos, cipher);
		int b;
		byte[] d = new byte[8];
		while ((b = fis.read(d)) != -1) {
			cos.write(d, 0, b);
		}
		// Flush and close streams.
		cos.flush();
		cos.close();
		fis.close();
	}
	//AES解密文件算法
	private void decrypt() throws Exception,{
		FileInputStream fis = new FileInputStream(outPath);
		FileOutputStream fos = new FileOutputStream(inPath);
		SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),
				"AES");
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(Cipher.DECRYPT_MODE, sks);
		CipherInputStream cis = new CipherInputStream(fis, cipher);
		int b;
		byte[] d = new byte[8];
		while ((b = cis.read(d)) != -1) {
			fos.write(d, 0, b);
		}
		fos.flush();
		fos.close();
		cis.close();
	}//AES解密文件算法
	private void decrypt() throws Exception,{
		FileInputStream fis = new FileInputStream(outPath);
		FileOutputStream fos = new FileOutputStream(inPath);
		SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(),
				"AES");
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(Cipher.DECRYPT_MODE, sks);
		CipherInputStream cis = new CipherInputStream(fis, cipher);
		int b;
		byte[] d = new byte[8];
		while ((b = cis.read(d)) != -1) {
			fos.write(d, 0, b);
		}
		fos.flush();
		fos.close();
		cis.close();
	}

2.1,对称加密之DES加密
des对称加密算法现不推荐使用,因为des使用56位密钥,以现代计算能力,24小时内即可被破解,另外密码key须是8的整数倍,下面还是将算法列举出来

	//des加密算法
	public static byte[] encrypt2(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对象  
        cipher.init(Cipher.ENCRYPT_MODE, securekey, random);  
        //现在,获取数据并加密  
        //正式执行加密操作  
        return cipher.doFinal(datasource);  
        }catch(Throwable e){  
                e.printStackTrace();  
        }  
        return null;  
	}  //des加密算法
	public static byte[] encrypt2(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对象  
        cipher.init(Cipher.ENCRYPT_MODE, securekey, random);  
        //现在,获取数据并加密  
        //正式执行加密操作  
        return cipher.doFinal(datasource);  
        }catch(Throwable e){  
                e.printStackTrace();  
        }  
        return null;  
	}  

2.2,对称加密之DES解密

	//des解密算法
	private static byte[] decrypt2(byte[] src, String password) throws Exception {  
        // DES算法要求有一个可信任的随机数源  
        SecureRandom random = new SecureRandom();  
        // 创建一个DESKeySpec对象  
        DESKeySpec desKey = new DESKeySpec(password.getBytes());  
        // 创建一个密匙工厂  
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");  
        // 将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);  
	}  //des解密算法
	private static byte[] decrypt2(byte[] src, String password) throws Exception {  
        // DES算法要求有一个可信任的随机数源  
        SecureRandom random = new SecureRandom();  
        // 创建一个DESKeySpec对象  
        DESKeySpec desKey = new DESKeySpec(password.getBytes());  
        // 创建一个密匙工厂  
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");  
        // 将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);  
	}  

2.3,测试结果

测试结果

3.1,对称加密之SHA加密

	/**
     * SHA加密
     *
     * @param strSrc
     *            明文
     * @return 加密之后的密文
     */
    public static String shaEncrypt(String strSrc) {
        MessageDigest md = null;
        String strDes = null;
        byte[] bt = strSrc.getBytes();
        try {
            md = MessageDigest.getInstance("SHA-1");// 将此换成SHA-1、SHA-512、SHA-384等参数
            md.update(bt);
            strDes = bytes2Hex(md.digest()); // to HexString
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        return strDes;
    }


    /**
     * byte数组转换为16进制字符串
     *
     * @param bts
     *            数据源
     * @return 16进制字符串
     */
    public static String bytes2Hex(byte[] bts) {
        String des = "";
        String tmp = null;
        for (int i = 0; i < bts.length; i++) {
            tmp = (Integer.toHexString(bts[i] & 0xFF));
            if (tmp.length() == 1) {
                des += "0";
            }
            des += tmp;
        }
        return des;
    }/**
     * SHA加密
     *
     * @param strSrc
     *            明文
     * @return 加密之后的密文
     */
    public static String shaEncrypt(String strSrc) {
        MessageDigest md = null;
        String strDes = null;
        byte[] bt = strSrc.getBytes();
        try {
            md = MessageDigest.getInstance("SHA-1");// 将此换成SHA-1、SHA-512、SHA-384等参数
            md.update(bt);
            strDes = bytes2Hex(md.digest()); // to HexString
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        return strDes;
    }


    /**
     * byte数组转换为16进制字符串
     *
     * @param bts
     *            数据源
     * @return 16进制字符串
     */
    public static String bytes2Hex(byte[] bts) {
        String des = "";
        String tmp = null;
        for (int i = 0; i < bts.length; i++) {
            tmp = (Integer.toHexString(bts[i] & 0xFF));
            if (tmp.length() == 1) {
                des += "0";
            }
            des += tmp;
        }
        return des;
    }

SHA系列的算法属于不可逆的单向哈希算法,主要应用还是验证如数字签名等。

3.2,测试结果

测试结果

二、非对称加密:一对密钥由公钥和私钥组成(可以使用很多对密钥)。私钥解密公钥加密数据,公钥解密私钥加密数据(私钥公钥可以互相加密解密)。

私钥只能由一方保管,不能外泄。公钥可以交给任何请求方。

1.1,对称加密算法之MD5加解密

MD5属于hash算法,严格意义上并不算加密算法,但是这里还是列举一下其用法:

     /*** 
     * MD5加码 生成32位md5码 
     */  
    public static String string2MD5(String inStr){  
        MessageDigest md5 = null;  
        try{  
            md5 = MessageDigest.getInstance("MD5");  
        }catch (Exception e){  
            System.out.println(e.toString());  
            e.printStackTrace();  
            return "";  
        }  
        char[] charArray = inStr.toCharArray();  
        byte[] byteArray = new byte[charArray.length];  
  
        for (int i = 0; i < charArray.length; i++)  
            byteArray[i] = (byte) charArray[i];  
        byte[] md5Bytes = md5.digest(byteArray);  
        StringBuffer hexValue = new StringBuffer();  
        for (int i = 0; i < md5Bytes.length; i++){  
            int val = ((int) md5Bytes[i]) & 0xff;  
            if (val < 16)  
                hexValue.append("0");  
            hexValue.append(Integer.toHexString(val));  
        }  
        return hexValue.toString();  
  
    }  
  
    /** 
     * 加密解密算法 执行一次加密,两次解密 
     */   
    public static String convertMD5(String inStr){  
  
        char[] a = inStr.toCharArray();  
        for (int i = 0; i < a.length; i++){  
            a[i] = (char) (a[i] ^ 't');  
        }  
        String s = new String(a);  
        return s;  
  
    }  

1.2,测试结果

测试结果

2.1,RSA加解密算法

     public static void generateKey() {  
        try {  
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");  
            kpg.initialize(1024);  
            KeyPair kp = kpg.genKeyPair();  
            PublicKey pbkey = kp.getPublic();  
            PrivateKey prkey = kp.getPrivate();  
            // 保存公钥  
            FileOutputStream f1 = new FileOutputStream("pubkey.dat");  
            ObjectOutputStream b1 = new ObjectOutputStream(f1);  
            b1.writeObject(pbkey);  
            // 保存私钥  
            FileOutputStream f2 = new FileOutputStream("privatekey.dat");  
            ObjectOutputStream b2 = new ObjectOutputStream(f2);  
            b2.writeObject(prkey);  
        } catch (Exception e) {  
        }  
    }  
    public static void encrypt() throws Exception {  
        String s = "helloworld";  
        // 获取公钥及参数e,n  
        FileInputStream f = new FileInputStream("pubkey.dat");  
        ObjectInputStream b = new ObjectInputStream(f);  
        RSAPublicKey pbk = (RSAPublicKey) b.readObject();  
        BigInteger e = pbk.getPublicExponent();  
        BigInteger n = pbk.getModulus();  
        System.out.println("e= " + e);  
        System.out.println("n= " + n);  
        // 获取明文m  
        byte ptext[] = s.getBytes("UTF-8");  
        BigInteger m = new BigInteger(ptext);  
        // 计算密文c  
        BigInteger c = m.modPow(e, n);  
        System.out.println("c= " + c);  
        // 保存密文  
        String cs = c.toString();  
        BufferedWriter out =  
            new BufferedWriter(  
                new OutputStreamWriter(new FileOutputStream("encrypt.dat")));  
        out.write(cs, 0, cs.length());  
        out.close();  
    }  
    public static void decrypt() throws Exception {  
        // 读取密文  
        BufferedReader in =  
            new BufferedReader(  
                new InputStreamReader(new FileInputStream("encrypt.dat")));  
        String ctext = in.readLine();  
        BigInteger c = new BigInteger(ctext);  
        // 读取私钥  
        FileInputStream f = new FileInputStream("privatekey.dat");  
        ObjectInputStream b = new ObjectInputStream(f);  
        RSAPrivateKey prk = (RSAPrivateKey) b.readObject();  
        BigInteger d = prk.getPrivateExponent();  
        // 获取私钥参数及解密  
        BigInteger n = prk.getModulus();  
        System.out.println("d= " + d);  
        System.out.println("n= " + n);  
        BigInteger m = c.modPow(d, n);  
        // 显示解密结果  
        System.out.println("m= " + m);  
        byte[] mt = m.toByteArray();  
        String s = new String(mt,"UTF-8");
        System.out.println("\n解密后的明文:" + s);
    }  

	这里只是简单地利用了公钥加密,私钥解密,较为全面的还有私钥加密,公钥解密,更为全面的请参考Central-Perk的博客这里只是简单地利用了公钥加密,私钥解密,较为全面的还有私钥加密,公钥解密,更为全面的请参考Central-Perk的博客

2.2,测试结果

测试结果