基于RSA算法的Java加密解密与数字签名

package com.face.utils.rsa;

import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateCrtKey;
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;

/**
 * RSA 非对称加密算法的理论依据:基于大数因子分解数学难题。
 *
 * RSA数字签名中为什么不能先加密后签名?
 *
 * 用RSA给别人发送一个信息,首先要用私钥加密签名,
 * 然后再用对方的公钥加密信息和签名,把消息发送给对方。
 *
 * @desc 使用要求:先签名,再加密
 *
 * RSA算法中:公钥长度 << 远小于 私钥长度,必须遵循[公钥加密 则 私钥解密],[私钥加密 则 公钥解密]这两个原则。
 *
 * 使用流程:data --> 签名 --> 加密 --> 解密 --> 校验签名 --> data
 *
 * 加/解密原则:
 */
public abstract class RSACoder {

    /**
     * 数字签名密钥算法
     */
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * 数字签名 - 签名/验证算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    // 公钥
    private static final String PUBLIC_KEY = "RSAPublicKey";
    // 私钥
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * RSA - 密钥长度,默认1024位,密钥长度必须是64的倍数,范围在512 ~ 65536 之间。
     */
    private static final int keySize = 512;

    /**
     * @desc 签名(私钥)
     * @param data  要签名的数据
     * @param privateKey 私钥
     * @return byte[] 数字签名
     */
    public static byte[] sign(byte[] data, byte[] privateKey) throws NoSuchAlgorithmException,
            InvalidKeySpecException,
            InvalidKeyException,
            SignatureException {

        // 转换私钥材料
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);

        // 实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 生成私钥 或者 获取已经生成保存好的私钥
        PrivateKey privKey = keyFactory.generatePrivate(keySpec);

        // 实例化 Signature
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

        // 初始化 Signature
        signature.initSign(privKey);
        // 更新
        signature.update(data);

        // Returns the signature bytes - 返回签名字节
        return signature.sign();
    }


    /**
     * @desc 校验(公钥) - 验证传入的签名
     * @param data 待校验的数据
     * @param publicKey 公钥
     * @param sign 数字签名
     * @return boolean - 成功:返回 true,失败:返回 false
     * @throws Exception
     */
    public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception {
        // 转换公钥材料
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);

        // 实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 生成密钥
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        // 实例化 Signature
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

        // 初始化 Signature
        signature.initVerify(pubKey);
        // 更新
        signature.update(data);

        // 验证 - 验证传入的签名
        return signature.verify(sign);

    }


    /**
     * @desc 获取私钥 - 从容器Map中
     * @param keyMap  密钥Map
     * @return byte[] 私钥
     * @throws Exception
     */
    public static byte[] getPrivateKey(Map<String,Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
     * @desc 获取公钥 - 从容器Map中
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }


    /**
     * @desc 初始化密钥对
     * @return Map - 密钥Map
     * @throws NoSuchAlgorithmException
     */
    public static Map<String,Object> initKey() throws NoSuchAlgorithmException {
        // 实例化密钥对生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);

        // 初始化密钥对生成器
        keyPairGen.initialize(keySize);

        // 生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();

        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        // 封装密钥
        Map<String,Object> keyMap = new HashMap<String,Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;
    }


    /**********************************【加密与解密】*********************************/


    // 加密


    /**
     * @desc 公钥加密
     * @param data - 待加密数据
     * @param pubKey - 公钥
     * @return byte[] - 加密后数据
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] pubKey) throws Exception {
        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        byte[] result = cipher.doFinal(data);
        System.out.println("加密结果:" + Base64.encode(result));
        
        return cipher.doFinal(data);
    }


    /**
     * @desc 私钥加密
     * @param data - 待加密数据
     * @param privKey - 私钥
     * @return byte[] - 加密后数据
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] privKey) throws Exception {

        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    

    // 解密
    /**
     * @desc 私钥解密
     * @param data 待解密数据
     * @param privKey 私钥
     * @return byte[] 解密数据
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] privKey) throws Exception {
        // 取得私钥
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        // 解密数据
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

    /**
     * @desc 公钥解密
     * @param data
     * @param pubKey - 公钥
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] pubKey) throws Exception {
        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }






}

 

【测试 - 签名与加/解密】

 

package com.test.rsa;

import com.face.utils.rsa.RSACoder;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.junit.Before;
import org.junit.Test;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.util.Map;

public class TestRSACoder {


    // 公钥 \ 私钥
    private byte[] publicKey;
    private byte[] privateKey;

    @Before
    public void initKey() throws Exception {

        Map<String,Object> keyMap = RSACoder.initKey();

        publicKey = RSACoder.getPublicKey(keyMap);
        privateKey = RSACoder.getPrivateKey(keyMap);

        System.out.println("公钥:" + Base64.encode(publicKey));
        System.out.println("私钥:" + Base64.encode(privateKey));

    }

    /**
     * @desc 测试签名/校验
     * @throws Exception
     */
    @Test
    public void testSign() throws Exception {
        String myData = "我的账号:accout: no-654321";
        // 生成签名
        byte[] sign = RSACoder.sign(myData.getBytes(), privateKey);
        System.out.println("生成的签名:" + Base64.encode(sign));

        // 验证签名
        boolean verifyResult = RSACoder.verify(myData.getBytes(), publicKey,sign);

        System.out.println("签名验证结果:" + verifyResult);

    }

    @Test
    public void testEncrypt() throws Exception {

        System.out.println("------------ 私钥加密 <--> 公钥解密 ------------");

        String input = "RSA原始数据:密码123abc";
        byte[] byteData = input.getBytes();

        System.out.println("原文:" + input);

        // 加密
        byte[] encodeData = RSACoder.encryptByPrivateKey(byteData,privateKey);
        System.out.println("加密后:" + Base64.encode(encodeData));

        // 解密
        byte[] decodeData = RSACoder.decryptByPublicKey(encodeData, publicKey);
        System.out.println("解密结果:" + new String(decodeData));




    }






}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值