JAVA开发经验(二):常用工具类1.5-加解密-RSA

摘要说明:

RSA:RSA加密算法是一种非对称加密算法。在公开密钥加密电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

       RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。 

        RSA的本质是一种非对称加解密算法。

Maven依赖:

	<dependencies>
		<!-- Apache Commons IO库包含实用程序类,流实现,文件过滤器,文件比较器,字节序转换类等等。 -->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.0.1</version>
		</dependency>

		<!-- Apache Commons Codec软件包包含各种格式的简单编码器和解码器,如Base64和Hexadecimal。除了这些广泛使用的编码器和解码器之外,编解码器包还维护着一组语音编码实用程序。 -->
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.9</version>
		</dependency>
	</dependencies>

java工具类:

     解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到解密者,解密者用私钥解密将密文解码为明文。

       以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为密匙,将这个KEY始终保存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。接下来通过网络把这个公钥传给甲,甲收到公钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进行解码了

       RSAUtil主要包括秘钥生成,公钥加密,私钥解密,私钥加密,私钥解密等方法:


package com.tit.taf.encryption;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

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

/**
 * @模块名:taf
 * @包名:com.tit.taf.encryption
 * @类名称: RSAUtil
 * @类描述:【类描述】
 * @版本:1.0
 * @创建人:cc
 * @创建时间:2018年8月27日上午10:06:50
 */

public class RSAUtil {
    public static final String CHARSET = "UTF-8";

    public static final String RSA_ALGORITHM = "RSA";

    /**
     * 
     * @方法名:createKeys
     * @方法描述【方法功能描述】 生成加解密公钥和私钥
     * @param keySize 秘钥大小
     * @return 公钥:publicKey,私钥:privateKey
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:22:40
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:22:40
     */
    public static Map < String, String > createKeys(int keySize) {
        // 为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try {
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        }
        catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }

        // 初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        // 生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        // 得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
        // 得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
        Map < String, String > keyPairMap = new HashMap < String, String >();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);

        return keyPairMap;
    }

    /**
     * 
     * @方法名:getPublicKey
     * @方法描述【方法功能描述】 得到公钥
     * @param publicKey 密钥字符串(经过base64编码)
     * @return 公钥
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:30:05
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:30:05
     */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    /**
     * 
     * @方法名:getPrivateKey
     * @方法描述【方法功能描述】 得到私钥
     * @param privateKey 密钥字符串(经过base64编码)
     * @return 得到私钥
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:30:31
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:30:31
     */
    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException,
            InvalidKeySpecException {
        // 通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }

    /**
     * 
     * @方法名:publicEncrypt
     * @方法描述【方法功能描述】 公钥加密
     * @param data 明文
     * @param publicKey 公钥
     * @return 公钥加密密文
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:30:54
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:30:54
     */
    public static String publicEncrypt(String data, String publicKey) {
        try {
            RSAPublicKey rsaPublicKey = RSAUtil.getPublicKey(publicKey);
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET),
                    rsaPublicKey.getModulus().bitLength()));
        }
        catch (Exception e) {
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 
     * @方法名:privateDecrypt
     * @方法描述【方法功能描述】私钥解密
     * @param data 公钥加密密文
     * @param privateKey 私钥
     * @return 私钥解密密文
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:31:52
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:31:52
     */
    public static String privateDecrypt(String data, String privateKey) {
        try {
            RSAPrivateKey rsaPrivateKey = RSAUtil.getPrivateKey(privateKey);
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), rsaPrivateKey
                    .getModulus().bitLength()), CHARSET);
        }
        catch (Exception e) {
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 
     * @方法名:privateEncrypt
     * @方法描述【方法功能描述】 私钥加密
     * @param data 明文
     * @param privateKey 私钥
     * @return 私钥加密密文
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:32:41
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:32:41
     */
    public static String privateEncrypt(String data, String privateKey) {
        try {
            RSAPrivateKey rsaPrivateKey = RSAUtil.getPrivateKey(privateKey);
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, rsaPrivateKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET),
                    rsaPrivateKey.getModulus().bitLength()));
        }
        catch (Exception e) {
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 
     * @方法名:publicDecrypt
     * @方法描述【方法功能描述】 公钥解密
     * @param data 私钥加密密文
     * @param publicKey 公钥
     * @return 公钥解密明文
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:33:16
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:33:16
     */
    public static String publicDecrypt(String data, String publicKey) {
        try {
            RSAPublicKey rsaPublicKey = RSAUtil.getPublicKey(publicKey);
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), rsaPublicKey
                    .getModulus().bitLength()), CHARSET);
        }
        catch (Exception e) {
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 
     * @方法名:rsaSplitCodec
     * @方法描述【方法功能描述】RSA加密算法对于加密数据的长度是有要求的。一般来说,明文长度小于等于密钥长度(Bytes)-11。解决这个问题需要对较长的明文进行分段加解密
     * @param cipher
     * @param opmode
     * @param datas
     * @param keySize
     * @return
     * @修改描述【修改描述】
     * @版本:1.0
     * @创建人:cc
     * @创建时间:2018年8月27日 上午10:37:59
     * @修改人:cc
     * @修改时间:2018年8月27日 上午10:37:59
     */
    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
        int maxBlock = 0;
        if (opmode == Cipher.DECRYPT_MODE) {
            maxBlock = keySize / 8;
        }
        else {
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try {
            while (datas.length > offSet) {
                if (datas.length - offSet > maxBlock) {
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                }
                else {
                    buff = cipher.doFinal(datas, offSet, datas.length - offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        }
        catch (Exception e) {
            throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        IOUtils.closeQuietly(out);
        return resultDatas;
    }

    public static void main(String[] args) {
        try {
            Map < String, String > keyMap = RSAUtil.createKeys(1024);
            String publicKey = keyMap.get("publicKey");
            String privateKey = keyMap.get("privateKey");
            System.out.println("公钥:" + publicKey);
            System.out.println("私钥" + privateKey);

            String str = "cc";
            System.out.println("公钥加密——私钥解密");
            String encodedData = RSAUtil.publicEncrypt(str, publicKey);
            System.out.println("密文:" + encodedData);
            String decodedData = RSAUtil.privateDecrypt(encodedData, privateKey);
            System.out.println("解密后文字: " + decodedData);

            System.out.println("私钥加密——公钥解密");
            String encodedData1 = RSAUtil.privateEncrypt(str, privateKey);
            System.out.println("密文:" + encodedData1);
            String decodedData1 = RSAUtil.publicDecrypt(encodedData1, publicKey);
            System.out.println("解密后文字: " + decodedData1);
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/u010904188/article/details/82108790
今日推荐