RSA加密

生成公钥私钥配对加解密

注意:

 

RSA 加密或签名后的结果是不可读的二进制,使用时经常会转为 BASE64 码再传输。

RSA 加密时,对要加密数据的大小有限制,最大不大于密钥长度。例如在使用 1024 bit 的密钥时(genrsa -out rsa_private_key.pem 1024),最大可以加密 1024/8=128 Bytes 的数据。数据大于 128 Bytes 时,需要对数据进行分组加密(如果数据超限,加解密时会失败,openssl 函数会返回 false),分组加密后的加密串拼接成一个字符串后发送给客户端。

为了保证每次加密的结果都不同,RSA 加密时会在待加密数据后拼接一个随机字符串,再进行加密。不同的填充方式 Padding 表示这个字符串的不同长度,在对超限数据进行分组后,会按照这个 Padding 指定的长度填入随机字符串。例如如果 Padding 填充方式使用默认的 OPENSSL_PKCS1_PADDING(需要占用 11 个字节用于填充),那么明文长度最多只能就是 128-11=117 Bytes。

一般默认使用 OPENSSL_PKCS1_PADDING。PHP 支持的 Padding 有 OPENSSL_PKCS1_PADDING、OPENSSL_SSLV23_PADDING、OPENSSL_PKCS1_OAEP_PADDING 和 OPENSSL_NO_PADDING。

接收方解密时也需要分组。将加密后的原始二进制数据(对于经过 BASE64 的数据,需要解码),每 128 Bytes 分为一组,然后再进行解密。解密后,根据 Padding 的长度丢弃随机字符串,把得到的原字符串拼接起来,就得到原始报文。

import java.io.IOException;

import java.security.KeyFactory;

import java.security.NoSuchAlgorithmException;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.spec.InvalidKeySpecException;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

 

import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

 

import org.apache.commons.io.output.ByteArrayOutputStream;

import org.springframework.util.Base64Utils;

 

import com.bessky.hrmis.common.uconfig.UConfigHelper;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;

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

 

public class RSAHelper

{

    private static final String publicKeyBase64 = "";

 

    private static final String privateKeyBase64 = "";

    

    /**

     * RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024

     */

    public static final int KEY_SIZE = 2048;

 

    /**

     * 获取公钥对象

     *

     * @param publicKeyBase64

     * @return

     * @throws InvalidKeySpecException

     * @throws NoSuchAlgorithmException

     */

    public static PublicKey getPublicKey(String publicKeyBase64) throws InvalidKeySpecException, NoSuchAlgorithmException, Base64DecodingException

    {

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        X509EncodedKeySpec publicpkcs8KeySpec = new X509EncodedKeySpec(Base64.decode(publicKeyBase64));

        PublicKey publicKey = keyFactory.generatePublic(publicpkcs8KeySpec);

        return publicKey;

    }

 

    /**

     * 获取私钥对象

     *

     * @param privateKeyBase64

     * @return

     * @throws NoSuchAlgorithmException

     * @throws InvalidKeySpecException

     */

    public static PrivateKey getPrivateKey(String privateKeyBase64) throws NoSuchAlgorithmException, InvalidKeySpecException, Base64DecodingException

    {

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PKCS8EncodedKeySpec privatekcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyBase64));

        PrivateKey privateKey = keyFactory.generatePrivate(privatekcs8KeySpec);

        return privateKey;

    }

 

    /**

     * 使用工钥加密

     *

     * @param content         待加密内容

     * @param publicKeyBase64 公钥 base64 编码

     * @return 经过 base64 编码后的字符串

     */

    public static String encipher(String content)

    {

        return encipher(content, publicKeyBase64, KEY_SIZE / 8 - 11);

    }

 

    /**

     * 使用公司钥加密(分段加密)

     *

     * @param content         待加密内容

     * @param publicKeyBase64 公钥 base64 编码

     * @param segmentSize     分段大小,一般小于 keySize/8(段小于等于0时,将不使用分段加密)

     * @return 经过 base64 编码后的字符串

     */

    public static String encipher(String content, String publicKeyBase64, int segmentSize)

    {

        try

        {

            PublicKey publicKey = getPublicKey(publicKeyBase64);

            return encipher(content, publicKey, segmentSize);

        }

        catch (Exception e)

        {

            e.printStackTrace();

            return null;

        }

    }

 

    /**

     * 分段加密

     *

     * @param ciphertext  密文

     * @param key         加密秘钥

     * @param segmentSize 分段大小,<=0 不分段

     * @return

     */

    public static String encipher(String ciphertext, java.security.Key key, int segmentSize)

    {

        try

        {

            // 用公钥加密

            byte[] srcBytes = ciphertext.getBytes();

 

            // Cipher负责完成加密或解密工作,基于RSA

            Cipher cipher = Cipher.getInstance("RSA");

            // 根据公钥,对Cipher对象进行初始化

            cipher.init(Cipher.ENCRYPT_MODE, key);

            byte[] resultBytes = null;

 

            if (segmentSize > 0)

                resultBytes = cipherDoFinal(cipher, srcBytes, segmentSize); // 分段加密

            else

                resultBytes = cipher.doFinal(srcBytes);

            String base64Str = Base64Utils.encodeToString(resultBytes);

            return base64Str;

        }

        catch (Exception e)

        {

            e.printStackTrace();

            return null;

        }

    }

 

    /**

     * 分段大小

     *

     * @param cipher

     * @param srcBytes

     * @param segmentSize

     * @return

     * @throws IllegalBlockSizeException

     * @throws BadPaddingException

     * @throws IOException

     */

    public static byte[] cipherDoFinal(Cipher cipher, byte[] srcBytes, int segmentSize) throws IllegalBlockSizeException, BadPaddingException, IOException

    {

        if (segmentSize <= 0)

            throw new RuntimeException("分段大小必须大于0");

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        int inputLen = srcBytes.length;

        int offSet = 0;

        byte[] cache;

        int i = 0;

        // 对数据分段解密

        while (inputLen - offSet > 0)

        {

            if (inputLen - offSet > segmentSize)

            {

                cache = cipher.doFinal(srcBytes, offSet, segmentSize);

            }

            else

            {

                cache = cipher.doFinal(srcBytes, offSet, inputLen - offSet);

            }

            out.write(cache, 0, cache.length);

            i++;

            offSet = i * segmentSize;

        }

        byte[] data = out.toByteArray();

        out.close();

        return data;

    }

 

    /**

     * 使用私钥解密

     *

     * @param contentBase64    待加密内容,base64 编码

     * @param privateKeyBase64 私钥 base64 编码

     * @return

     * @segmentSize 分段大小

     */

    public static String decipher(String contentBase64)

    {

        return decipher(contentBase64, privateKeyBase64, KEY_SIZE / 8);

    }

 

    /**

     * 使用私钥解密(分段解密)

     *

     * @param contentBase64    待加密内容,base64 编码

     * @param privateKeyBase64 私钥 base64 编码

     * @return

     * @segmentSize 分段大小

     */

    public static String decipher(String contentBase64, String privateKeyBase64, int segmentSize)

    {

        try

        {

            PrivateKey privateKey = getPrivateKey(privateKeyBase64);

            return decipher(contentBase64, privateKey, segmentSize);

        }

        catch (Exception e)

        {

            e.printStackTrace();

            return null;

        }

    }

 

    /**

     * 分段解密

     *

     * @param contentBase64 密文

     * @param key           解密秘钥

     * @param segmentSize   分段大小(小于等于0不分段)

     * @return

     */

    public static String decipher(String contentBase64, java.security.Key key, int segmentSize)

    {

        try

        {

            // 用私钥解密

            byte[] srcBytes = Base64Utils.decodeFromString(contentBase64);

            // Cipher负责完成加密或解密工作,基于RSA

            Cipher deCipher = Cipher.getInstance("RSA");

            // 根据公钥,对Cipher对象进行初始化

            deCipher.init(Cipher.DECRYPT_MODE, key);

            byte[] decBytes = null;// deCipher.doFinal(srcBytes);

            if (segmentSize > 0)

                decBytes = cipherDoFinal(deCipher, srcBytes, segmentSize); // 分段加密

            else

                decBytes = deCipher.doFinal(srcBytes);

 

            String decrytStr = new String(decBytes);

            return decrytStr;

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }
    }
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值